如何知道 Google 地图何时在平移之后重新定位了一个或所有标记

How to know when Google Maps has repositioned a or all Markers after Pan

我用map.panTo(perthLatLng);移动地图。然后我等待空闲事件 addListenerOnce(map, 'idle', panDone); 到目前为止一切顺利,但是在“panDone”时间,我的地图标记仍处于“旧”屏幕 Top/Left 位置并且尚未迁移到其新位置 x/y.

当 Google 地图最终将我的标记位置与新 Pan 同步时,是否有事件或其他启发式让我知道?

编辑: 因为地图 API 键你不能 运行 testmap.html 直接从 Github 文件,但您可以将 testmap.html 复制到您的文件系统并从那里激活(double-click 或 file:// URL)。

下面是我为解决这个难题而尽力而为的完整 SSCCE 策略。我使用 CSS 转换为:-

  1. 检测地图 API 何时最终在 Pan
  2. 之后重新定位我的标记
  3. 顺利地将我的标记转移到旅程中的下一个位置

注意:一旦“重播”功能可用,我将很快用大量新代码更新 Brotkrumen:-(

另请注意,对于 运行 下面的示例,只需将代码复制到 HTML 文件并单击它。但在此之前,您还必须将 Hansel and Gretal 的副本复制到同一文件夹。

如果您有 another/better 诱捕 Google-Map-API-PanTo-Really-Really-Finished 的方法,请告诉我。 “空闲”事件有助于了解地图图块何时就位,仅此而已。

PS。如果有人认为 CSS Transitions 在这里没有任何价值,这应该用现有的口吃库来完成,那么请不要用相同的东西来混淆这个问题。

<!DOCTYPE html>
<html>
  <head>
    <title>Smooth Runnings</title>

    <script type="application/javascript">
        'use strict';
        
/* identification division.
 * program-id.    GotTheMovesLikeJagger.
 * author.        Richard Maher.
 * version.       1.0
 */
        
        document.addEventListener("DOMContentLoaded", isDOMIsGood); 
        
        const MARKER_SELECTOR       = "img[src*='hg.png'";
        const MARKER_SRC            = "http://localhost/hg.png";                    
        const myLatLng              = { lat: -25.363, lng: 131.044 };
        
        var mapDiv, protagonists, HandG, map, observer, markerDiv,
            markerStyle, travelListener;
        
        var dest =  [
                    { lat: -31.9523, lng: 115.8613 }, 
                    { lat: -33.8688, lng: 151.2093 }, 
                    { lat: -27.4705, lng: 153.0260 },
                    { lat: -34.9285, lng: 138.6007 }
                    ];
                    
        var destIndex   = 0;
        var touchDown   = false;
        
        function isDOMIsGood(e) {
            console.log("DOM");
            mapDiv = document.getElementById("map");
        }
        
        function initMap() {
            console.log("Init");
            
            map = new google.maps.Map(mapDiv, {
                zoom: 4,
                center: myLatLng,
            });
            
            observer = new MutationObserver(waitForMarker);
            
            protagonists = {size: new google.maps.Size(45, 40),
                            scaledSize: new google.maps.Size(45, 40),
                            url: MARKER_SRC};
                            
            google.maps.event.addListenerOnce(map,'tilesloaded', tilesUp);
        }
        
        function tilesUp() {
            console.log("Map Tiles Here");

            travelListener = google.maps.event.addListener(map, 'center_changed', centerChanged);
            
            observer.observe(mapDiv, {
                            childList     : true,
                            subtree       : true ,
                            attributes    : true ,
                            characterData : false
                            });
                    
            HandG = new google.maps.Marker(
                {
                position: myLatLng, 
                map: map, 
                draggable: false,
                title: "HandG", 
                zIndex: 12, 
                visible: true, 
                icon: protagonists, 
                optimized: false
                });                     
        }
        
        function makeDestCenter(){
            console.log("Panning to new Center");           
            map.panTo(dest[destIndex]);
        }
        
        function centerChanged() {
            console.log("Center changed Left = " + markerStyle.left + " Top = " + markerStyle.top);
            markerDiv.style.visibility = "hidden";
            markerDiv.style.transitionDuration = "1ms";
            markerDiv.style.transitionTimingFunction = "linear";
            markerDiv.style.transitionProperty = "left, top";
            markerDiv.addEventListener('transitionend', quiesced, { 'once': true });
            markerDiv.addEventListener('transitioncancel', quiesced, { 'once': true });
        }
                
        function quiesced(e) {
            markerDiv.style.visibility = "visible";
            console.log("Quiesced " + e.type + " left " + markerStyle.left + " top " + markerStyle.top);
            setTimeout(handover, 0);
        }
        
        function handover(e) {
            console.log("in handover left " + markerStyle.left + " top " + markerStyle.top);
            markerDiv.style.transitionDuration = 2000 + "ms";
            markerDiv.style.transitionTimingFunction = "linear";
            markerDiv.addEventListener('transitionend', incrSteps, { 'once': true });
            markerDiv.style.transitionProperty = "left, top";
            HandG.setPosition(dest[destIndex]);
        }
        
        function startLeg(e) {
            console.log("start leg " + e.propertyName + " left " + e.target.style.left + " top " + e.target.style.top);
        }
        
        function cancelLeg(e) {
            console.log("Cancel leg " + e.propertyName + " left " + e.target.style.left + " top " + e.target.style.top);
            markerDiv.style.transitionDuration = "0s";
        }
        function incrSteps(e) {
            console.log("Incr Steps " + e.propertyName + " left " + e.target.style.left + " top " + e.target.style.top);
            if (++destIndex >= dest.length) {
                console.log("Journey's end");
                markerDiv.style.transitionDuration = "0s";
                travelListener.remove();
                return;
            }

            setTimeout(makeDestCenter,0);
        }
        
        function waitForMarker(mutations, myInstance) {
            outer:
            for (var i=0; i<mutations.length; i++){
                if (mutations[i].type           == "attributes" && 
                    mutations[i].target.tagName == "IMG"        &&
                    mutations[i].target.src.toLowerCase().indexOf(MARKER_SRC) != -1){
                    touchDown = true;
                    break outer;
                }
                if (mutations[i].type != "childList" ||
                    mutations[i].addedNodes.length   == 0) 
                    continue;
                for (var j=0; j<mutations[i].addedNodes.length; j++) {
                    var node = mutations[i].addedNodes[j];
                    if (node.tagName == "DIV" && node.firstChild && node.firstChild.tagName == "IMG" &&
                        node.firstChild.src.toLowerCase().indexOf(MARKER_SRC) != -1){
                        touchDown = true;
                        break outer;
                    }
                }
            }

            if (touchDown) {
                console.log("Got Marker");
                myInstance.disconnect();
                var markerImgs = document.querySelectorAll(MARKER_SELECTOR);
                if (markerImgs.length != 1) {
                    throw new Error("Expecting one and only one Hansel and Gretal. Found: " + markerImgs.length);
                };
                markerDiv = markerImgs[0].parentNode;
                markerStyle = getComputedStyle(markerDiv);
                markerDiv.addEventListener('transitionstart', startLeg);
                markerDiv.addEventListener('transitioncancel', cancelLeg);
                console.log("Left = " + markerStyle.left + " Top = " + markerStyle.top);
                setTimeout(makeDestCenter,0);
            }
        }
    </script>
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&v=weekly&channel=2" async
    ></script>
    <style type="text/css">
        #map {
          height: 100%;
        }

        /* Optional: Makes the sample page fill the window. */
        html,
        body {
          height: 100%;
          margin: 0;
          padding: 0;
        }
    </style>
  </head>
  <body>
    <div id="map"></div>


  </body>
</html>