I’m trying to make a zoom and drag system with javascript and css3 transform scale.
Dragging works but scaling has some problems. I would like to have so that it zooms toward the center of the mouse.
Here is my code:
<!DOCTYPE html>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
<meta charset="utf-8">
<viewport>
<container>
<img src="http://placehold.it/300x200">
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<div style="position: absolute; top: 100px; left: 400px; width: 40px; height: 40px; background: red;"></div>
</container>
</viewport>
<input type="text" id="zoom">
<button onclick="setScale(Number(document.getElementById('zoom').value))">Set Scale</button>
<p>
Zoom with mousewheel and drag with middle mouseclick;
</p>
<style>
viewport {
display: block;
position: relative;
height: 500px;
background: #4c4e58;
overflow: hidden;
}
container {
display: block;
position: relative;
width: 1000px; height: 1000px;
transform-origin: 0 0;
}
</style>
<script>
class Container {
constructor(container) {
this.container = container;
this.viewport = container.parentNode;
let rect = this.viewport.getBoundingClientRect();
this.width = rect.width;
this.height = rect.height;
this.x = 0, this.y = 0;
this.scale = 1; // default scale
this.zoom = 1.1; // 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.preventDefault();
this.dragging = true;
this.updateStyles();
let rect = container.getBoundingClientRect();
startPos = {x: e.clientX - rect.left, y: e.clientY - rect.top};
}
});
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.setZoom(scale, mouseX, mouseY);
};
viewport.addEventListener('DOMMouseScroll', onscroll); // Firefox
viewport.addEventListener('mousewheel', onscroll); // Chrome, etc.
}
setZoom(scale, x = this.width / 2, y = this.height / 2) {
let oldscale = this.scale;
this.scale = scale;
// let scalechange = (this.scale - oldscale) / this.scale;
let scalechange = this.scale - oldscale;
this.scale = this.scale < .25 ? .25 : this.scale;
this.scale = this.scale > 4 ? 4 : this.scale;
this.x = Math.round(-(x - this.x) * scalechange + this.x);
this.y = Math.round(-(y - this.y) * scalechange + this.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.viewport.style.cursor = this.dragging ? 'move' : '';
}
}
let container = new Container(document.querySelector('container'));
function setScale(scale) {
console.log("scale", scale);
container.setZoom(scale);
}
</script>
The code is not yet quite as good. It would be cool if someone can help me with the code.