Search code examples
fabricjs

Snap fabric.Line to 45 degree angle


I'm trying to play with fabric.Line() in fabricJS so that when the user starts drawing a line it snaps to one of eight angles at a 45 degree angle from the start point. It would be similar to holding down shift when using an Adobe product. Is that possible with fabricJS?


Solution

  • EDIT march 2020

    • The snap rotation is now a built in feature in fabric.js

    original answer:

    You have to check the angle you are building during mouse move and approximate it to a 45° degree line.

    var canvas = new fabric.Canvas('c', {
      selection: false
    });
    
    var line, isDown, points;
    
    canvas.on('mouse:down', function(o) {
      isDown = true;
      var pointer = canvas.getPointer(o.e);
      points = [pointer.x, pointer.y, pointer.x, pointer.y];
      line = new fabric.Line(points, {
        strokeWidth: 2,
        fill: 'red',
        stroke: 'red',
        originX: 'left',
        originY: 'center'
    
      });
      canvas.add(line);
    });
    
    canvas.on('mouse:move', function(o) {
      if (!isDown) return;
      var pointer = canvas.getPointer(o.e);
    
      var startX = points[0];
      var startY = points[1];
      var x2 = pointer.x - startX;
      var y2 = pointer.y - startY;
      var r = Math.sqrt(x2*x2 + y2*y2);
      var angle = (Math.atan2(y2, x2) / Math.PI * 180);
    
      angle = (angle) % 360 + 180;
    
      if (angle <= 22.5 || angle >= 337.5) {
        angle = 0;
      } else if (angle <= 67.5) {
        angle = 45;
      } else if (angle <= 112.5) {
        angle = 90;  
      } else if (angle <= 157.5) {
        angle = 135  
      } else if (angle <= 202.5) {
        angle = 180
      } else if (angle <= 247.5) {
        angle = 225
      } else if (angle <= 292.5) {
        angle = 270
      } else if (angle < 337.5) {
        angle = 315
      }
      angle -= 180;
    
      var cosx = r * Math.cos(angle * Math.PI / 180);
      var sinx = r * Math.sin(angle * Math.PI / 180);
      
      line.set({
        x2: cosx + startX,
        y2: sinx + startY
      });
      canvas.renderAll();
    });
    
    canvas.on('mouse:up', function(o) {
      isDown = false;
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
    
    <canvas id="c" width="500" height="500"></canvas>