score:1

Accepted answer

reorder elements in the dom

to reorder elements in the dom with d3 you can use selection.sort and selection.order:

// sort & then order:
selection.sort(function(a,b) {
  return a.property - b.property; 
})
.order();

selection.sort sorts a selection based on the bound data, a and b each represent a datum bound to a single element. the resulting behavior is essentially the same as array.sort, but rather than using an array, you are sorting elements in a selection using their bound data. the content of the function provided to selection.sort (the compare function) determines sorting order:

the compare function, which defaults to ascending, is passed two elements’ data a and b to compare. it should return either a negative, positive, or zero value. if negative, then a should be before b; if positive, then a should be after b; otherwise, a and b are considered equal and the order is arbitrary. (docs)

once we have a sorted selection we can apply selection.order(), which re-inserts each element into the dom based on the selection's order. remember that elements drawn first can be covered by elements drawn later - first in the selection means potentially underneath everything.


so if we had something like this, where overlapping bars are drawn sequentially based on the order of a data array:

enter image description here

var bars = [
  {value: 100},
  {value: 50},
  {value: 200},
  {value: 70},
  {value: 40},
  {value: 120}
];

var height = 200;
var width = 500;

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

var bars = svg.selectall("rect")
  .data(bars)
  .enter()
  .append("rect")
  .attr("width", 45)
  .attr("height", function(d) { return d.value; })
  .attr("y", function(d) { return height-d.value; })
  .attr("x", function(d,i) { return i * 30 + 50; })
  .attr("fill", function(d,i){ return d3.schemecategory10[i]; })
  .attr("stroke","black")
  .attr("stroke-width",1);


// order the bars:
bars.sort(function(a,b) {
  return b.value - a.value;
}).order();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

we can pull up the small bars, say, for greater visibility with a sort and order:

enter image description here

var bars = [
  {value: 100},
  {value: 50},
  {value: 200},
  {value: 70},
  {value: 40},
  {value: 120}
];

var height = 200;
var width = 500;

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

var bars = svg.selectall("rect")
  .data(bars)
  .enter()
  .append("rect")
  .attr("width", 45)
  .attr("height", function(d) { return d.value; })
  .attr("y", function(d) { return height-d.value; })
  .attr("x", function(d,i) { return i * 30 + 50; })
  .attr("fill", function(d,i){ return d3.schemecategory10[i]; })
  .attr("stroke","black")
  .attr("stroke-width",1);

  
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>


reposition based on order

as you can see above, this doesn't reset the x or y attribute of each bar to reflect the ordering on the z (as in your example). as in my basic example above, we can reset the x values based on i (this can be done by rescaling too, but is enough to be a separate question and answer):

var bars = [
  {value: 100},
  {value: 50},
  {value: 200},
  {value: 70},
  {value: 40},
  {value: 120}
];

var height = 200;
var width = 500;

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

var bars = svg.selectall("rect")
  .data(bars)
  .enter()
  .append("rect")
  .attr("width", 45)
  .attr("height", function(d) { return d.value; })
  .attr("y", function(d) { return height-d.value; })
  .attr("x", function(d,i) { return i * 30 + 50; })
  .attr("fill", function(d,i){ return d3.schemecategory10[i]; })
  .attr("stroke","black")
  .attr("stroke-width",1)
  
bars = bars.sort(function(a,b) {
  return a.value - b.value;
}).order();

bars.transition()
  .attr("x", function(d,i) { return i * 30 + 50; })
  .delay(500)
  .duration(2000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>


see also: this question and answer which has a lot of similarities to the example you have: sorting and ordering are used while transitioning both length of bars and bar order.


Related Query

More Query from same tag