Web Dev Solutions

Catalin Mititiuc

aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--index.js2
-rw-r--r--src/modules/pan.js79
-rw-r--r--src/modules/zoom.js43
3 files changed, 78 insertions, 46 deletions
diff --git a/index.js b/index.js
index b619e1b..c0afa1b 100644
--- a/index.js
+++ b/index.js
@@ -1,2 +1,2 @@
-export { default as pan } from './src/modules/pan.js';
+export { default as pan, programmaticPan } from './src/modules/pan.js';
export { default as zoom } from './src/modules/zoom.js';
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 }
+ );
+ }
}
diff --git a/src/modules/zoom.js b/src/modules/zoom.js
index fc0540b..834602b 100644
--- a/src/modules/zoom.js
+++ b/src/modules/zoom.js
@@ -5,14 +5,17 @@ function zoomIn(deltaY) {
}
function getScale(e, factor) {
- return zoomIn(e.deltaY) ? 1 + factor : 1 - factor;
+ const outMult = 1 - factor;
+ const inMult = 1 + factor / outMult
+
+ return zoomIn(e.deltaY) ? inMult : outMult;
}
function getFocalPointBeforeTransform(el, e, inverseScreenCTM) {
- const { x, y, width, height } = el.getBoundingClientRect(),
- pointer = (new DOMPoint(e.clientX, e.clientY)).matrixTransform(inverseScreenCTM),
- origin = (new DOMPoint(x, y)).matrixTransform(inverseScreenCTM),
- terminus = (new DOMPoint(x + width, y + height)).matrixTransform(inverseScreenCTM);
+ const { x, y, width, height } = el.getBoundingClientRect();
+ const pointer = (new DOMPoint(e.clientX, e.clientY)).matrixTransform(inverseScreenCTM);
+ const origin = (new DOMPoint(x, y)).matrixTransform(inverseScreenCTM);
+ const terminus = (new DOMPoint(x + width, y + height)).matrixTransform(inverseScreenCTM);
return {
x: pointer.x,
@@ -25,10 +28,10 @@ function getFocalPointBeforeTransform(el, e, inverseScreenCTM) {
}
function getFocalPointAfterTransform(el, fpBeforeTrans, inverseScreenCTM) {
- const { x, y, width, height } = el.getBoundingClientRect(),
- origin = (new DOMPoint(x, y)).matrixTransform(inverseScreenCTM),
- terminus = (new DOMPoint(x + width, y + height)).matrixTransform(inverseScreenCTM),
- relativeFocalPoint = fpBeforeTrans.relativeToImageSize;
+ const { x, y, width, height } = el.getBoundingClientRect();
+ const origin = (new DOMPoint(x, y)).matrixTransform(inverseScreenCTM);
+ const terminus = (new DOMPoint(x + width, y + height)).matrixTransform(inverseScreenCTM);
+ const relativeFocalPoint = fpBeforeTrans.relativeToImageSize;
return {
x: origin.x + (terminus.x - origin.x) * relativeFocalPoint.x,
@@ -37,13 +40,13 @@ function getFocalPointAfterTransform(el, fpBeforeTrans, inverseScreenCTM) {
}
function getTranslateMatrix(el, e, scaleMatrix) {
- const inverseScreenCTM = el.getScreenCTM().inverse(),
- fpBeforeTrans = getFocalPointBeforeTransform(el, e, inverseScreenCTM);
+ const inverseScreenCTM = el.getScreenCTM().inverse();
+ const fpBeforeTrans = getFocalPointBeforeTransform(el, e, inverseScreenCTM);
el.style.transform = scaleMatrix;
- const fpAfterTrans = getFocalPointAfterTransform(el, fpBeforeTrans, inverseScreenCTM),
- translateMatrix = new DOMMatrix();
+ const fpAfterTrans = getFocalPointAfterTransform(el, fpBeforeTrans, inverseScreenCTM);
+ const translateMatrix = new DOMMatrix();
return translateMatrix.translate(
fpBeforeTrans.x - fpAfterTrans.x,
@@ -51,12 +54,14 @@ function getTranslateMatrix(el, e, scaleMatrix) {
);
}
-export default function (el, e, factor = 0.1) {
- e.preventDefault();
+export default function (el, factor = 0.1) {
+ return e => {
+ e.preventDefault();
- const mtx = getComputedTransformMatrix(el),
- scale = getScale(e, factor),
- transMtx = getTranslateMatrix(el, e, mtx.scale(scale));
+ const mtx = getComputedTransformMatrix(el);
+ const scale = getScale(e, factor);
+ const transMtx = getTranslateMatrix(el, e, mtx.scale(scale));
- el.style.transform = mtx.multiply(transMtx).scale(scale);
+ el.style.transform = mtx.multiply(transMtx).scale(scale);
+ }
}