[英]Updating data in a simple reusable D3 chart
在《用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()};
}));
然后,作者创建图表的实例并定义比例尺的域:
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()
方法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();
}
我的问题是 ,在按下Update
按钮(即在update()
函数中update()
之后, 如果不再次调用addSeries()
方法 , 就无法理解图中数据的更新方式 。 数据在内部被存储在变量_data
,其可与该方法被修改addSeries()
有任何想法吗?
非常感谢!
完整的代码在这里 ,但是下面我复制了最重要的部分:
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();
update()
函数会修改每个序列,这些序列会由render()
函数自动获取。 之所以可行,是因为闭包存储对系列的引用 (已修改),而不是实际值。
发生的情况与修改全局变量的情况相同。 addSeries()
函数添加了一个新系列,但是在这种特殊情况下,您没有添加任何新系列,而是修改了现有系列。
就是说,我不会认为代码设计得特别好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.