简体   繁体   中英

Dragging a path using D3

I have a case where I am creating a view pane, paths "inside" it. To give the impression the paths are inside I am clipping them. I would also like to be able to drag these paths. The usual suggestions is to use SVG transform attribute. But this presents two problems:

  • clipped paths stay that way, while dragging only on partial paths are shown
  • dragged paths "float" outside of the given pane.

Complete JSFiddle .

The data is:

var outlines = [
[{ "x": 100.0, "y": 100.0}, {"x": 200.0, "y": 100.0}, {"x": 200.0, "y": 200.0}, {"x": 100.0,"y": 200.0}, {"x": 100.0, "y": 100.0}],
[{ "x": -100.0, "y": 200.0}, {"x": 100.0, "y": 200.0}, {"x": 100.0, "y": 300.0}, {"x": -100.0,"y": 300.0}, {"x": -100.0, "y": 200.0}],
];

I create the paths like this:

layout
.selectAll('.instance')
.data(outlines)
.enter()
.append('path')
.attr('class', 'instance')
.attr('d', function(d) { return line(d); })
.call(drag);

And the drag is:

var drag = d3.behavior.drag()
.origin(function(d) {
  return {
    x: 0,
    y: 0
  };
})
.on("dragstart", function(d) {
  d3.event.sourceEvent.stopPropagation();
})
.on("drag", function(d) {
  d3.select(this)
    .classed("dragging", true)
    .attr('transform', function(d) { return 'translate(' + d3.event.x + ',' + d3.event.y + ')'; });
})
.on("dragend", function(d) {
  d3.select(this)
    .classed("dragging", false)
    .attr('transform', null);
});

I think I would like to actually move the paths to the new location. But I am not sure how to manipulate the data with the d3.event offsets. How do I do that? Or are there better ways to do this?

To work properly, the transform must be strictly inside the clip-path (or to put it in another way, if an element has a clip-path and a transform attributes, then the coordinates of the clip-path are shifted just like the rest of the object.

The easy way to solve this in your case is to wrap your rectangles inside clip-path'd groups:

layout
.selectAll('.instance')
.data(outlines)
.enter()
.append("g")    //this group defines the clipping
.attr("clip-path","url(#clip)")
.append('path') //this path can be moved around
.attr('class', 'instance')
.attr('d', function(d) {
  return line(d);
})
.call(drag)

See https://jsfiddle.net/xhfcdbb7/

I've also removed all other references to clip-path (this way, the group remains clip to the same absolute rectangle, whether it is dragged or not)

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