Skip to content

Introduction to Fabric.js. Part 5

Zoom and pan, introduction to Fabric.js part 5

Section titled “Zoom and pan, introduction to Fabric.js part 5”

We’ve covered so many topics in the previous series; from basic object manipulations to animations, events, filters, groups, and subclasses. But there’s still couple of very interesting and useful things to discuss!

Let’s see how we can implement a basic system of zoom and pan with the mouse interactions. We will use the mouse wheel to zoom up to 20X ( 2000% ) on a canvas and a alt + click action to drag around.
We start be hooking up the basic controls:

canvas.on('mouse:wheel', function(opt) {
var delta = opt.e.deltaY;
var zoom = canvas.getZoom();
zoom *= 0.999 ** delta;
if (zoom > 20) zoom = 20;
if (zoom < 0.01) zoom = 0.01;
canvas.setZoom(zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
})

This is a basic zoom control, limited between 1% and 2000%. we want now to add dragging of the canvas. We will use ALT + DRAG, but you can change to another combination. The idea is that a mousedown with alt will set a boolean to true, so that a mouse move event can then understand that is time for dragging.

canvas.on('mouse:down', function(opt) {
var evt = opt.e;
if (evt.altKey === true) {
this.isDragging = true;
this.selection = false;
this.lastPosX = evt.clientX;
this.lastPosY = evt.clientY;
}
});
canvas.on('mouse:move', function(opt) {
if (this.isDragging) {
var e = opt.e;
var vpt = this.viewportTransform;
vpt[4] += e.clientX - this.lastPosX;
vpt[5] += e.clientY - this.lastPosY;
this.requestRenderAll();
this.lastPosX = e.clientX;
this.lastPosY = e.clientY;
}
});
canvas.on('mouse:up', function(opt) {
// on mouse up we want to recalculate new interaction
// for all objects, so we call setViewportTransform
this.setViewportTransform(this.viewportTransform);
this.isDragging = false;
this.selection = true;
});

Ok, this is a basic setup that will allow you to control zoom and panning. There are still a couple of possible enhancement.
For example we can make the wheel-zoom to center the canvas around the point where the cursor is:

canvas.on('mouse:wheel', function(opt) {
var delta = opt.e.deltaY;
var zoom = canvas.getZoom();
zoom *= 0.999 ** delta;
if (zoom > 20) zoom = 20;
if (zoom < 0.01) zoom = 0.01;
canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
});

As a final touch we can limit the panning area to avoid view to go infinity in one direction. We stroke a rect of 1000x1000 pixels that will represent our panning area. And we add the code to limit the movements in that boundaries:

canvas.on('mouse:wheel', function(opt) {
var delta = opt.e.deltaY;
var zoom = canvas.getZoom();
zoom *= 0.999 ** delta;
if (zoom > 20) zoom = 20;
if (zoom < 0.01) zoom = 0.01;
canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
var vpt = this.viewportTransform;
if (zoom < 400 / 1000) {
vpt[4] = 200 - 1000 * zoom / 2;
vpt[5] = 200 - 1000 * zoom / 2;
} else {
if (vpt[4] >= 0) {
vpt[4] = 0;
} else if (vpt[4] < canvas.getWidth() - 1000 * zoom) {
vpt[4] = canvas.getWidth() - 1000 * zoom;
}
if (vpt[5] >= 0) {
vpt[5] = 0;
} else if (vpt[5] < canvas.getHeight() - 1000 * zoom) {
vpt[5] = canvas.getHeight() - 1000 * zoom;
}
})