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

17,856

Solution 1

First off, the <g> element doesn't care about xand y attributes (as in: they're just ignored). You can use transform="translate(x,y)" instead.

Second, you will need to check that the element you get in the dragmove handler actually is the <g> element, and not a child element of it. This is because <g> elements have no actual hit area themselves. Their children do though, and the mouse events first go to the children then bubble up to the parent. You can inspect evt.target and evt.currentTarget to see this in action. target is the element that was hit originally, currentTarget is the event target that is currently handling the event (e.g the <g> element if the event bubbled up).

Solution 2

For d3 v4:

var drag_this = d3.drag().subject(this)
    .on('start',function (d) {
        if (d.x1){
            d.x1 =  d3.event.x - d.xt;
            d.y1 =  d3.event.y - d.yt;
        }else{
            d.x1 = d3.event.x;
            d.y1 = d3.event.y;
        }
    })
    .on('drag',function(d){
        d3.select(this)
        .attr("transform", "translate(" + (d3.event.x - d.x1)  + "," + (d3.event.y - d.y1) + ")");

        d.xt = d3.event.x - d.x1;
        d.yt = d3.event.y - d.y1;
    });

my_group.call(drag_this);

This assumes that you have data bound to the group.

Share:
17,856
Sudarshan
Author by

Sudarshan

I started programming in last year of my graduation(2011). Well, so far there is not really more to say but that i simply began to love writing code. It simply makes me happy =) In general, writing abstract or complex code snippets is what satisfies me the most. The more of a brain ache, the better If you didn't see me around on SO today... I am on a secret mission! ☻

Updated on June 26, 2022

Comments

  • Sudarshan
    Sudarshan almost 2 years

    I am using D3js drag. single element is get dragged perfectly fine. but i want to drag a group of elements.How it can be done. Here is what is on my Js Fiddle link:

      function onDragDrop(dragHandler, dropHandler) {
            var drag = d3.behavior.drag();
    
        drag.on("drag", dragHandler)
        .on("dragend", dropHandler);
        return drag;
        }
    
        var g = d3.select("body").select("svg").append("g")
        .data([{ x: 50, y: 50 }]);
    
        g.append("rect")
        .attr("width", 40)
        .attr("height", 40)
        .attr("stroke", "red")
        .attr("fill","transparent")
        .attr("x", function (d) { return d.x; })
        .attr("y", function (d) { return d.y; })
        .call(onDragDrop(dragmove, dropHandler));
    
        g.append("text")
        .text("Any Text")
        .attr("x", function (d) { return d.x; })
        .attr("y", function (d) { return d.y; })
        .call(onDragDrop(dragmove, dropHandler));
    
        function dropHandler(d) {
           // alert('dropped');
        }
    
        function dragmove(d) {
            d3.select(this)
          .attr("x", d.x = d3.event.x)
          .attr("y", d.y = d3.event.y);
        }
    

    I want to drag both rect and text simultaneously. Here is what I tried, but no luck. I think am missing something simple.

  • Sudarshan
    Sudarshan about 11 years
    i tried your approach. but elements are blinking on dragging them. have look over here. jsfiddle.net/xnjGD/3
  • Erik Dahlström
    Erik Dahlström about 11 years
    That's because you're not calling the drag from the <g> element. Here's a simple fixup: jsfiddle.net/xnjGD/4. Also see stackoverflow.com/questions/13078535/….
  • Sudarshan
    Sudarshan about 11 years
    thanks Erik. you saved me second time.thanks a lot. and here is the final solution of my problem. jsfiddle.net/xnjGD/6
  • kwerle
    kwerle about 10 years
    Super helpful! Thanks!