Как обновить положение маркера Google Maps без их дублирования?

Я делаю вызов API каждые 15 секунд и обновляю позицию маркера внутри своего цикла. Это работает, за исключением того, что после обновления остается старый маркер, а новый ставится поверх него. Я не мог придумать логику, чтобы исправить это. Я пробовал использовать логические значения, это не сработало. Теперь я проверяю, не определен ли 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);

......

Рабочий фрагмент: https://codepen.io/Limpuls/full/rgpKjy

Я создал массив и поместил в него все новые объекты-маркеры. Затем я проверяю, больше ли длина массива 0, а затем просто setLocation(), если нет, то инициирую новый маркер. К сожалению, он выводит только один самолет вместо 50 и каждые 15 секунд обновляет не местоположение самолета, а добавляет совершенно новое случайное местоположение самолета. Как раньше был Таиланд, потом США.

Axios загружается каждые 15 секунд, и вы можете видеть, как значки складываются.

Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Сравнение структур данных: Массивы и объекты в Javascript
Сравнение структур данных: Массивы и объекты в Javascript
Итак, вы изучили основы JavaScript и хотите перейти к изучению структур данных. Мотивация для изучения/понимания Структур данных может быть разной,...
Создание собственной системы электронной коммерции на базе Keystone.js - настройка среды и базовые модели
Создание собственной системы электронной коммерции на базе Keystone.js - настройка среды и базовые модели
Прошлая статья была первой из цикла статей о создании системы электронной коммерции с использованием Keystone.js, и она была посвящена главным образом...
Приложение для отслеживания бюджета на React js для начинающих
Приложение для отслеживания бюджета на React js для начинающих
Обучение на практике - это проверенная тема для достижения успеха в любой области. Если вы знаете контекст фразы "Практика делает человека...
Стоит ли использовать React в 2022 году?
Стоит ли использовать React в 2022 году?
В 2022 году мы все слышим о трендах фронтенда (React, Vue), но мы не знаем, почему мы должны использовать эти фреймворки, когда их использовать, а...
0
0
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Глядя на API, который вы используете, первая запись является уникальным идентификатором самолета.

Одним из вариантов было бы создать массив маркеров с этим уникальным идентификатором в качестве ключа. При поступлении новых данных обновите маркеры по этому уникальному идентификатору. Затем устаревшие маркеры могут быть удалены, если данные для маркера не поступали в течение достаточно долгого времени.

  // 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();
    }
  }

доказательство концепции скрипки

screenshot of resulting map

фрагмент кода:

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() из соображений производительности? Извлекать данные и отображать значки для данной области карты и не более того? И как именно работает этот код? если(!bounds.contains(myLatlng)) продолжить; inBoundCnt++; Он проверяет, содержат ли текущие границы карты широту и долготу, и если нет, то пропускает цикл и продолжает другую итерацию?

Laimis 27.05.2019 15:43

Да, это ограничивает маркеры на карте видимыми. Исходный код обрабатывал первые 50 записей. Поскольку порядок казался непоследовательным, это не лучший способ ограничить отображаемые маркеры.

geocodezip 27.05.2019 16:00

Да, это действительно умно, я не знал о границах в API карт Google. А что насчет дельты времени. Это та же разница во времени, о которой говорят в разработке игр? Я никогда не использовал это и не уверен, что происходит. Я вижу, вы проверяете, превышает ли дельта-время 10000 мс (так же, как наш таймер setInterval), затем удаляете значок с карты с помощью .setMap(null) и удаляете плоскости из массива, верно? Значит, если бы мы не использовали дельта-время, это бы не сработало? Разве мы не можем просто удалять плоскости внутри функции setInterval каждые 10000 мс, прежде чем добавлять новые на карту?

Laimis 27.05.2019 16:12

Это удаление «устаревших» записей.

geocodezip 27.05.2019 16:39

Другие вопросы по теме