问题
I'm not sure if this is a d3 bug or if I'm doing something wrong. Take a look at the following:
http://jsfiddle.net/Jakobud/SfWjB/6/
var data = [
{ value: 20, color: 'red' },
{ value: 30, color: 'blue' },
{ value: 30, color: 'purple' } // Same value as 2nd object
];
var w = 140,
h = d3.max(data, function(d){ return d.value; }) + 30,
barPadding = 4,
topPadding = 1,
bottomPadding = 20;
var svg = d3.select('#chart')
.append('svg:svg')
.attr('width', w)
.attr('height', h);
var rects = svg.selectAll('rect')
.data(data, function(d){ console.log(d); return d.value; }) // All 3 objects found here
.enter()
.append('rect')
.attr('x', function(d,i){ console.log(i); return i * w / data.length + 1; }) // Last data object ignored, not placed at all
.attr('y', function(d){ return h - d.value - topPadding - bottomPadding })
.attr('width', w / data.length - barPadding - 3 )
.attr('height', function(d) { return d.value })
.attr('fill', function(d) { return d.color })
.attr('stroke', '#333')
.attr('stroke-width', 2);
text = svg.selectAll('text')
.data(data, function(d){ return d.value; })
.enter()
.append('text')
.text(function(d){ return d.value; })
.attr('x', function(d,i){ return i * w / data.length + 20; })
.attr('y', function(d,i){ return h - 0; })
.attr("text-anchor", "middle")
.attr("font-size", "20px")
.attr("fill", "#333");
You can see in my data objects, the 2nd and 3rd objects have the same "value".
When the svg rects are being created, the 3rd data object is ignored and as a result, not placed in the chart. If you change the value of the 3rd object from 30 to 31 or something else, you can see the bar does show up then. But since it's the same as the 2nd object's value, it doesn't show up.
Why is this? How do you prevent this? What is it in the code here that would cause this? the rects.data() function see's all three objects, as you can see with the console.log() I added into the function.
回答1:
The way in which you are matching the data to existing data is causing the problem, in particular the line
.data(data, function(d){ return d.value; })
This tells d3 that you consider two data objects the same if their value attribute is the same. And this is the case for your second and third objects, hence only the first is added. If you want both, you can either omit the function that tells d3 how to compare data objects (and thus rely on the default behaviour of matching by array index), or change that function to take e.g. color into account as well.
Just to summarise, what you are seeing is not a bug, but a feature :) This behaviour is entirely expected and wanted.
来源:https://stackoverflow.com/questions/16112939/complex-data-object-with-duplicate-values-missing-chart-bars