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; } })