我正在进行一个D3项目,该项目涉及一个大型可缩放地图。一切看起来都很好,工作也很好,只是当我缩放和平移时,视图可能会变得有点滞后。
我想知道D3是否有办法避免投影超出帧的地图数据。如果可能的话,我希望在不牺牲细节的情况下提高性能。任何提示或提示都将不胜感激!
这里有几个选项。我将把这个问题概括为使用d3优化显示大量地理数据的方法。
投影.clipExtent(范围)
该方法采用一个数组,标记绘制的特征范围的左上角和右下角(在投影/像素坐标空间中)。特征将剪裁到指定的范围。每个点仍然贯穿投影,但您不必绘制它们或沿着边进行大圆采样。严格地说,这接近于这个问题所要求的。
投影.clipAngle(角度)
上述方法适用于投影空间,而此方法适用于未投影空间。此方法采用一个表示角度(以度为单位)的值,并根据该角度和投影的旋转中心剪裁特征。根据您的投影,旋转可能是平移和居中地图的合适方法。您必须计算给定缩放级别和居中的最大剪裁角度,然后在投影到由剪裁角度指定的小圆之前剪裁贴图。这在上面的基础上进行了改进,避免了在剪裁之前投影点的需要,但由于小圆圈很少符合视口,因此会绘制一些超出所需范围的特征(尽管要少得多)。以上内容可以与此方法相结合。
为了获得更好的结果,可以使用自定义的预切功能。对于圆柱形投影来说,这将比其他投影更容易,以便在投影之前将特征剪裁到指定的框,这将提高效率。
其他选项
- 矢量瓦片
Vector tile有很多来源,尽管我并不特别喜欢d3 tile(我一直在研究替代方案,但太忙了,没有真正关注它)。您仍然需要在每次缩放时加载平铺,在每次平移时加载一些平铺,但此选项可以为您提供最大范围的细节和适当的数据分辨率。
- 边界框
上面的一个替代方案是在每个多边形上存储边界框信息(不要在运行中执行)。绘制地图时,对与视口有任何重叠的多边形进行过滤,可以只选择性地渲染相关特征。根据投影和缩放机制,这可以在投影或未投影的坐标空间中完成。
这可以通过以两个或多个比例加载特征来补充:缩小后,无论可见性如何,都会绘制所有特征,但缩小后的分辨率适当。当放大超过一定深度时,请使用更详细的特征,但要根据边界框进行过滤。
- 画布
我在这里包含这一点只是因为SVG有时会成为夹点,这取决于绘制的特征的数量和类型。切换到Canvas可能是一个改进。
- 投影类型
投影类型确实会影响速度,矩形很快,一些方位角投影很慢。虽然我只测试了projection.invert()
的任何细节,但投影类型是一个因素。
预投影几何图形是最快的,它完全绕过了投影:特征坐标空间以像素为单位。有关该主题的更多信息,请参阅此处。
结合边界框方法和/或基于当前范围进行剪裁的函数,这可能是一种非常快速的方法。
- 缩放事件
我根据你的问题文本添加了这一点:投影功能应该花费与放大或不放大相同的时间。绘图可能是可变的,但投影的运行方式是相同的。这表明您可能正在使用.on("zoom"
事件。这不是很有效:平移事件的每一次勾选都需要重新绘制,换句话说,一次平移可能会触发许多缩放事件。这意味着您需要在平移过程中几乎不断地投影特征。
对此,一个简单的解决方案是使用.on("end"
事件作为重绘映射的事件。这样,我们每次缩放只重绘一次地图。
然而,你可能会变得更加复杂。如果希望贴图在整个平移事件中跟随鼠标,可以使用变换来平移贴图,避免投影任何内容,然后在缩放结束时,重新投影贴图并移除变换。这几乎肯定需要重新思考缩放功能。我以前也采取过类似的方法来确定是否发生了平移,以避免在缩放比例不变的情况下重新绘制簇(例如)。