Search code examples
javascriptobjectrotationfabricjsangle

After rotating fabricjs objects as a selected group the individual object angles are not correct


<body>
    <button id="showangle" type="button" onclick="showAngle()">Show Angle</button>
    <canvas id="c" width="1000" height="1000" />
</body>


fabric.Object.prototype.set({
  snapThreshold: 45,
  snapAngle: 90
});

var canvas = new fabric.Canvas("c");

var text1 = new fabric.IText("Text 1", {
  name: 'text1',
  fontSize: 30,
  type: 'i-text',
  left: 100,
  top: 100,
});

var text2 = new fabric.IText("Text 2", {
  name: 'text2',
  fontSize: 30,
  type: 'i-text',
  left: 200,
  top: 150,
});

canvas.add(text1);
canvas.add(text2);
canvas.renderAll();


function showAngle() {
  alert("text1 angle = " + text1.getAngle() + "\ntext2 angle = " + text2.getAngle());
} 

Steps to reproduce:

1) Run this jsfiddle... http://jsfiddle.net/Outrageous/a50nrcv0/
2) Click the "Show Angle" button. (it should read 0 degrees, and it does)
2) Select both text objects ("text1" and "text2") with your mouse.
3) Rotate the selected group 90 degrees to the right.
4) Click on the canvas to Un-Select the text box group.
5) Click the "Show Angle" button. (it should read 90 degrees, and it does)
6) Select both text objects ("text1" and "text2") with your mouse.
7) Rotate the selected group 90 degrees to the left.
8) Click on the canvas to Un-Select the text box group.
9) Click the "Show Angle" button. (it should read 0 degrees and instead reads -1.4033418597069752e-14 degrees)

From here on out all of the angles are off when rotating via a group - Why does the angle of the objects show -1.4033418597069752e-14 degrees instead of 0 degrees when rotating objects as a group. Note: this code uses a snapThreshold: 45, and a snapAngle: 90 so I wouldn't think this would happen. When I rotate the objects individually the angles correct themselves. I have tried using the setCoords() with no luck. Any help or suggestions will be greatly appreciated.


Solution

  • This issue was fixed by Andrea Bogazzi on April 24th, 2017 with github commit https://github.com/fabricjs/fabric.js/commit/51a24b497332a4ffbcad82fe7f1a1eb037418747

    OLD fabric.js "_calcRotateMatrix" function:

    _calcRotateMatrix: function() {
      if (this.angle) {
         var theta = degreesToRadians(this.angle), cos = Math.cos(theta), sin = Math.sin(theta);
            return [cos, sin, -sin, cos, 0, 0];
         }
      return fabric.iMatrix.concat();
    },
    

    NEW fabric.js "_calcRotateMatrix" function with fix in place:

    _calcRotateMatrix: function() { 
      if (this.angle) { 
         var theta = degreesToRadians(this.angle), cos = Math.cos(theta), sin = Math.sin(theta); 
            // trying to keep rounding error small, ugly but it works. 
            if (cos === 6.123233995736766e-17 || cos === -1.8369701987210297e-16) { 
              cos = 0; 
            } 
            return [cos, sin, -sin, cos, 0, 0]; 
         } 
      return fabric.iMatrix.concat(); 
    },
    

    ALTERNATE fix would be to add the following JS to your project. . .

    // ******* fix for group rotate angle issue  ******
    // ************************************************
    canvas.on('after:render', function (e) {
        canvas.forEachObject(function (o) {
            var angles = [0, 90, 180, 270, 360];
            var angle = o.angle % 360;
            // normalize angle to positive value
            if (angle < 0) {
                angle = 360 + angle;
            }
            // angles at 360 we will call 0
            if (angle == 360) {
                angle = 0;
            }
    
            for (var i = 0; i < angles.length; i++) {
                if (angle <= angles[i]) {
                    o.angle = angles[i];
                    break;
                }
            }
        });
    });