0

I have been trying to use d3 library for drag n drop of dvg element by using transform translate. I am able to drag an element but it flickers while dragging.

I have been searching and doing trial and error so far from below links but it doesn't help me.

"Stuttering" drag when using d3.behavior.drag() and transform

D3.js: Dragging everything in group ('g') by element contained in the group using origin() function

How to drag an svg group using d3.js drag behavior?

For the last link, I think I am not able to understand the necessity of svg structure for this requirement which causes this issue. Can anyone help me here?

Dipesh Raichana
  • 1,008
  • 3
  • 18
  • 36
  • I am not familiar with d3 library, but I noticed that your dragged function parameter sometimes receives undefined as a parameter, which is causing it to flick. You can start by checking that .on("drag", dragged) is called from the correct location and it passes the correct parameters data to the callback. – Alexander Apr 24 '18 at 06:52
  • However, I'm new in D3 and I'm not sure about that but that parameter has not been used in the function.I tried removing it but no luck – Dipesh Raichana Apr 24 '18 at 07:02
  • I have posted the cause and a solution for this Problem [here](https://stackoverflow.com/a/45817005/3620572). – roland Apr 24 '18 at 09:53
  • @roland: Out of my curiosity, doesn't it possible without appending anything into dragging object or just changing the structure of my svg? The reason of this requirement is that I am dealing with large svg and I dont want to add anyting from javascript if possible – Dipesh Raichana Apr 24 '18 at 10:19
  • @DipeshRaichana: Have you tried the second Approach? – roland Apr 24 '18 at 10:39

1 Answers1

3

It is easier to use d3.event instead of d3.mouse for this. Here is a d3 style approach with .data():

  1. Read out the translate attribute of the <g> in your source svg.
  2. Add the x and y value of the translate to the data of the d3 object.
  3. Adjust the data and the translate of the <g> during the drag event.

function bindDragging() {

    // Define d3 object
    var g = d3.select("#group");

    // Get translate (from: https://stackoverflow.com/a/38230545/3620572)
    var elem = document.createElementNS("http://www.w3.org/2000/svg", "g");
    elem.setAttributeNS(null, "transform", g.attr("transform"));
    var matrix = elem.transform.baseVal.consolidate().matrix;
    var x = matrix.e;
    var y = matrix.f;

    g.data([{
        // Position of the group
        x: x,
        y: y
        }])
        .call(d3.drag()
            .on("start", dragstarted)
            .on("drag", dragged)
            .on("end", dragend)
        );

    function dragstarted(d) {
        g.selectAll("rect").classed("active", true);
    }

    function dragged(d) {
        // Set the new position
        d.x += d3.event.dx;
        d.y += d3.event.dy;
        d3.select(this).attr("transform", function (d) {
            return "translate(" + [d.x, d.y] + ")"
        });

    }

    function dragend(d) {
        g.selectAll("rect").classed("active", false);
    }
}
bindDragging();
#group {
    stroke-width: 3;
    stroke: #808080;
    cursor: -webkit-grab;
    cursor: grab;
}

.active {
    stroke: #ff0000;
    cursor: -webkit-grabbing;
    cursor: grabbing;
}
<div class="svgContainer">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 776.63 680.09">
    <g id="group" transform="translate(0, 0)">
        <rect width="100" height="50" style="fill:rgb(40, 40, 109);" />
        <rect width="100" height="50" y="50" style="fill:rgb(63, 149, 75);" />
    </g>
</svg>
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>
roland
  • 900
  • 12
  • 25
  • Thanks a ton for this. I would kindly like to request you to share thought process behind it. I mean, what was the issue in my code and how did you figure it out(It would really grateful if you can answer)? – Dipesh Raichana Apr 24 '18 at 16:15
  • @DipeshRaichana: You are welcome. This is just how D3.js is intended to be used. You did something odd with the x and y variables. It is best practice to bind the data to D3-objects (D3 = Data-Driven Documents). First you have to read the data (in this case the x and y of transform) from the given svg. Then this data are bound to the D3-object (of the ``). And now you can use this data for the translocation. BTW the JavaScript could be even shorter. – roland Apr 25 '18 at 12:28
  • Thanks for this explanation. I am using D3 because there are more functionalities than just Drag n Drop with SVG(I searched and came to know that svg animations cannot work with jquery). – Dipesh Raichana Apr 25 '18 at 19:33