annotate src/app/visualisations/WavesJunk.ts @ 509:041468f553e1 tip master

Merge pull request #57 from LucasThompson/fix/session-stack-max-call-stack Fix accidental recursion in PersistentStack
author Lucas Thompson <LucasThompson@users.noreply.github.com>
date Mon, 27 Nov 2017 11:04:30 +0000
parents 82d476b976e0
children
rev   line source
dev@347 1 /**
dev@347 2 * Created by lucast on 24/05/2017.
dev@347 3 */
dev@347 4 import wavesUI from 'waves-ui-piper';
dev@347 5 import * as Hammer from 'hammerjs';
dev@347 6 import {TimePixelMapper} from '../playhead/PlayHeadHelpers';
dev@347 7
dev@347 8 // TODO this is named as such as a reminder that it needs to be re-factored
dev@347 9 export function attachTouchHandlerBodges(element: HTMLElement,
dev@347 10 timeline: Timeline) {
dev@347 11 interface Point {
dev@347 12 x: number;
dev@347 13 y: number;
dev@347 14 }
dev@347 15
dev@347 16 let zoomGestureJustEnded = false;
dev@347 17
dev@347 18 const pixelToExponent: Function = wavesUI.utils.scales.linear()
dev@347 19 .domain([0, 100]) // 100px => factor 2
dev@347 20 .range([0, 1]);
dev@347 21
dev@347 22 const calculateDistance: (p1: Point, p2: Point) => number = (p1, p2) => {
dev@347 23 return Math.pow(
dev@347 24 Math.pow(p2.x - p1.x, 2) +
dev@347 25 Math.pow(p2.y - p1.y, 2), 0.5);
dev@347 26 };
dev@347 27
dev@347 28 const calculateMidPoint: (p1: Point, p2: Point) => Point = (p1, p2) => {
dev@347 29 return {
dev@347 30 x: 0.5 * (p1.x + p2.x),
dev@347 31 y: 0.5 * (p1.y + p2.y)
dev@347 32 };
dev@347 33 };
dev@347 34
dev@347 35 const hammertime = new Hammer.Manager(element, {
dev@347 36 recognizers: [
dev@347 37 [Hammer.Pan, { direction: Hammer.DIRECTION_HORIZONTAL }]
dev@347 38 ]
dev@347 39 });
dev@347 40
dev@347 41 // it seems HammerJs binds the event to the window?
dev@347 42 // causing these events to propagate to other components?
dev@347 43 let initialZoom;
dev@347 44 let initialDistance;
dev@347 45 let offsetAtPanStart;
dev@347 46 let startX;
dev@347 47 let isZooming;
dev@347 48
dev@347 49 const scroll = (ev) => {
dev@347 50 if (ev.center.x - startX === 0) {
dev@347 51 return;
dev@347 52 }
dev@347 53
dev@347 54 if (zoomGestureJustEnded) {
dev@347 55 zoomGestureJustEnded = false;
dev@347 56 console.log('Skip this event: likely a single touch dangling from pinch');
dev@347 57 return;
dev@347 58 }
dev@347 59 timeline.timeContext.offset = offsetAtPanStart +
dev@347 60 timeline.timeContext.timeToPixel.invert(ev.deltaX);
dev@347 61 timeline.tracks.update();
dev@347 62 };
dev@347 63
dev@347 64 const zoom = (ev) => {
dev@347 65 if (ev.touches.length < 2) {
dev@347 66 return;
dev@347 67 }
dev@347 68
dev@347 69 ev.preventDefault();
dev@347 70 const minZoom = timeline.state.minZoom;
dev@347 71 const maxZoom = timeline.state.maxZoom;
dev@347 72 const p1: Point = {
dev@347 73 x: ev.touches[0].clientX,
dev@347 74 y: ev.touches[0].clientY
dev@347 75 };
dev@347 76 const p2: Point = {
dev@347 77 x: ev.touches[1].clientX,
dev@347 78 y: ev.touches[1].clientY
dev@347 79 };
dev@347 80 const distance = calculateDistance(p1, p2);
dev@347 81 const midPoint = calculateMidPoint(p1, p2);
dev@347 82
dev@347 83 const lastCenterTime =
dev@347 84 timeline.timeContext.timeToPixel.invert(midPoint.x);
dev@347 85
dev@347 86 const exponent = pixelToExponent(distance - initialDistance);
dev@347 87 const targetZoom = initialZoom * Math.pow(2, exponent);
dev@347 88
dev@347 89 timeline.timeContext.zoom =
dev@347 90 Math.min(Math.max(targetZoom, minZoom), maxZoom);
dev@347 91
dev@347 92 const newCenterTime =
dev@347 93 timeline.timeContext.timeToPixel.invert(midPoint.x);
dev@347 94
dev@347 95 timeline.timeContext.offset += newCenterTime - lastCenterTime;
dev@347 96 timeline.tracks.update();
dev@347 97 };
dev@347 98 hammertime.on('panstart', (ev) => {
dev@347 99 offsetAtPanStart = timeline.timeContext.offset;
dev@347 100 startX = ev.center.x;
dev@347 101 });
dev@347 102 hammertime.on('panleft', scroll);
dev@347 103 hammertime.on('panright', scroll);
dev@347 104
dev@347 105 element.addEventListener('touchstart', (e) => {
dev@347 106 if (e.touches.length < 2) {
dev@347 107 return;
dev@347 108 }
dev@347 109
dev@347 110 isZooming = true;
dev@347 111 initialZoom = timeline.timeContext.zoom;
dev@347 112
dev@347 113 initialDistance = calculateDistance({
dev@347 114 x: e.touches[0].clientX,
dev@347 115 y: e.touches[0].clientY
dev@347 116 }, {
dev@347 117 x: e.touches[1].clientX,
dev@347 118 y: e.touches[1].clientY
dev@347 119 });
dev@347 120 });
dev@347 121 element.addEventListener('touchend', () => {
dev@347 122 if (isZooming) {
dev@347 123 isZooming = false;
dev@347 124 zoomGestureJustEnded = true;
dev@347 125 }
dev@347 126 });
dev@347 127 element.addEventListener('touchmove', zoom);
dev@347 128 }
dev@347 129
dev@347 130 export function naivePagingMapper(timeline: Timeline): TimePixelMapper {
dev@347 131 return (currentTime: number) => {
dev@347 132 const currentOffset = timeline.timeContext.offset;
dev@347 133 const offsetTimestamp = currentOffset
dev@347 134 + currentTime;
dev@347 135
dev@347 136 const visibleDuration = timeline.timeContext.visibleDuration;
dev@347 137 const mustPageForward = offsetTimestamp > visibleDuration;
dev@347 138 const mustPageBackward = currentTime < -currentOffset;
dev@347 139
dev@347 140 if (mustPageForward) {
dev@347 141 const hasSkippedMultiplePages =
dev@347 142 offsetTimestamp - visibleDuration > visibleDuration;
dev@347 143
dev@347 144 timeline.timeContext.offset = hasSkippedMultiplePages ?
dev@347 145 -currentTime + 0.5 * visibleDuration :
dev@347 146 currentOffset - visibleDuration;
dev@347 147 }
dev@347 148
dev@347 149 if (mustPageBackward) {
dev@347 150 const hasSkippedMultiplePages =
dev@347 151 currentTime + visibleDuration < -currentOffset;
dev@347 152 timeline.timeContext.offset = hasSkippedMultiplePages ?
dev@347 153 -currentTime + 0.5 * visibleDuration :
dev@347 154 currentOffset + visibleDuration;
dev@347 155 }
dev@347 156
dev@347 157 if (mustPageForward || mustPageBackward) {
dev@347 158 timeline.tracks.update();
dev@347 159 }
dev@347 160 //
dev@347 161 return timeline.timeContext.timeToPixel(timeline.offset + currentTime);
dev@347 162 };
dev@347 163 }