我正在创建一个带有传单和d3的地图。很多圆圈都会在地图上绘制出来。在浏览器兼容性方面,预计会限制浏览器可以呈现多少svg元素。然而,就用户体验而言,我希望用户可以在地图上看到尽可能多的元素(否则用户可能需要不断地放大和缩小,并且需要等待ajax返回数据)。我需要考虑一些优化(用户等待时间用户与服务器查询负载与浏览器可以处理的内容相比)。
参见情节,现在对服务器返回的点数有一个限制,因此只填充了一部分地图。
浏览器无法在此处理完全填充的地图,用户也需要等待太长时间才能获得服务器响应。
我认为我面临的问题需要通过回答两个问题来解决:
我正在考虑以下几点,但我不确定它是否会有所帮助;
答案 0 :(得分:5)
一般而言,您正在考虑的两点都没有帮助。在这两种情况下,浏览器要显示的处理量/信息将大致相同。
关于你的第一个问题,不是我所知道的。浏览器和平台之间存在巨大差异(特别是如果您考虑移动设备),平均值几乎毫无意义。此外,这种情况在不断变化。我发现多达1000个简单的形状通常不是问题。
要在地图上显示尽可能多的形状,我会将它们预先渲染为位图图块,然后使用传单API或类似d3.geo.tile(示例here)覆盖它实际的地图。通过这种方式,您可以轻松扩展到数百万个点。
答案 1 :(得分:5)
Although you can only render ~2-5k SVG elements before you start to see noticeable slowdown (depending on size, use of gradient fills, etc.), you can store and manipulate much larger datasets client-side. You can often handle tens or hundreds of thousands of data points efficiently in SVG: the trick is to be very selective about what you actually render, and to use techniques like debouncing to redraw only when necessary.
(For very large datasets: yes, you'll need to either aggregate/subsample points or pre-render.)
With this in mind, one technique I've used for d3 maps in particular is to use d3.geom.quadtree()
to dynamically cull points as the user pans/zooms. More specifically, I avoid drawing points that are either
In JS-ish pseudocode, this would look roughly like:
function getIndicesToDraw(data, r, bbox) {
var indicesToDraw = [];
var Q = d3.geom.quadtree();
// set bounds in pixel space
for (var i = 0; i < data.length; i++) {
var d = data[i];
var p = getPointForDatum(d);
if (isInsideBoundingBox(bbox, p) && !hasPointWithinRadius(Q, r, p)) {
Q.add(p);
indicesToDraw.push(i);
}
}
return indicesToDraw;
}
function redraw(svg, data, r, bbox) {
var indicesToDraw = getIndicesToDraw(data, r, bbox);
var points = svg.selectAll('.data-point')
.data(indicesToDraw, function(i) { return i; });
// draw new points for points.enter()
points.exit().remove();
// update positions of points (or SVG transforms, etc.)
}
答案 2 :(得分:2)
这是一个制图问题,就像技术一样。仅仅因为你可以在地图上放置数千个点并不意味着你应该。您应该问自己,您的用户是否需要同时查看尽可能多的点,并且会更好地理解数据。看到这么多点会让用户感到困惑和压力,还是会帮助他们完成他们想要的任务?有什么方法可以过滤数据,以便不需要立即绘制所有点吗?
此问题最常见的解决方案是使用群集,通常使用类似Leaflet MarkerCluster的内容。在过去使用D3和Leaflet的过程中,我创建了一种热图,通过创建任意网格,将每个点分配到一个bin,并将颜色渐变应用于网格。然而,回到原来的问题,它是计算密集型的。
根据您要支持的平台,请注意手机和平板电脑并不总能很好地处理SVG,尤其是在绘制数千个功能时。
潜在性能提升的另一个地方是点几何的交付。我不确定你当前是如何加载它们的,但使用空间索引的PostGIS表并通过边界框选择通常很快,但因为你是绘制点而不是多边形,你甚至可以将它们加载到浏览器中通过CSV,它比GeoJSON或Topojson小得多。
答案 3 :(得分:1)
我会一次加载所有数据,但只在视口中绘制足够大的圆圈。在缩放或平移时,删除不应显示的圆圈,并检查是否应添加以前隐藏的圆圈。