【问题标题】:Detect user-initiated pan/zoom operations on Leaflet在 Leaflet 上检测用户发起的平移/缩放操作
【发布时间】:2023-04-05 20:21:02
【问题描述】:

我有一张用于位置共享的传单地图。当用户分享他们的位置时,显示他们位置的标记会添加到地图中,以供所有其他用户查看。每当添加、移动或删除标记时,它都会自动调整地图以显示所有标记。我还添加了一个自定义控件,可以打开和关闭自动调整行为。这一切都很好,但我还想让地图足够智能,以便在用户平移或缩放地图时自动关闭自动调整行为。

事实证明这非常困难,因为我找不到一个好的方法来区分平移/缩放操作是由用户发起还是由自动调整发起的。我最初是在监听 panstart 和 zoomstart 事件,但这些也是由自动调整触发的。我想我可以设置一个标志来告诉它当缩放/平移是由自动调整引起时不要关闭自动调整。我在关闭自动适应以响应 panstart 和 zoomstart 之前先检查此标志,然后在收到 panend 和 zoomend 时清除它。

这似乎可以正常工作,直到发生不会导致平移或缩放的自动调整。假设我们有一大群自动拟合的标记,中间的一个被删除了。由于绑定框未更改,因此不会触发平移或缩放,因此告诉它不要关闭自动调整的标志永远不会被清除。下次用户平移或缩放地图时,它不会像应有的那样关闭自动调整,因为它认为它仍处于自动调整操作的中间。

如何做到这一点,以便在用户直接平移或缩放地图时可以可靠地关闭自动拟合,但在通过其他方式平移或缩放地图时保持开启?

以下是相关代码:

var markers = [];        // Map markers are stored in this array.
var autoFit = true;      // Whether auto-fit is turned on
var lockAutoFit = false; // Temporarily lock auto-fit if true
var map;                 // Leaflet map object

function initMap() {
    // Leaflet map initialized here
    map.on('movestart zoomstart', function() {
        if (!lockAutoFit) {
            autoFit = false;
        }
    });
    map.on('moveend zoomend', function() {
        lockAutoFit = false;
    });
}

function toggleAutoFit() {
    autoFit = !autoFit;

    if (autoFit) {
        lockAutoFit = true;
        fitMap();
    }
}

function addOrUpdateMarker(marker, coords) {
    lockAutoFit = true;
    // do the marker update here
    fitMap();
}

function removeMarker(marker) {
    lockAutoFit = true;
    // remove the marker here
    fitMap();
}

// Pans and zooms the map so that all markers fit in the map view.
// Invoked whenever a marker is added, moved or deleted, or when
// the user turns on auto-fit.
function fitMap() {
  if (!autoFit || !markers.length) {
    return;
  }

  map.fitBounds(new L.featureGroup(markers).getBounds());
}

【问题讨论】:

    标签: javascript leaflet


    【解决方案1】:

    我最终在我的 fitBoundssetView 呼叫周围设置了一个标志,例如:

    isProgramaticZoom = true
    map.fitBounds(new L.featureGroup(markers).getBounds());
    isProgramaticZoom = false
    

    然后是关闭自动适应的代码:

    map.on('zoomstart', function() {
      if (!isProgramaticZoom) {
        //turn off auto-fit
      }
    })
    
    map.on('dragstart', function() {
      //turn off auto-fit
    })
    

    不幸的是,仍然不理想,但应该可以解决问题

    【讨论】:

    • 标志重置需要安排在下一个动画帧之后,即实际边界更改和缩放事件被触发时
    【解决方案2】:

    编辑:这显然已被删除,不再有效

    这是一个老问题,但正如我最近发现的那样,我认为它仍然具有足够的相关性,值得给出一个解决方案。

    我遵循了这个解决方案:Leaflet User Triggered Events

    使用哪个:

    map.on('dragstart', function (e) {
        if (e.hard) {
            // moved by bounds
        } else {
           // moved by drag/keyboard
        }
    });
    

    未记录的 e.hard 部分是这里的解决方案; cmets 为自己说话。

    或者,您可能想要使用moveend 而不是dragstart

    【讨论】:

    • 此未记录的标志已从传单核心中完全删除,因此不再有效
    • @Wayneio 这个方法已经失效了
    【解决方案3】:

    您可以使用拖动、拖动开始、拖动结束 - 至少用于地图平移。对于地图缩放,我认为没有这样的等价物。

    【讨论】:

    • 是的,我知道拖动的那些,但就像你说的,没有任何缩放这样的东西,所以很遗憾它并不能真正解决我的问题。
    【解决方案4】:

    Leaflet reference 声明它具有zoomstartzoomendzoomlevelschange 事件。

    【讨论】:

    • 查看源代码:我其实是在代码中使用缩放事件。问题在于,当用户手动缩放和发生自动拟合时,都会触发这些事件。我目前没有可靠的方法来确定事件是由用户操作控件还是由自动调整操作触发的。这就是我要解决的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多