Ashitaka Ashitaka - 27 days ago 7
Javascript Question

How can I fix this bar chart sorting?

Here is a JSFiddle of the issue I'm currently facing.

Basically, I have an array of objects that I use to draw some bars. After sorting the array, I try to update the bars'

y
positions accordingly but that does not work.

So, this is the scale I use to draw the bars:

var yScale = d3.scale.ordinal()
.domain(d3.range(0, numberOfBars))
.rangeBands([0, numberOfBars * barHeight]);


So if I have 3 bars and a bar is 40px high, then I'm mapping 0-3 => 0-120px.

Next, I have a function that uses this scale to return the right
y
position:

var y = function(d, i) {
return yScale(i);
};


After drawing the bars using this
y
function, I then sort the data array and try to redraw the bars:

barsContainer.selectAll('.bar')
.data(chartData.users)
.transition()
.duration(750)
.delay(delay)
.attr('y', y); // Not working. I thought this would order the bars.
//.attr('y', 120); // This works though. It moves all the bars to this y.


This is where I'm stumped. Since I reordered the array (chartData.users), and since the bars are "joined" with the data, shouldn't the bars change their
y
according to the data's new position in the array?

Answer

So I figured out what the problem was. Since I was sorting an array of objects, D3.js couldn't figure out by itself which array objects matched which DOM objects. So I had to create a key function to identify the objects:

var key = function(d) { return d.id }

Then, all I had to do was call data() using this key function and then order(), so the DOM order matches the array order:

barsContainer.selectAll('.bar')
  .data(chartData.users, key)
  .order()
  .transition()
    .delay(delay)
    .duration(750)
    .attr('y', y);

Here's the working JSFiddle.