changeset 205:b638c714bd1d

Implement pinch-zoom manually using touchevents, as HammerJS was preventing scrolling the page. This should also allow for smoother transitioning between gestures - needs testing on a device.
author Lucas Thompson <dev@lucas.im>
date Fri, 24 Mar 2017 15:27:07 +0000
parents bdfd4b4b7130
children 1db0bb28688b
files src/app/waveform/waveform.component.ts
diffstat 1 files changed, 47 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/app/waveform/waveform.component.ts	Fri Mar 24 12:08:36 2017 +0000
+++ b/src/app/waveform/waveform.component.ts	Fri Mar 24 15:27:07 2017 +0000
@@ -247,7 +247,18 @@
           Math.pow(p2.y - p1.y, 2), 0.5);
       };
 
-      const hammertime = new Hammer(this.trackDiv.nativeElement);
+      const calculateMidPoint: (p1: Point, p2: Point) => Point = (p1, p2) => {
+        return {
+          x: 0.5 * (p1.x + p2.x),
+          y: 0.5 * (p1.y + p2.y)
+        };
+      };
+
+      const hammertime = new Hammer.Manager(this.trackDiv.nativeElement, {
+        recognizers: [
+          [Hammer.Pan, { direction: Hammer.DIRECTION_HORIZONTAL }]
+        ]
+      });
 
       // it seems HammerJs binds the event to the window?
       // causing these events to propagate to other components?
@@ -255,8 +266,11 @@
       let initialZoom;
       let initialDistance;
       let offsetAtPanStart;
+      let startX;
+      let isZooming;
 
       const scroll = (ev) => {
+        if (ev.center.x - startX === 0) return;
         if (zoomGestureJustEnded) {
           zoomGestureJustEnded = false;
           console.log("Skip this event: likely a single touch dangling from pinch");
@@ -268,18 +282,22 @@
       };
 
       const zoom = (ev) => {
+        if (ev.touches.length < 2) return;
         const minZoom = componentTimeline.state.minZoom;
         const maxZoom = componentTimeline.state.maxZoom;
-        const distance = calculateDistance({
-          x: ev.pointers[0].clientX,
-          y: ev.pointers[0].clientY
-        }, {
-          x: ev.pointers[1].clientX,
-          y: ev.pointers[1].clientY
-        });
+        const p1: Point = {
+          x: ev.touches[0].clientX,
+          y: ev.touches[0].clientY
+        };
+        const p2: Point = {
+          x: ev.touches[1].clientX,
+          y: ev.touches[1].clientY
+        };
+        const distance = calculateDistance(p1, p2);
+        const midPoint = calculateMidPoint(p1, p2);
 
         const lastCenterTime =
-          componentTimeline.timeContext.timeToPixel.invert(ev.center.x);
+          componentTimeline.timeContext.timeToPixel.invert(midPoint.x);
 
         const exponent = pixelToExponent(distance - initialDistance);
         const targetZoom = initialZoom * Math.pow(2, exponent);
@@ -288,32 +306,40 @@
           Math.min(Math.max(targetZoom, minZoom), maxZoom);
 
         const newCenterTime =
-          componentTimeline.timeContext.timeToPixel.invert(ev.center.x);
+          componentTimeline.timeContext.timeToPixel.invert(midPoint.x);
 
         componentTimeline.timeContext.offset += newCenterTime - lastCenterTime;
         componentTimeline.tracks.update();
       };
-      hammertime.get('pinch').set({ enable: true });
-      hammertime.on('panstart', () => {
+      hammertime.on('panstart', (ev) => {
         offsetAtPanStart = componentTimeline.timeContext.offset;
+        startX = ev.center.x;
       });
       hammertime.on('panleft', scroll);
       hammertime.on('panright', scroll);
-      hammertime.on('pinchstart', (e) => {
+
+
+      const element: HTMLElement = this.trackDiv.nativeElement;
+      element.addEventListener('touchstart', (e) => {
+        if (e.touches.length < 2) return;
+        isZooming = true;
         initialZoom = componentTimeline.timeContext.zoom;
 
         initialDistance = calculateDistance({
-          x: e.pointers[0].clientX,
-          y: e.pointers[0].clientY
+          x: e.touches[0].clientX,
+          y: e.touches[0].clientY
         }, {
-          x: e.pointers[1].clientX,
-          y: e.pointers[1].clientY
+          x: e.touches[1].clientX,
+          y: e.touches[1].clientY
         });
       });
-      hammertime.on('pinch', zoom);
-      hammertime.on('pinchend', () => {
-        zoomGestureJustEnded = true;
-      });
+      element.addEventListener('touchend', () => {
+        if (isZooming) {
+          isZooming = false;
+          zoomGestureJustEnded = true;
+        }
+       });
+      element.addEventListener('touchmove', zoom);
     }
     // this.timeline.createTrack(track, height/2, `wave-${this.trackIdPrefix}`);
     // this.timeline.createTrack(track, height/2, `grid-${this.trackIdPrefix}`);