I’m currently trying to use the d3 zoom library to add smooth zooming and panning to my canvas element. It should work for different viewport sizes, so I need to have the size of the canvas elements relative to the viewport.
When zoomed out as far as possible (as controlled by the scaleExtent) the elements should fill the screen width nicely on all devices.
const canvas = document.querySelector('canvas')
const context = canvas.getContext('2d')
canvas.width = canvas.offsetWidth
canvas.height = canvas.offsetHeight
const zoom = d3.zoom()
.scaleExtent([0.4, 2])
.on('zoom', ({transform}) => zoomed(transform))
d3.select(canvas).call(zoom)
zoomed(d3.zoomIdentity)
function zoomed(transform) {
console.log(transform);
context.save()
context.clearRect(0,0, canvas.width, canvas.height)
const scale = transform.k * canvas.width/2000
context.translate(transform.x, transform.y)
context.scale(scale, scale)
drawPaths()
context.restore()
}
I tried adding some sort of value (that’s relative to the canvas width) to the scale value, but I’m just guessing the 2000 and I am afraid it might mess with my code later on, when I don’t manipulate the d3 transform object.
Here is a Codepen: https://codepen.io/lkssmnt-the-lessful/pen/wvgjmbw
I solved it by using a zoom-to-fit method on initialization:
function initCanvas() {
const midX = bbox.x + bbox.width / 2;
const midY = bbox.y + bbox.height / 2;
const scale = Math.min(viewportWidth / bbox.width, viewportHeight / bbox.height);
const translateX = viewportWidth / 2 - midX * scale;
const translateY = viewportHeight / 2 - midY * scale;
d3.select(canvas).call(
zoom_function.transform,
d3.zoomIdentity.translate(translateX, translateY).scale(scale)
);
}
This will center your paths on initialization but will not make the zoomExtent relative to the viewportsize. This could however also be done by just giving the scaleExtent function a relative value.
Additional info about bounding box: In my case, as the paths were not changing, figuring out the bounding box was not something I had to do programmatically but there are ways to do it like this: https://codepen.io/TomashKhamlai/pen/KNrjqE