Fabricjs pan and zoom

匿名 (未验证) 提交于 2019-12-03 02:13:02

问题:

How can I pan and zoom using fabricjs? I've tried using the methods zoomToPoint and setZoom but they do not work for panning. Once I start using different zoom points I start having trouble.

$('#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/

回答1:

Solved it using:

relativePan() absolutePan()

[Update]

$('#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/



回答2:

I know it is already answered, but I had to do a mouse panning, so I adapted the fiddle of the accepted answer to do so. I post it here for anyone who has to do something like this. This is just the main idea:

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 && e.e) {         var units = 10;         var delta = new fabric.Point(e.e.movementX, e.e.movementY);         canvas.relativePan(delta);     } }); 

Here is the fiddle: http://jsfiddle.net/gncabrera/hkee5L6d/5/



回答3:

Here is my solution for canvas zoom (using mouse wheel) and pan (using left/up/right /down keys or shift key + mouse left down + mouse move).

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> 


回答4:

I have an example on Github using fabric.js Canvas panning and zooming: https://sabatinomasala.github.io/fabric-clipping-demo/

The code responsible for the panning behaviour is the following: https://github.com/SabatinoMasala/fabric-clipping-demo/blob/master/src/classes/Panning.js

It's a simple extension on the fabric.Canvas.prototype, which enables you to toggle 'drag mode' on the canvas as follows:

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

Take a look at the following snippet, documentation is available throughout the code.

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 stored 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 = e.e.clientX;       lastClientY = e.e.clientY;     });     // When the mouse moves, and we're panning (mouse down), we continue     this.on('mouse:move', (e) => {       if (state === STATE_PANNING && e && e.e) {         // let delta = new fabric.Point(e.e.movementX, e.e.movementY); // 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 = e.e.clientX - lastClientX;         }         if (lastClientY) {           deltaY = e.e.clientY - lastClientY;         }         // Update the last X and Y values         lastClientX = e.e.clientX;         lastClientY = e.e.clientY;          let delta = new fabric.Point(deltaX, deltaY);         this.relativePan(delta);         this.trigger('moved');       }     });   } else {     // When we exit dragmode, we restore 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>


回答5:

If you just want to pan the canvas in the display, and not to change the position of the elements, you can use this solution.

The idea is to have a fixed size container with css of overflow: hidden that has an expended canvas inside it. the pan will move the canvas inside the container so the user will see different areas of the expended canvas every time.



文章来源: Fabricjs pan and zoom
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!