在书"数据可视化与D3 Cookbook" (第8章)出现了一个例子,作者绘制了两行。基本上,数据是随机创建的:
var numberOfSeries = 2,
numberOfDataPoint = 11,
data = [];
for (var i = 0; i < numberOfSeries; ++i)
data.push(d3.range(numberOfDataPoint).map(function (i) {
return {x: i, y: randomData()};
}));
然后,作者创建了一个图表实例并定义了尺度&#39;域:
var chart = lineChart()
.x(d3.scale.linear().domain([0, 10]))
.y(d3.scale.linear().domain([0, 10]));
之后,使用addSeries()
方法引入数据:
data.forEach(function (series) {
chart.addSeries(series);
});
最后,渲染图表调用render()
方法:
chart.render();
此外,该图有一个Update
按钮,允许通过调用此函数来更新显示的数据:
function update() {
for (var i = 0; i < data.length; ++i) {
var series = data[i];
series.length = 0;
for (var j = 0; j < numberOfDataPoint; ++j)
series.push({x: j, y: randomData()});
}
chart.render();
}
我的问题是,在按下addSeries()
按钮后,无法再次调用Update
方法,我无法理解数据的更新方式,即,在update()
函数中。内部数据存储在变量_data
中,可以使用方法addSeries()
进行修改。有什么想法吗?
非常感谢!
完整的代码是here,但是我已经复制了最重要的部分:
function lineChart() { // <-1A
var _chart = {};
var _width = 600, _height = 300, // <-1B
_margins = {top: 30, left: 30, right: 30, bottom: 30},
_x, _y,
_data = [],
_colors = d3.scale.category10(),
_svg,
_bodyG,
_line;
_chart.render = function () { // <-2A
if (!_svg) {
_svg = d3.select("body").append("svg") // <-2B
.attr("height", _height)
.attr("width", _width);
renderAxes(_svg);
defineBodyClip(_svg);
}
renderBody(_svg);
};
// Axis rendering functions ...
function renderBody(svg) { // <-2D
if (!_bodyG)
_bodyG = svg.append("g")
.attr("class", "body")
.attr("transform", "translate("
+ xStart() + ","
+ yEnd() + ")") // <-2E
.attr("clip-path", "url(#body-clip)");
renderLines();
}
function renderLines() {
_line = d3.svg.line() //<-4A
.x(function (d) { return _x(d.x); })
.y(function (d) { return _y(d.y); });
_bodyG.selectAll("path.line")
.data(_data)
.enter() //<-4B
.append("path")
.style("stroke", function (d, i) {
return _colors(i); //<-4C
})
.attr("class", "line");
_bodyG.selectAll("path.line")
.data(_data)
.transition() //<-4D
.attr("d", function (d) { return _line(d); });
}
//Some getter/setters functions and other stuff
_chart.addSeries = function (series) { // <-1D
_data.push(series);
return _chart;
};
return _chart; // <-1E
}
function randomData() {
return Math.random() * 9;
}
function update() {
for (var i = 0; i < data.length; ++i) {
var series = data[i];
series.length = 0;
for (var j = 0; j < numberOfDataPoint; ++j)
series.push({x: j, y: randomData()});
}
chart.render();
}
var numberOfSeries = 2,
numberOfDataPoint = 11,
data = [];
for (var i = 0; i < numberOfSeries; ++i)
data.push(d3.range(numberOfDataPoint).map(function (i) {
return {x: i, y: randomData()};
}));
var chart = lineChart()
.x(d3.scale.linear().domain([0, 10]))
.y(d3.scale.linear().domain([0, 10]));
data.forEach(function (series) {
chart.addSeries(series);
});
chart.render();
答案 0 :(得分:1)
update()
函数正在修改每个系列,由render()
函数自动拾取。这是有效的,因为闭包存储引用到系列(被修改)而不是实际值。
发生的情况与修改全局变量的情况相同。 addSeries()
函数添加了一个新系列,但在这种特殊情况下,您不会添加任何新系列,而是修改现有系列。
那就是说,我不会认为代码设计得特别好。