Pan y zoom Fabricjs

¿Cómo puedo desplazarme y hacer zoom usando fabricjs? He intentado utilizar los methods zoomToPoint y setZoom, pero no funcionan para la panorámica. Una vez que empiezo a usar diferentes puntos de acercamiento, empiezo a tener problemas.

$('#zoomIn').click(function(){ canvas.setZoom(canvas.getZoom() * 1.1 ) ; }) ; $('#zoomOut').click(function(){ canvas.setZoom(canvas.getZoom() / 1.1 ) ; }) ; $('#goRight').click(function(){ //Need to implement }) ; $('#goLeft').click(function(){ //Need to implement }) ; 

http://jsfiddle.net/hdramos/ux16013L/

Resuelto usando:

relativePan () absolutePan ()

[Actualizar]

 $('#goRight').click(function(){ var units = 10 ; var delta = new fabric.Point(units,0) ; canvas.relativePan(delta) ; }) ; $('#goLeft').click(function(){ var units = 10 ; var delta = new fabric.Point(-units,0) ; canvas.relativePan(delta) ; }) ; $('#goUp').click(function(){ var units = 10 ; var delta = new fabric.Point(0,-units) ; canvas.relativePan(delta) ; }) ; $('#goDown').click(function(){ var units = 10 ; var delta = new fabric.Point(0,units) ; canvas.relativePan(delta) ; }); 

http://jsfiddle.net/ux16013L/2/

Sé que ya está respondida, pero tuve que hacer una panorámica del mouse, así que adapté el violín de la respuesta aceptada para hacerlo. Lo publico aquí para cualquiera que tenga que hacer algo como esto. Esta es solo la idea principal:

 var panning = false; canvas.on('mouse:up', function (e) { panning = false; }); canvas.on('mouse:down', function (e) { panning = true; }); canvas.on('mouse:move', function (e) { if (panning && e && ee) { var units = 10; var delta = new fabric.Point(eemovementX, eemovementY); canvas.relativePan(delta); } }); 

Aquí está el violín: http://jsfiddle.net/gncabrera/hkee5L6d/5/

Aquí está mi solución para el zoom de canvas (usando la rueda del mouse) y la panorámica (usando las teclas izquierda / arriba / derecha / abajo o la tecla Mayús + ratón hacia abajo + movimiento del mouse).

https://jsfiddle.net/milanhlinak/7s4w0uLy/8/

 <!DOCTYPE html> <html> <head> <script type="text/javascript" src="lib/jquery-3.1.1.min.js"></script> <script type="text/javascript" src="lib/fabric.min.js"></script> </head> <body> <canvas id="canvas" style="border: 1px solid #cccccc"></canvas> <script> var Direction = { LEFT: 0, UP: 1, RIGHT: 2, DOWN: 3 }; var zoomLevel = 0; var zoomLevelMin = 0; var zoomLevelMax = 3; var shiftKeyDown = false; var mouseDownPoint = null; var canvas = new fabric.Canvas('canvas', { width: 500, height: 500, selectionKey: 'ctrlKey' }); canvas.add(new fabric.Rect({ left: 100, top: 100, width: 50, height: 50, fill: '#faa' })); canvas.add(new fabric.Rect({ left: 300, top: 300, width: 50, height: 50, fill: '#afa' })); canvas.on('mouse:down', function (options) { var pointer = canvas.getPointer(options.e, true); mouseDownPoint = new fabric.Point(pointer.x, pointer.y); }); canvas.on('mouse:up', function (options) { mouseDownPoint = null; }); canvas.on('mouse:move', function (options) { if (shiftKeyDown && mouseDownPoint) { var pointer = canvas.getPointer(options.e, true); var mouseMovePoint = new fabric.Point(pointer.x, pointer.y); canvas.relativePan(mouseMovePoint.subtract(mouseDownPoint)); mouseDownPoint = mouseMovePoint; keepPositionInBounds(canvas); } }); fabric.util.addListener(document.body, 'keydown', function (options) { if (options.repeat) { return; } var key = options.which || options.keyCode; // key detection if (key == 16) { // handle Shift key canvas.defaultCursor = 'move'; canvas.selection = false; shiftKeyDown = true; } else if (key === 37) { // handle Left key move(Direction.LEFT); } else if (key === 38) { // handle Up key move(Direction.UP); } else if (key === 39) { // handle Right key move(Direction.RIGHT); } else if (key === 40) { // handle Down key move(Direction.DOWN); } }); fabric.util.addListener(document.body, 'keyup', function (options) { var key = options.which || options.keyCode; // key detection if (key == 16) { // handle Shift key canvas.defaultCursor = 'default'; canvas.selection = true; shiftKeyDown = false; } }); jQuery('.canvas-container').on('mousewheel', function (options) { var delta = options.originalEvent.wheelDelta; if (delta != 0) { var pointer = canvas.getPointer(options.e, true); var point = new fabric.Point(pointer.x, pointer.y); if (delta > 0) { zoomIn(point); } else if (delta < 0) { zoomOut(point); } } }); function move(direction) { switch (direction) { case Direction.LEFT: canvas.relativePan(new fabric.Point(-10 * canvas.getZoom(), 0)); break; case Direction.UP: canvas.relativePan(new fabric.Point(0, -10 * canvas.getZoom())); break; case Direction.RIGHT: canvas.relativePan(new fabric.Point(10 * canvas.getZoom(), 0)); break; case Direction.DOWN: canvas.relativePan(new fabric.Point(0, 10 * canvas.getZoom())); break; } keepPositionInBounds(canvas); } function zoomIn(point) { if (zoomLevel < zoomLevelMax) { zoomLevel++; canvas.zoomToPoint(point, Math.pow(2, zoomLevel)); keepPositionInBounds(canvas); } } function zoomOut(point) { if (zoomLevel > zoomLevelMin) { zoomLevel--; canvas.zoomToPoint(point, Math.pow(2, zoomLevel)); keepPositionInBounds(canvas); } } function keepPositionInBounds() { var zoom = canvas.getZoom(); var xMin = (2 - zoom) * canvas.getWidth() / 2; var xMax = zoom * canvas.getWidth() / 2; var yMin = (2 - zoom) * canvas.getHeight() / 2; var yMax = zoom * canvas.getHeight() / 2; var point = new fabric.Point(canvas.getWidth() / 2, canvas.getHeight() / 2); var center = fabric.util.transformPoint(point, canvas.viewportTransform); var clampedCenterX = clamp(center.x, xMin, xMax); var clampedCenterY = clamp(center.y, yMin, yMax); var diffX = clampedCenterX - center.x; var diffY = clampedCenterY - center.y; if (diffX != 0 || diffY != 0) { canvas.relativePan(new fabric.Point(diffX, diffY)); } } function clamp(value, min, max) { return Math.max(min, Math.min(value, max)); } </script> </body> </html> 

Tengo un ejemplo en Github usando fabric.js Toma de panorámica de la lona y zoom: https://sabatinomasala.github.io/fabric-clipping-demo/

El código responsable del comportamiento de paneo es el siguiente: https://github.com/SabatinoMasala/fabric-clipping-demo/blob/master/src/classes/Panning.js

Es una extensión simple en fabric.Canvas.prototype , que le permite alternar 'modo de arrastre' en el canvas de la siguiente manera:

 canvas.toggleDragMode(true); // Start panning canvas.toggleDragMode(false); // Stop panning 

Eche un vistazo al siguiente fragment, la documentation está disponible en todo el código.

 const STATE_IDLE = 'idle'; const STATE_PANNING = 'panning'; fabric.Canvas.prototype.toggleDragMode = function(dragMode) { // Remember the previous X and Y coordinates for delta calculations let lastClientX; let lastClientY; // Keep track of the state let state = STATE_IDLE; // We're entering dragmode if (dragMode) { // Discard any active object this.discardActiveObject(); // Set the cursor to 'move' this.defaultCursor = 'move'; // Loop over all objects and disable events / selectable. We remember its value in a temp variable stonetworking on each object this.forEachObject(function(object) { object.prevEvented = object.evented; object.prevSelectable = object.selectable; object.evented = false; object.selectable = false; }); // Remove selection ability on the canvas this.selection = false; // When MouseUp fires, we set the state to idle this.on('mouse:up', function(e) { state = STATE_IDLE; }); // When MouseDown fires, we set the state to panning this.on('mouse:down', (e) => { state = STATE_PANNING; lastClientX = eeclientX; lastClientY = eeclientY; }); // When the mouse moves, and we're panning (mouse down), we continue this.on('mouse:move', (e) => { if (state === STATE_PANNING && e && ee) { // let delta = new fabric.Point(eemovementX, eemovementY); // No Safari support for movementX and movementY // For cross-browser compatibility, I had to manually keep track of the delta // Calculate deltas let deltaX = 0; let deltaY = 0; if (lastClientX) { deltaX = eeclientX - lastClientX; } if (lastClientY) { deltaY = eeclientY - lastClientY; } // Update the last X and Y values lastClientX = eeclientX; lastClientY = eeclientY; let delta = new fabric.Point(deltaX, deltaY); this.relativePan(delta); this.trigger('moved'); } }); } else { // When we exit dragmode, we restre the previous values on all objects this.forEachObject(function(object) { object.evented = (object.prevEvented !== undefined) ? object.prevEvented : object.evented; object.selectable = (object.prevSelectable !== undefined) ? object.prevSelectable : object.selectable; }); // Reset the cursor this.defaultCursor = 'default'; // Remove the event listeners this.off('mouse:up'); this.off('mouse:down'); this.off('mouse:move'); // Restore selection ability on the canvas this.selection = true; } }; // Create the canvas let canvas = new fabric.Canvas('fabric') canvas.backgroundColor = '#f1f1f1'; // Add a couple of rects let rect = new fabric.Rect({ width: 100, height: 100, fill: '#f00' }); canvas.add(rect) rect = new fabric.Rect({ width: 200, height: 200, top: 200, left: 200, fill: '#f00' }); canvas.add(rect) // Handle dragmode change let dragMode = false; $('#dragmode').change(_ => { dragMode = !dragMode; canvas.toggleDragMode(dragMode); }); 
 <div> <label for="dragmode"> Enable panning <input type="checkbox" id="dragmode" name="dragmode" /> </label> </div> <canvas width="300" height="300" id="fabric"></canvas> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.15/fabric.min.js"></script> 

Si solo desea desplazar el canvas en la pantalla y no cambiar la position de los elementos, puede usar esta solución .

La idea es tener un contenedor de tamaño fijo con CSS de overflow: hidden que tiene un canvas gastado dentro de él. la bandeja moverá el canvas dentro del contenedor para que el usuario vea diferentes áreas del canvas gastado cada vez.