fabric.js canvas to json with svg custom attributes - fabricjs

I added new attributes for path svg:
var canvas = new fabric.Canvas('c');
var group = [];
fabric.loadSVGFromURL(svg_file, function(objects,options) {
var obj = fabric.util.groupSVGElements(objects, options);
obj.set({
left: 100,
top: 100
});
canvas.add(obj);
canvas.renderAll();
},
// add new attributes
function(item, object) {
object.set('id',item.getAttribute('id'));
object.set('tag_id', tag_id);
object.set('elem_id', elem_id );
group.push(object);
}
);
And:
// see new attributes
console.log(canvas.getObjects());
// save to JSON
console.log('json:', canvas.toJSON())
But new attributes not save.
Saving JSON in canvas with fabric.js not work for me.
I read Saving JSON in canvas with fabric.js,
it says to create a new class based on fabric.Image, it works for me,
but what to do with fabric.LoadSVGFromURL and fabric.util.groupSVGElements?
Need to create a new class or something else? Help me.
Solved:
https://github.com/kangax/fabric.js/issues/471
http://jsfiddle.net/Ypn2k/4/

You should try to set custom attribute in this way :
svgelement.toObject = (function (toObject) {
return function () {
return fabric.util.object.extend(toObject.call(this), {
"custom_attr_key": "Value",
"custom_attr_key": "Value",
});
};
})(svgelement.toObject);
and also pass this custom attribute key in toJson function like This :
canvas.toJSON(['custom_attr_key','custom_attr_key']);

Related

Can't manage object alignments selection with FabricJs 2

