dtx
dtx

Reputation: 340

FabricJS - Why rotated object inside shape are not vertically centered?

I'm creating a shape with certain width and height (this shape is a clipping rect) inside canvas. Then inside this shape I'm loading an object which can be moved and rotated. I wrote a custom function for get center point inside this shape, and it works good if object are not rotated. If I rotate this object over 90deg and click "center" button - the object is moved up outside the clipping rect.

I cannot use a native FabricJs "centerV" function, because I would like that object will be centered inside clipping rect - not the canvas container, so that is why I made a variable "objectVerticalCenter".

My code is presented here:

var canvas = new fabric.Canvas('canvas', {
  'selection': false
});

var clippingRect = new fabric.Rect({
  left: 170,
  top: 90,
  width: 185,
  height: 400,
  fill: 'transparent',
  stroke: 1,
  opacity: 1,
  hasBorders: false,
  hasControls: false,
  hasRotatingPoint: false,
  selectable: false,
  preserveObjectStacking: true,
  objectCaching: false
});

var retinaScalling = canvas.getRetinaScaling();

var pol = new fabric.Polygon([{
  x: 200,
  y: 0
}, {
  x: 250,
  y: 50
}, {
  x: 250,
  y: 100
}, {
  x: 150,
  y: 100
}, {
  x: 150,
  y: 50
}], {
  left: 250,
  top: 150,
  angle: 0,
  fill: 'green'
});

pol.scaleX = 0.5;
pol.scaleY = 0.5;
pol.set('id', 'shape');
pol.scaleToWidth(clippingRect.getWidth());
pol.setCoords();
pol.clipTo = function(ctx) {
  ctx.save();
  ctx.setTransform(retinaScalling, 0, 0, retinaScalling, 0, 0);
  clippingRect.render(ctx);
  ctx.restore();
};
canvas.centerObjectH(pol);
canvas.add(pol);
canvas.renderAll();
canvas.setActiveObject(pol);
canvas.add(pol);
canvas.renderAll();

document.getElementById('rotate').onclick = function() {
  var activeObject = canvas.getActiveObject();
  activeObject.setAngle(200);
  activeObject.setCoords();
  canvas.renderAll();
};

document.getElementById('center').onclick = function() {
  var activeObject = canvas.getActiveObject();
  var rectHeight = activeObject.getBoundingRectHeight();
  var objectVerticalCenter = (clippingRect.getHeight() / 2) - (rectHeight / 2) + clippingRect.top;

  activeObject.set('top', objectVerticalCenter);
  activeObject.setCoords();
  canvas.renderAll();
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.21/fabric.min.js"></script>
<button id="rotate">Rotate</button>
<button id="center">Center</button>
<canvas id="canvas" width="530" height="600"></canvas>

JSFiddle

To reproduce my problem you have to, click "rotate", then "center" button and you will see that shape is moved up outside the clipping rect.

If object is not rotated centering works fine.

Is there any way to fix my centering function or way to use "centerV" function inside the clipping rect?

Regards

Upvotes: 0

Views: 1371

Answers (1)

AndreaBogazzi
AndreaBogazzi

Reputation: 14731

If you want to center an object inside another, the safest thing to do is:

  • get the center point of the container

  • set the center point of the object in that point

in code this could equal to:

var clipCenter = clippingRect.getCenterPoint();
activeObject.setPositionByOrigin(clipCenter,'center','center');

var canvas = new fabric.Canvas('canvas', {
          'selection': false
        });

        var clippingRect = new fabric.Rect({
          left: 170,
          top: 90,
          width: 185,
          height: 400,
          fill: 'transparent',
          stroke: 1,
          opacity: 1,
          hasBorders: false,
          hasControls: false,
          hasRotatingPoint: false,
          selectable: false,
          preserveObjectStacking: true,
          objectCaching: false
        });

        var retinaScalling = canvas.getRetinaScaling();

        var pol = new fabric.Polygon([{
          x: 200,
          y: 0
        }, {
          x: 250,
          y: 50
        }, {
          x: 250,
          y: 100
        }, {
          x: 150,
          y: 100
        }, {
          x: 150,
          y: 50
        }], {
          left: 250,
          top: 150,
          angle: 0,
          fill: 'green'
        });

        pol.scaleX = 0.5;
        pol.scaleY = 0.5;
        pol.set('id', 'shape');
        pol.scaleToWidth(clippingRect.getWidth());
        pol.setCoords();
        pol.clipTo = function(ctx) {
          ctx.save();
          ctx.setTransform(retinaScalling, 0, 0, retinaScalling, 0, 0);
          clippingRect.render(ctx);
          ctx.restore();
        };
        canvas.centerObjectH(pol);
        canvas.setActiveObject(pol);
        canvas.add(pol);
        canvas.renderAll();



        document.getElementById('rotate').onclick = function() {
          var activeObject = canvas.getActiveObject();
          activeObject.setAngle(200);
          activeObject.setCoords();
          canvas.renderAll();
        };

        document.getElementById('center').onclick = function() {
          var activeObject = canvas.getActiveObject();
          var clipCenter = clippingRect.getCenterPoint();
   activeObject.setPositionByOrigin(clipCenter,'center','center');
          canvas.renderAll();
        };
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.21/fabric.min.js"></script>
<button id="rotate">Rotate</button>
<button id="center">Center</button>
<canvas id="canvas" width="530" height="600"></canvas>

Upvotes: 4

Related Questions