平移 500 个特征时 OpenLayers 3 性能低下

Slow performance in OpenLayers 3 when panning with 500 features

我正在构建一个应用程序,用于将特征映射到描绘平面图的图像层(使用 OL 的 ImageStatic 层)。每个功能都有一个 svg 图标作为样式,并且可能在边缘周围有其他 svg 图标作为 "badges"。

我在this jsfiddle中设置了代码相关部分的简化版本。

var map = new ol.Map({
  layers: [],
  interactions: ol.interaction.defaults({}),
  target: "map"
});

var pixelProjection = new ol.proj.Projection({
    code: 'pixel',
    units: 'pixels',
    extent: [0, 0, 4097, 1596]
  }),
  // create layer
  floorMapLayer = new ol.layer.Image({
    source: new ol.source.ImageStatic({
      url: "https://sunriverassistedliving.com/wp-content/uploads/Main-Floor-Plan.jpg",
      imageSize: [4097, 1596],
      projection: pixelProjection,
      imageExtent: pixelProjection.getExtent()
    })
  }),
  // create view
  floorMapView = new ol.View({
    projection: pixelProjection,
    center: [2000, 750] || ol.extent.getCenter(pixelProjection.getExtent()),
    zoom: 1
  }),
  poiSource = new ol.source.Vector({
    features: []
  }),
  vectorLayer = new ol.layer.Vector({
    source: poiSource
  }),
  layerGroup = new ol.layer.Group({
    layers: [floorMapLayer, vectorLayer]
  });

map.setView(floorMapView);
map.setLayerGroup(layerGroup);

var iconStyle = new ol.style.Icon( /** @type {olx.style.IconOptions} */ ({
  anchor: [0.5, 1],
  anchorXUnits: 'fraction',
  anchorYUnits: 'fraction',
  size: [25, 25],
  imageSize: [25, 25],
  src: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgo8c3ZnIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4wIiB3aWR0aD0iMjUiIGhlaWdodD0iMjUiIGlkPSJzdmczNjQ4Ij4KICA8ZGVmcyBpZD0iZGVmczM2NTAiLz4KICA8cGF0aCBkPSJNIDEyLjUxNDksNC45NmUtMDA3IEMgNS42MTE3NCw0Ljk2ZS0wMDcgMCw1LjU4MTk0MDUgMCwxMi40ODUxIEMgMCwxOS4zODgyNiA1LjYxMTc0LDI1IDEyLjUxNDksMjUgQyAxNS4yNzY5NCwyNSAxNy44MDQ4LDI0LjA3NDg5IDE5Ljg3NDg1LDIyLjU1NjYyIEwgMTIuNTQ0NywxNy4xOTMwOSBMIDUuMjE0NTQsMjIuNTg2NDEgTCA4LjA0NTI5LDEzLjk0NTE3IEwgMC42NTU1NCw4LjY3MTA0MDUgTCA5Ljc0MzczOTUsOC42NzEwNDA1IEwgMTIuNDg1MSwwLjAyOTgwMDUgTCAxNS4yODYwNSw4LjY3MTA0MDUgTCAyNC4zNDQ0NTksOC42MTE0NDA1IEwgMTcuMDE0MywxMy45MTUzOCBMIDE5Ljg3NDg1LDIyLjU1NjYyIEMgMjIuOTc4NDc5LDIwLjI4MDI4IDI1LDE2LjYyNjIyIDI1LDEyLjQ4NTEgQyAyNSw1LjU4MTk0MDUgMTkuNDE4MDYsNC45NmUtMDA3IDEyLjUxNDksNC45NmUtMDA3IHogIi8+Cjwvc3ZnPg=="
}));

var styleCache = {};

