Setting a background image in fabric.js throws an exception when clicked - javascript

I am trying to set change the backround image for a canvas using fabric.js but running into some instability. The call to add the background works with no trouble but if I then click anywhere on the canvas it goes blank and seems to move to selection mode - although this just seems to be due to an untrapped exception.
I cannot figure out what is causing the behavior. It works fine on this page http://fabricjs.com/customization/ but the following jsfiddle is failing http://jsfiddle.net/YH9yD/20/
var canvas = window._canvas = new fabric.Canvas('c');
canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));
canvas.setBackgroundImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {
backgroundImageOpacity: 0.5,
backgroundImageStretch: false
});
this.__canvases.push(canvas);

try loading the image before you add to the canvas. if you add an image that hasnt been loaded you will get an exception. This works for us:
var img = new Image();
img.onload = function(){
canvas.setBackgroundImage(img.src, canvas.renderAll.bind(canvas), {
originX: 'left',
originY: 'top',
left: 0,
top: 0
});
};
img.src = "your image source"
regards,
Benick

Try this
canvas.setBackgroundImage('add image source', canvas.renderAll.bind(canvas), {
scaleY: canvas.height ,
scaleX: canvas.width
});
canvas.renderAll();

Related

Is it possible to make a dynamic mask/crop system via fabric.js that behaves like canva.com?

edit 2016, Oct 24
I've an idea about this feature by using 'pattern' which seems to be a good idea.
I tried to prove my thoughts with this pen, its still buggy but at least we can set the image(pattern) position and keep the original image when double click.
I'am not very good at javascript, So if you are interest in this please help to make this more useable, any discussions/thoughts or code correction is welcome.
http://codepen.io/wushan/pen/LRrQEL?editors=1010
// Create Canvas
var canvas = this.__canvas = new fabric.CanvasEx('c', {
preserveObjectStacking: true
});
fabric.Object.prototype.transparentCorners = false;
// Global Settings
var url = "http://fabricjs.com/assets/pug.jpg";
//Make the Pattern by url
function createMaskedImage(url) {
//Load Image
fabric.Image.fromURL(url, function(img) {
img.scaleToWidth(300);
//Make a Pattern
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(img);
var pattern = new fabric.Pattern({
source: function() {
patternSourceCanvas.setDimensions({
width: img.getWidth(),
height: img.getHeight()
});
return patternSourceCanvas.getElement();
},
repeat: 'no-repeat'
});
console.log(pattern.offsetX)
console.log(pattern.offsetY)
console.log(img.getWidth()) // 縮小後 (*scale)
console.log(img.width) // 原尺寸
//Mask (can be any shape ex: Polygon, Circles....)
var rect = new fabric.Rect({
width: 200,
height: 200,
left: 150,
top: 100,
fill: pattern
})
//Bind Double Click Event from fabric.ext
//https://github.com/mazong1123/fabric.ext
rect.on('object:dblclick', function (options) {
//Pass pattern out
enterEditMode(rect, img);
});
canvas.add(rect);
canvas.setActiveObject(rect);
});
}
function enterEditMode(mask, image) {
image.left = mask.left;
image.top = mask.top;
// New Image
// Fake Crop Area (fixed)
var rect = new fabric.Rect({
width: mask.width,
height: mask.height,
left: mask.left,
top: mask.top,
fill: '#000000',
opacity: 0.8,
selectable: false
})
canvas.remove(mask);
canvas.add(image);
image.on('object:dblclick', function (options) {
//Flatten
flatten(rect, image);
});
canvas.add(rect);
// console.log(JSON.stringify(canvas));
}
function flatten(mask, image) {
//Make a Pattern
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(image);
var pattern = new fabric.Pattern({
source: function() {
patternSourceCanvas.setDimensions({
width: image.getWidth(),
height: image.getHeight()
});
return patternSourceCanvas.getElement();
},
repeat: 'no-repeat'
});
//Offsets
pattern.offsetX = image.left - mask.left - image.left;
pattern.offsetY = image.top - mask.top - image.top;
var rect = new fabric.Rect({
width: mask.width,
height: mask.height,
left: mask.left,
top: mask.top,
fill: pattern
})
//Bind Double Click Event from fabric.ext
//https://github.com/mazong1123/fabric.ext
rect.on('object:dblclick', function (options) {
//Pass pattern out
enterEditMode(rect, image);
});
canvas.remove(mask);
canvas.remove(image);
canvas.add(rect);
canvas.setActiveObject(rect);
canvas.renderAll();
}
//Button Events
//Create
document.getElementById('createMaskedImage').addEventListener('click', function () {
createMaskedImage(url);
});
Test this :
click 'create'
double click on the image object
move/scale the image
double click the image to flatten the obejct.
Know issue:
when cutting the image without scale, the image position looks correct but there is a wired transparent space.
It generates a lot duplicate objects on the scene...
Original Post
I've been working with fabric.js for a few month, haven't seen any example or discussions about a mask/crop system which is behaves like canva.com ( which is way easy to understand for users. )
the object looks like this:
when double clicked on a group/mask, it shows the original image with an unselectable mask, you can move/scale the image whatever you need and click 'OK' to made the change without modifying the original image.
I'd like to know if there is any possible solutions about making this in fabricjs, or maybe some thoughts about this issue is welcome.
Thank you a lot !

Multiplier property not working properly in "toDataURL" function with cropping in Fabric.js

My original size of the canvas is 800X700.
I am using clipTo to work in a selected portion of a canvas:
var rect = new fabric.Rect({
left: 100,
top: 50,
fill: '#fff',
width: 376,
height: 602,
strokeWidth: 0,
selectable: false
});
rect.set({
clipFor: 'mainCanvas',
});
I make sure all the images and text fall within this portion of the canvas.
What I want to Do:
I want to scale up this portion of canvas to a width and height of 1500X2400 so that it can be used for printing
I am using the below toDataURL function with multiplier as 3
var imgData= canvas.toDataURL({
format: 'png',
width: 376,
height: 602,
top: 50,
left: 100,
multiplier: 3
});
But I am getting only top most portion of the image. Any solution?
Update: More info about the problem
I am using Ubuntu 16.04 and Fabric.js-1.6.2
Demonstrating the problem on JsFiddle
When I click on the enhance image button, only the top left portion of the image is displayed.

FabricJS adding Image to Group causes odd control behavior

I'm attempting to add a loaded image into a fabric Group object. Everything looks ok, but the selection controls aren't selectable and I can't drag the object around. The top left control works though and after clicking it everything is fine.
Here is a jsfiddle that demonstrates the behavior.
var canvas = new fabric.Canvas('canvas', {
width: 200,
height: 200
});
var group = new fabric.Group();
canvas.add(group);
fabric.Image.fromURL('https://placehold.it/100x100', function(img) {
group.addWithUpdate(img);
canvas.setActiveObject(group);
canvas.renderAll();
});
Is this a bug or am I doing something wrong?
For some performance reason, fabricjs does not call setCoords automatically after adding objects to a group ( in case of many object added you can call setCoords just once ).
So after doing addWithUpdate, just call group.setCoords();
var canvas = new fabric.Canvas('canvas', {
width: 200,
height: 200
});
var group = new fabric.Group();
canvas.add(group);
fabric.Image.fromURL('https://placehold.it/100x100', function(img) {
group.addWithUpdate(img);
group.setCoords();
canvas.setActiveObject(group);
canvas.renderAll();
});
I came across this post because I was having trouble getting the positioning of images to work properly. I ended up finding that it's easier to just create create an image element using document.createElement and set the src, then feed that into fabric.Image with all the options you need (instead of using fabric.Image.fromURL which was too much of a headache to use), before adding it to the group.
var oImg = document.createElement("img");
oImg.setAttribute('src', 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/92/Cog_font_awesome.svg/512px-Cog_font_awesome.svg.png');
var i = new fabric.Image(oImg, {
originX: 'center',
originY: 'center',
left: left+35,
top: top-30,
scaleX:.05,
scaleY:.05,
});
g = new fabric.Group([r, t, i]); // where r and t are other fabric objects

Multiple background images in fabricjs

I am building a new app with fabricjs,
in this I need
User controlled multiple background images in which behave like normal image, user can rotate, drag resize it,
it done some stuff like this for multiple BG,
// 1st img
var img = new Image();
img.onload = function(){
canvas.setBackgroundImage(img.src, canvas.renderAll.bind(canvas), {
originX: 'left',
originY: 'top',
left: 100,
top: 100
});
};
img.src = "site_image/temp/zig3.jpg";
// 2nd img
var img1 = new Image();
img1.onload = function(){
canvas.setBackgroundImage(img1.src, canvas.renderAll.bind(canvas), {
originX: 'left',
originY: 'top',
left: 300,
top: 300
});
};
img1.src = "site_image/temp/zig1.jpg";
But first BG is replaced by second one,
multiple backgrounds controlled by user are possible or not?
One more issue I faced,
I have JSON of fabricjs, which include an image(normal image not background),
when I will show it to user I want that this image will become background of canvas,
Just use an absolute path in that JSON file and use AJAX to change the background image. Also, you can follow this [link][1] for a JSFiddle example.
[1]: https://jsfiddle . net/manish1706/qxnh4j53/

get backgroundImage object

i am currently trying to get the backgroundImage object of my canvas instance and it does not work. i get what ever properties of the canvas object but not of my current loaded backgroundImage. anyone else figured out that issue? here is what i have
var bgImg = canvas.setBackgroundImage(img.src, canvas.renderAll.bind(canvas), {
width: bgWidth,
height: bgHeight,
originX: 'left',
originY: 'top',
left: 0,
top: bgTop
});
if i then do something like: console.log(bgImg.backgroundImage) i get null as result. for all other properties of the canvas element i get either the object return or the value if i want the width for example - so all other properties do work. what is the reason that the backgroundImage is not working?
any help is very much appreciated.
many thanks,
michael
It's because setBackgroundImage is not finished (asynchronous) when you try to display with the console.log();
html:
<canvas width="320" height="510" id="canvas"></canvas>
<button id="click">Click here !</button>
Javascript:
var canvas = new fabric.Canvas('canvas');
var img = new Image()
img.src = 'http://fabricjs.com/assets/jail_cell_bars.png';
var bgImg = canvas.setBackgroundImage(img.src, canvas.renderAll.bind(canvas), {
width: 320,
height: 510,
originX: 'left',
originY: 'top',
left: 0,
top: 0
});
document.getElementById("click").addEventListener("click", function () {
console.log(bgImg.backgroundImage);
});
In this example, canvas.backgroundImage is displayed in the console when you click on the button : http://jsfiddle.net/LOLKFC/PQe5e/

Categories

Resources