How to add custom content in fabric.Image() - fabricjs

I am trying to use the following suggested way to store canvas in the server:
Fabric.js - how to save canvas on server with custom attributes
But in my case, I am loading an image from a url like:
fabric.Image.fromURL(url, function(image) {
image.alt = product.skuId;
image.productClass = product.productClass;
canvas.add(image);
}, {
crossOrigin: "Annoymous"
});
But when I try to store the same in the db the newer attributes are not stored.
Is there a way to store custom attribute (or even "alt") in the DB?
Edit:
Created a fiddle with what I tried:
https://jsfiddle.net/anjhawar/dpyb7cf7/
When we press save the canvas is dumped in the local storage, but when we check the "objects" array we do not get the custom attributes i.e. "id" and "alt", as per the example.
Am I missing something?

Here my solution to store custom attribute (id).
fabric.Image.fromURL(link, function(img) {
img.set({
id : 'image_'+index,
width : canvas.width / 2,
height : canvas.height / 2
});
canvas.add(img).renderAll().setActiveObject(img);
});
For quick review here is a working code : http://jsfiddle.net/mullainathan/dpyb7cf7/1

Related

svg.js with existing svg

I'm trying to implement svg.js to make a map of a clickable floorplan.
But I cannot make this work properly, or this works but doesn't work like I expected:
const map = SVG.get('mysvg');
map.click(function( event ) {
this.fill({ color: '#000' });
console.log(this);
console.log(event.target);
});
When I try to click on some area on the map, instead of change fill color I get nothing.
Actually svgjs triggers 'create' as you can see in console with inspector.
Not sure what am I doing wrong here?
I would expect that the area will change fill color?
https://codepen.io/bobz-zg/pen/LdyXBe
You can use the select function as described here to create a Set. You'd then use the each() method from Set to iterate over each entry and apply the click event handler. For example:
const map = SVG.get("mysvg");
var restaurants = map.select('[id*="restaurant"]:not(g)'); // Create an svg.js Set, but do not capture the group in the set
restaurants.each(function() {
this.click(function(event) {
this.fill({ color: "#000" });
});
});
If you can edit the svg that you are using as an input, I would suggest adding a class to each of the clickable elements to use that as the reference for select. Otherwise, you'll have to do something like selecting all element id 'types' (i.e. restaurant, retail etc.) separately and concatenating the Sets using Set.add() before you do the loop to add the click listener, but that could get messy.

Select and manipulate particular paths within a path group fabric.js

I am making an app that involves shapes like cylinders and boxes, and need to be able to do this with fabric.js. I know about three.js but for my purposes, it must be in 2D.
Initially I thought I would just create them in 3D software and render images which can then be added to the canvas, which I did successfully...
However, I have run into a hurdle where fabric only allows patterns to be filled onto paths or objects (rect, circle etc.)....not images (png).
Since I absolutely need patterns, I now need to create these cylinders in SVG. I have gotten as far as making the cylinders in Illustrator, saving them as SVG's and then using them on the canvas, then adding fill patterns on them. So far so good.
Now I want to be able to fill a different pattern for the top of the cylinder, and a different pattern to the side BUT still have it as one object.
So...How can I select and manipulate particular paths within a path group? Is there anyway to give each path within the group a custom attribute (eg. name) which I can then target? Do I need to create two seperate SVG files and then add them seperately, and if so, how can I do this and still have it as one object?
Here's how I am adding the svg to the canvas...
fabric.loadSVGFromURL("/shapes/50-250R.png", function(objects) {
var oImg = fabric.util.groupSVGElements(objects);
oImg.perPixelTargetFind = true;
oImg.targetFindTolerance = 4;
oImg.componentType = "Shape";
oImg.lockUniScaling = true;
oImg.lockScalingX = true;
oImg.lockScalingY = true;
oImg.setControlsVisibility({'tl': false, 'tr': false, 'bl': false, 'br': false});
canvas.add(oImg);
canvas.renderAll();
});
Here is how I am adding the pattern...
var textureIMG = new Image;
textureIMG.crossOrigin = "anonymous";
textureIMG.src = texture.image;
obj.setFill(); //For some reason, the fill doesn't happen without this line.
var pattern = new fabric.Pattern({
source: textureIMG,
repeat: 'repeat'
});
if (obj instanceof fabric.PathGroup) {
obj.getObjects().forEach(function(o) {
o.setFill(pattern);
});
} else {
obj.setFill(pattern);
}
canvas.renderAll();
Thanks in advance.
So I managed to figure this out. Each path within the path group is stored in the 'paths' array of the object.
I can now add a pattern to the top of the cylinder using...
var obj = canvas.getActiveObject();
obj.paths[0].fill = patternOne;
and to the sides using...
obj.paths[1].fill = patternTwo;

