@@ -26,7 +26,7 @@ import {
2626 ASTEROID_BASE , COMET_BASE , EARTH , FIRST_PLANET , HALF_MINUTE , ISkyObserver , LAST_PLANET , NO_MATCH , SkyObserver , SolarSystem ,
2727 StarCatalog , UT_to_TDB
2828} from 'ks-astronomy' ;
29- import { abs , ceil , max , Point } from 'ks-math' ;
29+ import { abs , ceil , max , Point , sqrt } from 'ks-math' ;
3030import { FontMetrics , getFontMetrics , isSafari } from 'ks-util' ;
3131import * as _ from 'lodash' ;
3232import { KsDateTime } from 'ks-date-time-zone' ;
@@ -75,9 +75,10 @@ export abstract class GenericView implements AfterViewInit {
7575 protected clickX = - 1 ;
7676 protected clickY = - 1 ;
7777 protected canDrag = true ;
78+ protected canTouchZoom = false ;
79+ protected initialZoomSpread = 0 ; // 0 means not zooming.
7880 protected goodDragStart = false ;
79- protected debouncedDraw : ( ) => void ;
80- protected throttledMouseMove : ( ) => void ;
81+ protected throttledRedraw : ( ) => void ;
8182 protected debouncedResize : ( ) => void ;
8283 protected dragging = false ;
8384 protected excludedPlanets : number [ ] = [ EARTH ] ;
@@ -125,9 +126,9 @@ export abstract class GenericView implements AfterViewInit {
125126
126127 this . updatePlanetsToDraw ( ) ;
127128
128- this . debouncedDraw = _ . debounce ( ( ) => {
129+ this . throttledRedraw = _ . throttle ( ( ) => {
129130 this . draw ( ) ;
130- } , 0 ) ;
131+ } , 100 ) ;
131132
132133 appService . getCurrentTabUpdates ( ( currentTab : CurrentTab ) => {
133134 if ( this . tabId === currentTab )
@@ -221,19 +222,27 @@ export abstract class GenericView implements AfterViewInit {
221222
222223 // TODO: Turn into utility function
223224 // noinspection JSMethodCanBeStatic
224- protected getXYForTouchEvent ( event : TouchEvent ) : Point {
225+ protected getXYForTouchEvent ( event : TouchEvent , index = 0 ) : Point {
225226 const touches = event . touches ;
226227
227- if ( touches . length < 1 )
228+ if ( touches . length <= index )
228229 return { x : - 1 , y : - 1 } ;
229230
230- const rect = ( touches [ 0 ] . target as HTMLElement ) . getBoundingClientRect ( ) ;
231+ const rect = ( touches [ index ] . target as HTMLElement ) . getBoundingClientRect ( ) ;
231232
232- return { x : touches [ 0 ] . clientX - rect . left , y : touches [ 0 ] . clientY - rect . top } ;
233+ return { x : touches [ index ] . clientX - rect . left , y : touches [ 0 ] . clientY - rect . top } ;
233234 }
234235
235236 onTouchStart ( event : TouchEvent ) : void {
236- const pt = this . getXYForTouchEvent ( event ) ;
237+ const pt0 = this . getXYForTouchEvent ( event ) ;
238+ const pt = _ . clone ( pt0 ) ;
239+ let pt1 ;
240+
241+ if ( event . touches . length > 1 ) {
242+ pt1 = this . getXYForTouchEvent ( event , 1 ) ;
243+ pt . x = ( pt0 . x + pt1 . x ) / 2 ;
244+ pt . y = ( pt0 . y + pt1 . y ) / 2 ;
245+ }
237246
238247 this . clickX = this . lastMoveX = pt . x ;
239248 this . clickY = this . lastMoveY = pt . y ;
@@ -242,9 +251,21 @@ export abstract class GenericView implements AfterViewInit {
242251 this . goodDragStart = true ;
243252 this . draw ( ) ;
244253 event . preventDefault ( ) ;
254+
255+ if ( this . canTouchZoom && pt1 ) {
256+ const dx = pt1 . x - pt0 . x ;
257+ const dy = pt1 . y - pt0 . y ;
258+
259+ this . initialZoomSpread = max ( sqrt ( dx * dx + dy * dy ) , 1 ) ;
260+ this . startTouchZoom ( ) ;
261+ }
262+ else
263+ this . initialZoomSpread = 0 ;
245264 }
246- else
265+ else {
247266 this . goodDragStart = false ;
267+ this . initialZoomSpread = 0 ;
268+ }
248269 }
249270
250271 onMouseDown ( event : MouseEvent ) : void {
@@ -254,15 +275,42 @@ export abstract class GenericView implements AfterViewInit {
254275 }
255276
256277 onTouchMove ( event : TouchEvent ) : void {
257- const pt = this . getXYForTouchEvent ( event ) ;
278+ const pt0 = this . getXYForTouchEvent ( event ) ;
279+ const pt = _ . clone ( pt0 ) ;
280+ let pt1 ;
281+
282+ if ( event . touches . length > 1 ) {
283+ pt1 = this . getXYForTouchEvent ( event , 1 ) ;
284+ pt . x = ( pt0 . x + pt1 . x ) / 2 ;
285+ pt . y = ( pt0 . y + pt1 . y ) / 2 ;
286+ }
258287
259288 if ( this . goodDragStart )
260289 this . handleMouseMove ( pt . x , pt . y , true ) ;
261290
291+ if ( this . initialZoomSpread ) {
292+ if ( pt1 ) {
293+ const dx = pt1 . x - pt0 . x ;
294+ const dy = pt1 . y - pt0 . y ;
295+ const newSpread = max ( sqrt ( dx * dx + dy * dy ) , 1 ) ;
296+ const zoomRatio = newSpread / this . initialZoomSpread ;
297+
298+ this . touchZoom ( zoomRatio ) ;
299+ }
300+ else
301+ this . initialZoomSpread = 0 ;
302+ }
303+
262304 if ( this . isInsideView ( ) )
263305 event . preventDefault ( ) ;
264306 }
265307
308+ protected startTouchZoom ( ) : void {
309+ }
310+
311+ protected touchZoom ( zoomRatio : number ) : void {
312+ }
313+
266314 onMouseMove ( event : MouseEvent ) : void {
267315 if ( this . goodDragStart || ! this . dragging )
268316 this . handleMouseMove ( event . offsetX , event . offsetY , ! ! ( ( event . buttons & 0x01 ) || ( this . isSafari && ( event . which & 0x01 ) ) ) ) ;
@@ -272,7 +320,7 @@ export abstract class GenericView implements AfterViewInit {
272320 this . lastMoveX = x ;
273321 this . lastMoveY = y ;
274322
275- let justCleared = false ;
323+ let justCleared = false ;
276324
277325 if ( ! this . isInsideView ( ) ) {
278326 this . clearMouseHighlighting ( ) ;
@@ -289,30 +337,26 @@ export abstract class GenericView implements AfterViewInit {
289337 this . resetCursor ( ) ;
290338 }
291339
292- if ( ! this . dragging || justCleared ) {
293- if ( ! this . throttledMouseMove ) {
294- this . throttledMouseMove = _ . throttle ( ( ) => {
295- this . draw ( ) ;
296- } , 100 ) ;
297- }
298-
299- this . throttledMouseMove ( ) ;
300- }
340+ if ( ! this . dragging || justCleared )
341+ this . throttledRedraw ( ) ;
301342 }
302343
303344 protected clearMouseHighlighting ( ) : void {
304345 this . lastMoveX = this . lastMoveY = - 1 ;
305346 }
306347
307348 onTouchEnd ( event : TouchEvent ) : void {
308- const pt = this . getXYForTouchEvent ( event ) ;
349+ if ( event . touches . length < 2 )
350+ this . initialZoomSpread = 0 ;
309351
310- this . lastMoveX = pt . x ;
311- this . lastMoveY = pt . y ;
312- this . resetCursor ( ) ;
313- this . draw ( ) ;
314- this . dragging = false ;
315- event . preventDefault ( ) ;
352+ if ( event . touches . length === 1 )
353+ this . onTouchStart ( event ) ;
354+ else if ( event . touches . length === 0 ) {
355+ this . resetCursor ( ) ;
356+ this . draw ( ) ;
357+ this . dragging = false ;
358+ event . preventDefault ( ) ;
359+ }
316360 }
317361
318362 onMouseUp ( event : MouseEvent ) : void {
0 commit comments