web-dev-qa-db-fra.com

Fabricjs pan et zoom

Comment puis-je effectuer un panoramique et un zoom à l'aide de fabricjs? J'ai essayé d'utiliser les méthodes zoomToPoint et setZoom mais elles ne fonctionnent pas en panoramique. Une fois que je commence à utiliser différents points de zoom, je commence à avoir des problèmes.

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

16
d0001

Résolu en utilisant:

relativePan () absolutePan ()

[Mettre à jour]

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

17
d0001

Je sais que la réponse est déjà faite, mais je devais faire un panoramique avec la souris, alors j’ai adapté le violon de la réponse acceptée pour le faire. Je le poste ici pour quiconque doit faire quelque chose comme ça. C'est juste l'idée principale:

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

Voici le violon: http://jsfiddle.net/gncabrera/hkee5L6d/5/

14
gncabrera

Voici ma solution pour le zoom sur toile (avec la molette de la souris) et le panoramique (avec les touches gauche/haut/droite/bas ou la touche Maj + souris gauche/gauche + déplacement de la souris).

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>
6
Milan Hlinák

J'ai un exemple sur Github en utilisant fabric.js Panoramique et zoom sur toile: https://sabatinomasala.github.io/fabric-clipping-demo/

Le code responsable du comportement de panoramique est le suivant: https://github.com/SabatinoMasala/fabric-clipping-demo/blob/master/src/classes/Panning.js

C'est une simple extension sur le fabric.Canvas.prototype, qui vous permet d'activer le mode "glisser" de la manière suivante:

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

Jetez un coup d'œil à l'extrait de code suivant. La documentation est disponible dans le 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>

2
Sabatino

Si vous souhaitez simplement déplacer le canevas à l’affichage sans changer la position des éléments, vous pouvez utiliser cette solution

L'idée est d'avoir un conteneur de taille fixe avec le css de overflow: hidden qui contient un canevas étendu. le panoramique déplacera la toile à l'intérieur du conteneur afin que l'utilisateur voie chaque fois différentes zones de la toile utilisée. 

0
Dudi