sairaj
sairaj

Reputation: 157

Prevent svg groups from overlapping (D3 js v4)

How can I prevent the svg's "g" element from overlapping on the other "g" elements when I drag the element to switch/change its position. Below is the link to the code.

https://jsfiddle.net/3jxqgjcL/

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", 300)
     .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("y", d.y = d3.event.y);
  d3.select(this).select("rect")
    .attr("y", d.y = d3.event.y);
}

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

Upvotes: 2

Views: 1432

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102174

Your question is not exactly clear. I'm assuming that by prevent the svg's "g" element from overlapping you want to rearrange the groups when you release one of them.

That being the case, you can get all the <g> elements in the dragended function, sort them and translate them according to their indices:

function dragended(d) {
    d3.select(this).classed("active", false);
    var theseGroups = svg.selectAll(".groups").sort(function(a, b) {
        return d3.ascending(a.y, b.y);
    });
    theseGroups.attr("transform", function(d, i) {
        return "translate(" + margin.left / 2 + "," + (d.y = barHeight * i) + ")";
    })
}

Here is a demo:

var margin = {
    top: 10,
    right: 10,
    bottom: 30,
    left: 10
  },
  width = 500 - margin.left - margin.right,
  height = 500 - margin.top - margin.bottom
distance = 0, barHeight = 75, i = 0;

function yAxis() {
  if (i == 0) {
    i++;
    return 2;
  } else {
    distance = parseInt(barHeight) * i;
    i++;
    return distance;
  }
}
var rectangles = d3.range(5).map(function() {
  return {
    x: 5,
    y: Math.round(yAxis())
  };
});

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

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

var group = svg.selectAll('g')
  .data(rectangles)
  .enter().append("g")
  .attr("class", "groups")
  .attr("transform", function(d) {
    return "translate(" + d.x + "," + d.y + ")"
  })
  .call(d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended));

group.append("rect")
  .attr("height", 60)
  .attr("width", 300)
  .style("fill", function(d, i) {
    return color(i);
  });

group.append("text")
  .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).attr("transform", "translate(" + margin.left / 2 + "," + (d.y = d3.event.y) + ")");
}

function dragended(d) {
  d3.select(this).classed("active", false);
  var theseGroups = svg.selectAll(".groups").sort(function(a, b) {
    return d3.ascending(a.y, b.y);
  });
  theseGroups.attr("transform", function(d, i) {
    return "translate(" + margin.left / 2 + "," + (d.y = barHeight * i) + ")";
  })
}
svg {
  border: 1px solid #000;
}
<script src="https://d3js.org/d3.v4.min.js"></script>

Upvotes: 1

Related Questions