Disable Object Selection Outside ClipPath - fabricjs

How can I disable object selection outside of clipPath?
var canvas = new fabric.Canvas('c');
var clipath = new fabric.Rect({ width: 400, height: 300,left:50,fill: '#eee', absolutePositioned: true, selectable: false,hoverCursor: "default",strokeWidth: 0 });
var rect = new fabric.Rect({ width: 100, height: 100, fill: 'red',left:80,top:20 });
rect.clipPath = clipath;
canvas.add(clipath);
canvas.add(rect);
<canvas id="c" width="600" height="350" style="border:1px solid #ccc"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.1.0/fabric.min.js"></script>

Related

Fabric.js: Initial position object outside canvas no longer working

Recently I have started to use a newer version of Fabric.js (from 1.7.22 to 2.3.5). I had to make a few modifications to existing code that seem logical to me. However, I notice that you cannot initially place an object outside the canvas anymore, to reposition it later onto the canvas. Like in the code below. It won't show. My question is: has this changed for some reason, or is this an issue (bug)? And do I have other options than postpone adding the object to the canvas, or using the visible attribute?
$( document ).ready(() => {
const canvas = new fabric.Canvas('canvas');
var rect = new fabric.Rect({
left: 301,
top: 10,
originX: 'left',
originY: 'top',
width: 50,
height: 50,
fill: '#336699'
});
canvas.add(rect);
rect.set({"left": 10});
rect.set({"top": 10});
canvas.renderAll();
});
canvas {
border: 1px solid tomato;
}
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.5/fabric.min.js"></script>
<canvas id="canvas" width="300" height="100"></canvas>
You need to use setCoords() after repositioning.
$( document ).ready(() => {
const canvas = new fabric.Canvas('canvas');
var rect = new fabric.Rect({
left: 301,
top: 10,
originX: 'left',
originY: 'top',
width: 50,
height: 50,
fill: '#336699'
});
canvas.add(rect);
rect.set({"left": 10});
rect.set({"top": 10});
rect.setCoords();
canvas.renderAll();
});
canvas {
border: 1px solid tomato;
}
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.5/fabric.min.js"></script>
<canvas id="canvas" width="300" height="100"></canvas>

Edit FabricJS objects by HTML <input>

