问题
I have a nvd3 multibar chart (but the same problem occurs with a pie chart).
I want to save the status of the legend when the user enables or disables a series, by clicking on it in the legend. So I'm listening to stateChange events.
In the following example code there are two series. When the user clicks, say, on series1 to disable it, the console should log:
New State: {"disabled":[true,false]}
The problem starts occurring after refreshing the chart with new data from the server (simulated by setInterval in the code below). After the first refresh I always get a wrong event, i.e., values of the disabled attribute are messed up.
Maybe the way I refresh the graph is wrong?
Here the sample code:
var initialData = [
{ key: 'series1', values: [
{ x: 0, y: 10},
{ x: 1, y: 44}
]},
{ key: 'series2', values: [
{ x: 0, y: 25},
{ x: 1, y: 11}
]}
];
var chart;
nv.addGraph(function() {
chart = nv.models.multiBarChart()
.delay(0);
d3.select('#chart1 svg')
.datum(initialData)
.call(chart);
nv.utils.windowResize(chart.update);
chart.dispatch.on('stateChange', function(e) {
nv.log('New State:', JSON.stringify(e));
});
setInterval(function ()
{
var newDataFromServer = [
{ key: 'series1', values: [
{ x: 0, y: Math.floor((Math.random()*100)+1)},
{ x: 1, y: Math.floor((Math.random()*100)+1)}
]},
{ key: 'series2', values: [
{ x: 0, y: Math.floor((Math.random()*100)+1)},
{ x: 1, y: Math.floor((Math.random()*100)+1)}
]}
];
d3.select('#chart1 svg')
.datum(newDataFromServer)
.call(chart);
nv.utils.windowResize(chart.update);
}, 5000);
return chart;
});
回答1:
I have found a working solution. I don't have time to investigate further, but in the following code (nvd3/legend.js):
.on('click', function(d,i) {
dispatch.legendClick(d,i);
if (updateState) {
if (radioButtonMode) {
// etc ...
}
else {
// Note: this 'd' doesn't belong to the 'data' array in the current scope
d.disabled = !d.disabled;
// etc ...
}
dispatch.stateChange({
// The old data is notified as event
disabled: data.map(function(d) { return !!d.disabled })
});
}
})
when it is misbehaving (i.e., after the first update), the d object doesn't belong to the data array in this scope (it is supposed to do). I guess this data always points to the initial data array.
As a workaround to update the chart, I get the initial array and update it in-place:
// Get reference to data array object
var chartDatum = d3.select('#chart1 svg')
.datum();
// Clear array and copy new data into it
chartDatum.length = 0;
angular.extend(chartDatum, newDataFromServer); // Or jQuery extend, or equivalent
chart.update();
来源:https://stackoverflow.com/questions/23015095/nvd3-passing-wrong-event-on-statechange-when-clicking-legend-after-chart-is-re