Skip to content

Instantly share code, notes, and snippets.

@HMilbradt
Last active March 26, 2023 19:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save HMilbradt/84cf24e735f99da8115ba523bbc1def2 to your computer and use it in GitHub Desktop.
Save HMilbradt/84cf24e735f99da8115ba523bbc1def2 to your computer and use it in GitHub Desktop.
Zooming and panning natively in HTML Canvas.
<html>
<body>
<canvas width="500" height="500" id="canvas"></canvas>
<script>
// Read here: https://harrisonmilbradt.com/articles/canvas-panning-and-zooming
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
const viewportTransform = {
x: 0,
y: 0,
scale: 1
}
// From here on, everything we'll write will go below 👇
const drawRect = (x, y, width, height, color) => {
ctx.fillStyle = color
ctx.fillRect(x, y, width, height)
}
const render = () => {
// New code 👇
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.setTransform(viewportTransform.scale, 0, 0, viewportTransform.scale, viewportTransform.x, viewportTransform.y);
// New Code 👆
drawRect(0, 0, 100, 100, 'red');
drawRect(200, 200, 100, 100, 'blue');
}
// We need to keep track of our previous mouse position for later
let previousX = 0, previousY = 0;
const updatePanning = (e) => {
const localX = e.clientX;
const localY = e.clientY;
viewportTransform.x += localX - previousX;
viewportTransform.y += localY - previousY;
previousX = localX;
previousY = localY;
}
const updateZooming = (e) => {
const oldScale = viewportTransform.scale;
const oldX = viewportTransform.x;
const oldY = viewportTransform.y;
const localX = e.clientX;
const localY = e.clientY;
const previousScale = viewportTransform.scale;
const newScale = viewportTransform.scale += e.deltaY * -0.01;
const newX = localX - (localX - oldX) * (newScale / previousScale);
const newY = localY - (localY - oldY) * (newScale / previousScale);
viewportTransform.x = newX;
viewportTransform.y = newY;
viewportTransform.scale = newScale;
}
const onMouseMove = (e) => {
updatePanning(e)
render()
console.log(e)
}
const onMouseWheel = (e) => {
updateZooming(e)
render()
console.log(e)
}
canvas.addEventListener("wheel", onMouseWheel);
canvas.addEventListener("mousedown", (e) => {
previousX = e.clientX;
previousY = e.clientY;
canvas.addEventListener("mousemove", onMouseMove);
})
canvas.addEventListener("mouseup", (e) => {
canvas.removeEventListener("mousemove", onMouseMove);
})
render()
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment