I'm currently working on a canvas built with fabric.js.
I have three objects on a canvas:
First, that cannot be selected/resized/replaced
Second ,that behave the same as the first one
And a third one, which can be replaced/selected etc.
My problem is that when I multiselect them (by using my mouse),
they all became capable of resizing/replacing etc.
My question is:
How can I disable grouping them together, so that the first two objects cannot be select?
I have already tried canvas.selection = false - but this option disables the whole canvas.
To disable the ability to click and drag in order to select multiple objects you can simply add a key:value pair in the options of the fabric.Canvas initialization...
let canvas = new fabric.Canvas("some_id_attribute_value",{selection: false});
The specific key value is selection:false and "some_id_attribute_value" is whatever you specified as the id of the canvas element(basic canvas init step).
I was also having this problem, hope this helps!
I don't know if I follow your question but each object has a selectable property.
Perhaps that will help?
selectable :Boolean
When set to false, an object can not be selected
for modification (using either point-click-based or group-based
selection). But events still fire on it.
http://fabricjs.com/docs/fabric.Object.html#selectable
Related
I'm not sure whether I'm using the right terminology here - but here is an example:
https://gist.run/?id=57ed46429e4583eb4c3fb11814451a55
This is how it looks like in Chromium:
Basically, the entries on top (red outline) are a visualization of an array as the "first-level" data display; here one can toggle each element's selection, and make a multi-element selection (red background). The array that is the source of the "first-level" display is mydata in first-level-items.js.
Those items that are selected in "first-level", are then shown again in "second-level" (green outline); here the same information of name and value is displayed, although a bit differently. Here also one can toggle an elements selection - but only one "second-level" element can be selected. The array that is the source of the "second-level" display is myseldata in second-level-items.js.
The intent here, is that once a "second-level" selection has been made, a slider appears, to change the .value property of the particular object which is the selected array element.
My original question (which is why I started this post/example at all), was:
How do I ensure that whenever the slider is changed, the value is updated in both second-level and first-level display?
... however, for reasons beyond me, this in fact does work somewhat in this gist.run example (but it still doesn't work in my actual project, which forced me to come up with the example to begin with). Also it only works somewhat, in the sense that when loading the example page at first, after making first and second level selections, and then changing the slider, the .value will be updated in both first- and second-level display. But as soon as I try deselecting on second level - or changing the selection on second level - then updating stops. So, I guess this question still stands...
After a second-level selection has been made, deselecting on second level (by clicking to toggle) does NOT remove the slider; how can I have it behave like that?
The update happens only on the slider's onChange - basically, while you drag and slide, this component emits onSlide, but it will generate onChange only at the end when the mouse is released (that is, when the sliding has stopped). How can I update both first- and second- level display while the slider is sliding?
And finally - is this how this kind of a problem is best addressed in Aurelia? That is - I currently have one array in first-level-items.js; first-level-items.js then has a singleton reference to second-level-items.js, so it can call a method within it, to change a filtered copy of the array on the second level, which then serves as a source both for second-level display and the slider... Is there a better way to organise this?
Boy, this was a pain, but here's what I think is the solution:
https://gist.run/?id=c09fea3b82a9ebc41e0a4c90e8665b04
Here are some notes:
Apparently, there is something wrong applying if.bind or show.bind on the input element of the slider - instead, the input element should be put in an enclosing div, and the div should have if/show.bind applied
Furthermore, if.bind should not be used, as it re-instantiates the slider element - use show.bind so we can get a reference to the slider widget at start already, even if it is hidden
Seemingly, using TaskQueue in attached() is the only way to get a reference to the slider at start
Once we have a reference to the widget, re-apply it on each second level element, whenever they change
Do not set this.myselChanging to null to specify no target of the slider (simply count on hiding the slider appropriately)
For a continuous change (onSlide), simply use this.myselChanging.value = e.value; in the handler - both first-level and second-level values will be changed
Beyond this, it seems arrays are copied by reference, so the multi-level update happens without further intervention...
Though, would still love to know what is the proper way to do this...
I am looking to create a tool where I can drag an image from one div to another and on drop, the following to happen:
1 - The dragged image returns to where it came from
2 - A series of controls are added within a container
Similar to https://formbuilder.online/ when a textbox is added to the form.
I understand how to perform the drag (i.e. make the item draggable) and I can understand the drop event. I'm struggling to return the dropped object back to it's original location.
The overall aim is to drop a list item into a sortable list so I can reorder the items (it's similar to the formbuilder linked above, but for a custom application, nothing to do with forms.
I'm just not sure what I need to put into my dropEvent function to return the dragged item to it's location. I can use jQuery append to add the list item containing the controls I want to the list, so that should be fine, it's just the returning the item to where it came from.
Sory, have just seen the documentation and the revert option when making an item draggable.
You might wanna try jQuery Sortable:
https://jqueryui.com/sortable/
I am able to select object programatically using fabricjs. However, it does not behave like when one selects an object using mouse click. On a mouse click, the object comes under focus, and one can, for example, drag it. However, on programatic selection, I cannot immediately move an object. An example jsfiddle:
http://jsfiddle.net/ThzXM/1/
Programmatic selection:
canvas.setActiveObject(canvas.item(0));
What I would like to ultimately achieve is this: on clicking a button, a new rectangle is added to canvas, which the user can move around before placing it on canvas - without requiring extra clicks. Is it possible to do this in a cross-browser compatible way? (I know in some browsers I can fire a mouseclick event but most disallow it.)
You have to do this. Don´t forget to call setCoords() to update the bounding box of your object.
// Set the active element
canvas.setActiveObject(canvas.item(0));
// Set left, o right,or angle... check documentation.
//Don´t forget to call setCoords() after changes.
canvas.item(0).setLeft(80).setCoords();
//Then render the canvas
canvas.renderAll()
I'm trying my way around building a graphics editor with Paper.js
I would like to select the first(1st) element that was picked using a selection tool(either Shift+Click, or dragging a selection box). Direct-click detection is done via hit-testing and selection box via getIntersection
If it's Shift+Click its the first selected element. Which element was clicked is found with HitResult
If its selectionBox, the first intersection? result of the selection box.
Is it possible to get this?
I do a FOR loop to get all the elements in the Paper.js selectedItems array which returns all the selected items on the canvas.
I've tried this:
var selected = paper.project.selectedItems;
var firstSelected = selected[0];
but this doesn't return what i need.
The above code snippet fetches an array that is agnostic to which element was selected first. It simply orders the selectedItems in the array starting from the ''oldest drawn path''.
What i need is a way to find out which is the 1st element that was selected.
Either the 1st that get's ''touched(intersected)'' with the selection
rectangle
Or the first that was clicked while in Shift+Click
functionality(Select more than one element with click).
The reason for this is that i would like to add to my editor, align-relative-to functionality.
In order to have a correct UX, the user must have the ability to align an element relative to another that he sets as the ''reference item''. Therefore i need to know the 1st element selected relative to others in order to use it as the ''reference item''.
Any ideas ?
Here is a working example of what I understood you want to achieve for the selection (without the align-relative-to functionality).
And here is the code (under SelectPaperJS) https://c9.io/arthursw/oiio/
It should not be too hard to make something similar on Stylii (since you're using it).
You can have an array to keep track of the order of selection of your items. For example in the mousedown function of the direct select tool (from line 789 of editor.js) you can add the newly selected element to this array (line 800). Same thing when you select with the rectangular selection tool.
I am new to Fabricjs, but have been reading the docs, doing the tutorials.
It is a very powerful library. I see places where I can lock objects, but what I want to do is stay on an object I select, and not release it by clicking outside its boundaries. I am building a mobile & touch screen version and using your fingers, you tend to click outside the bounds of an object.
Basically: select an object, be able to edit, apply properties from a palette, and have a release button, so it is not released before the user is done editing it.
You can lock single elements with:
canvas.item(0).selectable = false;
But you still have the problem of losing selection on the object you are trying to edit should you click outside its bounds.
Any help is very appreciated!
If I understand you correctly, you would just need to prevent deselection of object by selecting it back again when it's deselected. This can be done via events in Fabric:
var selectedObject;
canvas.on('object:selected', function(options) {
selectedObject = options.target;
});
canvas.on('selection:cleared', function() {
canvas.setActiveObject(selectedObject);
});
I made a simple example (jsfiddle) to demonstrate this.