Web Dev Solutions

Catalin Mititiuc

aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/pan.js62
-rw-r--r--src/modules/utils.js8
-rw-r--r--src/modules/zoom.js75
3 files changed, 68 insertions, 77 deletions
diff --git a/src/modules/pan.js b/src/modules/pan.js
index 9faae0a..201c2f1 100644
--- a/src/modules/pan.js
+++ b/src/modules/pan.js
@@ -1,5 +1,14 @@
+import getComputedTransformMatrix from './utils.js';
+
const minDistanceThreshold = 5;
+function setToCurrentPointerCoords(point, e) {
+ point.x = e.clientX;
+ point.y = e.clientY;
+
+ return point;
+}
+
function distanceBetween({ x: x1, y: y1 }, { x: x2, y: y2 }) {
return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
}
@@ -8,46 +17,21 @@ function minDistanceThresholdIsMet(startPt, endPt) {
return distanceBetween(startPt, endPt) >= minDistanceThreshold;
}
-function getPositionChangeInLocalCoords(svg, startPt, endPt) {
- const matrix = svg.getScreenCTM().inverse(),
- localStartPt = startPt.matrixTransform(matrix),
- localEndPt = endPt.matrixTransform(matrix);
-
- return {
- x: localStartPt.x - localEndPt.x,
- y: localStartPt.y - localEndPt.y
- };
-}
-
-function stopEventPropagationToChildren(svg, type) {
- svg.addEventListener(type, e => e.stopPropagation(), { capture: true, once: true });
-}
-
-function setToCurrentPointerCoords(point, e) {
- point.x = e.clientX;
- point.y = e.clientY;
-
- return point;
+function stopEventPropagationToChildren(el, type) {
+ el.addEventListener(type, e => e.stopPropagation(), { capture: true, once: true });
}
-function getPanCoords(svg, startPt, movePt, initialPos) {
- const posChange = getPositionChangeInLocalCoords(svg, startPt, movePt);
+function getTranslateMatrix(startPt, movePt) {
+ const translateMatrix = new DOMMatrix();
- return {
- x: initialPos.x + posChange.x,
- y: initialPos.y + posChange.y
- };
+ return translateMatrix.translate(movePt.x - startPt.x, movePt.y - startPt.y);
}
-function setViewBoxPosition(svg, { x, y }) {
- const { width, height } = svg.viewBox.baseVal;
-
- svg.setAttributeNS(null, 'viewBox', `${x} ${y} ${width} ${height}`);
-}
+export default function (el, e) {
+ e.preventDefault();
-export default function (svg, e) {
- const { x, y } = svg.viewBox.baseVal,
- startPt = setToCurrentPointerCoords(new DOMPoint(), e),
+ const mtx = getComputedTransformMatrix(el),
+ startPt = new DOMPoint(e.clientX, e.clientY),
movePt = new DOMPoint();
let isPanning = false;
@@ -59,19 +43,19 @@ export default function (svg, e) {
isPanning = true;
e.target.setPointerCapture(e.pointerId);
setToCurrentPointerCoords(startPt, e);
- stopEventPropagationToChildren(svg, 'click');
+ stopEventPropagationToChildren(el, 'click');
}
if (isPanning) {
- setViewBoxPosition(svg, getPanCoords(svg, startPt, movePt, { x, y }));
+ el.style.transform = getTranslateMatrix(startPt, movePt).multiply(mtx);
}
}
- svg.addEventListener('pointermove', pointerMove);
+ el.addEventListener('pointermove', pointerMove);
- svg.addEventListener(
+ el.addEventListener(
'pointerup',
- () => svg.removeEventListener('pointermove', pointerMove),
+ () => el.removeEventListener('pointermove', pointerMove),
{ once: true }
);
}
diff --git a/src/modules/utils.js b/src/modules/utils.js
new file mode 100644
index 0000000..e7f5c55
--- /dev/null
+++ b/src/modules/utils.js
@@ -0,0 +1,8 @@
+const digits = /-?\d+\.?\d*/g;
+
+export default function getComputedTransformMatrix(el) {
+ const matrixSequence = getComputedStyle(el).transform.match(digits),
+ identityMatrix = '';
+
+ return new DOMMatrix(matrixSequence || identityMatrix);
+}
diff --git a/src/modules/zoom.js b/src/modules/zoom.js
index 24ddb79..97a23e1 100644
--- a/src/modules/zoom.js
+++ b/src/modules/zoom.js
@@ -1,57 +1,56 @@
-const zoomStepRatio = 0.25,
- positive = 1,
- negative = -1;
-
-function toLocalCoords(svg, x, y) {
- const clientP = new DOMPoint(x, y);
-
- return clientP.matrixTransform(svg.getScreenCTM().inverse());
-}
+import getComputedTransformMatrix from './utils.js';
function zoomIn(deltaY) {
return deltaY < 0;
}
-function calcSizeChangeAmounts(width, height) {
- return {
- width: width * zoomStepRatio,
- height: height * zoomStepRatio
- };
+function getScale(e, factor) {
+ return zoomIn(e.deltaY) ? 1 + factor : 1 - factor;
}
-function calcValChangeRatios(focusPoint, x, y, width, height) {
+function getFocalPointBeforeTransform(el, e) {
+ const { x, y, width, height } = el.getBoundingClientRect();
+
return {
- x: (focusPoint.x - x) / width,
- y: (focusPoint.y - y) / height,
- width: (width + x - focusPoint.x) / width,
- height: (height + y - focusPoint.y) / height
+ x: e.clientX,
+ y: e.clientY,
+ relativeToImageSize: {
+ x: (e.clientX - x) / width,
+ y: (e.clientY - y) / height
+ }
};
}
-function calcValChangeAmounts(focusPoint, x, y, width, height) {
- const changeAmount = calcSizeChangeAmounts(width, height),
- valChangeRatio = calcValChangeRatios(focusPoint, x, y, width, height);
+function getFocalPointAfterTransform(el, fpBeforeTrans) {
+ const { x, y, width, height } = el.getBoundingClientRect(),
+ relativeFocalPoint = fpBeforeTrans.relativeToImageSize;
return {
- x: valChangeRatio.x * changeAmount.width,
- y: valChangeRatio.y * changeAmount.height,
- width: valChangeRatio.width * changeAmount.width,
- height: valChangeRatio.height * changeAmount.height
+ x: x + width * relativeFocalPoint.x,
+ y: y + height * relativeFocalPoint.y
};
}
-export default function (svg, e) {
- const pointerPosition = toLocalCoords(svg, e.clientX, e.clientY),
- sign = zoomIn(e.deltaY) ? positive : negative,
- { x, y, width, height } = svg.viewBox.baseVal,
- changeAmount = calcValChangeAmounts(pointerPosition, x, y, width, height),
+function getTranslateMatrix(el, e, scaleMatrix) {
+ const fpBeforeTrans = getFocalPointBeforeTransform(el, e);
+
+ el.style.transform = scaleMatrix;
+
+ const fpAfterTrans = getFocalPointAfterTransform(el, fpBeforeTrans),
+ translateMatrix = new DOMMatrix();
+
+ return translateMatrix.translate(
+ fpBeforeTrans.x - fpAfterTrans.x,
+ fpBeforeTrans.y - fpAfterTrans.y
+ );
+}
+
+export default function (el, e, factor = 0.1) {
+ e.preventDefault();
- attr = {
- x: x + sign * changeAmount.x,
- y: y + sign * changeAmount.y,
- width: width + sign * (-changeAmount.x - changeAmount.width),
- height: height + sign * (-changeAmount.y - changeAmount.height)
- };
+ const mtx = getComputedTransformMatrix(el),
+ scale = getScale(e, factor),
+ transMtx = getTranslateMatrix(el, e, mtx.scale(scale));
- return `${attr.x} ${attr.y} ${attr.width} ${attr.height}`;
+ el.style.transform = transMtx.multiply(mtx).scale(scale);
}