我正在使用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)
})
答案 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。