Bernhard
Bernhard

Reputation: 705

svg.js svg.draggable.js and manipulation of appearance

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:

  1. 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").

  2. 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.

  3. 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.

  4. 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().

  5. 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

Answers (1)

Fuzzyma
Fuzzyma

Reputation: 8474

Wow thats a bunch of questions. I will try to work them through.

1. Why does 'this' refer to the dragged object?

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)

2. Why the fill of the fermata does not change

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

3. Why is dragging of text only working vertically

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

4. Is there a better way to get the delta as result of drag?

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

5. Are there performance issues when using many elements

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

Related Questions