From 4ec34c2a5f3038c5d490727167952e25b81e1e19 Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Tue, 28 Jul 2026 16:09:27 +0200 Subject: [PATCH] fix(canvas): un swipe sobre una pantalla tactil en Run ya no panea el canvas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit El caso ownsPointer retornaba sin stopPropagation y el mousedown llegaba al fondo del canvas, cuyo convenio arrastre-izquierdo-panea movia el mundo entero bajo el dedo a mitad de swipe (solo el tap funcionaba). El modelo tactil escucha POINTER events — stream aparte — asi que cortar el mousedown (y el touchstart movil) no le quita nada. Los knobs wokwi conservan el pass-through de siempre. --- frontend/src/components/DynamicComponent.tsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/DynamicComponent.tsx b/frontend/src/components/DynamicComponent.tsx index b85b5786..0f37f8e7 100644 --- a/frontend/src/components/DynamicComponent.tsx +++ b/frontend/src/components/DynamicComponent.tsx @@ -488,7 +488,15 @@ export const DynamicComponent: React.FC = ({ // glass was painting the green dot AND dragging the shield around. (target as { ownsPointer?: boolean }).ownsPointer === true); if (ownsPointer) { - // Let the wokwi component own this pointerdown. + // A declared touch SCREEN (ownsPointer property, not the wokwi tag + // list): its model listens on POINTER events — a separate stream — + // so stopping THIS mousedown costs it nothing, and it must be + // stopped: left-drag that reaches the canvas background pans the + // whole world under the finger mid-swipe. Wokwi knobs keep the + // legacy pass-through, their internal handlers may bind this very + // mouse event. + if ((target as { ownsPointer?: boolean }).ownsPointer === true) e.stopPropagation(); + // Let the component own this pointerdown. return; } e.stopPropagation(); @@ -743,6 +751,13 @@ export const DynamicComponent: React.FC = ({ transformOrigin: 'center center', }} onMouseDownCapture={handleMouseDown} + onTouchStartCapture={(e) => { + // Mobile mirror of the ownsPointer guard: while the sim runs, a + // finger on a declared touch screen is INPUT for the screen (its + // pointer handlers still fire), never a canvas pan/drag gesture. + const t = e.target as { ownsPointer?: boolean }; + if (interactionRunning && t.ownsPointer === true) e.stopPropagation(); + }} onDoubleClick={handleDoubleClick} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}