【问题标题】:How to update Google Maps marker position without them duplicating?如何在不重复的情况下更新谷歌地图标记位置?
【发布时间】:2019-10-08 20:33:51
【问题描述】:

我每 15 秒调用一次 API,并更新循环内的标记位置。它可以工作,只是在更新后旧标记保留并且新标记堆叠在它上面。我想不出解决这个问题的逻辑。我尝试使用布尔值,但没有用。现在我正在检查 planeIcon 是否未定义,然后初始化一个新标记,如果已定义,则只需 .setPosition()。这没有给我任何错误,但图标根本不会出现在屏幕上或开始堆叠。我做错了什么?

var map, marker1, marker2, myLatlng, icon;
var boo = true;
var planeIcon = [];
function initMap() {
    var infoWindow = new google.maps.InfoWindow();
    // Create a new StyledMapType object, passing it an array of styles,
    // and the name to be displayed on the map type control.
setInterval(
function () {
    axios.get('http://localhost:8888/lsapp/public/planes/')
        .then(function (response) {
            var infowindow = new google.maps.InfoWindow();
            var north = new google.maps.LatLng(90.0000, 0.0000);
            var northPole = new google.maps.Marker({
                position: {lat: 90.0000, lng: 0.0000},
                map: map
            });
            northPole.setIcon({
                path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
                scaledSize: new google.maps.Size(10, 10),
                scale: 6
            });

            for (var i = 0; i < 50; i++) {
                //console.log(response.data["states"][i]);
                console.log(response.data["states"][i]);

                var direction = new google.maps.LatLng(response.data["states"][i][6], response.data["states"][i][5]);
                var heading = google.maps.geometry.spherical.computeHeading(direction, north);

                myLatlng = new google.maps.LatLng(response.data["states"][i][6],response.data["states"][i][5]);
                    icon = {
                        path: "M 356.26958,135.02702 L 356.26958,249.31026 L 296.72689,289.12758 C 298.37366,285.78981 297.94877,282.22185 297.97085,278.70356 L 297.7704,238.6142 L 268.80878,238.44964 L 269.05561,285.18318 C  ",
                        fillColor: '#111111',
                        fillOpacity: 1,
                        scaledSize: new google.maps.Size(0.01, 0.01),
                        rotation: heading + response.data["states"][i][10],
                        scale: 0.02
                    }

                    if(planeIcon.length > 0) {
                        for (var j = 0; j < planeIcon.length; j++)
                        planeIcon[j].setPosition(myLatlng);
                    } else {
                        planeIcon.push(new google.maps.Marker({
                            position: {lat: response.data["states"][i][6], lng: response.data["states"][i][5]},
                            map: map,
                            title: response.data["states"][i][1],
                            icon: icon
                        }));
                    }
                    console.log(planeIcon);

......

工作sn-p:https://codepen.io/Limpuls/full/rgpKjy

我创建了一个数组并将所有新的标记对象推送到它。然后我检查数组长度是否大于 0,如果没有,则只需 setLocation(),然后初始化新标记。不幸的是,它只输出一个平面而不是 50 个,并且每 15 秒它更新的不是平面位置,而是放置一个全新的随机平面位置。就像以前是泰国,然后是美国。

Axios 每 15 秒获取一次,您可以看到图标堆叠。

【问题讨论】:

    标签: javascript loops google-maps-api-3 setinterval google-maps-api-2


    【解决方案1】:

    查看您正在使用的the API,第一个条目是飞机的唯一标识符。

    一种选择是创建一个以该唯一 ID 作为键的标记数组。当新数据到达时,通过该唯一 ID 更新标记。然后,当一个标记的数据没有收到足够长的时间时,可以删除陈旧的标记。

      // in the global scope
      var planesArray = [];
    
      var bounds = map.getBounds();
      for (var i = 0; i < response.data["states"].length; i++) {
        var myLatlng = new google.maps.LatLng(response.data["states"][i][6], response.data["states"][i][5]);
        // limit to the planes currently in view on the map
        if (!bounds.contains(myLatlng))
          continue;
        inBoundCnt++;
        var direction = new google.maps.LatLng(response.data["states"][i][6], response.data["states"][i][5]);
        var heading = google.maps.geometry.spherical.computeHeading(direction, north);
        icon.rotation = heading + response.data["states"][i][10];
    
        var uniqueId = response.data["states"][i][0];
        // if marker doesn't already exist, make a new one
        if (!planesArray[uniqueId] || !planesArray[uniqueId].setPosition) {
          var planeIcon = new google.maps.Marker({
            position: myLatlng,
            map: map,
            title: response.data["states"][i][1],
            icon: icon,
            uniqueId: uniqueId,
            displayCnt: 0,
            timeStamp: now
          });
          google.maps.event.addListener(planeIcon, 'click', (function(planeIcon, i) {
            return function() {
              infowindow.setContent(response.data["states"][i][0].toLowerCase());
              infowindow.open(map, planeIcon);
              console.log(response.data["states"][i][0].toLowerCase());
            }
          })(planeIcon, i));
          planesArray[uniqueId] = planeIcon;
        } else {
          // if marker already exists, change its position
          planesArray[uniqueId].setPosition(myLatlng);
          planesArray[uniqueId].displayCnt++;
          planesArray[uniqueId].timeStamp = Date.now();
        }
      }
    

    proof of concept fiddle

    代码 sn-p:

    var map, marker1, marker2, myLatlng, icon;
    var boo = true;
    var planeIcon;
    var planesArray = [];
    
    function initMap() {
      icon.scaledSize = new google.maps.Size(0.01, 0.01);
      var infoWindow = new google.maps.InfoWindow();
      setInterval(
        function() {
          axios.get('https://opensky-network.org/api/states/all')
    
            .then(function(response) {
              var now = Date.now();
              var infowindow = new google.maps.InfoWindow();
              var north = new google.maps.LatLng(90.0000, 0.0000);
              var northPole = new google.maps.Marker({
                position: {
                  lat: 90.0000,
                  lng: 0.0000
                },
                map: map
              });
              northPole.setIcon({
                path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
                scaledSize: new google.maps.Size(10, 10),
                scale: 6
              });
              var bounds = map.getBounds();
              console.log("processing " + response.data["states"].length + " entries");
              var inBoundCnt = 0;
              for (var i = 0; i < response.data["states"].length /* && i < 50 */ ; i++) {
                // console.log(i + ":" + response.data["states"][i]);
                var myLatlng = new google.maps.LatLng(response.data["states"][i][6], response.data["states"][i][5]);
                if (!bounds.contains(myLatlng))
                  continue;
                inBoundCnt++;
                var direction = new google.maps.LatLng(response.data["states"][i][6], response.data["states"][i][5]);
                var heading = google.maps.geometry.spherical.computeHeading(direction, north);
                icon.rotation = heading + response.data["states"][i][10];
    
                var uniqueId = response.data["states"][i][0];
                if (!planesArray[uniqueId] || !planesArray[uniqueId].setPosition) {
                  var planeIcon = new google.maps.Marker({
                    position: myLatlng,
                    map: map,
                    title: response.data["states"][i][1],
                    icon: icon,
                    uniqueId: uniqueId,
                    displayCnt: 0,
                    timeStamp: now
                  });
                  google.maps.event.addListener(planeIcon, 'click', (function(planeIcon, i) {
                    return function() {
                      axios.get('http://localhost:8888/lsapp/public/planes/' + response.data["states"][i][0].toLowerCase())
                        .then(function(res) {
                          div.innerHTML = '';
                          div.innerHTML += "<h5>" + res.data + "</h5>";
                        }).catch(function(error) {
                          // handle error
                          console.log(error);
                        });
                      infowindow.setContent(response.data["states"][i][0].toLowerCase());
                      infowindow.open(map, planeIcon);
                      console.log(response.data["states"][i][0].toLowerCase());
                    }
                  })(planeIcon, i));
                  planesArray[uniqueId] = planeIcon;
                } else {
                  // console.log("[" + i + "] moving " + uniqueId + " to " + myLatlng.toUrlValue(6));
                  planesArray[uniqueId].setPosition(myLatlng);
                  planesArray[uniqueId].displayCnt++;
                  planesArray[uniqueId].timeStamp = Date.now();
                }
              }
              console.log("in bounds markers=" + inBoundCnt);
              // remove stale markers
              for (plane in planesArray) {
                var deltaT = now - planesArray[plane].timeStamp;
                // console.log("plane="+plane+" uniqueId="+planesArray[plane].uniqueId+" deltaT="+deltaT);
                if (deltaT > 10000) {
                  console.log("removing " + plane + " deltaT=" + deltaT);
                  planesArray[plane].setMap(null);
                  delete planesArray[plane];
                }
              }
            })
            .catch(function(error) {
              // handle error
              console.log(error);
            })
            .finally(function() {
              // always executed
            });
    
        }, 10000);
      map = new google.maps.Map(document.getElementById('map'), {
        center: {
          lat: 40.7127753,
          lng: -74.0059728
        },
        zoom: 8
      });
    }
    var icon = {
      path: "M 356.26958,135.02702 L 356.26958,249.31026 L 296.72689,289.12758 C 298.37366,285.78981 297.94877,282.22185 297.97085,278.70356 L 297.7704,238.6142 L 268.80878,238.44964 L 269.05561,285.18318 C 269.06227,292.68821 270.04683,297.17053 276.7074,301.30953 L 204.8529,348.4504 C 207.01499,345.12276 206.84863,341.2911 206.84863,337.51874 L 206.77165,295.05645 L 178.71508,294.89191 L 178.6328,342.1191 C 178.84508,349.00225 179.88792,356.28465 186.12004,360.54922 L 30.615857,462.16174 C 3.2664942,481.49054 8.4728732,501.69026 10.293349,521.73054 L 356.26958,404.23849 L 356.26958,582.78033 L 365.64921,648.51992 L 252.92924,731.45549 C 236.829,745.21163 238.89783,759.656 241.98635,773.74604 L 388.44003,735.48708 C 390.1301,775.95885 408.69374,776.66877 411.55996,735.56935 L 558.01364,773.82832 C 561.10216,759.73826 563.17099,745.29391 547.07076,731.53776 L 434.3508,648.6022 L 443.73041,582.86261 L 443.73041,404.32077 L 789.70665,521.73054 C 791.52713,501.6903 796.7335,481.57282 769.38414,462.24402 L 613.87995,360.6315 C 620.11205,356.3669 621.07263,349.08453 621.28491,342.20138 L 621.28491,294.97418 L 593.22834,295.13873 L 593.15851,338.35476 C 593.1282,342.1754 593.2504,345.43211 595.47226,348.97078 L 523.21031,301.39181 C 529.87094,297.25281 530.93773,292.77049 530.94439,285.26546 L 531.19122,238.53192 L 502.22959,238.69647 L 502.02452,278.95408 C 502.0435,282.62018 501.76549,285.90838 503.64551,289.27217 L 443.73041,249.39253 L 443.73041,135.10929 C 429.29576,-9.7066548 372.45267,-10.54689 356.26958,135.02702 z ",
      fillColor: '#111111',
      fillOpacity: 1,
      scale: 0.02
    }
    html,
    body,
    #map {
      height: 100%;
      margin: 0;
      padding: 0;
    }
    <div id="map"></div>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <!-- Replace the value of the key parameter with your own API key. -->
    <script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&libraries=geometry&callback=initMap"></script>

    【讨论】:

    • 感谢您的回答,您真的帮助了我,因为我被困了很长时间。我只有两个问题。我们是否出于性能原因使用 map.getBounds() ?为给定的地图区域检索数据和显示图标,而不需要更多?这段代码到底是如何工作的? if(!bounds.contains(myLatlng)) 继续; inBoundCnt++;是否检查当前地图边界是否包含 Lat 和 Lng,如果不包含则跳过循环并继续其他迭代?
    • 是的,这会将地图上的标记限制在视野范围内。原始代码处理了前 50 条记录。由于顺序似乎不一致,这似乎不是限制显示标记的好方法。
    • 是的,这真的很聪明,我不知道 google maps api 中的边界。那么增量时间呢。人们在游戏开发中谈论的增量时间是否相同?我从来没有用过,也不知道发生了什么。我看到您正在检查增量时间是否超过 10000 毫秒(与我们的 setInterval 计时器相同),然后使用 .setMap(null) 从地图中删除图标并从数组中删除平面,对吗?所以如果我们不使用增量时间,这不会起作用吗?我们不能每 10000 毫秒删除 setInterval 函数中的平面,然后再将新平面放到地图上吗?
    • 那是删除“陈旧”的条目。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-24
    • 1970-01-01
    • 2017-03-22
    • 1970-01-01
    • 1970-01-01
    • 2019-01-08
    • 2015-10-18
    相关资源
    最近更新 更多