简体   繁体   中英

using d3 drag behavior's origin to create a “drag handle” for a tree node

I am relatively new to d3, and I'm still bumping into things that stump me.

Basically, I have a tree with draggable nodes. I want to restrict the "drag handle" of the nodes to only the circle, not the circle and text (and whatever else I end up adding).

I know that it has something to do with properly setting the origin in my drag behavior, but I just can't quite seem to get it.

I've found some useful information here on stackoverflow (sorry, I can only post two links), and looking at https://groups.google.com/forum/#!topic/d3-js/fjp1mpvVW1M it appears that I'm applying the drag behavior to a child element of ag container and then trying to apply the transform to its g container.

How can I accomplish this?

here's the relevant code:

var dragListener = d3.behavior.drag()
.origin(function () {
    var t = d3.select(this);
    return {
        x: t.attr("x") + d3.transform(t.attr("transform")).translate[0],
        y: t.attr("y") + d3.transform(t.attr("transform")).translate[1]
    };
})
.on("drag", function (d) {
    d.x0 += d3.event.dy;
    d.y0 += d3.event.dx;       
    //var node = d3.select(this);  //this works
    var node = d3.select(this.parentNode)  //this doesn't work
    node.attr("transform", "translate(" + d.y0 + "," + d.x0 + ")");
});

  var nodeEnter = node.enter().append("g")
  //.call(dragListener)  // this works
  .attr("class", "node")
  .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
  .on("click", click);

  nodeEnter.append("circle")
  .call(dragListener)  // this doesn't work
  .attr("r", 1e-6)
  .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

Here's a fiddle: http://jsfiddle.net/tsmith77/4R3Cb/

UPDATE

I wasn't able to get the child group to do what I wanted, but I accomplished what I want by intercepting the mousedown event on the text:

  nodeEnter.append("text")
  .on("mousedown", function (d) {
      d3.event.stopPropagation();
      })
  .on("click", function (d) {
      alert("text clicked");
  })

This prevents the text from being a drag handle, but still allows me to perform an action when the text is clicked.

Set up following line in your CSS for text correspondent to nodes:

  pointer-events: none;

(one way to do it would be to assign a class named let's say " node-label " to all such texts, and then, to define that class' property " pointer-events " as above)

This will prevent dragging by grabbing text.

I'll give you also two live examples. They deal with force layout, not tree like in your case, but it shouldn't matter, the principle is the same.

example 1 - dragging possible by grabbing both circles and labels

example 2 - dragging possible by grabbing only circles

The difference between them is only the line:

  pointer-events: none;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM