How to animate rotate around center in fabric js - fabricjs

When you use one of the handle bars to rotate an object in fabricjs it will rotate the object around center. However, when using
tri.animate('angle', 45, {
onChange: canvas.renderAll.bind(canvas)
});
It will rotate around the top-left corner. How to rotate around center just like with the handle bar?
Example: http://jsfiddle.net/QQ6eA/1/

Add:
originX: 'center',
originY: 'center',
to your triangle creation code.

If you rotate an image with his default origin, this will do it around top left corner. We don't want to set the origin of the image on the center all the time, because it will affect all the functionalities (for example, its left and top positions).
So, we can set the origin to center when we need it and then set it again to the top-left corner and still use all the others functionalities normally.
const target = canvas.getActiveObject(); //or your target
const angleValue = 10; //your angle
target._setOriginToCenter();
target.set('angle', angleValue).setCoords();
target._resetOrigin();

Related

fabricjs clippath not working as per size

I am trying to apply clippath on image, i am passing rect as clippath to image and size of rect is same as image including scale, still after apply clippath image cropped like clipath is less then what we applied.
i have checked clippath scaled width , height after apply is still same but image is clipped bit small like given in attached image.
var rect = new fabric.Rect({
left: 0,
top: 0,
width: obj.getScaledWidth(),
height: obj.getScaledHeight(),
originX: 'center',
originY: 'center'
});
rect.setCoords();
obj.clipPath = rect;
obj.clipPath.dirty = true;
obj.dirty = true; canvas.renderAll();
My fabric version is 3.4.0.
original image on left side and after apply same size rect as clippath clipped image on right side, actual result should be same size image without any clipped part
one thing i have noticed is cacheHeight and cacheWidth of clipath is less then width and height of clippath. please find below screenshot, is it reason for that, if then what will be solution?

How to align the jointjs graph to the center / middle of the paper horizontally with the flow direction from top to bottom?

I have a graph generated using JointJs and it uses Dagre Layout provided by jointjs. Currently, the graph gets aligned from Top To Bottom which is the correct way but then the complete graph gets aligned to the left of the paper.
I need the graph to be aligned in the middle of the Paper Horizontally.
Current configuration used is this:
joint.layout.DirectedGraph.layout(graph,
{
rankDir: "TB",
marginX: 30,
marginY: 30,
clusterPadding: {
top: 10,
left: 10,
right: 10,
bottom: 10
}
}
I see that the option to make graph flow from Top to bottom is given rankDir: "TB". Is there any similar option which can align it horizontally to the middle instead of left which is by default? or any other way which can do so.
After calling directedGraph.layout you can then use Paper class to center the diagram.
const paper = new joint.dia.Paper({
height: 1000,
width: 1000,
...
});
const paperArea = paper.getArea();
const contentArea = paper.getContentArea();
paper.translate((paperArea.width - contentArea.width) / 2, (paperArea.height - contentArea.height) / 2);
This will effectively center the diagram, although care should be taken to avoid the content being larger than the paper size.

pixi.js retina display doubled in size

I know the same question has been asked by other people before, but that was a long time ago and the API are changed, and they didn't solve my problem.
Here is my problem:
I have a problem about retina display, let's take iPhone 6 for example. The size of the screen is 375x667, and the device pixel ratio is 2, which means the physical pixel is 750x1334 and the CSS pixel is 375x667.
If we want a full screen canvas, what we usually do is to set the canvas size to 750x1334, and then set the actually display size of canvas to 375x667.
This is what I have done in pixi.js(v5.1.1):
let app = new Application({
width: 375,
height: 667,
antialiasing: true,
resolution: 2,
autoDensity: true,
})
I set the resolution : 2, and autoDensity : true, but when I add a sprite with size of 750x1334, it only shows a quarter of the sprite(The size is doubled). It seems that the autoDensity is not working.
What now I am doing is setting the whole stage with scale(0.5):
app.stage.scale.set(0.5);
It temporarily solved my problem, but I feel like this is not the current way to go. You shouldn't use scale for this kind of thing.
What should I do then?
Use CSS to set the canvas size in CSS units, and initialize the renderer using the proper dimensions according to the devices pixel ratio.
let canvas = document.createElement("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let app = new Application({
width:window.innerWidth*window.devicePixelRatio,
height:window.innerHeight*window.devicePixelRatio,
antialiasing: true,
view:canvas
});

FabricJS: Issue when changing objects coordinates inside a Group after some Transformations

