在OpenLayers 3中与除Chrome以外的任何浏览器的悬停交互非常缓慢



我有两种交互样式,一种突出显示功能,另一种放置带有功能名称的工具顶。注释掉这两个,它们都非常快,留下任何一个,地图应用程序在IE和Firefox中会变慢(但不是Chrome)。

map.addInteraction(new ol.interaction.Select({
    condition: ol.events.condition.pointerMove,
    layers: [stationLayer],
    style: null // this is actually a style function but even as null it slows
}));
$(map.getViewport()).on('mousemove', function(evt) {
    if(!dragging) {
        var pixel = map.getEventPixel(evt.originalEvent);
        var feature = null;
        // this block directly below is the offending function, comment it out and it works fine
        map.forEachFeatureAtPixel(pixel, function(f, l) {
            if(f.get("type") === "station") {
                feature = f;
            }
        });
        // commenting out just below (getting the feature but doing nothing with it, still slow
        if(feature) {
            target.css("cursor", "pointer");
            $("#FeatureTooltip").html(feature.get("name"))
              .css({
                top: pixel[1]-10,
                left: pixel[0]+15
              }).show();
        } else {
            target.css("cursor", "");
            $("#FeatureTooltip").hide();
        }
    }
});

我的意思是这似乎是OpenLayers-3的一个问题,但我只是想确保我没有在这里忽略其他东西。

哦,是的,大约有600多个点。这是很多,但我认为不是不合理的。放大以限制所看到的功能无疑是有帮助的。所以我想这是一个#功能问题

这是一个已知的错误,需要更多的调查。你可以在这里跟踪进度:https://github.com/openlayers/ol3/issues/4232.

然而,有一件事你可以做,使事情更快:从map.forEachFeatureAtPixel返回一个真值,停止检查功能一旦找到:

var feature = map.forEachFeatureAtPixel(pixel, function(f) {
  if (f.get('type') == 'station') {
    return feature;
  }
});

我有同样的问题,通过setInterval解决了一个问题,关于这个稍后1)每次鼠标移动到1个像素触发事件,你将有一个事件队列,直到你停止移动,队列将在回调函数中运行,并冻结2)如果你有一个具有困难样式的对象,那么画布上显示的所有元素都需要花费时间来计算它们是否击中了光标

解决:1. 使用setInterval2. 检查从预览中移动的像素大小,如果小于N,返回3.对于有多个样式的图层,尝试通过划分多个样式来简化它们,并且只让一个图层对光标移动进行交互

function mouseMove(evt) {
  clearTimeout(mm.sheduled);
  function squareDist(coord1, coord2) {
    var dx = coord1[0] - coord2[0];
    var dy = coord1[1] - coord2[1];
    return dx * dx + dy * dy;
  }
  if (mm.isActive === false) {
    map.unByKey(mm.listener);
    return;
  }
  //shedules FIFO, last pixel processed after 200msec last process
  const elapsed = (performance.now() - mm.finishTime);
  const pixel = evt.pixel;
  const distance = squareDist(mm.lastP, pixel);
  if (distance > 0) {
    mm.lastP = pixel;
    mm.finishTime = performance.now();
    mm.sheduled = setTimeout(function () {
      mouseMove(evt);
    }, MIN_ELAPSE_MSEC);
    return;
  } else if (elapsed < MIN_ELAPSE_MSEC || mm.working === true) {
    // console.log(`distance = ${distance} and elapsed = ${elapsed} mesc , it never should happen`);
    mm.sheduled = setTimeout(function () {
      mouseMove(evt);
    }, MIN_ELAPSE_MSEC);
    return;
  }
  //while multithreading is not working on browsers, this flag is unusable
  mm.working = true;
  let t = performance.now();
  //region drag map
  const vStyle = map.getViewport().style;
  vStyle.cursor = 'default';
  if (evt.dragging) {
    vStyle.cursor = 'grabbing';
  }//endregion
  else {
    //todo replace calback with cursor=wait,cursor=busy
    UtGeo.doInCallback(function () {
      checkPixel(pixel);
    });
  }
  mm.finishTime = performance.now();
  mm.working = false;
  console.log('mm finished', performance.now() - t);
}

除了@ahocevar的答案之外,您还可以利用select交互的select事件进行优化。

似乎选择交互和你的mousemove监听器都在检查同一层上的命中,做双重工作。每当选择的特性集发生变化时,选择交互将触发select事件。你可以听它,当某些功能被选中时显示弹出窗口,当没有选中时隐藏它。

假设占用系统的是forEachFeatureAtPixel,这应该可以减少一半的工作量。

相关内容

最新更新