在简单的可重复使用的D3图表中更新数据

时间:2015-03-11 18:46:53

标签: javascript d3.js

在书"数据可视化与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();

1 个答案:

答案 0 :(得分:1)

update()函数正在修改每个系列,由render()函数自动拾取。这是有效的,因为闭包存储引用到系列(被修改)而不是实际值。

发生的情况与修改全局变量的情况相同。 addSeries()函数添加了一个新系列,但在这种特殊情况下,您不会添加任何新系列,而是修改现有系列。

那就是说,我不会认为代码设计得特别好。