FabricJS load from SVG as Canvas Objects and not path - svg

When I load the SVG to Canvas, I get the type as path and a path array.
Is it possible to get the type (object) as "Circle", "Rect", "Line", etc, depending upon the path rather than path? OR Is it possible to convert the path to Canvas standard objects like circle, Rect, etc?

I had a same problem, It was described here: FabricJs - Clipping area by SVG object.
I resolved that by bringing the SVG coords like "M0,0H63.7V63.7H0Z" (rect) and create FabricJS path:
fabric.loadSVGFromURL('object.svg', function (objects, options) {
let img1 = new fabric.Path(objects[0].d, {
fill: '#333',
opacity: 1,
hasBorders: true,
hasControls: true,
hasRotatingPoint: true,
selectable: true,
preserveObjectStacking: true,
objectCaching: false,
});
}
And now you have a valid FabricJS object :)
Also, to achieve that I have to combine my svg images into path, without any polygons and other SVG elements.

Related

how to make a hole through only overlay Rectangle using fabric js?

I am working on image cropper using fabric js version 1.7.22.
As usually, every cropper display black transparent overlay over the image (where image look like dull), and also display one Rect. (crop Area where image look full with color).
we can create this functionality using fabric js with background image and fabric.Rect object.
My problem is that when I use GlobalCompositeOperation with destination-out property to fabric.Rect object. It will make hole through canvas.
In simple word :
when I add globalCompositeOperation to destination-out, it will make hole through canvas also.
Expected result of canvas:
Current Result of canvas:
I have made one codepen for demonstration :
https://codepen.io/mayurkukadiya0/pen/zYYWOGL?editors=0110
I have found one codepen also for do same but they are add multiple canvas for display image in separate layer and rect and overlay in separate layer
Is there any way to do this without add external any canvas or css image behind canvas ?
Here is that reference : https://codepen.io/s0nnyv123/pen/eravaN
try using setOverlayImage
here'a demonstration, based on your codepen
var canvas = new fabric.Canvas('canvas', {preserveObjectStacking: 'true'});
canvas.setHeight(300);
canvas.setWidth(300);
canvas.setOverlayImage('https://images.pexels.com/videos/856973/free-video-856973.jpg?auto=compress&cs=tinysrgb&dpr=1&w=500', canvas.renderAll.bind(canvas), {
top: 0,
left: 0,
width: 300,
height:300,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
selectable: false,
globalCompositeOperation: 'destination-atop',
});
var overlay = new fabric.Rect({
left: 0,
top: 0,
width: 300,
height: 300,
fill: '#00000050',
selectable: false,
globalCompositeOperation: 'source-over'
});
canvas.add(overlay);
var rect = new fabric.Rect({
left: 100,
top: 100,
width: 100,
height: 100,
fill: '#451245',
globalCompositeOperation: 'destination-out'
});
canvas.add(rect);
canvas.renderAll();

Image clipping with visible overflow in Fabricjs

I want to clip image, BUT default clipping behaviour just hiding a part of image which out of border. Is there a way to make it visible and set less opacity for overflowed content?
There's one of old clipping examples I told about. It also using lodash to bind clip name to object:
return _.bind(clipByName, pug)(ctx)
Is there a way to replace this functionality with vanilla es5?
I found unclear solution. Again.
Background color of canvas could make an opacity and background image could be clipping object (w/o clipping by itself).
Also, loaded image shoul define globalCompositeOperation set to source-atop.
var canvas = new fabric.Canvas('c');
var clipingRect = new fabric.Rect({
originX: 'left',
originY: 'top',
top: 50,
left: 50,
height: 300,
width: 300,
fill: 'white',
selectable: false
});
canvas.backgroundColor = 'rgba(255,255,0,0.5)';
canvas.setBackgroundImage(clipingRect);
fabric.Image.fromURL('http://placeimg.com/640/480/any', function(fimg) {
canvas.add(fimg.set({
left: 0,
top: 0,
width: canvas.getWidth(),
height: canvas.getHeight(),
globalCompositeOperation: 'source-atop'
}));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.12/fabric.min.js"></script>
<canvas id="c" width="400" height="400"></canvas>

Open Layers Styling draw interaction in polygon mode

I'm trying to alter the default style for the draw polygon interaction. Currently it draws a line string of blue lines, and fills in the polygon so far with a semi-transparent fill.
However if I change it, it always connects the current point to the first point.
Can anyone guide me on how this was achieved?
You should set the style for both, Layer and Interaction.
By setting the style in the Draw element, you will change the style of the polygon while you are drawing it:
var draw = new ol.interaction.Draw({
source: source,
type: 'Polygon',
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.5)'
})
})
});
And changing the style for the vector layer which shares source with the Draw element, you will be modifying the style of the polygon once it is drawn:
var vector = new ol.layer.Vector({
source: source,
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.9)'
})
})
});
I have created a jsfiddle

