在 openlayers 3 上,如何在更新功能时暂停更改事件?

On openlayers 3, how do you pause a change event when updating features?

基本上,我必须更新多个功能,特别是 setGeometry,但每次对单个功能应用更新时,都会触发更改事件,导致图层重绘。所以,如果更新了 500 个要素,图层将重绘 500 次。 我想支付重绘事件,直到所有功能都更新。

更新: 我能想到的解决方法之一是:

  1. getFeatures()
  2. 清晰(真)
  3. (更新功能)
  4. addFeatures(特征)

但我不确定是否有比这更干净的方法

简答:

var feature = layer.getFeatureById("myId");
var geometry = new ol.geom.Point(ol.proj.fromLonLat([lon, lat]));
feature.set(feature.getGeometryName(), geometry, true);
........
source.changed()

长答案:

查看 setGeometry 源代码后 (feature.js), basically it will use the set method on geometryName_. So by explicitly setting the same property and set opt_silent to true, it will not fire the change event (object.js)。

完成更改后,只需在图层上触发更改事件即可。

不要跳过更改事件

问题的基本前提 - 每个特征变化都会导致图层重绘 - 是不正确的。

当要素发生变化时,地图将请求在下一个动画帧上重绘。但是,如果在同一个执行线程中更改了多个功能,则在脚本完成之前,浏览器不会重绘任何内容。只需一次重绘,您就可以遍历并更改数百万个要素。

您可以通过侦听 postrender 事件来验证渲染何时完成:

map.on('postrender', function(event){
  console.log('did render', new Date())
})

您可以在不触发任何事件的情况下设置几何体,如 中所建议的那样。但这样做可能会导致源中的空间索引损坏等问题。仅当您确定没有人对该更改感兴趣时,才应省略更改事件。

那有什么延迟?

尽管如此,更新许多功能仍然会影响性能。我写了 this demo,它会在每次点击地图时替换所有要素的几何形状。在我的笔记本电脑上,替换所有 10000 个几何图形大约需要 600 毫秒。在此期间,地图和浏览器没有响应,并且在下一次重绘之前不会显示任何更新。重绘的持续时间取决于缩放级别。

在要素上设置几何时,它将:

  • 将几何体添加到它的属性中
  • 删除对先前几何图形的所有侦听器。
  • 为新几何体添加变化监听器。
  • 触发更改事件以通知侦听器它已更改。

该功能的一个听众将成为来源,这将:

  • 更新空间索引(如果使用)。
  • 触发更改事件以通知侦听器它已更改。

图层和最终地图将通知我们这些更改,并排队重绘。

可能的优化

如果您希望能够以更高效的方式更改许多功能,我建议您考虑:

禁用空间索引

docs 中所述,将 useSpatialIndex 设置为 false 可能会在某些情况下提高性能。如果没有空间索引,源对每个要素更改的计算量就会减少。但是,如果没有索引,源的其他用途可能会变得性能较低。

修改几何而不是替换它

在几何体上使用 setCoordinates 比在要素上使用 setGeometry 更快。可以跳过整个 Geometry 实例的创建,并且不必修改任何侦听器。这假设您可以修改几何体,例如如果该特征是几何体的唯一 'owner'。

尝试将特征修改拆分成更小的块

这与提问的意图相悖。如果修改功能需要花费大量时间,您可能希望更频繁地触发渲染。这将使地图看起来更具响应性,并允许浏览器赶上处理事件和其他未决任务。