D3会在修改数据源时停止绘制点

时间:2016-03-10 11:08:50

标签: javascript d3.js plot

我正在使用D3关闭实时数据流在英国地图上绘制点。当数据点超过10,000时,浏览器变得迟钝,动画不再平滑。所以我修改dataPoints数组只保留最后5000个点。

但是当我第一次使用dataPoints修改splice()时,D3停止渲染任何新点。旧点逐渐消失(由于过渡)但没有新点。我不确定我在这里做错了什么。

我通过加载CSV数据并将其存储在内存中并以每100毫秒1点的速率绘制它来模拟问题。一旦点数超过10,我就会拼接以保留最后5个点。我看到了同样的行为。有人可以查看代码并让我知道我做错了什么吗?

设置和绘图功能:

    var width = 960,
        height = 1160;

    var dataPoints = []

    var svg = d3.select("#map").append("svg")
        .attr("width", width)
        .attr("height", height);

    var projection = d3.geo.albers()
        .center([0, 55.4])
        .rotate([4.4, 0])
        .parallels([40, 70])
        .scale(5000)
        .translate([width / 2, height / 2]);

    function renderPoints() {
        var points = svg.selectAll("circle")
            .data(dataPoints)

        points.enter()
            .append("circle")
            .attr("cx", function (d) { 
                prj = projection([d.longitude, d.latitude]) 
                return prj[0]; 
            })
            .attr("cy", function (d) { 
                prj = projection([d.longitude, d.latitude]) 
                return prj[1]; 
            })
            .attr("r", "4px")
            .attr("fill", "blue")
            .attr("fill-opacity", ".4")
            .transition()
            .delay(5000)
            .attr("r", "0px") 
    }

    /* JavaScript goes here. */
    d3.json("uk.json", function(error, uk) {
        if (error) return console.error(error);
        console.log(uk);

        var subunits = topojson.feature(uk, uk.objects.subunits);
        var path = d3.geo.path()
            .projection(projection);

        svg.selectAll(".subunit")
            .data(subunits.features)
            .enter().append("path")
                .attr("class", function(d) { return "subunit " + d.id })
                .attr("d", path);

        svg.append("path")
            .datum(topojson.mesh(uk, uk.objects.subunits, function(a,b) {return a!== b && a.id !== 'IRL';}))
            .attr("d", path)
            .attr("class", "subunit-boundary")
        svg.append("path")
            .datum(topojson.mesh(uk, uk.objects.subunits, function(a,b) {return a=== b && a.id === 'IRL';}))
            .attr("d", path)
            .attr("class", "subunit-boundary IRL")

        svg.selectAll(".place-label")
            .attr("x", function(d) { return d.geometry.coordinates[0] > -1 ? 6 : -6; })
            .style("text-anchor", function(d) { return d.geometry.coordinates[0] > -1 ? "start": "end"; });

        svg.selectAll(".subunit-label")
            .data(topojson.feature(uk, uk.objects.subunits).features)
            .enter().append("text")
                .attr("class", function(d) { return "subunit-label " + d.id })
                .attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; })
                .attr("dy", ".35em")
                .text(function(d) { return d.properties.name; })

        // function applyProjection(d) {
        //     console.log(d);
        //     prj = projection(d) 
        //     console.log(prj); 
        //     return prj; 
        // }

        lon = -4.6
        lat = 55.45
        dataPoints.push([lon,lat])
        renderPoints() 
    });

清理旧点的功能

    var cleanupDataPoints = function() {
        num_of_elements = dataPoints.length
        console.log("Pre:" + num_of_elements)
        if(num_of_elements > 10) {
            dataPoints = dataPoints.splice(-5, 5)
        }
        console.log("Post:" + dataPoints.length)
    }

从CSV加载数据并以节流率绘制

    var bufferedData = null
    var ptr = 0
    var renderNext = function() {
        d = bufferedData[ptr]
        console.log(d)
        dataPoints.push(d)
        ptr++;
        renderPoints()
        cleanupDataPoints()
        if(ptr < bufferedData.length)
            setTimeout(renderNext, 100)
    }
    d3.csv('test.csv', function (error, data) {
        bufferedData = data
        console.log(data)
        setTimeout(renderNext, 100)
    })

1 个答案:

答案 0 :(得分:2)

在行

points = svg.selectAll("circle")
        .data(dataPoints)

    points.enter() (...)

d3将dataPoints中的每个元素(从0到5000索引)映射到circle元素(最终应该有5000个元素)。所以从它的角度来看,没有enter个数据:有足够的圆圈可以容纳你的所有积分。

要确保在更改其数组中的索引后将相同的数据点映射到同一个html元素,您需要使用附加到每个数据点的某种id字段,并告知d3使用此id将数据映射到元素,而不是它们的索引。

points = svg.selectAll("circle")
        .data(dataPoints, function(d){return d.id})

如果坐标是您的观点的良好标识符,您可以直接使用:

points = svg.selectAll("circle")
        .data(dataPoints, function(d){return d.longitude+" "+d.latitude})

有关详细信息,请参阅https://github.com/mbostock/d3/wiki/Selections#data