Skip to content

Instantly share code, notes, and snippets.

@zopieux
Created December 25, 2023 23:29
Show Gist options
  • Save zopieux/8dae05ca985b0fcf65e0d38df65704d5 to your computer and use it in GitHub Desktop.
Save zopieux/8dae05ca985b0fcf65e0d38df65704d5 to your computer and use it in GitHub Desktop.
SVG *coordinate* (abstract, manual, maths) pan zoom, *not* using SVG transforms
const s = document.querySelector('svg');
const [c1, c2] = [...s.querySelectorAll('circle')];
const mat = new DOMMatrix();
let origScene = null, lastWorld = null;
s.addEventListener('mousedown', (evt) => {
lastWorld = { x: evt.offsetX || (evt.pageX - s.offsetLeft), y: evt.offsetY || (evt.pageY - s.offsetTop) };
origScene = new DOMPoint(lastWorld.x, lastWorld.y).matrixTransform(mat.inverse());
});
s.addEventListener('mousemove', (evt) => {
if (!!origScene) {
lastWorld = { x: evt.offsetX, y: evt.offsetY };
const lastScene = new DOMPoint(lastWorld.x, lastWorld.y).matrixTransform(mat.inverse());
mat.translateSelf(lastScene.x - origScene.x, lastScene.y - origScene.y);
redraw();
}
});
s.addEventListener('mouseup', (evt) => {
origScene = null;
});
s.addEventListener('wheel', (evt) => {
const sign = evt.deltaY > 0 ? -1 : 1, scale = Math.pow(1.1, sign * 1);
const dragOffset = new DOMPoint(evt.offsetX, evt.offsetY);
mat.preMultiplySelf(new DOMMatrix().translateSelf(dragOffset.x, dragOffset.y).scaleSelf(scale, scale).translateSelf(-dragOffset.x, -dragOffset.y))
redraw();
})
function redraw() {
let ptScene = mat.transformPoint(new DOMPoint(100, 100));
c1.setAttribute('cx', ptScene.x);
c1.setAttribute('cy', ptScene.y);
ptScene = mat.transformPoint(new DOMPoint(200, 150));
c2.setAttribute('cx', ptScene.x);
c2.setAttribute('cy', ptScene.y);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment