From e3dc402b13efb5a8af2cbae729f7bd7d12e54ad0 Mon Sep 17 00:00:00 2001 From: Matt Nathan Date: Thu, 6 Feb 2020 14:45:27 +0000 Subject: [PATCH] feat: add a minDistance configuration option This change makes it possible to configure a minimum distance that is used as a threshold to determine whether to begin a pan or zoom operation when triggered via pointer events. This option can help in situations when small movements during a click/tap cause the element to move slightly which is a little off putting. --- src/panzoom.ts | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/panzoom.ts b/src/panzoom.ts index c8d1f610..9a38f36c 100644 --- a/src/panzoom.ts +++ b/src/panzoom.ts @@ -36,6 +36,7 @@ const defaultOptions: PanzoomOptions = { e.stopPropagation() }, maxScale: 4, + minDistance: 0, minScale: 0.125, overflow: 'hidden', panOnlyWhenZoomed: false, @@ -121,6 +122,7 @@ function Panzoom( let x = 0 let y = 0 let scale = 1 + let isWatching = false let isPanning = false zoom(options.startScale, { animate: false }) // Wait for scale to update @@ -407,13 +409,11 @@ function Panzoom( return } addPointer(pointers, event) - isPanning = true + isWatching = true options.handleStartEvent(event) origX = x origY = y - trigger('panzoomstart', { x, y, scale }, options) - // This works whether there are multiple // pointers or not const point = getMiddle(pointers) @@ -425,7 +425,7 @@ function Panzoom( function move(event: PointerEvent) { if ( - !isPanning || + !isWatching || origX === undefined || origY === undefined || startClientX === undefined || @@ -435,21 +435,36 @@ function Panzoom( } addPointer(pointers, event) const current = getMiddle(pointers) + let scaleDiff = 0 if (pointers.length > 1) { // Use the distance between the first 2 pointers // to determine the current scale - const diff = getDistance(pointers) - startDistance - const toScale = constrainScale((diff * options.step) / 80 + startScale).scale - zoomToPoint(toScale, current) + scaleDiff = getDistance(pointers) - startDistance + } + + if (!isPanning) { + // have we moved far enough to trigger panning/zooming + const panDiff = Math.hypot(current.clientX - startClientX, current.clientY - startClientY) + if (Math.abs(scaleDiff) > options.minDistance || panDiff > options.minDistance) { + trigger('panzoomstart', { origX, origY, startScale }, options) + isPanning = true + } } - pan( - origX + (current.clientX - startClientX) / scale, - origY + (current.clientY - startClientY) / scale, - { - animate: false + if (isPanning) { + if (pointers.length > 1) { + const toScale = constrainScale((scaleDiff * options.step) / 80 + startScale).scale + zoomToPoint(toScale, current) } - ) + + pan( + origX + (current.clientX - startClientX) / scale, + origY + (current.clientY - startClientY) / scale, + { + animate: false + } + ) + } } function handleUp(event: PointerEvent) { @@ -462,9 +477,10 @@ function Panzoom( // Can restart without having to reinitiate all of them // Remove the pointer regardless of the isPanning state removePointer(pointers, event) - if (!isPanning) { + if (!isWatching) { return } + isWatching = false isPanning = false origX = origY = startClientX = startClientY = undefined }