Mat
Mat

Reputation: 1011

How to drag complete svg with d3js?

I am trying to have a drag behavior when clicking anywhere on the svg.

Here is a JSFiddle of what I tried : https://jsfiddle.net/d2fx196n/2/

The intuitive thing I tried was this :

svg = d3.select("body")
  .append("svg:svg")
  .attr("width", 200)
  .attr("height", 200)
  .style("border", "solid")
  .call(drag);

Is there a simple way to apply the drag behavior to the whole svg, making every object move identically ?

EDIT : What I want more precisely is to drag everything that is inside the svg by clicking anywhere in the svg (even the "background"). And when I drag, everything inside the svg should move together.

EDIT2: Basically, I'd like to have the same behavior that can be seen here : http://jsfiddle.net/superboggly/2hfx3/ , but with lines as well

Upvotes: 0

Views: 2081

Answers (1)

Cool Blue
Cool Blue

Reputation: 6476

Strategy

You can wrap the contents of the svg in a g and put a transform on it, then update the transform translate on drag.

Tactics

  1. d3.event exposes dx and dy so you can just add these to the transform on drag.
  2. There is a handy API for transform in the d3 Math module, you can use that to save the bother of parsing the transform attribute of the g element.

Code

    var drag = d3.behavior.drag()
          //.origin(function (d) { return d; })
          .on("dragstart", dragstarted)
          .on("drag", dragged)
          .on("dragend", dragended),

        data = {
          "nodes": [
              { "id": "0", "x": 50, "y": 50 },
              { "id": "1", "x": 100, "y": 50 },
              { "id": "2", "x": 50, "y": 100 },
              { "id": "3", "x": 100, "y": 100 }
          ],
          "edges": [
              { "id": "0", "source": "0", "target": "1" },
              { "id": "1", "source": "2", "target": "3" }
          ]
        },

        log = d3.select("body").append("div")
          .style({ "background-color": "1px solid #ccc" })
          .text("waiting..."),

        svg = d3.select("body")
          .append("svg:svg")
          .attr("width", 200)
          .attr("height", 200)
          .style("border", "solid")
          .call(drag)
          .append("g"),

        nodes = data.nodes,

        links = data.edges;

    for (var i in data.edges) {
      for (var j in nodes) {
        if (nodes[j].id == data.edges[i].source) {
          data.edges[i].source = nodes[j];
        } else if (nodes[j].id == data.edges[i].target) {
          data.edges[i].target = nodes[j];
        }
      }
    }

    var lines = svg.selectAll(".line")
        .data(links)
        .enter()
        .append("line")
        .attr("x1", function (d) { return d.source.x })
        .attr("y1", function (d) { return d.source.y })
        .attr("x2", function (d) { return d.target.x })
        .attr("y2", function (d) { return d.target.y })
        .attr("stroke-width", "4")
        .style("stroke", "#000000");

    var circles = svg.selectAll("circle.nodes")
        .data(nodes)
        .enter()
        .append("svg:circle")
        .attr("cx", function (d) { return d.x; })
        .attr("cy", function (d) { return d.y; })
        .attr("r", "8px")
        .attr("fill", "#FF0000");


    function dragstarted(d) {
      d3.event.sourceEvent.stopPropagation();
      d3.event.sourceEvent.preventDefault;
      console.log("start")
      log.text("start")
    }

    function dragged(e) {
      var t = d3.transform(svg.attr("transform")).translate;
      svg.attr("transform", "translate(" + [t[0] + d3.event.dx, t[1] + d3.event.dy] + ")")
      console.log("drag: " + d3.transform(svg.attr("transform")).translate);
      log.text("drag: " + d3.transform(svg.attr("transform")).translate)
    }

    function dragended(d) {
      console.log("end")
      log.text("end")
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Upvotes: 1

Related Questions