浏览器在地图中支持的SVG元素最大数量是多少?

12

我正在使用leaflet和d3创建地图,并将在地图上绘制许多圆。就浏览器兼容性而言,浏览器可以渲染的svg元素数量存在预期限制。然而就用户体验而言,我希望用户可以尽可能看到地图上的所有元素(否则用户可能需要不断缩放地图并等待ajax返回数据)。我需要考虑一些优化问题(用户等待时间与服务器查询负载与浏览器处理能力之间的平衡)。

如图所示,在目前设定下,服务器仅会返回部分点,因此仅部分地图被填充。

enter image description here

浏览器无法完全处理这样的地图,用户也需要等待太长时间以获取服务器的响应。

我认为我面临的问题需要通过回答以下两个问题来解决:

  • 在地图上使用简单svg形状(圆)的数量方面,平均浏览器可以处理的标准是什么?
  • 最佳技术是什么,以便在地图上尽可能多地显示形状?

我正在考虑以下观点,但不确定它是否有所帮助:

  • 使用正方形代替圆形
  • 使用leaflet API而不是D3
5个回答

6

一般来说,你考虑的两个点都不会有所帮助。在这两种情况下,浏览器要处理的数据量/要显示的信息大致相同。

关于你的第一个问题,据我所知没有这样的数据。特别是如果考虑到移动设备,浏览器和平台之间存在巨大的差异,平均值几乎没有意义。此外,这种情况在不断变化。我发现通常最多可以处理约1000个简单的形状。

为了在地图上显示尽可能多的形状,我建议将它们预先渲染为位图瓦片,然后使用leaflet API或类似d3.geo.tile(例如这里)来将其叠加在实际地图上。这样你就可以轻松地扩展到数百万点。


没有考虑到瓦片,很有趣。您是否知道除了示例之外还有教程吗? - cantdutchthis
很抱歉,无法从D3渲染的SVG生成它们。如果可能的话,采用与Openstreetmap相同的方式可能更容易。 - Lars Kotthoff
我正在自学一些编程知识。OpenStreetMap是如何实现的?你有链接吗? - cantdutchthis
维基上有大量关于此的信息。有许多不同的方法--最适合您特定应用程序的方法取决于您的选择。 - Lars Kotthoff

5

尽管你只能在渲染2-5k个SVG元素之后开始看到明显的减速(取决于大小、使用渐变填充等因素),但你可以在客户端存储和操纵更大的数据集。在SVG中,通常可以高效地处理数万或数十万个数据点:关键是要非常谨慎地选择实际渲染的内容,并使用像防抖技术这样的技术,仅在必要时重新绘制。

(对于非常大的数据集:是的,您需要聚合/子采样点或预先渲染。)

有了这个想法,我特别针对d3地图使用了一种技术,即使用d3.geom.quadtree()动态剔除用户平移/缩放时的点。更具体地说,我避免绘制以下点:

  1. 位于当前地图边界框之外的点(因为这些点根本不可见),或者
  2. 距离其他点太近(因为这些点会增加视觉噪声,也很难进行交互)。

在类似JS的伪代码中,这将大致如下:

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.)
}

4
这是一道地图制作问题,也是技术问题。仅仅因为你可以在地图上标注成千上万个点,并不意味着你应该这样做。你需要问自己,你的用户是否需要一次性看到尽可能多的点,以便更好地理解数据。看到这么多点会让用户感到困惑和不知所措吗?还是会帮助他们完成所需的任务?是否有任何方法可以过滤数据,使得不需要一次性绘制所有点?
解决这个问题最常见的方法是使用聚类,通常使用 Leaflet MarkerCluster 等工具。过去我曾经在使用 D3 和 Leaflet 时通过创建一个任意网格、将每个点分配到一个 bin 中并将颜色渐变应用于网格来创建一种热力图。然而,回到你最初的担忧,这相当耗费计算资源。
根据你想要支持的平台,要注意手机和平板电脑并不总是很好地处理 SVG,特别是在绘制数千个要素时。
另一个潜在的性能提升点是在点几何图形的传输方面。我不确定你目前是如何加载它们的,但是使用空间索引的PostGIS表并通过边界框进行选择通常非常快,但因为你正在绘制点而不是多边形,所以甚至可以通过CSV将它们加载到浏览器中,这比GeoJSON或Topojson要小得多。

1
我希望一次性加载所有数据,但只在视口中绘制足够大的圆。缩放或平移时,删除不应显示的圆并检查之前隐藏的圆是否应添加。

0

您可以使用canvas + three.js或webgl,其中可以加入另一张地图和10k动画创造的3D模型或原生代码svg的一些元素,在一个场景中进行交互式实时动画非常不错。我为了好玩而尝试了这种方法,抱歉我的英语不好。另外还可以考虑使用dlsl着色器、opengl+wasm等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接