index : pan-zoom | |
SVG pan/zoom library. |
aboutsummaryrefslogtreecommitdiff |
diff options
Diffstat (limited to 'src/modules/pan.js')
-rw-r--r-- | src/modules/pan.js | 79 |
1 files changed, 53 insertions, 26 deletions
diff --git a/src/modules/pan.js b/src/modules/pan.js index 6f2cacf..4e6485c 100644 --- a/src/modules/pan.js +++ b/src/modules/pan.js @@ -2,11 +2,15 @@ import getComputedTransformMatrix from './utils.js'; const minDistanceThreshold = 5; +function mainButtonPressed(e) { + return e.button === 0; +} + function distanceBetween({ x: x1, y: y1 }, { x: x2, y: y2 }) { return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2); } -function minDistanceThresholdIsMet(startPt, endPt) { +function exceedsMinDistanceThreshhold(startPt, endPt) { return distanceBetween(startPt, endPt) >= minDistanceThreshold; } @@ -20,45 +24,68 @@ function getTranslateMatrix(startPt, movePt) { return translateMatrix.translate(movePt.x - startPt.x, movePt.y - startPt.y); } -export default function (svg, el, e) { - e.preventDefault(); +function getTransformMatrices(el) { + return { + computed: getComputedTransformMatrix(el), + inverseScreen: el.getScreenCTM().inverse() + }; +} - const mtx = getComputedTransformMatrix(el), - inverseScreenCTM = el.getScreenCTM().inverse(); +function clientToSvgPt({ clientX, clientY }, { inverseScreen }, pt = new DOMPoint()) { + pt.x = clientX; + pt.y = clientY; + return pt.matrixTransform(inverseScreen); +} - let startPt = new DOMPoint(e.clientX, e.clientY), - movePt = new DOMPoint(), - isPanning = false; +function setPanTransform(el, { computed }, startPt, endPt) { + el.style.transform = computed.multiply(getTranslateMatrix(startPt, endPt)); +} + +export function programmaticPan(el, from, to) { + const matrices = getTransformMatrices(el); + const startPt = clientToSvgPt(from, matrices); + const endPt = clientToSvgPt(to, matrices); + + el.style.transition = 'transform 0.5s'; + setPanTransform(el, matrices, startPt, endPt); + el.addEventListener('transitionend', () => el.style.transition = '', { once: true }); +} + +export default function (el) { + let matrices, startPt, movePt, isPanning; function pointerMove(e) { movePt.x = e.clientX; movePt.y = e.clientY; - if (!isPanning && minDistanceThresholdIsMet(startPt, movePt)) { + if (!isPanning && exceedsMinDistanceThreshhold(startPt, movePt)) { isPanning = true; - e.target.setPointerCapture(e.pointerId); - - startPt.x = e.clientX; - startPt.y = e.clientY; - startPt = startPt.matrixTransform(inverseScreenCTM); - + startPt = clientToSvgPt(e, matrices, startPt); stopEventPropagationToChildren(el, 'click'); } if (isPanning) { - movePt.x = e.clientX; - movePt.y = e.clientY; - movePt = movePt.matrixTransform(inverseScreenCTM); - - el.style.transform = mtx.multiply(getTranslateMatrix(startPt, movePt)); + movePt = clientToSvgPt(e, matrices, movePt); + setPanTransform(el, matrices, startPt, movePt); } } - svg.addEventListener('pointermove', pointerMove); + return function(e) { + if (!mainButtonPressed(e)) return; + e.preventDefault(); + e.target.setPointerCapture(e.pointerId); - svg.addEventListener( - 'pointerup', - () => svg.removeEventListener('pointermove', pointerMove), - { once: true } - ); + isPanning = false; + matrices = getTransformMatrices(el); + startPt = new DOMPoint(e.clientX, e.clientY); + movePt = new DOMPoint(); + + this.addEventListener('pointermove', pointerMove); + + this.addEventListener( + 'pointerup', + () => this.removeEventListener('pointermove', pointerMove), + { once: true } + ); + } } |