I am trying to remove all the objects on my Canvas without selecting them. The objects in the Canvas include Grouped and Ungrouped object. All the Examples I've seen demonstrate how to delete a single ungroup object.
Canvas.ForEachObject(function(o){
o.remove();
});
Please see the fiddle for an example of what I'm trying to achieve.
https://jsfiddle.net/Shane00711/r8su3ya0/
Did you know that canvas.remove can take more than one parameter?
So the easiest way should be this one:
canvas.remove(...canvas.getObjects());
Other than canvas.clear this will only remove the objects in the canvas and not also the background.
You just need to call
canvas.clear()
it will remove all object
I figured out what I need to do in order to delete every object(grouped/ungrouped) from my Canvas.
First I had to get all the objects in the canvas.
var obj = canvas.getObjects();
once I got all the objects I simply had to loop through them removing each one as I did.
canvas.remove(obj[0]).
The reason I reference the index 0 in my
canvas.remove(obj[0])
is because every time and object was removed from the canvas the number of object in the list 'obj' also decreased by 1, moving all the objects up by 1 index. which meant that every object on my canvas would at some point be at index 0 of the 'obj' list.
here's a fiddle of a working example. where I delete all objects on the canvas without selecting a single one.
http://jsfiddle.net/Shane00711/r8su3ya0/8/
Related
Using Meteor and React, I am building an application that has a fabric canvas in the middle, a 'components panel' on the left (a library of objects to add to the canvas), and a 'layers panel' on the right (similar to Photoshop, where each object on the canvas is represented as a layer with specific controls like color, opacity etc.).
So far I have managed to display the Layers Panel by using a Meteor session variable that contains an array for the objects on the canvas.
So each time I add, remove, adjust or make any functional change to any object on the canvas, I manually make the adjustment for the object within the session variable array as well.
This has worked well so far but I now want to implement grouping functionality. While it is easy to do this with fabric.js alone, I am having trouble representing the exact state of the groups on the layers panel. It needs to be displayed in a tree format where nested groups and items are within/under other objects.
I also still need to have the layers panel sortable as well.
Using fabric, we can group a set of objects, group another set of objects, and then group the two sets of objects together. This gets quite complicated and is quickly becoming a nightmare to maintain using the method I described above.
So now I am thinking, it would be much easier to just have the layers panel look at the object data directly from the canvas (reactively). This way, I don't need to maintain a second array and manually match every change that occurs. I could then use something like React Sortable Tree.
So in an attempt to make this happen, I am trying to store a copy of canvas.getObjects() into a Meteor session variable after any change occurs on the canvas.
canvas.on({
'after:render': function() {
var canvasObjects = [];
var objects = canvas.getObjects();
objects.forEach(object=>{
canvasObjects.push(object);
});
Session.set('canvasObjects', canvasObjects);
}
});
I am getting the following error though...
TypeError: callback is not a function
at modules.js?hash=d9804d9fae07a146610fc3c3c610d3e79bf33006:261816
at onLoaded (modules.js?hash=d9804d9fae07a146610fc3c3c610d3e79bf33006:244313)
at modules.js?hash=d9804d9fae07a146610fc3c3c610d3e79bf33006:244337
at modules.js?hash=d9804d9fae07a146610fc3c3c610d3e79bf33006:257179
at onLoaded (modules.js?hash=d9804d9fae07a146610fc3c3c610d3e79bf33006:244357)
at modules.js?hash=d9804d9fae07a146610fc3c3c610d3e79bf33006:244379
at Array.forEach (<anonymous>)
at Object.enlivenPatterns (modules.js?hash=d9804d9fae07a146610fc3c3c610d3e79bf33006:244370)
at Function.fabric.Object._fromObject (modules.js?hash=d9804d9fae07a146610fc3c3c610d3e79bf33006:257171)
at Function.fabric.Path.fromObject (modules.js?hash=d9804d9fae07a146610fc3c3c610d3e79bf33006:261457)
If I replace this line...
Session.set('canvasObjects', canvasObjects);
with this line...
console.log(canvasObjects);
I see the array printed in the console.
Why is it able to log the array but unable to store it into the session variable?
Is this even a good idea? I feel like it will be bad for performance. Would there be any other way to keep the canvas state and the layers panel in sync with all the properties that I want (visibility, opacity, fill, lock, index, group hierarchy etc.).
Thanks in advance.
So let's say that I have an array, and it contains 10 elements. I want to set the first element as the root, and then if the next number is smaller, put it to the left, if larger to the right. How would I do this?
Actually, I have figured it out now. I can just set another type called tree and it has itself, leftbranch and rightbranch, and leftbranch and rightbranch are also trees.
I'm displaying elements from an arraylist in table on the webpage. I want to make sure that once the user press "delete the data", the element in the table is immediately removed so the user does not have to refresh and wait to see the new table. So I'm currently doing it by removing the element from the arraylist, below is the code:
$scope.list= function(Id) {
var position = $scope.list.indexOf(fooCollection.findElementById({Id:Id}));
fooCollection.delete({Id:Id});
if (position>-1) {
$scope.list.splice(position,1);
}
$location.path('/list');
};
But I the position is always -1, so the last item is always removed from the list no matter which element I delete.
I found it strange you we're operating on two different lists to begin with so I assumed you were taking a copy of the initial list. This enabled me to reproduce your bug. On the following line you're trying to find an object that isn't present in your list.
var position = $scope.list.indexOf(fooCollection.findElementById({Id:Id}));
Eventhough we're talking about the same content, these two objects are not the same because:
indexOf compares searchElement to elements of the Array using strict
equality (the same method used by the ===, or triple-equals,
operator).
So there lies your problem. You can see this reproduced on this plunker.
Fixing it the quick way would mean looping over your $scope.list and finding out which element actually has the id that is being passed.
you can use the splice method of javascript which takes two paramete
arrayObject.splice(param1, param2);
param1 -> from this index elements will start removing
param2 -> no of elements will be remove
like if you want to remove only first element and your array object is arrayObject then we can write code as following
arrayObject.splice(0, 1);
I'm making a small appwith localstaorage (not implemented yet): you type a note int the text area and it is display in a list
the note are stacked in an object called notes (for localstorage in the future);
But my problem is : I can add a note, but when I try to remove on of them, I have to remove my li and the related note object in the 'notes' array, so i decided to use splice method, but it works in a strange way...
when i click 'close', it works fine one or two times but at a moment the array stays with one or two object in it...
I tried different ways to solve the problem but without success...
Here is the fiddle : http://jsfiddle.net/h8hg6/1/
thanks for your help
I have made some modifications to your fiddle that I think solve the problem. Essentially you were using .splice incorrectly, and your Array was falling out of sync with your note elements. I've replaced your array with an numeric-based object because it is much easier to deal with. Here are some of the relevant changes:
http://jsfiddle.net/h8hg6/2/
var notes = {}; // notes is now an object instead of an array
// snip
var number = jQuery(this).parents('li').data('number');
delete notes[number]; // this is how you remove properties from an object
// snip
var note = {
color: color,
text: text
};
notes[i] = note; // add this object as a property of the notes object
i++;
The problem is that your call to splice uses the value of the queue variable to determine the index of the element that will be removed in the notes array. Right here:
notes.splice(queue, 1);
Since the queue value is always increasing (right here):
function addNoteToPage(){
i++;
...
jQuery('ul#notes li:first').before('<li data-queue="'+ i +'">'+ note.text +' <a href=""#>CLOSE</a>
You hit a moment where you call splice on an non-existing index of the notes array and nothing is removed as a result. Basically, you end up with an out-of-sync notes array.
You need to make sure that the value of the data-queue attribute coincides with the real index of the element in the notes array so that your call to splice(queue,1) always succeeds and removes the appropriate array element.
With that said, if above answer works for you, I'd go with that one. I just wanted to give you more insight on what was going on...
With the power of jquery...
I'm attempting to add two selections together, they both contain the same type of element (<option>).
But the add(..) method doesn't seem to be playing ball.
var matchingRemovedOptions = removedOptions.filter(function() {
return this.text.toLowerCase().match(str.toLowerCase());
});
tempOptions.add(matchingRemovedOptions);
console.log(tempOptions.length);
console.log(matchingRemovedOptions.length);
As you can see im trying to filter out some option elements from the removedOptions selection and add these to the tempOptions selection.
But when using the console.log, the length of tempOptions stays the same as in, does not increase.
.add() returns a set with the elements/selector added, it doesn't actually add them to the set that it's called on. To get the effect you want, you need to update to the set it returns, like this:
tempOptions = tempOptions.add(matchingRemovedOptions);
If you think about all other tree traversal functions, they behave the same way, for example obj.find("...") doesn't change obj to what's found, only the rest of the chain operates on that set, which .find() returns.
You need to do another assignation:
tempOptions = tempOptions.add(matchingRemovedOptions);