Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 269
Sudarshan Avatar asked Apr 11 '13 07:04

Sudarshan


People also ask

Can we group SVG elements in d3js?

The <g> SVG element is a container used to group other SVG elements. Transformations applied to the <g> element are performed on its child elements, and its attributes are inherited by its children. We can create a group element with D3. js by appending a g element using any selection.

Which D3 component can be used to allow you to drag the canvas?

drag() This method is used to create a new dragging.

What is G in d3js?

g element is used to group SVG shapes together, so no it's not d3 specific.


2 Answers

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

like image 176
Erik Dahlström Avatar answered Oct 03 '22 06:10

Erik Dahlström


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.

like image 25
v4gil Avatar answered Oct 03 '22 07:10

v4gil