I’ve now changed for transform-origin
. Before the next scroll it reset the origin and set top, left style properties.
The first scroll works fine but the second is shifted.
class Container {
constructor(container) {
this.container = container;
this.viewport = container.parentNode;
let rect = container.getBoundingClientRect();
this.width = rect.width;
this.height = rect.height;
this.x = 0, this.y = 0;
this.origin = {x: 0, y: 0};
this.scale = 1; // default scale
this.zoom = 1.125; // zoom factor
this.dragging = false;
this.init();
}
init() {
this.updateStyles();
let container = this.container;
let viewport = this.viewport;
let viewRect = viewport.getBoundingClientRect();
let startPos = {x: 0, y: 0};
viewport.addEventListener('mousedown', (e) => {
if (e.button == 1 || e.shiftKey) {
e.preventDefault();
this.dragging = true;
this.updateStyles();
let rect = container.getBoundingClientRect();
startPos = {
x: e.pageX - this.x,
y: e.pageY - this.y
};
} else if (e.ctrlKey) {
// ctrl + click to recenter the origin
this.recenter();
this.updateStyles();
}
});
window.addEventListener('mousemove', (e) => {
if (this.dragging) {
this.x = e.pageX - startPos.x;
this.y = e.pageY - startPos.y;
this.updateStyles();
}
});
window.addEventListener('mouseup', () => {
if (this.dragging) {
this.dragging = false;
this.updateStyles();
}
});
let onscroll = (e) => {
e.preventDefault();
let scale = 0;
let wheel = e.detail || e.deltaY;
scale = wheel > 0 ? this.scale / this.zoom : this.scale * this.zoom;
let mouseX = (e.pageX - viewRect.left);
let mouseY = (e.pageY - viewRect.top);
this.setScale(scale, mouseX, mouseY);
};
viewport.addEventListener('DOMMouseScroll', onscroll); // Firefox
viewport.addEventListener('mousewheel', onscroll); // Chrome, etc.
}
recenter() {
// Calculate left and top property from origin and reset the origin
this.x -= (this.origin.x * this.scale) - this.origin.x;
this.y -= (this.origin.y * this.scale) - this.origin.y;
this.origin = {x:0, y:0};
}
setScale(scale, x = this.width / 2, y = this.height / 2) {
console.log("x, y", x, y);
this.recenter();
// Get relative pos from container
x = x - this.x;
y = y - this.y;
this.scale = scale;
this.scale = this.scale < .25 ? .25 : this.scale; // min zoom
this.scale = this.scale > 4 ? 4 : this.scale; // max zoom
this.origin = {
x: x,
y: y
};
this.updateStyles();
}
updateStyles() {
this.container.style.left = this.x + 'px';
this.container.style.top = this.y + 'px';
this.container.style.transform = `scale(${this.scale})`;
this.container.style.transformOrigin = `${this.origin.x}px ${this.origin.y}px`;
this.viewport.style.cursor = this.dragging ? 'move' : '';
}
}
df