I have a series of 4 images which I'm attempting to place at specified coordinates in fabricjs, and I'm getting them placed inconsistently sometimes when the page loads. Refreshing once or twice will usually give the correct layout. Trying to prevent this from happening.
Anybody know how to solve this? Here's my code:
var objects = [
{ type: "image", filename : "tv.png" , x: 688, y: 184, angle: 0, zIndex: 10 },
{ type: "image", filename : "polaroid.jpg" , x: 347, y: 515 },
{ type: "image", filename : "polaroid.jpg" , x: 138, y: 643 },
{ type: "image", filename : "polaroid.jpg" , x: 429, y: 803 },
{ type: "text", text: "Your favorite band", x: 1168, y: 1163, angle: -17, canvasRef: null,zIndex: 50 }
];
for (var i=0; i<objects.length;i++){
var objRef = objects[i];
switch(objRef.type){
case 'image':
var url = "img/" + objRef.filename;
fabric.Image.fromURL(url, function(img) {
var objRef = objects[curObject];
img.set({
left: objRef.x,
top: objRef.y,
angle: objRef.angle,
hasBorders: false,
hasControls: false,
hasRotatingPoint: false,
lockMovementX: true,
lockMovementY: true
});
canvas.add(img).renderAll();
img.moveTo(objRef.zIndex);
curObject++;
//canvas.setActiveObject(img);
});
break;
case 'text':
var text = objRef.text;
var fabricText = new fabric.Text(text, {
left: objRef.x,
top: objRef.y,
angle: objRef.angle,
hasBorders: false,
hasControls: false,
hasRotatingPoint: false,
lockMovementX: true,
lockMovementY: true
});
objRef.canvasRef = fabricText;
addTextListeners(fabricText);
canvas.add(fabricText);
break;
}
}
I should mention also that none of this code happens until after window.ready, and after all the images that fabric is attempting to load to canvas have been preloaded using the imagesloaded plugin.
I should also mention that I've tried delaying the loading of each successive image using setTimeout between each load (instead of a loop), and saving the canvas.renderAll() until after the loop, with no success. Even tried running a loop to re-position the items after they were placed on screen. Below are images of the issue - correct, and incorrect, respectively.
So the key to the answer is async call back. Just check when the Alert message called out.
It looks like you have a race condition from the images loading in different orders.
The
fabric.Image.fromURL()
method is using a callback function, which fires after the image has loaded, so you're not guaranteed to have that inner function fire in the same order you called it. But you're usingcurObject
to increment upwards each time the function is called, which assumes they're called in order. And theobjRef
can get re-assigned to a new object by the time the image loads, which would be why the x/y/rotate values are off (using the values from the other objects in the array).So, instead of using
img.set()
after the image had loaded, use the third parameter of theImage.fromURL()
method to pass in your attributes: