FabricJS adding Image to Group causes odd control behavior - javascript

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

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 !

Adding filter to pattern image of shape in fabric.js

I am trying to apply a filter to the pattern image of shape but receiving numerous errors. I googled a lot but still cannot find a solution that works. Below is my code. Q 1. Is it even possible? Q 2. How to achieve it!?
var canvas = new fabric.Canvas('c1');
var circle = new fabric.Circle({
radius: 100, fill: 'green', left: 100, top: 100
});
canvas.add(circle);
loadPattern('http://i0.wp.com/www.illustratoring.com/wp-content/uploads/2012/12/chevron-pattern-illustrator.png?resize=40%2C40', circle);
function loadPattern(url, obj){
fabric.util.loadImage(url, function(img) {
obj.setPatternFill({
source: img,
repeat: 'repeat'
});
canvas.renderAll();
});
}
here is the JSfilddle https://jsfiddle.net/eepmzy9n/2/ I want to apply filters to the pattern image.
Yes, this should be possible using the fabric js filters. Combining patterns and filters shouldn't be an issue.
Info on image filters:
http://fabricjs.com/fabric-intro-part-2/#image_filters
http://fabricjs.com/image-filters/
Other code examples using filters:
Fabric js image filter
How to apply filter to canvas backgroundImage in Fabric.js

Object's custom properties getting cleared in canvas to json

I have a canvas with multiple image objects. Every object has some custom attributes. I need to save this canvas as a json object into a database. I used following code to convert canvas into json.
canvasJson = JSON.stringify(canvas);
After converting, canvasJson can't have any custom attribute as well as it's values. It has only default attributes and it's values like width, height, opacity etc.
How can I fix that? Please suggest some right ways to solve this...
Edit
Following is my image object creation code to create image objects in canvas.
var imgObj = new Image();
var imgSrc = $IMAGE_URL;
imgObj.src = imgSrc;
var image = new fabric.Image(imgObj);
image.set({
left: 0,
top: 0,
angle: 0,
padding: 0,
cornersize: 0,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
elementId: $elementID,
elementname: $elementName,
elementstatus: $elementStatus,
width: componentImageWidth,
height: componentImageHeight
});
canvas.add(image);
image.setCoords();
canvas.renderAll();
canvas.selection = false;
canvas.renderAll();
setObjectAction(image, false);
Converting the canvas into json using JSON.stringify(canvas); the elementId, elementname and elementstatus are missing. but default attributes are gets correctly.
How to fix this ?
You can use fabric's canvas.toJson() or canvas.toDatalessJSON() functions, and you can include your custom properties as parameters like this:
var json = JSON.stringify(canvas.toDatalessJSON(['elementId','elementname', 'elementstatus']));

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/

Add multiple element to canvas with fabric js

Sorry for my bad English.
I want to learn the use of fabric.js.
For the basic commands I haven't had any problem. But I now have this problem.
I have two button in the index.html file :
<tr>
<td><button id="caricarettangolo" onMouseDown="caricarettangolo(), caricatutto()" type="button"><img src="immagini/prodotti/rettangolo.svg" /></button></td></tr>
<tr>
<td><button type="button" onMouseDown="caricastella()"><img src="immagini/prodotti/stella.svg" /></button></td></tr>
</tr>
and external js file with this code
function caricacerchio() {
var canvas = new fabric.Canvas('canvas');
var circle = new fabric.Circle({
radius: 20, fill: 'green', left: 100, top: 100
});
canvas.getObjects();
canvas.add(circle);
canvas.selection = false;
canvas.renderAll();
canvas.calcOffset();
};
function caricarettangolo() {
var canvas = new fabric.Canvas('canvas');
var rect = new fabric.Rect({
width: 50,
height: 50,
left: 50,
top: 50,
fill: 'rgb(255,0,0)'
});
canvas.getObjects();
canvas.add(rect);
canvas.selection = true;
canvas.renderAll();
canvas.calcOffset();
};
But I don't have the solution for seeing two elements.
I see the first element, next, if i push another button, this completely clears the canvas and adds the new element, but clears the first element. If I click in the canvas square, return the first created element. Why? As I can see when I have two different buttons two different element? Thanks.
You're rendering on a new canvas every time you press the button:
var canvas = new fabric.Canvas('canvas');
You want to render the canvas outside of your functions
window.canvas = new fabric.Canvas('canvas');
then use the buttons to add them.
You can see an example here: http://jsfiddle.net/33MME/2/

Categories

Resources