block by d3noob 204d08d309d2b2903e12554b0aef6a4d

d3.drag with grouped elements in v4

Full Screen

The resulting code (with some minor formatting alterations) from an answer on Stack Overflow to a question about how to group two elements and drag them using d3.drag.

Kudos (and thanks) to Dragon_Slayer for the solution.

A block for the original (not working correctly) code is here.

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<style>

.active {
  stroke: #000;
  stroke-width: 2px;
}

.rect {
  pointer-events: all;
  stroke: none;
  stroke-width: 40px;
}

</style>

<body>

<script src="//d3js.org/d3.v4.min.js"></script>
<script>

var margin = {top: 10, right: 10, bottom: 30, left: 10},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var rectangles = d3.range(10).map(function() {
  return {
    x: Math.round(Math.random() * (width)),
    y: Math.round(Math.random() * (height))
  };
});

var color = d3.scaleOrdinal(d3.schemeCategory20);

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom);

var group = svg.selectAll('g')
  .data(rectangles)
  .enter().append("g")
  .attr("transform", 
        "translate(" + margin.left + "," + margin.top + ")")
  .call(d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended));

group.append("rect")
     .attr("x", function(d) { return d.x; })
     .attr("y", function(d) { return d.y; })
     .attr("height", 60)
     .attr("width", 30)
     .style("fill", function(d, i) { return color(i); });
  
group.append("text")
     .attr("x", function(d) { return d.x; })
     .attr("y", function(d) { return d.y; })
       .attr("text-anchor", "start")
       .style("fill", "steelblue")
       .text("Close");  
    
function dragstarted(d) {
  d3.select(this).raise().classed("active", true);
}

function dragged(d) {
  d3.select(this).select("text")
    .attr("x", d.x = d3.event.x)
    .attr("y", d.y = d3.event.y);
  d3.select(this).select("rect")
    .attr("x", d.x = d3.event.x)
    .attr("y", d.y = d3.event.y);
}

function dragended(d) {
  d3.select(this).classed("active", false);
}

</script>
</body>