11/**
22 * Canvas viewport — pan offset and touch event translation.
3- * Two-finger drag pans the canvas. Single touch draws/selects.
3+ * Two-finger drag pans the canvas.
4+ * Single touch only interacts when a tool is active or object is selected.
45 * @module utils/canvasViewport
56 */
67
78/** @type {{ x: number, y: number } } */
89const offset = { x : 0 , y : 0 } ;
910
10- /** @type {{ x: number, y: number, dist: number }|null } */
11+ /** @type {{ x: number, y: number }|null } */
1112let pinch = null ;
1213
14+ /** @type {boolean } */
15+ let singleActive = false ;
16+
1317/**
1418 * Get the current pan offset.
1519 * @returns {{ x: number, y: number } }
@@ -20,23 +24,25 @@ export function getOffset() {
2024
2125/**
2226 * Set up touch handlers on an SVG element.
23- * Single touch → dispatches equivalent mouse events.
24- * Two-finger touch → pans the viewport.
2527 * @param {SVGSVGElement } svg
2628 * @param {(offset: { x: number, y: number }) => void } onPan
29+ * @param {() => boolean } shouldInteract - Returns true if single touch should draw/select
2730 */
28- export function setupTouch ( svg , onPan ) {
31+ export function setupTouch ( svg , onPan , shouldInteract ) {
2932 svg . addEventListener (
3033 'touchstart' ,
3134 ( e ) => {
3235 if ( e . touches . length === 2 ) {
3336 e . preventDefault ( ) ;
37+ singleActive = false ;
3438 const mx = ( e . touches [ 0 ] . clientX + e . touches [ 1 ] . clientX ) / 2 ;
3539 const my = ( e . touches [ 0 ] . clientY + e . touches [ 1 ] . clientY ) / 2 ;
36- pinch = { x : mx , y : my , dist : 0 } ;
40+ pinch = { x : mx , y : my } ;
3741 return ;
3842 }
39- if ( e . touches . length === 1 ) {
43+ if ( e . touches . length === 1 && shouldInteract ( ) ) {
44+ e . preventDefault ( ) ;
45+ singleActive = true ;
4046 dispatchMouse ( svg , 'mousedown' , e . touches [ 0 ] ) ;
4147 }
4248 } ,
@@ -57,7 +63,7 @@ export function setupTouch(svg, onPan) {
5763 onPan ( offset ) ;
5864 return ;
5965 }
60- if ( e . touches . length === 1 ) {
66+ if ( e . touches . length === 1 && singleActive ) {
6167 e . preventDefault ( ) ;
6268 dispatchMouse ( svg , 'mousemove' , e . touches [ 0 ] ) ;
6369 }
@@ -70,14 +76,14 @@ export function setupTouch(svg, onPan) {
7076 pinch = null ;
7177 return ;
7278 }
73- if ( e . changedTouches . length === 1 ) {
79+ if ( singleActive && e . changedTouches . length === 1 ) {
7480 dispatchMouse ( svg , 'mouseup' , e . changedTouches [ 0 ] ) ;
81+ singleActive = false ;
7582 }
7683 } ) ;
7784}
7885
7986/**
80- * Dispatch a synthetic mouse event from a touch point.
8187 * @param {SVGSVGElement } svg
8288 * @param {string } type
8389 * @param {Touch } touch
0 commit comments