I am looking for a way to space (and move in general) objects inside a group regardless of their transformation.
In the small example i have made below, you will see 2 circles and I am attempting to space them by a certain factor.
It is ok until I rotate or resize the group and it is still ok the very first time the coordinates are changed after a transformation but calling the same function twice while the spacing is still correct, the group starts jumping all over the places..
I am using Fabric JS version: 1.7.7
Here is a sample:
https://jsfiddle.net/u0patgck/
console.clear();
var canvas = new fabric.Canvas('root');
var circles = [];
circles.push(new fabric.Circle({id: "circle1", radius: 20, fill: 'green', left: 150, top: 100}));
circles.push(new fabric.Circle({id: "circle2", radius: 20, fill: 'green', left: 200, top: 100}));
g = new fabric.Group(circles);
//once circles are added to group their coordinates change so I store their new original base coordinates in custom variables
g.forEachObject(function(obj){
obj.originalLeft = obj.getLeft();
obj.originalTop = obj.getTop();
}, g);
canvas.add(g);
canvas.renderAll();
function moveCircles(){
var space = parseFloat(document.getElementById("spacingPixels").value);
g.forEachObject(function(obj){
switch (obj.id){
case "circle1":
obj.setLeft(obj.originalLeft - space)
break;
case "circle2":
obj.setLeft(obj.originalLeft + space)
break;
default:
}
})
g.addWithUpdate();
canvas.renderAll()
}
Steps to Reproduce:
Test 1 (ok):
Click the "Move Circles" button as many times you want (circles coordinates are recalculated and the group is not "misbehaving".
Test 2 (ok first time but not second time):
Rotate the group first.
Click the move circles button ONE time (all is still good)
Click the move circles button another time (you will see the group starts moving by itself around the canvas).
Expected Behaviour:
The group should not move around or change the order of the objects inside.
The group moves erratically.
At the moment I am caching the transformations manually and restoring them after changing the coordinates (like below)
https://jsfiddle.net/0tdg1dof/
var a = {scaleX: g.getScaleX(), scaleY: g.getScaleY(), skewX: g.getSkewX(), skewY: g.getSkewY(), flipX: g.getFlipX(), flipY:g.getFlipX(), angle: g.getAngle()};
fabric.util.resetObjectTransform(g);
g.addWithUpdate();
g.setScaleX(a.scaleX);
g.setScaleY(a.scaleY);
g.setSkewX(a.skewX);
g.setSkewY(a.skewY);
g.setFlipX(a.flipX);
g.setFlipY(a.flipY);
g.setAngle(a.angle);
Is there a better way to do this?
Thank you.
AlessandroDM, I believe you did right solution, because you are manipulating just only group object. If you will not manipulate (restore) group objects (parent) you will need to do manipulation each child inside the group like angle, scale, etc. Also, you have one minor bug, if you will rotate group, and after that resize it (not diagonal controls, scaleX should not be equal to scaleY) and then click "Move Circles" your group will behave as you described in Test 2. In order to fix that you will need to set scaleX and scaleY values after all your values which you want to set:
var a = {scaleX: g.getScaleX(), scaleY: g.getScaleY(), skewX: g.getSkewX(), skewY: g.getSkewY(), flipX: g.getFlipX(), flipY:g.getFlipX(), angle: g.getAngle()};
fabric.util.resetObjectTransform(g);
g.addWithUpdate();
g.setSkewX(a.skewX);
g.setSkewY(a.skewY);
g.setFlipX(a.flipX);
g.setFlipY(a.flipY);
g.setAngle(a.angle);
g.setScaleX(a.scaleX);
g.setScaleY(a.scaleY);
It is not a fabricjs bug setting scale after all manipulations, even native HTML5 canvas required scaling after all manipulations.

Raphaël-ZPD click to zoom in/out

Does anyone know how to trigger zoom in/out with Raphaël-ZPD by clicking on a button?
If take a look to the code of Raphael-ZPD you would see that all the zooming and panning are made by using svg matrices. In the particular case of zooming, it first draw a reference point where the mouse is, and calculates the zoom direction relative to that point, using the delta of the mouse wheel to apply the amount of zoom.
Now, if you want to use a button, you would have to decide the delta on your code, and you could maybe use the center of the screen as the relative point to calculate the direction of zooming.
For starters you could just use the svg scale property, something like this could be ok if you are using Raphael ZPD:
paper = Raphael('container',600, 600);
paper.ZPD({ zoom: true, pan: true, drag: false });
scale = 1;
var zoomin = document.getElementById('in')
var zoomout = document.getElementById('out')
zoomin.onclick = function(){
scale *= 1.2
paper.canvas.setAttribute("transform", "scale("+scale+")")
}
zoomout.onclick = function(){
scale *= 0.8
paper.canvas.setAttribute("transform", "scale("+scale+")")
}
Here is Fiddle with a working example
I reccomend to add some translate calculating the center of the screen, so the zoom doesn't go to corner. But think all this could point you in the right direction.

Resources