var customStyleFunctions = [
  function(resolution) {
    var style = new ol.style.Style({
      image: new ol.style.Icon(({
        anchor: [1, 2],
        anchorXUnits: 'fraction',
        anchorYUnits: 'fraction',
        size: [15, 15],
        imageSize: [15, 15],
        src: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgo8c3ZnIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4wIiB3aWR0aD0iMjUiIGhlaWdodD0iMjUiIGlkPSJzdmczNjQ4Ij4KICA8ZGVmcyBpZD0iZGVmczM2NTAiLz4KICA8cGF0aCBkPSJNIDEyLjUxNDksNC45NmUtMDA3IEMgNS42MTE3NCw0Ljk2ZS0wMDcgMCw1LjU4MTk0MDUgMCwxMi40ODUxIEMgMCwxOS4zODgyNiA1LjYxMTc0LDI1IDEyLjUxNDksMjUgQyAxNS4yNzY5NCwyNSAxNy44MDQ4LDI0LjA3NDg5IDE5Ljg3NDg1LDIyLjU1NjYyIEwgMTIuNTQ0NywxNy4xOTMwOSBMIDUuMjE0NTQsMjIuNTg2NDEgTCA4LjA0NTI5LDEzLjk0NTE3IEwgMC42NTU1NCw4LjY3MTA0MDUgTCA5Ljc0MzczOTUsOC42NzEwNDA1IEwgMTIuNDg1MSwwLjAyOTgwMDUgTCAxNS4yODYwNSw4LjY3MTA0MDUgTCAyNC4zNDQ0NTksOC42MTE0NDA1IEwgMTcuMDE0MywxMy45MTUzOCBMIDE5Ljg3NDg1LDIyLjU1NjYyIEMgMjIuOTc4NDc5LDIwLjI4MDI4IDI1LDE2LjYyNjIyIDI1LDEyLjQ4NTEgQyAyNSw1LjU4MTk0MDUgMTkuNDE4MDYsNC45NmUtMDA3IDEyLjUxNDksNC45NmUtMDA3IHogIi8+Cjwvc3ZnPg=="
      }))
    });
    return [style];
  }
];

var defaultStyleFunction = function(resolution) {
  var feature = this;
  this.set('manuallyHidden', false);

  if (!feature.get('selected') && (feature.get('hidden') || feature.get('manuallyHidden'))) {

    // use hidden marker style
    if (!styleCache.hidden) {
      styleCache.hidden = new ol.style.Style({});
    }
    return [styleCache.hidden];
  }

  // draw marker normally
  var iconSrc = iconStyle.getSrc();
  if (!styleCache[iconSrc]) {
    styleCache[iconSrc] = new ol.style.Style({
      image: iconStyle,
    });
  }

  var styles = [styleCache[iconSrc]];

  // add styles from registered overlay style functions
  for (var i = 0; i < customStyleFunctions.length; i++) {
    //console.log(customStyleFunctions[i]);
    styles = styles.concat(customStyleFunctions[i](resolution));
  }

  return styles;
};

for (var i = 0; i < 500; i++) {
  var posX = Math.random() * 4097;
  var posY = Math.random() * 1596;
  var feature = new ol.Feature({
    geometry: new ol.geom.Point([posX, posY]),
  });
  feature.setStyle(defaultStyleFunction);

  poiSource.addFeature(feature);
}

有 500 个特征,每个特征都有一个徽章。平移地图感觉不稳定,Chrome 中的时间轴注意到帧速率下降到 5 fps 左右。

这仍然有点可用,但在我的实际应用中,情况要糟糕得多,即使只使用大约 100 个特征,每个特征有 1-2 个徽章,也会完全冻结。我无法缩小我的实际应用程序响应不如此演示的原因,但探查器没有注意到任何其他代码 运行 而不是 OpenLayers 中的渲染和 GPU 忙碌气喘吁吁。不过,我实际应用测试中的底层图像要大得多。大约 10000x7000px(jsfiddle 大约 4000x1600px)。这当然会渲染一个巨大的 canvas ,这将需要重新绘制资源。

我想知道 OpenLayers 中是否有任何其他性能提升可以用来提高地图平移的响应速度?我在装有最新 Google Chrome / Firefox 的 2011 年末 13 英寸 MacBook Pro 上使用 3.15.1 版。

您可以使用 webgl 作为您的渲染选项,只需将 renderer: 'webgl' 添加到您的地图构造函数。 我已经在此处修改了您的示例,甚至使用了 10,000 点:https://jsfiddle.net/qmpd04y5/ 不幸的是,由于跨源请求失败,我不得不删除背景地板图层,当 Web 应用程序在背景图像具有相同来源的服务器上运行时,这当然可以重新添加。

如果 webgl 不是一个选项,您还可以设置一个 WMS 系统以将您的功能预呈现为平铺图像,这可以大大提高性能,具体取决于您的服务器。使用 WMS 的优势在于,您永远不会遇到取决于客户端的可扩展性问题,因为客户端只会加载图像块。

静态图像层应该没有问题。但是您正在以非常低效的方式为矢量图层使用样式函数。不要在每次调用样式函数时都创建一个新的样式实例。相反,在外部创建样式并且只让您的样式函数 return 它。另外,最好在图层上设置一个单一的样式函数,而不是在每个特征上设置一个。