【问题标题】:Very slow hover interactions in OpenLayers 3 with any browser except ChromeOpenLayers 3 中的悬停交互非常慢,除了 Chrome 之外的任何浏览器
【发布时间】:2015-10-20 20:19:18
【问题描述】:

我有两种交互方式,一种是突出显示功能,第二种是放置一个带有功能名称的工具栏。将两者都注释掉,它们都非常快,留下任何一个,地图应用程序在 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 多分。这是很多,但并非不合理,所以我认为。放大以限制视图中的功能肯定会有所帮助。所以我猜这是一个功能问题。

【问题讨论】:

  • 除了具有约 600 个点的图层之外,您在地图上还有其他矢量图层吗?
  • 您在哪些版本的浏览器上遇到此问题?还有操作系统?
  • 我有一个 CA 县图层(来自 kml),我不想与之交互(因此检查 forEachFeatureAtPixel 以确保它是一个车站功能)。现在就是这样。 Chrome 46.0.2490.71 m,IE 11.0.9600.18059,FF 38.01(刚刚更新到 41.02,同样的问题)。赢 7 专业版。
  • 你选择一个正确的答案并完成这个帖子怎么样?
  • 感谢您的帮助,但技术上没有解决方案,是吗?如果可以的话,我会赞成有用的建议,但我没有足够的声誉。现在,如果常见的礼仪是标记一个解决方案,即使它不是真的(因为这更像是一个我无法控制的错误),我肯定会这样做,但是,天哪,我显然是一个新帐户,没必要对此一味消极攻击。

标签: openlayers-3


【解决方案1】:

这是一个已知错误,需要进一步调查。您可以在此处跟踪进度:https://github.com/openlayers/ol3/issues/4232

但是,您可以做一件事来加快速度:从 map.forEachFeatureAtPixel 返回一个真实值,以便在找到特征后停止检查:

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

【讨论】:

  • 有道理。我一定会密切关注错误跟踪,知道这不仅仅是我的问题。
  • 对我来说,这只发生在加载一些较大的多边形或线时(Firefox Linux)。根据分析,它是命中检测,它可能与线条/多边形斗争。解决方案是在这种情况下禁用鼠标悬停或使用单击而不是鼠标悬停。
【解决方案2】:

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

解决: 1.使用setInterval 2.从预览中检查像素移动大小,如果小于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);
}

【讨论】:

    【解决方案3】:

    除了@ahocevar 的回答,对您来说可能的优化是利用选择interaction's select event

    似乎选择交互和您的mousemove 侦听器都在检查同一层上的命中,做双重工作。每当所选功能集发生更改时,选择交互将触发 select 事件。您可以收听它,并在选择某些功能时显示弹出窗口,并在未选择时隐藏它。

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

    【讨论】:

    • 很有意义。更新了工具提示内容以触发交互的 selectEvent。 FF 的速度差异不大,但无论哪种方式都可以简化代码。
    • 我发现定义我自己的 mousehover 事件比使用 Select 交互要好得多,因为我可以检查 evt.dragging 属性并防止调用 forEachFeatureAtPixel() 这是瓶颈。据我所见,选择交互调用 forEachFeatureAtPixel() 没有过滤。
    猜你喜欢
    • 2015-07-25
    • 2020-05-11
    • 2011-05-16
    • 2015-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    相关资源
    最近更新 更多