I used to manage object alignments selection on FabricJS with getActiveGroup as below :
canvas.on("selection:created", function(e) {
var activeObj = canvas.getActiveObject();
console.log('e.target.type', e.target.type);
if(activeObj.type === "group") {
console.log("Group created");
var groupWidth = e.target.getWidth();
var groupHeight = e.target.getHeight();
e.target.forEachObject(function(obj) {
var itemWidth = obj.getBoundingRect().width;
var itemHeight = obj.getBoundingRect().height;
$('#objAlignLeft').click(function() {
obj.set({
left: -(groupWidth / 2),
originX: 'left'
});
obj.setCoords();
canvas.renderAll();
});
...
}
});
more detailed here
But now that I use FabricJS 2 and that getActiveObject() has been removed, I don't know what to do. I read on the doc that we could use getActiveObjects(), but it does nothing.
Please how can I reproduce the action of this code with FabricJS 2 (where getActiveGroup isn't supported anymore) ?
Selections of more than one object have the type activeSelection. The group type is only used when you purposefully group multiple objects using new fabric.Group([ obj1, obj2]
When you create a multi-selection using the shift-key as opposed to drawing a selection box, you'll trigger the selection:created event only on the first object selected, while objects added to the selection will trigger the selection:updated event. By calling your alignment code from both the selection:created and selection:updated events you'll make sure that your code is executed every time a multi-selection is created.
Also, you can use getScaledWidth() and getScaledHeight() to get scaled dimensions, or just .width and .height if you just want the unscaled width/height values. Good luck!
canvas.on({
'selection:updated': function() {
manageSelection();
},
'selection:created': function() {
manageSelection();
}
});
function manageSelection() {
var activeObj = canvas.getActiveObject();
console.log('activeObj.type', activeObj.type);
if (activeObj.type === "activeSelection") {
console.log("Group created");
var groupWidth = activeObj.getScaledWidth();
var groupHeight = activeObj.getScaledHeight();
activeObj.forEachObject(function(obj) {
var itemWidth = obj.getBoundingRect().width;
var itemHeight = obj.getBoundingRect().height;
console.log(itemWidth);
$('#objAlignLeft').click(function() {
obj.set({
left: -(groupWidth / 2),
originX: 'left'
});
obj.setCoords();
canvas.renderAll();
});
});
}
}

Fabricjs custom serialization

I would like to create a canvas in which I would load images of some entity. the images of these entities could change from time to time.
FabricJs provides a built in serialization & de-serialization mechanism using following methods
fabric.Canvas#toJSON to serialize the canvas and
fabric.Canvas#loadFromJSON to de-serialize it but the problem with them is they serialize the image source as well which is enormous and useless in my case
(fabric.Canvas#toDatalessJSON & fabric.Canvas#loadFromDatalessJSON seems to work only for complex object but not images gitHub Ref)
whats is the approach to this?
should customize serialization by serializing all the required properties and recreate objects based on those info?
I have even try to create a subclass of Image removing src from toObject to avoid serializing it but it seems that does not work as well
here is what I have tried with subclass
fabric.MyImage = fabric.util.createClass(fabric.Image, {
type: 'MyImage',
initialize: function(options) {
options || (options = { })
this.callSuper('initialize', options)
this.set('artIndexes', options.artIndexes || '')
},
toObject: function() {
const TO = this.callSuper('toObject')
fabric.util.object.extend(TO, {
artIndexes: this.get('artIndexes')
})
delete TO.src
return TO
},
_render: function(ctx) {
this.callSuper('_render', ctx)
}// ,
// fromURL: function(a, b) {
// this.callSuper('fromURL', a, b)
// }
})
fabric.MyImage.fromObject = function (object, callback) {
fabric.util.enlivenObjects(object.objects, function (enlivenedObjects) {
delete object.objects
callback && callback(new fabric.MyImage(enlivenedObjects, object))
})
}
fabric.MyImage.async = true
and to add Image i would do somthing like this
let img = new fabric.MyImage({entetyReference: entetyRef})
img.setSrc(`${imageSource}`, image => {
this.canvas.add(img)
})
but during serialization and de-serializatiin using FabricJs provided method the object get lost from canvas
I am using latest version of fabricJs

fabric js how to use globalCompositeOperation in groups

I am trying to create groupe using fabricjs
var group = new fabric.Group(
[ circle, this.callerObject ],
{globalCompositeOperation:'xor'}
);
console.log(group);
this.mainCanvas.add(group);
But which globalCompositeOperation I have not set it is not working it always give the same result. I can make it using clear canvas, but I want to know, can I do it using native fabricjs methods?
I find solution myself)) to make it work need add globalCompositeOperation to the second object.
this.callerObject.set('globalCompositeOperation','xor');
var group = new fabric.Group(
[ circle, this.callerObject ]
);
But it have new problem)) this is work across all images)
To solve problem with cross showing
I have convert group to dataUrl, and to save state of object create new group, with object and image from previous group.
createXorGroup: function(object){
var self = this;
var baseStateTop = this.callerObject.top;
var baseStateLeft = this.callerObject.left;
this.callerObject.set('globalCompositeOperation','xor');
this.callerObject.set('active', false);
var group = new fabric.Group([ object, this.callerObject ]);
fabric.Image.fromURL(
group.toDataURL(),
function(image){
image.setOriginToCenter && image.setOriginToCenter();
self.callerObject.set('globalCompositeOperation','source-over');
self.callerObject.set('opacity', 0);
group = new fabric.Group([ self.callerObject, image ]);
self.mainCanvas.add(group);
group.setOriginToCenter && group.setOriginToCenter();
group.set('top', baseStateTop).set('left', baseStateLeft).setCoords();
group.setCenterToOrigin && group.setCenterToOrigin();
self.mainCanvas.remove(self.callerObject);
group.inCircle = true;
group.set('active', true);
},
{
originX: 'center',
originY: 'center',
top: this.callerObject.top,
left: this.callerObject.left
}
);
}
It is not native fabricjs object, I have override some properties for my work, but I hope you understand the main aim and it will be helpful
Continue to work with this library
To make xor to svg I have write this:
setGlobalCompositeOperation: function(object, type){
if(object.imageType == 'svg'){
for (var i = 0; i < object.paths.length; i++) {
this.setGlobalCompositeOperation(object.paths[i], type);
}
}else{
object.set('globalCompositeOperation', type);
}
}
But this do not work for text in mozila 31.6.0(( I'm looking solution for text

In fabric.js, how to disable text items when importing an SVG from URL

Good day,
Wondering, for fabric.js, while in the process of importing an SVG, how can I programmatically set the 'selectable' to false for all text items, but allow the image items to remain selectable?
fabric.loadSVGFromURL(urlString, function(objects, options) {
var group = fabric.util.groupSVGElements(objects, options);
canvas.add(group).centerObject(group).renderAll();
},
// set the 'selectable' values for each item
function(item, object) {
// how do I tell if the item is a text or image?
//psuedo code
if (item is text) {
object.selectable = false;
}
});
Any help would be greatly appreciated.
Thanks,
Johnny
if you want to set all text objects to selectable = false then just loop though all the objects on the canvas and then test the objects for their type with "obj.get('type')"
here is an example:
canvas.forEachObject(function(obj) {
if(obj.get('type') ==='text' || obj.get('type') ==='i-text') {
obj.selectable = false;
}
});
Fiddle

FabricJs - How do I Add properties to each object

I need to introduce few additional properties to existing object properties set.
like:
ID
Geo Location
etc
Whenever I draw a shape, I need to add additional properties to the shape and need to get from toDataLessJSON()
As of version 1.7.0 levon's code stopped working. All you need to do is to fix as follows:
// Save additional attributes in Serialization
fabric.Object.prototype.toObject = (function (toObject) {
return function (properties) {
return fabric.util.object.extend(toObject.call(this, properties), {
textID: this.textID
});
};
})(fabric.Object.prototype.toObject);
You have to receive properties argument and pass it on to toObject.
Here's a code for adding custom properties and saving them in JSON serialization for any object on canvas. (I used standard javascript object properties, but it works for me)
canvas.myImages = {};
fabric.Image.fromURL('SOME-IMAGE-URL.jpg', function(img) {
canvas.myImages.push(img);
var i = canvas.myImages.length-1;
canvas.myImages[i].ID = 1; // add your custom attributes
canvas.myImages[i].GeoLocation = [40, 40];
canvas.add(canvas.myImages[i]);
canvas.renderAll();
});
And you then include the custom attribute in object serialization.
// Save additional attributes in Serialization
fabric.Object.prototype.toObject = (function (toObject) {
return function () {
return fabric.util.object.extend(toObject.call(this), {
textID: this.textID
});
};
})(fabric.Object.prototype.toObject);
// Test Serialization
var json = JSON.stringify(canvas.toDatalessJSON());
console.log(json);
canvas.clear();
// and load everything from the same json
canvas.loadFromDatalessJSON(json, function() {
// making sure to render canvas at the end
canvas.renderAll();
}

Resources