@@ -40,6 +40,59 @@ export class PanAndZoom {
4040 ( e : WheelEvent ) => this . #on_wheel( e ) ,
4141 { passive : false } ,
4242 ) ;
43+
44+ let startDistance : number | null = null ;
45+ let startPosition : TouchList | null = null ;
46+
47+ this . target . addEventListener ( "touchstart" , ( e : TouchEvent ) => {
48+ if ( e . touches . length === 2 ) {
49+ startDistance = this . #getDistanceBetweenTouches( e . touches ) ;
50+ } else if ( e . touches . length === 1 ) {
51+ startPosition = e . touches ;
52+ }
53+ } ) ;
54+
55+ this . target . addEventListener ( "touchmove" , ( e : TouchEvent ) => {
56+ if ( e . touches . length === 2 ) {
57+ if ( startDistance !== null ) {
58+ const currentDistance = this . #getDistanceBetweenTouches(
59+ e . touches ,
60+ ) ;
61+ if ( Math . abs ( startDistance - currentDistance ) < 10 ) {
62+ const scale = ( currentDistance / startDistance ) * 4 ;
63+ if ( startDistance < currentDistance ) {
64+ this . #handle_zoom( scale * - 1 ) ;
65+ } else {
66+ this . #handle_zoom( scale ) ;
67+ }
68+ }
69+ startDistance = currentDistance ;
70+ }
71+ } else if ( e . touches . length === 1 && startPosition !== null ) {
72+ const sx = startPosition [ 0 ] ?. clientX ?? 0 ;
73+ const sy = startPosition [ 0 ] ?. clientY ?? 0 ;
74+ const ex = e . touches [ 0 ] ?. clientX ?? 0 ;
75+ const ey = e . touches [ 0 ] ?. clientY ?? 0 ;
76+ if ( Math . abs ( sx - ex ) < 100 && Math . abs ( sy - ey ) < 100 ) {
77+ this . #handle_pan( sx - ex , sy - ey ) ;
78+ }
79+ startPosition = e . touches ;
80+ }
81+ } ) ;
82+
83+ this . target . addEventListener ( "touchend" , ( ) => {
84+ startDistance = null ;
85+ startPosition = null ;
86+ } ) ;
87+ }
88+
89+ #getDistanceBetweenTouches( touches : TouchList ) {
90+ if ( touches [ 0 ] && touches [ 1 ] ) {
91+ const dx = touches [ 0 ] . clientX - touches [ 1 ] . clientX ;
92+ const dy = touches [ 0 ] . clientY - touches [ 1 ] . clientY ;
93+ return Math . sqrt ( dx * dx + dy * dy ) ;
94+ }
95+ return 0 ;
4396 }
4497
4598 #on_wheel( e : WheelEvent ) {
@@ -109,19 +162,20 @@ export class PanAndZoom {
109162 }
110163 }
111164
112- #handle_zoom( delta : number , mouse : Vec2 ) {
113- const mouse_world = this . camera . screen_to_world ( mouse ) ;
114-
165+ #handle_zoom( delta : number , mouse ?: Vec2 ) {
115166 this . camera . zoom *= Math . exp ( delta * - zoom_speed ) ;
116167 this . camera . zoom = Math . min (
117168 this . max_zoom ,
118169 Math . max ( this . camera . zoom , this . min_zoom ) ,
119170 ) ;
120171
121- const new_world = this . camera . screen_to_world ( mouse ) ;
122- const center_delta = mouse_world . sub ( new_world ) ;
172+ if ( mouse != null ) {
173+ const mouse_world = this . camera . screen_to_world ( mouse ) ;
174+ const new_world = this . camera . screen_to_world ( mouse ) ;
175+ const center_delta = mouse_world . sub ( new_world ) ;
123176
124- this . camera . translate ( center_delta ) ;
177+ this . camera . translate ( center_delta ) ;
178+ }
125179
126180 if ( this . callback ) {
127181 this . callback ( ) ;
0 commit comments