diff --git a/core/src/components/item-sliding/item-sliding.tsx b/core/src/components/item-sliding/item-sliding.tsx index 4d94de3bd9..6fda4e2c49 100644 --- a/core/src/components/item-sliding/item-sliding.tsx +++ b/core/src/components/item-sliding/item-sliding.tsx @@ -58,7 +58,7 @@ export class ItemSliding { this.updateOptions(); - this.gesture = (await import('../../utils/gesture/gesture')).create({ + this.gesture = (await import('../../utils/gesture/gesture')).createGesture({ el: this.el, queue: this.queue, gestureName: 'item-swipe', @@ -69,7 +69,7 @@ export class ItemSliding { onMove: this.onDragMove.bind(this), onEnd: this.onDragEnd.bind(this), }); - this.gesture.disabled = false; + this.gesture.setDisabled(false); } componentDidUnload() { diff --git a/core/src/components/menu/menu.tsx b/core/src/components/menu/menu.tsx index 4de1d51fb6..76d43e45c7 100644 --- a/core/src/components/menu/menu.tsx +++ b/core/src/components/menu/menu.tsx @@ -175,7 +175,7 @@ export class Menu { this.menuCtrl!._register(this); this.ionMenuChange.emit({ disabled: !isEnabled, open: this._isOpen }); - this.gesture = (await import('../../utils/gesture/gesture')).create({ + this.gesture = (await import('../../utils/gesture/gesture')).createGesture({ el: this.doc, queue: this.queue, gestureName: 'menu-swipe', @@ -439,7 +439,7 @@ export class Menu { private updateState() { const isActive = this.isActive(); if (this.gesture) { - this.gesture.disabled = !isActive || !this.swipeEnabled; + this.gesture.setDisabled(!isActive || !this.swipeEnabled); } // Close menu inmediately diff --git a/core/src/components/nav/nav.tsx b/core/src/components/nav/nav.tsx index 41ddb8d6c9..969745d1ab 100644 --- a/core/src/components/nav/nav.tsx +++ b/core/src/components/nav/nav.tsx @@ -41,7 +41,7 @@ export class Nav implements NavOutlet { @Watch('swipeBackEnabled') swipeBackEnabledChanged() { if (this.gesture) { - this.gesture.disabled = !this.swipeBackEnabled; + this.gesture.setDisabled(!this.swipeBackEnabled); } } @@ -110,7 +110,7 @@ export class Nav implements NavOutlet { async componentDidLoad() { this.rootChanged(); - this.gesture = (await import('../../utils/gesture/gesture')).create({ + this.gesture = (await import('../../utils/gesture/gesture')).createGesture({ el: this.win.document.body, queue: this.queue, gestureName: 'goback-swipe', diff --git a/core/src/components/picker-column/picker-column.tsx b/core/src/components/picker-column/picker-column.tsx index bf787730c2..ecc0086aa1 100644 --- a/core/src/components/picker-column/picker-column.tsx +++ b/core/src/components/picker-column/picker-column.tsx @@ -1,6 +1,6 @@ import { Component, Element, Prop, QueueApi } from '@stencil/core'; -import { Gesture, GestureDetail, Mode, PickerColumn, PickerColumnOption } from '../../interface'; +import { Gesture, GestureDetail, Mode, PickerColumn } from '../../interface'; import { hapticSelectionChanged } from '../../utils'; import { clamp } from '../../utils/helpers'; import { createThemedClasses } from '../../utils/theme'; @@ -18,13 +18,12 @@ export class PickerColumnCmp { private minY!: number; private maxY!: number; private optHeight = 0; - private pos: number[] = []; private rotateFactor = 0; private scaleFactor = 1; - private startY?: number; private velocity = 0; private y = 0; private gesture?: Gesture; + private rafId: any; @Element() el!: HTMLElement; @@ -54,27 +53,17 @@ export class PickerColumnCmp { this.refresh(); - this.gesture = (await import('../../utils/gesture/gesture')).create({ + this.gesture = (await import('../../utils/gesture/gesture')).createGesture({ el: this.el, queue: this.queue, gestureName: 'picker-swipe', gesturePriority: 10, threshold: 0, - canStart: this.canStart.bind(this), onStart: this.onDragStart.bind(this), onMove: this.onDragMove.bind(this), onEnd: this.onDragEnd.bind(this), }); - this.gesture.disabled = false; - } - - private optClick(ev: Event, index: number) { - if (!this.velocity) { - ev.preventDefault(); - ev.stopPropagation(); - - this.setSelected(index, 150); - } + this.gesture.setDisabled(false); } private setSelected(selectedIndex: number, duration: number) { @@ -85,6 +74,7 @@ export class PickerColumnCmp { this.velocity = 0; // set what y position we're at + cancelAnimationFrame(this.rafId); this.update(y, duration, true, true); } @@ -92,16 +82,8 @@ export class PickerColumnCmp { // ensure we've got a good round number :) y = Math.round(y); - let i: number; - let button: any; - let opt: PickerColumnOption; - let optOffset: number; - let visible: boolean; let translateY = 0; let translateZ = 0; - let rotateX: number; - let transform: string; - let selected: boolean; const parent = this.el.querySelector('.picker-opts')!; const children = parent.children; @@ -111,15 +93,15 @@ export class PickerColumnCmp { const durationStr = (duration === 0) ? null : duration + 'ms'; const scaleStr = `scale(${this.scaleFactor})`; - for (i = 0; i < length; i++) { - button = children[i]; - opt = this.col.options[i]; - optOffset = (i * this.optHeight) + y; - visible = true; - transform = ''; + for (let i = 0; i < length; i++) { + const button = children[i] as HTMLElement; + const opt = this.col.options[i]; + const optOffset = (i * this.optHeight) + y; + let visible = true; + let transform = ''; if (this.rotateFactor !== 0) { - rotateX = optOffset * this.rotateFactor; + const rotateX = optOffset * this.rotateFactor; if (Math.abs(rotateX) > 90) { visible = false; } else { @@ -135,7 +117,7 @@ export class PickerColumnCmp { } } - selected = selectedIndex === i; + const selected = selectedIndex === i; if (visible) { transform += `translate3d(0px,${translateY}px,${translateZ}px) `; if (this.scaleFactor !== 1 && !selected) { @@ -204,7 +186,7 @@ export class PickerColumnCmp { ? Math.max(this.velocity, 1) : Math.min(this.velocity, -1); - y = Math.round(this.y - this.velocity); + y = Math.round(this.y + this.velocity); if (y > this.minY) { // whoops, it's trying to scroll up farther than the options we have! @@ -223,7 +205,7 @@ export class PickerColumnCmp { if (notLockedIn) { // isn't locked in yet, keep decelerating until it is - this.queue.read(() => this.decelerate()); + this.rafId = requestAnimationFrame(() => this.decelerate()); } } else if (this.y % this.optHeight !== 0) { @@ -246,11 +228,8 @@ export class PickerColumnCmp { } // TODO should this check disabled? - private canStart() { - return true; - } - private onDragStart(detail: GestureDetail): boolean { + private onDragStart(detail: GestureDetail) { // We have to prevent default in order to block scrolling under the picker // but we DO NOT have to stop propagation, since we still want // some "click" events to capture @@ -259,14 +238,8 @@ export class PickerColumnCmp { detail.event.stopPropagation(); } - // remember where the pointer started from - this.startY = detail.startY; - // reset everything - this.velocity = 0; - this.pos.length = 0; - this.pos.push(this.startY, Date.now()); - + cancelAnimationFrame(this.rafId); const options = this.col.options; let minY = (options.length - 1); let maxY = 0; @@ -279,7 +252,6 @@ export class PickerColumnCmp { this.minY = (minY * this.optHeight * -1); this.maxY = (maxY * this.optHeight * -1); - return true; } private onDragMove(detail: GestureDetail) { @@ -288,15 +260,8 @@ export class PickerColumnCmp { detail.event.stopPropagation(); } - const currentY = detail.currentY; - this.pos.push(currentY, Date.now()); - - if (this.startY === undefined) { - return; - } - // update the scroll position relative to pointer start position - let y = this.y + (currentY - this.startY); + let y = this.y + detail.deltaY; if (y > this.minY) { // scrolling up higher than scroll area @@ -321,12 +286,6 @@ export class PickerColumnCmp { } private onDragEnd(detail: GestureDetail) { - if (this.startY === undefined) { - return; - } - - this.velocity = 0; - if (this.bounceFrom > 0) { // bounce back up this.update(this.minY, 100, true, true); @@ -337,36 +296,20 @@ export class PickerColumnCmp { return; } - const endY = detail.currentY; + this.velocity = clamp(-MAX_PICKER_SPEED, detail.velocityY * 17, MAX_PICKER_SPEED); + if (this.velocity === 0 && detail.deltaY === 0) { + const opt = (detail.event.target as Element).closest('.picker-opt'); + if (opt && opt.hasAttribute('opt-index')) { + this.setSelected(parseInt(opt.getAttribute('opt-index')!, 10), 150); + } - this.pos.push(endY, Date.now()); - - const endPos = (this.pos.length - 1); - let startPos = endPos; - const timeRange = (Date.now() - 100); - - // move pointer to position measured 100ms ago - for (let i = endPos; i > 0 && this.pos[i] > timeRange; i -= 2) { - startPos = i; + } else { + if (Math.abs(detail.deltaY) > 3) { + const y = this.y + detail.deltaY; + this.update(y, 0, true, true); + } + this.decelerate(); } - - if (startPos !== endPos) { - // compute relative movement between these two points - const timeOffset = (this.pos[endPos] - this.pos[startPos]); - const movedTop = (this.pos[startPos - 1] - this.pos[endPos - 1]); - - // based on XXms compute the movement to apply for each render step - const velocity = ((movedTop / timeOffset) * FRAME_MS); - this.velocity = clamp(-MAX_PICKER_SPEED, velocity, MAX_PICKER_SPEED); - } - - if (Math.abs(endY - this.startY) > 3) { - const y = this.y + (endY - this.startY); - this.update(y, 0, true, true); - } - - this.startY = undefined; - this.decelerate(); } private refresh() { @@ -406,45 +349,35 @@ export class PickerColumnCmp { const col = this.col; const options = col.options.map(o => { - if (typeof o === 'string') { - o = { text: o }; - } - return o; + return (typeof o === 'string') + ? { text: o } + : o; }) .filter(o => o !== null); - const results: JSX.Element[] = []; - - if (col.prefix) { - results.push( + const Button = 'button' as any; + return [ + col.prefix && (
{col.prefix}
- ); - } - - results.push( + ),
{options.map((o, index) => - + )} -
- ); - - if (col.suffix) { - results.push( + , + col.suffix && (
{col.suffix}
- ); - } - - return results; + ) + ]; } } diff --git a/core/src/components/range/range.tsx b/core/src/components/range/range.tsx index b42887c7d8..1280a25126 100644 --- a/core/src/components/range/range.tsx +++ b/core/src/components/range/range.tsx @@ -98,7 +98,7 @@ export class Range implements BaseInput { @Watch('disabled') protected disabledChanged() { if (this.gesture) { - this.gesture.disabled = this.disabled; + this.gesture.setDisabled(this.disabled); } this.emitStyle(); } @@ -145,7 +145,7 @@ export class Range implements BaseInput { } async componentDidLoad() { - this.gesture = (await import('../../utils/gesture/gesture')).create({ + this.gesture = (await import('../../utils/gesture/gesture')).createGesture({ el: this.rangeSlider!, queue: this.queue, gestureName: 'range', @@ -155,7 +155,7 @@ export class Range implements BaseInput { onMove: this.onDragMove.bind(this), onEnd: this.onDragEnd.bind(this), }); - this.gesture.disabled = this.disabled; + this.gesture.setDisabled(this.disabled); } @Listen('ionIncrease') diff --git a/core/src/components/refresher/refresher.tsx b/core/src/components/refresher/refresher.tsx index d4fa49cc3c..5e976862ec 100644 --- a/core/src/components/refresher/refresher.tsx +++ b/core/src/components/refresher/refresher.tsx @@ -67,7 +67,7 @@ export class Refresher { @Watch('disabled') disabledChanged() { if (this.gesture) { - this.gesture.disabled = this.disabled; + this.gesture.setDisabled(this.disabled); } } @@ -102,7 +102,7 @@ export class Refresher { console.error('ion-refresher did not attach, make sure the parent is an ion-content.'); } - this.gesture = (await import('../../utils/gesture/gesture')).create({ + this.gesture = (await import('../../utils/gesture/gesture')).createGesture({ el: this.el.closest('ion-content') as any, queue: this.queue, gestureName: 'refresher', diff --git a/core/src/components/reorder-group/reorder-group.tsx b/core/src/components/reorder-group/reorder-group.tsx index a250789e9a..c3a5d0621b 100644 --- a/core/src/components/reorder-group/reorder-group.tsx +++ b/core/src/components/reorder-group/reorder-group.tsx @@ -40,7 +40,7 @@ export class ReorderGroup { @Watch('disabled') disabledChanged() { if (this.gesture) { - this.gesture.disabled = this.disabled; + this.gesture.setDisabled(this.disabled); } } @@ -51,7 +51,7 @@ export class ReorderGroup { this.scrollEl = contentEl.getScrollElement(); } - this.gesture = (await import('../../utils/gesture/gesture')).create({ + this.gesture = (await import('../../utils/gesture/gesture')).createGesture({ el: this.doc.body, queue: this.queue, gestureName: 'reorder', diff --git a/core/src/components/toggle/toggle.tsx b/core/src/components/toggle/toggle.tsx index 507d319b15..ad9cd9f996 100644 --- a/core/src/components/toggle/toggle.tsx +++ b/core/src/components/toggle/toggle.tsx @@ -94,7 +94,7 @@ export class Toggle implements CheckboxInput { 'interactive-disabled': this.disabled, }); if (this.gesture) { - this.gesture.disabled = this.disabled; + this.gesture.setDisabled(this.disabled); } } @@ -112,7 +112,7 @@ export class Toggle implements CheckboxInput { } } - this.gesture = (await import('../../utils/gesture/gesture')).create({ + this.gesture = (await import('../../utils/gesture/gesture')).createGesture({ el: this.el, queue: this.queue, gestureName: 'toggle', diff --git a/core/src/utils/gesture/gesture.ts b/core/src/utils/gesture/gesture.ts index e41a0a9fbc..5a308617dc 100644 --- a/core/src/utils/gesture/gesture.ts +++ b/core/src/utils/gesture/gesture.ts @@ -2,7 +2,7 @@ import { QueueApi } from '@stencil/core'; import { PanRecognizer } from './recognizers'; -import { GestureDelegate, gestureController } from './gesture-controller'; +import { gestureController } from './gesture-controller'; import { PointerEvents } from './pointer-events'; export interface GestureDetail { @@ -23,6 +23,11 @@ export interface GestureDetail { export type GestureCallback = (detail?: GestureDetail) => boolean | void; +export interface Gesture { + setDisabled(disabled: boolean): void; + destroy(): void; +} + export interface GestureConfig { el: Node; disableScroll?: boolean; @@ -43,100 +48,70 @@ export interface GestureConfig { notCaptured?: GestureCallback; } -export function create(config: GestureConfig) { - return new Gesture(config); -} +export function createGesture(config: GestureConfig): Gesture { + const finalConfig = { + disableScroll: false, + direction: 'x', + gesturePriority: 0, + passive: true, + maxAngle: 40, + threshold: 10, -export class Gesture { + ...config + }; - private detail: GestureDetail; - private positions: number[] = []; - private gesture: GestureDelegate; - private pan: PanRecognizer; - private hasCapturedPan = false; - private hasStartedPan = false; - private hasFiredStart = true; - private isMoveQueued = false; - private pointerEvents: PointerEvents; + let hasCapturedPan = false; + let hasStartedPan = false; + let hasFiredStart = true; + let isMoveQueued = false; - private canStart?: GestureCallback; - private onWillStart?: (_: GestureDetail) => Promise; - private onStart?: GestureCallback; - private onMove?: GestureCallback; - private onEnd?: GestureCallback; - private notCaptured?: GestureCallback; - private threshold: number; - private queue: QueueApi; + const canStart = finalConfig.canStart; + const onWillStart = finalConfig.onWillStart; + const onStart = finalConfig.onStart; + const onEnd = finalConfig.onEnd; + const notCaptured = finalConfig.notCaptured; + const onMove = finalConfig.onMove; + const threshold = finalConfig.threshold; + const queue = finalConfig.queue; - constructor(config: GestureConfig) { - const finalConfig = { - disableScroll: false, - direction: 'x', - gesturePriority: 0, - passive: true, - maxAngle: 40, - threshold: 10, + const detail = { + type: 'pan', + startX: 0, + startY: 0, + startTimeStamp: 0, + currentX: 0, + currentY: 0, + velocityX: 0, + velocityY: 0, + deltaX: 0, + deltaY: 0, + timeStamp: 0, + event: undefined as any, + data: undefined + }; - ...config - }; + const pointerEvents = new PointerEvents( + finalConfig.el, + pointerDown, + pointerMove, + pointerUp, + { + capture: false, + } + ); - this.canStart = finalConfig.canStart; - this.onWillStart = finalConfig.onWillStart; - this.onStart = finalConfig.onStart; - this.onEnd = finalConfig.onEnd; - this.onMove = finalConfig.onMove; - this.threshold = finalConfig.threshold; - this.queue = finalConfig.queue; + const pan = new PanRecognizer(finalConfig.direction, finalConfig.threshold, finalConfig.maxAngle); + const gesture = gestureController.createGesture({ + name: config.gestureName, + priority: config.gesturePriority, + disableScroll: config.disableScroll + }); - this.detail = { - type: 'pan', - startX: 0, - startY: 0, - startTimeStamp: 0, - currentX: 0, - currentY: 0, - velocityX: 0, - velocityY: 0, - deltaX: 0, - deltaY: 0, - timeStamp: 0, - event: undefined as any, - data: undefined - }; - - this.pointerEvents = new PointerEvents( - finalConfig.el, - this.pointerDown.bind(this), - this.pointerMove.bind(this), - this.pointerUp.bind(this), - { - capture: false, - } - ); - - this.pan = new PanRecognizer(finalConfig.direction, finalConfig.threshold, finalConfig.maxAngle); - this.gesture = gestureController.createGesture({ - name: config.gestureName, - priority: config.gesturePriority, - disableScroll: config.disableScroll - }); - } - - set disabled(disabled: boolean) { - this.pointerEvents.disabled = disabled; - } - - destroy() { - this.gesture.destroy(); - this.pointerEvents.destroy(); - } - - private pointerDown(ev: UIEvent): boolean { + function pointerDown(ev: UIEvent): boolean { const timeStamp = now(ev); - if (this.hasStartedPan || !this.hasFiredStart) { + if (hasStartedPan || !hasFiredStart) { return false; } - const detail = this.detail; updateDetail(ev, detail); detail.startX = detail.currentX; @@ -144,109 +119,90 @@ export class Gesture { detail.startTimeStamp = detail.timeStamp = timeStamp; detail.velocityX = detail.velocityY = detail.deltaX = detail.deltaY = 0; detail.event = ev; - this.positions.length = 0; // Check if gesture can start - if (this.canStart && this.canStart(detail) === false) { + if (canStart && canStart(detail) === false) { return false; } // Release fallback - this.gesture.release(); + gesture.release(); // Start gesture - if (!this.gesture.start()) { + if (!gesture.start()) { return false; } - this.positions.push(detail.currentX, detail.currentY, timeStamp); - this.hasStartedPan = true; - if (this.threshold === 0) { - return this.tryToCapturePan(); + hasStartedPan = true; + if (threshold === 0) { + return tryToCapturePan(); } - this.pan.start(detail.startX, detail.startY); + pan.start(detail.startX, detail.startY); return true; } - private pointerMove(ev: UIEvent) { + function pointerMove(ev: UIEvent) { // fast path, if gesture is currently captured // do minimun job to get user-land even dispatched - if (this.hasCapturedPan) { - if (!this.isMoveQueued && this.hasFiredStart) { - this.isMoveQueued = true; - this.calcGestureData(ev); - this.queue.write(this.fireOnMove.bind(this)); + if (hasCapturedPan) { + if (!isMoveQueued && hasFiredStart) { + isMoveQueued = true; + calcGestureData(ev); + queue.write(fireOnMove); } return; } // gesture is currently being detected - const detail = this.detail; - this.calcGestureData(ev); - if (this.pan.detect(detail.currentX, detail.currentY)) { - if (this.pan.isGesture()) { - if (!this.tryToCapturePan()) { - this.abortGesture(); + calcGestureData(ev); + if (pan.detect(detail.currentX, detail.currentY)) { + if (pan.isGesture()) { + if (!tryToCapturePan()) { + abortGesture(); } } } } - private fireOnMove() { + function fireOnMove() { // Since fireOnMove is called inside a RAF, onEnd() might be called, // we must double check hasCapturedPan - if (!this.hasCapturedPan) { + if (!hasCapturedPan) { return; } - const detail = this.detail; - this.isMoveQueued = false; - if (this.onMove) { - this.onMove(detail); + isMoveQueued = false; + if (onMove) { + onMove(detail); } } - private calcGestureData(ev: UIEvent) { - const detail = this.detail; + function calcGestureData(ev: UIEvent) { + const prevX = detail.currentX; + const prevY = detail.currentY; + const prevT = detail.timeStamp; + updateDetail(ev, detail); const currentX = detail.currentX; const currentY = detail.currentY; const timestamp = detail.timeStamp = now(ev); + const timeDelta = timestamp - prevT; + if (timeDelta > 0 && timeDelta < 100) { + const velocityX = (currentX - prevX) / timeDelta; + const velocityY = (currentY - prevY) / timeDelta; + detail.velocityX = velocityX * 0.7 + detail.velocityX * 0.3; + detail.velocityY = velocityY * 0.7 + detail.velocityY * 0.3; + } detail.deltaX = currentX - detail.startX; detail.deltaY = currentY - detail.startY; detail.event = ev; - - const timeRange = timestamp - 100; - const positions = this.positions; - let startPos = positions.length - 1; - - // move pointer to position measured 100ms ago - while (startPos > 0 && positions[startPos] > timeRange) { - startPos -= 3; - } - - if (startPos > 1) { - // compute relative movement between these two points - const frequency = 1 / (positions[startPos] - timestamp); - const movedY = positions[startPos - 1] - currentY; - const movedX = positions[startPos - 2] - currentX; - - // based on XXms compute the movement to apply for each render step - // velocity = space/time = s*(1/t) = s*frequency - detail.velocityX = movedX * frequency; - detail.velocityY = movedY * frequency; - } else { - detail.velocityX = 0; - detail.velocityY = 0; - } - positions.push(currentX, currentY, timestamp); } - private tryToCapturePan(): boolean { - if (this.gesture && !this.gesture.capture()) { + function tryToCapturePan(): boolean { + if (gesture && !gesture.capture()) { return false; } - this.hasCapturedPan = true; - this.hasFiredStart = false; + hasCapturedPan = true; + hasFiredStart = false; // reset start position since the real user-land event starts here // If the pan detector threshold is big, not reseting the start position @@ -254,71 +210,77 @@ export class Gesture { // the array of positions used to calculate the gesture velocity does not // need to be cleaned, more points in the positions array always results in a // more acurate value of the velocity. - const detail = this.detail; detail.startX = detail.currentX; detail.startY = detail.currentY; detail.startTimeStamp = detail.timeStamp; - if (this.onWillStart) { - this.onWillStart(this.detail).then(this.fireOnStart.bind(this)); + if (onWillStart) { + onWillStart(detail).then(fireOnStart); } else { - this.fireOnStart(); + fireOnStart(); } return true; } - private fireOnStart() { - if (this.onStart) { - this.onStart(this.detail); + function fireOnStart() { + if (onStart) { + onStart(detail); } - this.hasFiredStart = true; + hasFiredStart = true; } - private abortGesture() { - this.reset(); - this.pointerEvents.stop(); - if (this.notCaptured) { - this.notCaptured(this.detail); + function abortGesture() { + reset(); + pointerEvents.stop(); + if (notCaptured) { + notCaptured(detail); } } - private reset() { - this.hasCapturedPan = false; - this.hasStartedPan = false; - this.isMoveQueued = false; - this.hasFiredStart = true; - if (this.gesture) { - this.gesture.release(); - } + function reset() { + hasCapturedPan = false; + hasStartedPan = false; + isMoveQueued = false; + hasFiredStart = true; + + gesture.release(); } // END ************************* - private pointerUp(ev: UIEvent) { - const hasCaptured = this.hasCapturedPan; - const hasFiredStart = this.hasFiredStart; - this.reset(); + function pointerUp(ev: UIEvent) { + const tmpHasCaptured = hasCapturedPan; + const tmpHasFiredStart = hasFiredStart; + reset(); - if (!hasFiredStart) { + if (!tmpHasFiredStart) { return; } - this.calcGestureData(ev); - - const detail = this.detail; + calcGestureData(ev); // Try to capture press - if (hasCaptured) { - if (this.onEnd) { - this.onEnd(detail); + if (tmpHasCaptured) { + if (onEnd) { + onEnd(detail); } return; } // Not captured any event - if (this.notCaptured) { - this.notCaptured(detail); + if (notCaptured) { + notCaptured(detail); } } + + return { + setDisabled(disabled: boolean) { + pointerEvents.disabled = disabled; + }, + destroy() { + gesture.destroy(); + pointerEvents.destroy(); + } + }; } function updateDetail(ev: any, detail: GestureDetail) {