var canvas = new fabric.Canvas('c');
canvas.add(new fabric.Rect({
left:10,
top:10,
width:50,
height:50,
fill:'#4169e1'
}));
canvas.add(new fabric.Rect({
left:140,
top:140,
width:50,
height:50,
fill:'#800000'
}));
canvas {
border: black solid 1px;
padding: 5px;
margin-top: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.18/fabric.min.js"></script>
<input type='color'></input>
<canvas id="c" width="200" height="200"></canvas>
I want to be able to select an object and the input field updates with the color, AND be able to change the color of the object from the input field. I know I can do one way binding with document.getElementById("example").innerHTML and '<input type="color" value="' + canvas.getActiveObject().fill +'">', but what is the best way for two way binding?
You need to use events object:selected selection:cleared to get the selected object. And set the color picker value from selected object fill value.
DEMO
var canvas = new fabric.Canvas('c');
canvas.add(new fabric.Rect({
left: 10,
top: 10,
width: 50,
height: 50,
fill: '#4169e1'
}));
canvas.add(new fabric.Rect({
left: 140,
top: 140,
width: 50,
height: 50,
fill: '#800000'
}));
var colorPick = document.getElementById('colorPick');
var activeSelected;
colorPick.onchange = function() {
if (activeSelected) {
activeSelected.fill = this.value;
activeSelected.dirty = true;
canvas.renderAll();
}
};
canvas.on('object:selected', function(option) {
activeSelected = option.target;
colorPick.value = activeSelected.fill;
})
canvas.on('selection:cleared', function(option) {
activeSelected = null;
console.log(activeSelected)
});
canvas {
border: black solid 1px;
padding: 5px;
margin-top: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.18/fabric.min.js"></script>
<input type='color' id='colorPick'></input>
<canvas id="c" width="200" height="200"></canvas>

fabric.js how to control selcted element to be not on top [duplicate]

I've a problem with my FabricJS app. By default, the object layer in fabricjs jumps to the top when I select it.
I want to disable this option so that the index of the active element not changing. It's possible ?
You just need to set the preserveObjectStacking options as shown in the below code when setting up the canvas.
var fabricCanvas = new fabric.Canvas("t", { preserveObjectStacking: true });
fabricCanvas
.add(new fabric.Rect({
top: 0,
left: 0,
width: 100,
height: 100,
fill: "green"
}))
.add(new fabric.Rect({
top: 50,
left: 50,
width: 100,
height: 100,
fill: "red"
}))
.add(new fabric.Rect({
top: 100,
left: 100,
width: 100,
height: 100,
fill: "blue"
}))
.renderAll();
canvas {
border: 1px solid black;
}
<canvas id="t" width="400" height="300"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.3/fabric.min.js"></script>

Position fabric.js text by baseline

In native HTML5 canvas the text is positioned by the text baseline but in Fabric.js it seems to be by the bottom of the text. I want Fabric.js to position text by the baseline. Is it possible?
See image
This is the code used for the example.
Fabric.js<br />
<canvas id="fabric" width="300" height="300" style="border:1px solid #d3d3d3;"></canvas>
<script src="fabric.js"></script>
<script>
var canvas = new fabric.Canvas('fabric');
canvas.add(new fabric.Line([100, 100, 200, 100], { left: 10, top: 50, stroke: 'red' }));
canvas.add(new fabric.Text('Hello World', { left: 10, top: 50, originY: 'bottom', useNative: true, fontSize: 50 }));
</script>
<br />
Native HTML5<br />
<canvas id="native" width="300" height="300" style="border:1px solid #d3d3d3;"></canvas>
<script>
var c = document.getElementById("native");
var ctx = c.getContext("2d");
ctx.font = "50px Times New Roman";
ctx.fillText("Hello World",10,50);
ctx.moveTo(10,50);
ctx.lineTo(100,50);
ctx.strokeStyle = '#ff0000';
ctx.stroke();
</script>
Unfortunately, it doesn't look possible at the moment. The textBaseline attribute is set to 'alphabetic' and the only available vertical alignment options are 'top', 'center', & 'bottom' (which are relative to the bounding box fabric draws around the text).
I've created an issue to request this feature. Hopefully, they add it!

Importing SVG in Fabric.js is not working correctly

I am creating SVG shape and exporting it to database. The jsfiddle for this is here - http://jsfiddle.net/rafi_ccj/MASeK/1/
And the code is below.
HTML part:
<button id="make_svg">toSVG</button>
<div id="canvas-wrapper">
<canvas id="canvas" width="400px" height="200px"></canvas>
</div>
Javascript part:
var canvas = new fabric.Canvas('canvas');
canvas.add(new fabric.Rect({
left: 100,
top: 100,
angle: 0,
fill: 'rgba(23,23,125,0.5)',
strokeWidth: 0.1,
stroke: '#FF0000',
width: 200,
height: 200,
opacity: 1
}));
canvas.add(new fabric.Circle({
left: 100,
top: 100,
fill: 'rgba(45, 255, 34, 0.5)',
strokeWidth: 0.1,
stroke: '#FF0000',
radius: 100,
opacity: 1
}));
$("#make_svg").click(function () {
canvas_data = canvas.toSVG();
console.log(canvas_data);
});
and then i am importing that svg into canvas but it is not same i did create. the jsfiddle is here - http://jsfiddle.net/rafi_ccj/2vtz2/
and the code is below---
html part
<div id="canvas-wrapper">
<canvas id="canvas" width="900px" height="800px"></canvas>
</div>
javascript part is here -
var canvas = new fabric.Canvas('canvas');
var canvas_data = '<?xml version="1.0" standalone="no" ?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="400" height="200" xml:space="preserve"><desc>Created with Fabric.js 1.1.8</desc><defs></defs><rect x="-100" y="-100" rx="0" ry="0" width="200" height="200" style="stroke: #FF0000; stroke-width: 0.1; stroke-dasharray: ; fill: rgba(23,23,125,0.5); opacity: 1;" transform="translate(100 100)"/><circle cx="0" cy="0" r="100" style="stroke: #FF0000; stroke-width: 0.1; stroke-dasharray: ; fill: rgba(45, 255, 34, 0.5); opacity: 1;" transform="translate(100 100)"/></svg> ';
fabric.loadSVGFromString(canvas_data, function (objects, options) {
var loadedObject = fabric.util.groupSVGElements(objects, options);
loadedObject.set({
left: 400,
top: 200
});
loadedObject.setCoords();
canvas.add(loadedObject);
canvas.calcOffset();
});
i also have noticed that if i use triangle, it is not present after import, it is just vanished.
can anyone please help me in this problem?
I have solved this problem by making all objects a group element, and after creating the group with these objects existed in the canvas, i have saved it with svg extension in device and also a json format in the database. Code is below-
var group = new fabric.Group([],{
left: 200,
top: 200
});
var canvas_item = canvas.item(0), x = 0;
while (canvas_item != undefined) {
group.addWithUpdate(canvas_item);
x += 1;
canvas_item = canvas.item(x);
}
canvas.clear();
canvas.add(group);
//then use canvas.toDatalessJSON(); and save it to database. while importing this data //use following codes
var canvas_data = JSON.stringify(canvas.toDatalessJSON());
canvasJSONdata = JSON.stringify(canvas.toDatalessJSON());
var stringifiedCanvasJSONdata = JSON.parse(canvasJSONdata,'');
var base_64 = canvas.toDataURL('png');
and now it is working perfect! Though i have faced many problems, i have learned a lot, i have enjoyed it! Hope this solution will help someone someday.

Resources