Drag multiple elements that aren't grouped in

2019-08-14 05:27发布

I'm using D3's drag behavior to drag circle elements in a force layout with circleGroup.call(force.drag), where force.drag is a drag behavior and circleGroup is a selection of all circle elements. This works fine for dragging a single element.

How can I drag an arbitrary selection of multiple circle elements all at once?

Note that because the selection must be arbitrary, I don't think I can just just group the ones I want to drag together in a <g> tag.

I've looked at these questions and still haven't been able to get it working.


1条回答
戒情不戒烟
2楼-- · 2019-08-14 05:42

You could do something like this... It's not a force layout, but you should be able to extend it to that pretty easily.

Click on a circle to select it, and then click and drag somewhere else to move them around.

Basically, I'm keeping track of the index of the selected circles in an array, and updating the corresponding data in the drag handler. After the data is updated, I then modify the cx and cy attributes of the selected circles.

Note: the drag handler is attached to a transparent rect that covers the entire SVG, and I'm using CSS styles to get the events to cascade to the respective SVG elements correctly with pointer-events: all; applied to the rect.

 var width = 500,
   height = 500;

 var data = d3.range(10).map(function(d) {
   return {
     x: parseInt(Math.random() * width),
     y: parseInt(Math.random() * height),
     r: parseInt(Math.random() * 10 + 10)
   }
 });

 var selectedNodes = [],
   selectedData = [];

 var drag = d3.behavior.drag()
   .on("drag", dragged)

 var vis = d3.select("#vis").append("svg")
   .attr("width", width)
   .attr("height", height);

 var dragRect = vis.append("rect")
   .attr("class", "drag")
   .attr("width", width)
   .attr("height", height)
   .call(drag);

 var nodes = vis.selectAll("circle.node")
   .data(data)
   .enter().append("circle")
   .attr("class", "node")
   .attr("r", function(d) {
     return d.r;
   })
   .attr("cx", function(d) {
     return d.x;
   })
   .attr("cy", function(d) {
     return d.y;
   })
   .on("click", clicked);

 function dragged(d) {
   selectedData.forEach(function(i) {
     data[i].x += d3.event.dx;
     data[i].y += d3.event.dy;
   });

   d3.selectAll("circle.node.selected")
     .attr("cx", function(d) {
       return d.x;
     })
     .attr("cy", function(d) {
       return d.y;
     });
 }

 function clicked(d, i) {
   var j = selectedData.indexOf(i);

   if (j === -1) {
     selectedData.push(i);
     d3.select(this).classed("selected", true);
   } else {
     selectedData.splice(j, 1);
     d3.select(this).classed("selected", false);
   }
 }
        rect.drag {
          fill: none;
          pointer-events: all;
        }
        circle.node {
          fill: #000;
        }
        circle.node:hover {
          cursor: pointer;
        }
        circle.node.selected {
          fill: #f00;
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="vis"></div>

查看更多
登录 后发表回答