Reputation: 705
I want to use svg.js in to implement drag and drop, and manipulate appearance of graphical elements. It mainly works, but I do not fully understand why.
I have extracted the essential part from my app to illustrate the situation my app. It is possible to play around there and see the effects.
https://jsfiddle.net/bwl21/ex8dcxtm/12/
The SVG is generated as a string by my application. I simulate this by adding the SVG to the HTML pane in jsfiddle.
I have a function "set_draggable(id) which gets the id of the svg element and attaches a drag handler.
function set_draggable(svg_element) {
var xx = SVG.get(svg_element);
xx.addClass("zn_draggable");
xx.draggable(function(x, y) {
return {
x: Math.floor(x),
y: Math.floor(y)
}
});
var sx = 0,
sy = 0;
xx.on('dragstart', function(e) {
sx = e.detail.p.x;
sy = e.detail.p.y;
this.fill("red");
});
// todo: don't know why 'this' is the only way to change the filling ...
xx.on('dragend', function(e) {
this.fill("green");
var result = {
delta: [ e.detail.p.x - sx, e.detail.p.y - sy],
element: svg_element
};
alert(JSON.stringify(result));
})
}
set_draggable("ZN_18");
set_draggable("ZN_19");
set_draggable("ZN_20");
set_draggable("ZN_21");
My questions:
in the draggable event handlers, I want to change the colors of the object.
Why does 'this' refer to the dragged object? It is the only way I found to apply fill() with an effect. I tried with xx
which is the dom node I attach the draggable. Also tried with e.target.fill("red")
.
When dragging the Fermata - Character (which is a path), the color does not change. It works when dragging text. What could be the reason?
Answer by bwl21: Meanwhile I found that the attributes of the group do not override attributes of the children. So I had to remove stroke and fill from the path.
Neverheless, I did not manage to navigate to the children and change the attributes there.
When dragging ZN_19 it can move only vertical as I made the draggable. If I wrap it in a group (like ZN_20) and call draggable() on this, I can move it around as I wish.
Is there a better way to get the delta as result of drag? I store x and y in the 'dragstart' handler, and compute the delta in the 'dragend' handler. I wourd expect the delta to be integer number as I round it by the function passed to the draggable().
If I have many objects (my app has about 300), will I face a performance issues, as I create many handlers? Is there a better way to do this.
Any help is welcome.
Upvotes: 3
Views: 3214
Reputation: 8474
Wow thats a bunch of questions. I will try to work them through.
This is something svg.js does in general. All event handler are executed in the context of the element.
So this prints true
when clicking on the element:
el.on('click', function() { console.log(this == el) })
So yes, you can use xx
instead and its working just fine in your example. Just replace this
with xx
.
However, this
is the save way because you can run into trouble with variable scoping when using an outer variable which might be redecleared somewhere else (typical example: attaching event handler in a loop)
This is already correctly answered. As a general tip I can say: Dont use groups if they only hold one shape. There is no need to do so.
For the follow up question about navigating through the dom: svg.js has a wonderful documentation. Just type children
into the search at http://svgjs.dev/.
You have multiple possibilities:
el.children() // array
el.get(index) // element at index
el.first() // first element
el.last() // last element
Your svg was not generated using svg.js. Svg.js treats every first level tspan as a new line IF it was created with svg.js. If not, it does nothing special with it. In your case that means: The text IS moved (look into the dom - you can see it). However, in your svg code you reset the x-coordinate to 80
in the tspan so it stays there forever. If you dont want that, dont use x
but instead use dx
or call newLine()
on the tspan which will enable the special handling for lines which also includes changes to the x coordinate when the texts x coordinate is changed.
A note on this: I did that in your example fiddle which made the text disappear. Thats because the text itself has an x of 189 which is out of the screen so you need to adjust that to 80 first
No there isnt.
Rounding is applied to the coordinates just before setting them on the element. However: The orginal point is given in the event object because its the source of truth
Lots of elements slow down dom operations. So dont move hundreds of elements together. Just applying handlers to them shouldnt be a problem.
However, performance also depends on the browser. Try to write performant code. Reuse the draggable-constraint function by defining them (el.draggable(nameOfFunc)
), try to avoid accessing outer variables (like xx
) in the handler so no closure needs to be generated, dont do heavy work on drag, use dragend instead to do the heavy lifting.
Hope I could help
Upvotes: 3