JointJs creating custom shapes and specifying their default link

I'm trying to implement my own shape class with ports. However I want the links that these shapes generate to be smooth. Right now, the only way i know to make smooth links is
link.set('smooth', true).
But how do i do that not through code? How do i get smooth links by just dragging?
I extended Link class (MyLink) but how do i tell JointJS which Link class to use when i drag on the port?
joint.shapes.myclass.Link = joint.dia.Link.extend({
defaults: {
type: 'myclass.Link',
attrs: { '.connection' : { 'stroke-width' : 5 }},
smooth:true
}
});
Links created via the UI by dragging ports are defined in the defaultLink property of the paper. It can either be an object in which case it is a link model or a function that returns a link model:
var paper = new joint.dia.Paper({
defaultLink: new joint.shapes.myclass.Link,
...
})
or:
var paper = new joint.dia.Paper({
defaultLink: function(elementView, magnet) {
if (aCondition) return new joint.dia.Link;
else return joint.shapes.myclass.Link;
}
})
The function gives you flexibility in creating different links on the fly depending on what element is underneath or what magnet (SVG element for port) is being dragged.

Fabric.js loadFromJSON width/height properties deserialization

I have a problem with Fabric.js.
When I'm trying to save fabric canvas like this:
var data = JSON.stringify(self.canvas.toJSON(['width', 'height']))
I get well serialized json with height and width properties.
But when I'm trying to deserialize it like that:
self.canvas.loadFromJSON(data, function () {
self.canvas.renderAll();
});
All objects init fine except height and width properties.
I saw deserialization example: http://jsfiddle.net/fmgXt/3/
If I add to json height and width properties its ignores with deserialization.
But if I set them into code - it also works well. Am I missing something?
At http://fabricjs.com/docs/fabric.StaticCanvas.html#loadFromJSON I didn't find any mentions for loadFromJSON about includedPropertiesNames list or something like that.
I've found a solution to get missing attributes at deserialization :
var object = JSON.parse(json); //use default json parser
canvas.loadFromJSON(json, function(){
canvas.width = object.width;
canvas.height = object.height;
});
This one made no luck for me.
I was able to make it working by setWidth and setHeight methods:
var object = JSON.parse(json);
canvas.loadFromJSON(json, function() {
canvas.setWidth(object.width);
canvas.setHeight(object.height);
canvas.renderAll.bind(canvas);
});

How to customize fabric canvas with customize property

Good morning,everyone ,I have a problem that I want to pass an array of fabric json data to server, and load it back for after a while, since I have to load the details from canvas from multiple page pdf. It has to pass the canvas name as well.
problem here is if I use JSON.stringify(mycanvas);
it doesn't convert my customize attribute into json data. So I have to do something like inherit from the fabric canvas to extend the attribute.
I found some useful like to create custom text, custom image, I tried something similar to them, it just doesn't work. Please help me on this.
my code :
code to create such customize canvas
//////////////////////////////////////////////////////////////
create CustomCanvas class from Text class
fabric.CustomCanvas = fabric.util.createClass(fabric.Canvas, {
type: 'custom-canvas',
initialize: function(element, options) {
this.callSuper('initialize', element, options);
options && this.set('canvasname', options.canvasname);
},
toObject: function() {
return fabric.util.object.extend(this.callSuper('toObject'),
{canvasname: this.canvasname});
}
});
fabric.CustomText.fromObject = function(object) {
return new fabric.canvasname(object`enter code here`);
};
fabric.canvasname.async = false;`enter code here`
//////////////////////////////////////////////////////////////
//and to create a new customize canvas
var canvas = new fabric.CustomCanvas();
canvas.setBackgroundImage(src, function() {
canvas.renderAll();
});
canvas.canvasname=1111;
I will so appreciate it, if someone could help me on this.

Resources