Reputation: 3325
I'm trying to generate multiple charts using nvd3 and d3. I have the right amount of divs.
If I remove the forloop, then I get a chart in #chart1
. If I put the for loop then I get a chart ONLY in #chart2
.
Can anyone see why?
for (var j = 1; j <= 2; j += 1) {
var s = '#chart' + j.toString() + ' svg';
console.log(s);
nv.addGraph(function() {
var chart = nv.models.lineChart();
chart.xAxis.axisLabel('Time step').tickFormat(d3.format(',r'));
chart.yAxis.axisLabel('eig(' + j.toString() + ')').tickFormat(d3.format('.02f'));
d3.select(s).datum(function() {
var sin = [], cos = [];
for (var i = 0; i < 100; i++) {
sin.push({
x : i,
y : Math.sin(i / 10)
});
cos.push({
x : i,
y : .5 * Math.cos(i / 10)
});
}
result = [];
result.push({
values : sin,
key : 'sin',
});
return result;
}).transition().duration(500).call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
}
Upvotes: 0
Views: 2832
Reputation: 61
Stumbled upon this when I was facing the same issue. Hope this helps another beginner like myself.
nv.addGraph()
takes a function as callback. This function you passed is not executed immediately but is instead pushed onto the event loop and executed some time later. Internally nv.addGraph
is actually quite simple and it makes use of setTimeout
.
The reason why for-loop didn't work is because of Javascript scoping. It's the same reason why this code prints 5
5 times instead of 0,1,2,3,4
.
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i)
}, 0)
}
In JS, the var
keyword declares a variable to the enclosing function scope (it ignores block scope - for
or if
curly braces). If you put all the above code in $()
then the i
variable would be available everywhere inside the $()
.
When the callback function is executed, it has access to the parent environment where it was first declared.
Inside the callback function, it encounters i
. Since i
is not declared inside the callback function, it goes one level up to look for i
. It finds i
in the enclosing function scope but i
variable has already been updated to 5
before the callback function was even run.
Upvotes: 2
Reputation: 6192
Firstly it's not common to use a for loop like you have (Data Driven Documents). In d3 it is preferred to select all the elements you want and use .each()
like so
d3.selectAll('.chart svg')
.each(function(data){
// Do what you would have done in the loop here
})
Secondly it looks like there is an issue with using an anonymous function the way you have (not sure why and not spent too much time looking). By calling it as an actual function it works.
nv.addGraph(addMyChart(this))
See this JSFiddle http://jsfiddle.net/a5BYP/
Upvotes: 2