Why does shape appears on click of canvas element after removing it? - javascript

When I remove the object and click on canvas element , the removed shape re-appears and I am not able to select it also.
var delete = function(){
var canvas = document.getElementById("canvas").fabric;
canvas.remove(canvas.getActiveObject());
}

You have to register an handler to object selection on canvas, then remove the object.
Check the runnable snippet below if could work for your needs:
$(function() {
var canvas = new fabric.Canvas('c')
var operation = '';
var circle = new fabric.Circle({
radius: 20,
fill: 'green',
left: 100,
top: 100
});
var triangle = new fabric.Triangle({
width: 20,
height: 30,
fill: 'blue',
left: 50,
top: 50
});
canvas.add(circle, triangle);
canvas.on('object:selected', doOperationHandler);
function doOperationHandler() {
if (operation == 'remove') {
remove();
}
}
function remove() {
canvas.remove(canvas.getActiveObject());
}
$('#btn_select').on('click', function() {
operation = '';
});
$('#btn_delete').on('click', function() {
operation = 'remove';
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id='c'>
</canvas>
<button id='btn_select'>Select</button>
<button id='btn_delete'>Delete</button>

Related

How can I get IDs of items on Canvas uploaded as JSON in Fabric JS?

I have a canvas and I am loading this canvas from JSON. There are two group elements and they have their own ID (ID: 1047,1048). I keep the ID numbers to be deleted in an array of 1048,1049,1050.
var toDelete = ['1048', '1049', '1050'] ;
After JSON is loaded, if there is an item belonging to the ID in the array, I want it to be deleted. How can I do that?
According to the comparison, the ID number 1048 should be deleted.
I wrote function such code to throw incoming IDs into an array, but it didn't work.
MY PEN
function loadedIdsFunction(){ // I wrote this function to get incoming IDs but it didn't work
var loadedIds = []; //IDs of items from JSON Canvas
document.getElementById("c").fabric = canvas;
canvas.getObjects().forEach(function(o) {
if(o.type == 'group'){
loadedIds.push(o.id);
}
});
}
var canvas = new fabric.Canvas('c');
var json = '{"version":"3.1.0","objects":[{"type":"group","version":"3.1.0","originX":"left","originY":"top","left":194,"top":157,"width":40,"height":80,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"id":"1047","objects":[{"type":"rect","version":"3.1.0","originX":"left","originY":"top","left":-20,"top":-15,"width":35,"height":50,"fill":"blue","stroke":"blue","strokeWidth":5,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"rx":0,"ry":0,"id":"1047"},{"type":"text","version":"3.1.0","originX":"center","originY":"top","left":0,"top":-40,"width":36,"height":20.34,"fill":"red","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"white","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"1047","fontSize":18,"fontWeight":"normal","fontFamily":"Quicksand","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"left","textBackgroundColor":"","charSpacing":0,"styles":{}}]},{"type":"group","version":"3.1.0","originX":"left","originY":"top","left":640,"top":473,"width":40,"height":80,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"id":"1048","objects":[{"type":"rect","version":"3.1.0","originX":"left","originY":"top","left":-20,"top":-15,"width":35,"height":50,"fill":"blue","stroke":"blue","strokeWidth":5,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"rx":0,"ry":0,"id":"1048"},{"type":"text","version":"3.1.0","originX":"center","originY":"top","left":0,"top":-40,"width":36,"height":20.34,"fill":"red","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"white","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"1048","fontSize":18,"fontWeight":"normal","fontFamily":"Quicksand","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"left","textBackgroundColor":"","charSpacing":0,"styles":{}}]}],"backgroundImage":{"type":"image","version":"3.1.0","originX":"left","originY":"top","left":0,"top":0,"width":780,"height":646,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"crossOrigin":"","cropX":0,"cropY":0,"src":"https://i1.wp.com/onideal.com/wp-content/uploads/2020/03/Schlafzimmer-Grundriss-ideale-Position-Bett-Moebel-Kleiderschrank-dreieckchen-4-780x646.jpg?fit=780%2C646&ssl=1","filters":[]}}'
canvas.loadFromJSON(json, () => canvas.renderAll(), (o, object) => {
// console.log(o, object.on);
object.on('selected', () => {
console.log(object.id);
});
});
//canvas.setBackgroundImage('https://i.hizliresim.com/iBHC0t.jpg', canvas.renderAll.bind(canvas));
//var uniqid = "0";
var uniqids = 0;
$("#door").on("click", function(e) {
rect = new fabric.Rect({
id: uniqid,
left: 40,
top: 40,
width: 35,
height: 50,
fill: 'blue',
stroke: 'blue',
strokeWidth: 5,
strokeUniform: false,
hasControls: true,
});
var uniqid = uniqids.toString();
var text = new fabric.Text(uniqid, {
fontSize: 30,
originX: 'center',
originY: 'right'
});
var group = new fabric.Group([rect, text], {
left: 0,
top: 100,
});
canvas.add(group);
uniqids++;
});
//*****************************
canvas.on('mouse:wheel', function(opt) {
var delta = opt.e.deltaY;
var zoom = canvas.getZoom();
zoom *= 0.999 ** delta;
if (zoom > 20) zoom = 20;
if (zoom < 0.01) zoom = 0.01;
canvas.setZoom(zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
})
$('#getid').click(function() {
var activeObject = canvas.getActiveObjects();
alert(canvas.getActiveObject().id);
});
//***************************************
$("#save").on("click", function(e) {
$(".save").html(canvas.toSVG());
});
$('#delete').click(function() {
var activeObject = canvas.getActiveObjects();
canvas.discardActiveObject();
canvas.remove(...activeObject);
});
#c {
background-color: grey;
margin-top: 10px;
}
button {
padding: 10px 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.1.0/fabric.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<button id="door">Door</button>
<button id="delete">Delete Door</button>
<button id="save">Save</button>
<button id="getid">GET ID</button>
<p>Save bastıktan sonra altta SVG dosyası oluşur</p>
<br>
<canvas id="c" width="800" height="800"></canvas>
<br>
<p class="save">
</p>
You can filter the all the objects based on their id, if the id is in the list, remove the item. Like this:
canvas.getObjects()
.filter(obj =>
['1048', '1049', '1050'].includes(obj.id)
)
.forEach(item => canvas.remove(item));
canvas.renderAll();
var canvas = new fabric.Canvas('c');
var json = '{"version":"3.1.0","objects":[{"type":"group","version":"3.1.0","originX":"left","originY":"top","left":194,"top":157,"width":40,"height":80,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"id":"1047","objects":[{"type":"rect","version":"3.1.0","originX":"left","originY":"top","left":-20,"top":-15,"width":35,"height":50,"fill":"blue","stroke":"blue","strokeWidth":5,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"rx":0,"ry":0,"id":"1047"},{"type":"text","version":"3.1.0","originX":"center","originY":"top","left":0,"top":-40,"width":36,"height":20.34,"fill":"red","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"white","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"1047","fontSize":18,"fontWeight":"normal","fontFamily":"Quicksand","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"left","textBackgroundColor":"","charSpacing":0,"styles":{}}]},{"type":"group","version":"3.1.0","originX":"left","originY":"top","left":640,"top":473,"width":40,"height":80,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"id":"1048","objects":[{"type":"rect","version":"3.1.0","originX":"left","originY":"top","left":-20,"top":-15,"width":35,"height":50,"fill":"blue","stroke":"blue","strokeWidth":5,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"rx":0,"ry":0,"id":"1048"},{"type":"text","version":"3.1.0","originX":"center","originY":"top","left":0,"top":-40,"width":36,"height":20.34,"fill":"red","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"white","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"1048","fontSize":18,"fontWeight":"normal","fontFamily":"Quicksand","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"left","textBackgroundColor":"","charSpacing":0,"styles":{}}]}],"backgroundImage":{"type":"image","version":"3.1.0","originX":"left","originY":"top","left":0,"top":0,"width":780,"height":646,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"crossOrigin":"","cropX":0,"cropY":0,"src":"https://i1.wp.com/onideal.com/wp-content/uploads/2020/03/Schlafzimmer-Grundriss-ideale-Position-Bett-Moebel-Kleiderschrank-dreieckchen-4-780x646.jpg?fit=780%2C646&ssl=1","filters":[]}}'
canvas.loadFromJSON(json, () => {
canvas.getObjects()
.filter(obj => ['1048', '1049', '1050'].includes(obj.id))
.forEach(item => canvas.remove(item));
canvas.renderAll();
}, (o, object) => {
// console.log(o, object.on);
object.on('selected', () => {
console.log(object.id);
});
});
//canvas.setBackgroundImage('https://i.hizliresim.com/iBHC0t.jpg', canvas.renderAll.bind(canvas));
//var uniqid = "0";
var uniqids = 0;
$("#door").on("click", function(e) {
rect = new fabric.Rect({
id: uniqid,
left: 40,
top: 40,
width: 35,
height: 50,
fill: 'blue',
stroke: 'blue',
strokeWidth: 5,
strokeUniform: false,
hasControls: true,
});
var uniqid = uniqids.toString();
var text = new fabric.Text(uniqid, {
fontSize: 30,
originX: 'center',
originY: 'right'
});
var group = new fabric.Group([rect, text], {
left: 0,
top: 100,
});
canvas.add(group);
uniqids++;
});
//*****************************
canvas.on('mouse:wheel', function(opt) {
var delta = opt.e.deltaY;
var zoom = canvas.getZoom();
zoom *= 0.999 ** delta;
if (zoom > 20) zoom = 20;
if (zoom < 0.01) zoom = 0.01;
canvas.setZoom(zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
})
$('#getid').click(function() {
var activeObject = canvas.getActiveObjects();
alert(canvas.getActiveObject().id);
});
//***************************************
$("#save").on("click", function(e) {
$(".save").html(canvas.toSVG());
});
$('#delete').click(function() {
var activeObject = canvas.getActiveObjects();
canvas.discardActiveObject();
canvas.remove(...activeObject);
});
/*
canvas.on('mouse:over', function(e) {
e.target.set('fill', 'red');
canvas.renderAll();
});
canvas.on('mouse:out', function(e) {
e.target.set('fill', 'green');
canvas.renderAll();
});
*/
#c {
background-color: grey;
margin-top: 10px;
}
button {
padding: 10px 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.1.0/fabric.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<button id="door">Door</button>
<button id="delete">Delete Door</button>
<button id="save">Save</button>
<button id="getid">GET ID</button>
<p>Save bastıktan sonra altta SVG dosyası oluşur</p>
<br>
<canvas id="c" width="800" height="800"></canvas>
<br>
<p class="save">
</p>
https://codepen.io/moshfeu/pen/gOMBQqL?editors=0010

FabricJS: Why cant I click on objects during animations?

I need a circle, which gets bigger every second. If I click the circle, it should disappear.
Ok so I added an animation and a mousedown function. But at the end of the animation the mousedown function does not work.
The circle is not recognized any more and is null until the animation finishes.
Any suggestions?
MyCode:
let canvas = new fabric.Canvas('c');
var temp = new fabric.Circle({
left: 0,
top: 0,
fill: 'red',
radius: 20
});
temp.on('mousedown', function(e){
console.log("clicked");
});
temp.selectable = false;
canvas.add(temp);
function animate(c){
c.animate('radius', '80',{
duration: 6000,
onChange: canvas.renderAll.bind(canvas)
});
}
animate(temp);
You need to call object#setCoords. in onChange handler.
DEMO
let canvas = new fabric.Canvas('c');
var temp = new fabric.Circle({
left: 0,
top: 0,
fill: 'red',
radius: 20,
selectable: false
});
temp.on('mousedown', function(e) {
console.log("clicked");
canvas.remove(temp);
temp.isRemoved = true;
});
canvas.add(temp);
function animate(c) {
c.animate('radius', '80', {
duration: 6000,
onChange: function() {
c.setCoords();
canvas.requestRenderAll();
},
abort: function() {
return c.isRemoved;
}
});
}
animate(temp);
canvas {
border: 1px solid #999;
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.0.0/fabric.js"></script>
<canvas id='c' width=300 height=200></canvas>
<div id='result'></div>
<div id='result2'>
</div>

Sending multiple objects forward changes their order (z-index)

The following snippet has a green square above a red square
Select both squares by dragging over them.
Click the bring forward button
After clicking bring forward the squares have switched order. It is my understanding that the items should stay in the same order, but be moved increasingly above other non-selected items as the button is further clicked.
If you deselect, and repeat the experiment you will see that they switch again.
Any ideas?
var canvas = new fabric.Canvas('c',
{
preserveObjectStacking : true
});
var rect = new fabric.Rect({
left: 10, top: 10,
fill: 'red',
width: 100, height: 100,
hasControls: true
});
canvas.add(rect);
var rect2 = new fabric.Rect({
left: 40, top: 40,
fill: 'green',
width: 100, height: 100,
hasControls: true
});
canvas.add(rect2);
$("#bringForward").click(function()
{
var items = canvas.getActiveObject() || canvas.getActiveGroup();
if(items)
items.bringForward();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.6/fabric.min.js"></script>
<button id="bringForward">Bring Forward</button>
<canvas id="c" width="640" height="480"></canvas>
This can be considered a bug or not, depending on what do you expect the function to do.
The documentation for the feature says:
Moves an object or a selection up in stack of drawn objects
And is actually doing so.
The object on top cannot go more on top, the one under can and goes.
Still for a dev this can look like a weird behaviour, to me not really. But guess is personal.
Here is your widget with a modified snippet to try a better solution.
var removeFromArray = fabric.util.removeFromArray;
// modified function to avoid snapping
fabric.StaticCanvas.prototype.bringForward = function (object, intersecting) {
if (!object) {
return this;
}
var activeGroup = this._activeGroup,
i, obj, idx, newIdx, objs, latestIndex;
if (object === activeGroup) {
objs = activeGroup._objects;
latestIndex = this._objects.length;
for (i = objs.length; i--;) {
obj = objs[i];
idx = this._objects.indexOf(obj);
if (idx !== this._objects.length - 1 && idx < latestIndex - 1) {
newIdx = idx + 1;
latestIndex = newIdx;
removeFromArray(this._objects, obj);
this._objects.splice(newIdx, 0, obj);
} else {
latestIndex = idx;
}
}
}
else {
idx = this._objects.indexOf(object);
if (idx !== this._objects.length - 1) {
// if object is not on top of stack (last item in an array)
newIdx = this._findNewUpperIndex(object, idx, intersecting);
removeFromArray(this._objects, object);
this._objects.splice(newIdx, 0, object);
}
}
this.renderAll && this.renderAll();
return this;
};
var canvas = new fabric.Canvas('c',
{
preserveObjectStacking : true
});
var rect = new fabric.Rect({
left: 10, top: 10,
fill: 'red',
width: 100, height: 100,
hasControls: true
});
canvas.add(rect);
var rect2 = new fabric.Rect({
left: 40, top: 40,
fill: 'green',
width: 100, height: 100,
hasControls: true
});
canvas.add(rect2);
var rect3 = new fabric.Rect({
left: 70, top: 70,
fill: 'blue',
width: 100, height: 100,
hasControls: true
});
canvas.add(rect3);
var rect4 = new fabric.Rect({
left: 100, top: 100,
fill: 'orange',
width: 100, height: 100,
hasControls: true
});
canvas.add(rect4);
$("#bringForward").click(function()
{
var items = canvas.getActiveObject() || canvas.getActiveGroup();
if(items)
items.bringForward();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.6/fabric.min.js"></script>
<button id="bringForward">Bring Forward</button>
<canvas id="c" width="640" height="480"></canvas>

How to select covered objects via mouse in fabricJS?

I'm trying to develop a way to select objects that are layered below and (totally) covered by other objects. One idea is to select the top object and then via doubleclick walk downwards through the layers. This is what I got at the moment:
var canvas = new fabric.Canvas("c");
fabric.util.addListener(canvas.upperCanvasEl, "dblclick", function (e) {
var _canvas = canvas;
var _mouse = _canvas.getPointer(e);
var _active = _canvas.getActiveObject();
if (e.target) {
var _targets = _canvas.getObjects().filter(function (_obj) {
return _obj.containsPoint(_mouse);
});
//console.warn(_targets);
for (var _i=0, _max=_targets.length; _i<_max; _i+=1) {
//check if target is currently active
if (_targets[_i] == _active) {
//then select the one on the layer below
_targets[_i-1] && _canvas.setActiveObject(_targets[_i-1]);
break;
}
}
}
});
canvas
.add(new fabric.Rect({
top: 25,
left: 25,
width: 100,
height: 100,
fill: "red"
}))
.add(new fabric.Rect({
top: 50,
left: 50,
width: 100,
height: 100,
fill: "green"
}))
.add(new fabric.Rect({
top: 75,
left: 75,
width: 100,
height: 100,
fill: "blue"
}))
.renderAll();
canvas {
border: 1px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.3/fabric.min.js"></script>
<canvas id="c" width="300" height="200"></canvas>
As you can see, trying to select the red rectangle from within the blue one is not working. I'm only able to select the green or the blue. I guess that after the first doubleclick worked (green is selected), clicking again just selects blue so the following doubleclick is only able to get green again.
Is there a way around this? Any other ideas?
After some time I finally was able to solve that by myself. Clicking on an object brings it to the top. On double-clicking I try to get the object one layer behind the current object. On another dblclick I get the one behind and so on. Works great for me and also allows for the selection of fully covered objects without the need to move others.
var canvas = new fabric.Canvas("c");
canvas.on("object:selected", function (e) {
if (e.target) {
e.target.bringToFront();
this.renderAll();
}
});
var _prevActive = 0;
var _layer = 0;
//
fabric.util.addListener(canvas.upperCanvasEl, "dblclick", function (e) {
var _canvas = canvas;
//current mouse position
var _mouse = _canvas.getPointer(e);
//active object (that has been selected on click)
var _active = _canvas.getActiveObject();
//possible dblclick targets (objects that share mousepointer)
var _targets = _canvas.getObjects().filter(function (_obj) {
return _obj.containsPoint(_mouse) && !_canvas.isTargetTransparent(_obj, _mouse.x, _mouse.y);
});
_canvas.deactivateAll();
//new top layer target
if (_prevActive !== _active) {
//try to go one layer below current target
_layer = Math.max(_targets.length-2, 0);
}
//top layer target is same as before
else {
//try to go one more layer down
_layer = --_layer < 0 ? Math.max(_targets.length-2, 0) : _layer;
}
//get obj on current layer
var _obj = _targets[_layer];
if (_obj) {
_prevActive = _obj;
_obj.bringToFront();
_canvas.setActiveObject(_obj).renderAll();
}
});
//create something to play with
canvas
//fully covered rect is selectable with dblclicks
.add(new fabric.Rect({
top: 75,
left: 75,
width: 50,
height: 50,
fill: "black",
stroke: "black",
globalCompositeOperation: "xor",
perPixelTargetFind: true
}))
.add(new fabric.Circle({
top: 25,
left: 25,
radius: 50,
fill: "rgba(255,0,0,.5)",
stroke: "black",
perPixelTargetFind: true
}))
.add(new fabric.Circle({
top: 50,
left: 50,
radius: 50,
fill: "rgba(0,255,0,.5)",
stroke: "black",
perPixelTargetFind: true
}))
.add(new fabric.Circle({
top: 75,
left: 75,
radius: 50,
fill: "rgba(0,0,255,.5)",
stroke: "black",
perPixelTargetFind: true
}))
.renderAll();
canvas {
border: 1px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.min.js"></script>
<canvas id="c" width="300" height="200"></canvas>
Just add one property during adding object to the canvas.
perPixelTargetFind: true
My task is a bit different - the mission is to pick the overlapping obj behind the current one:
[Left-click]+[Cmd-Key] on an selected-object to pick the first overlapping object which is right behind it.
If no overlapping objs are found, restart the search from top-layer
The idea is, for each click-event, intercept the selected object and replace it with our desired object.
A Fabric mouse-down event is like this:
User clicks on canvas
On canvas: find the target-obj by the coordinates of mouse cursor and stores it in the instance-variable (canvas._target)
Run event-handlers for mouse:down:before
Compare the target-obj found from step(2) with current selected object, fire selection:cleared/update/create events according to the results of comparison.
Set new activeObject(s)
Run event-handlers for mouse:down
We can use a customized event handler on mouse:down:before to intercept the target-obj found on Step(2) and replace it by our desired-object
fCanvas = new fabric.Canvas('my-canvas', {
backgroundColor: '#cbf1f1',
width: 800,
height: 600,
preserveObjectStacking: true
})
const r1 = new fabric.Rect({ width: 200, height: 200, stroke: null, top: 0, left: 0, fill:'red'})
const r2 = new fabric.Rect({ width: 200, height: 200, stroke: null, top: 50, left: 50, fill:'green'})
const r3 = new fabric.Rect({ width: 200, height: 200, stroke: null, top: 100, left: 100, fill:'yellow'})
fCanvas.add(r1, r2, r3)
fCanvas.requestRenderAll()
fCanvas.on('mouse:down:before', ev => {
if (!ev.e.metaKey) {
return
}
// Prevent conflicts with multi-selection
if (ev.e[fCanvas.altSelectionKey]) {
return
}
const currActiveObj = fCanvas.getActiveObject()
if (!currActiveObj) {
return
}
const pointer = fCanvas.getPointer(ev, true)
const hitObj = fCanvas._searchPossibleTargets([currActiveObj], pointer)
if (!hitObj) {
return
}
let excludeObjs = []
if (currActiveObj instanceof fabric.Group) {
currActiveObj._objects.forEach(x => { excludeObjs.push(x) })
} else {
// Target is single active object
excludeObjs.push(currActiveObj)
}
let remain = excludeObjs.length
let objsToSearch = []
let lastIdx = -1
const canvasObjs = fCanvas._objects
for (let i = canvasObjs.length-1; i >=0 ; i--) {
if (remain === 0) {
lastIdx = i
break
}
const obj = canvasObjs[i]
if (excludeObjs.includes(obj)) {
remain -= 1
} else {
objsToSearch.push(obj)
}
}
const headObjs = canvasObjs.slice(0, lastIdx+1)
objsToSearch = objsToSearch.reverse().concat(headObjs)
const found = fCanvas._searchPossibleTargets(objsToSearch, pointer)
if (found) {
fCanvas._target = found
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.min.js"></script>
<html>
<h4>Left-click + Cmd-key on overlapping area to pick the obj which is behind current one</h4>
<canvas id="my-canvas"></canvas>
</html>

change text once it is added on canvas

In fabric-js, i am making Group of Rect and text field and then adding it to the canvas. i am using following code , but can i change the Text of text field once it is added in canvas .
I have made Fiddle Please Check,
http://jsfiddle.net/HAb4N/5/
var canvas = new fabric.Canvas('c');
var Bar = new fabric.Text('Bar', {selectable: false, top: 50, left: 10});
var rect = new fabric.Rect({width: 100, height: 100, left: 100, top: 100, fill: 'red'});
var group = new fabric.Group([rect, Bar], {selectable: true, top: 50, left: 100});
canvas.add(group);
canvas.renderAll();
$(document).click(function(e) {
console.log('click');
console.log('ActiveObject', canvas.getActiveObject());
console.log('ActiveGroup', canvas.getActiveGroup());
Bar.set('Text','Selectedoooooooo');
});
This works for me:
Bar.setText("my_text");
canvas.renderAll();
When using the "set" function try camelcase for the first argument!
In other words change:
Bar.set('Text','Selectedoooooooo');
to:
Bar.set('text','Selectedoooooooo');
This works for me 🙏🏼
Use the new IText in FabricJS. Here is a nice solution
This is my answer to it
addText(color) {
color = color ? color : '#333';
let textEl = new fabric.IText('', {
fontFamily: 'Open Sans',
fill: color,
fontSize: 50
});
this.canvas.add(textEl).setActiveObject(textEl);
textEl.enterEditing();
}
Yes you can set text once it is added to canvas.Here is the jsfiddle
try changing your
Bar.set('Text','Selectedoooooooo');
to
Bar.setText('Selectedoooooooo');
Hope it helps....
You can access children of a group via getObjects() or item() methods:
canvas.on('object:selected', function(e) {
e.target.item(1).setText('Selectedoooooooo');
});
See http://jsfiddle.net/fabricjs/HAb4N/12/
Hope this will help select first object then enter text in text area
<canvas id="c" width="600" height="200"></canvas>
<textarea id="textinput" name="textarea" placeholder="Enter Text"> </textarea>
var canvas = new fabric.Canvas('c');
document.getElementById('textinput').addEventListener('keyup', function (e) {
var obj = canvas.getActiveObject();
if (!obj) return;
obj.setText(e.target.value);
canvas.renderAll();
});
var text = new fabric.Text('Your Text Here', { left: 400, top: 200,fill:'#A0A0A0'});
canvas.add(text);
var rect = new fabric.Rect({width: 100, height: 200, left: 200, top: 100, fill:'red'});
var group = new fabric.Group([rect,text], {selectable: true, top: 50, left: 350});
canvas.add(group);
canvas.renderAll();

Categories