How to add an image to an element as a decorator?

Imagine I have Rect element and I wish to decorate it with a small (say 16x16) PNG image in the upper left. I am unable to determine how to achieve that task. I have studied the docs but have (so far) been unable to find a sample or reference on how to achieve that task. Does anyone have a recipe or a sample pointer that they would be willing to share to help me achieve my goal?
Better is to create your own custom shape that has a rectangle, image and text. This gives you much more flexibility and you don't have to have two elements in order to express one shape. Your shape decorated with a little image in the top left corner may look like:
joint.shapes.basic.DecoratedRect = joint.shapes.basic.Generic.extend({
markup: '<g class="rotatable"><g class="scalable"><rect/></g><image/><text/></g>',
defaults: joint.util.deepSupplement({
type: 'basic.DecoratedRect',
size: { width: 100, height: 60 },
attrs: {
'rect': { fill: '#FFFFFF', stroke: 'black', width: 100, height: 60 },
'text': { 'font-size': 14, text: '', 'ref-x': .5, 'ref-y': .5, ref: 'rect', 'y-alignment': 'middle', 'x-alignment': 'middle', fill: 'black' },
'image': { 'ref-x': 2, 'ref-y': 2, ref: 'rect', width: 16, height: 16 }
}
}, joint.shapes.basic.Generic.prototype.defaults)
});
And you can use it like this in your diagrams:
var decoratedRect = new joint.shapes.basic.DecoratedRect({
position: { x: 150, y: 80 },
size: { width: 100, height: 60 },
attrs: {
text: { text: 'My Element' },
image: { 'xlink:href': 'http://placehold.it/16x16' }
}
});
graph.addCell(decoratedRect);
Note how is the shape specified, the important bits are the markup, type and the attrs object that references the SVG elements in the markup by normal CSS selectors (here just tag selectors but you can use classes if you want). For the image tag, we take advantage of the JointJS special attributes for relative positioning (ref, ref-x and ref-y). With these attributes, we position the image relatively to the top left corner of the rect element and we offset it by 2px from the top edge (ref-y) and 2px from the left edge (ref-x).
One note: It is important that the type attribute ('basic.DecoratedRect') matches the namespace the shape is defined in (joint.shapes.basic.DecoratedRect). This is because when JointJS re-constructs graphs from JSON, it looks at the type attribute and makes a simple lookup to the joint.shapes namespace to see if there is a shape defined for this type.
We can create an element type for an image using the following recipe:
var image = new joint.shapes.basic.Image({
position : {
x : 100,
y : 100
},
size : {
width : 16,
height : 16
},
attrs : {
image : {
"xlink:href" : "images/myImage.png",
width : 16,
height : 16
}
}
});
graph.addCell(image);
This will position the image at x=100,y=100. It is important to make the size width/height match the attrs/image width/height and be the width/height of the image itself.
Although this doesn't decorate a previous element, it can be positioned over a previous element achieving the desired effect.

Can't get an svg to animate

I imported an SVG from InkScape using the ReadySetRaphael tool. I wanted to animate the svg, and ease it in. So just for test purposes, i tried to transform it using the animate method.
I keep getting an error to say my object doesnt have a method of "animate". I've checked other SO answers which suggest i have to clone the object and set the final path, but not sure if that does, or how it applies to me?
Here's my js code so far.
//code created using readysetraphael. Original svg made in inkscape.
var rsr = Raphael('rsr', '744.09448', '1052.3622');
var layer1 = rsr.set();
var path2993 = rsr.path("m 344.93716,348.36218 c 0,0 34.17415,-33.06016 -1.26571,-83.92195 -35.43985,-50.86178 39.23699,-38.14634 6.32855,-91.55121 -32.90844,-53.40487 -50.62837,-36.8748 -50.62837,-36.8748 -9.49282,-0.63577 -8.85996,-0.63577 -8.85996,-0.63577");
path2993.attr({
id: 'path2993',
parent: 'layer1',
fill: 'none',
stroke: '#cf0000',
"stroke-width": '2.92',
"stroke-linecap": 'butt',
"stroke-linejoin": 'miter',
"stroke-miterlimit": '4',
"stroke-opacity": '1',
"stroke-dasharray": 'none',
"marker-start": 'none',
"marker-mid": 'none',
"marker-end": 'url(#TriangleInL)'
}).data('id', 'path2993');
layer1.attr({
'id': 'layer1',
'name': 'layer1'
});
var rsrGroups = [layer1];
//Animate svg
rsr.animate({
transform: 's2'
}, 2000);
Your code pulls an animation call over the paper object. As animate() is a member of Element, the call fails.
I assume you're trying to animate a specific shape, e.g. path2993. Simply call it on the relevant element instead:
path2993.animate({transform: 's2'}, 2000);

Resources