You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Maps API JavaScript:Rover标记仅移动到最后航点问题排查

问题描述

我基于Google Maps API JavaScript开发了一款Rover导航面板,功能流程如下:在地图上定位Rover(旗帜图标),添加模拟航点的标记;点击START按钮后,Rover需依次移动到每个航点,最终停在最后一个。但当前问题是,Rover仅会移动到最后一个添加的标记。我使用动态数组存储标记,原计划通过For循环结合setPosition()方法,让Rover先抵达第一个标记,等待5秒(setTimeout(5000))后再移动到下一个航点。请问我的代码存在什么问题?


JavaScript代码

/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

//MAP---------------------------------

function initMap() {
//array arr1 which will contain the dynamically added markers      
  var arr1=[];

//myLatLng object with lat and lng attributes for position (europe)
  let myLatLng = { lat: 44.525961, lng: 15.255119  };

//constant map and assigned the map placed in the div id="map"
        const map = new google.maps.Map(document.getElementById("map"), {
          zoom: 4,
          //coordinates europe
          center: myLatLng,
        });
        
      //MARKER--------------------------------------
//marker object to put starting marker (rover)
        var markerRover = new google.maps.Marker({
          position: myLatLng,
          map: map,
          draggable: true,
          title: "ROVER",
          icon: "https://developers.google.com/maps/documentation/javascript/examples/full/images/beachflag.png"
  
        });
  
//variables to write the rover coordinates in form input

        let latitudine= document.getElementById('latitudine').value= markerRover.position.lat();
        let longitudine= document.getElementById('longitudine').value= markerRover.position.lng();
  
//CLICK EVENT TO ADD MARKER by clicking on the map, calls the placeMarker function which places the marker on the map where the click occurred
        map.addListener("click", (e) => {
          placeMarker(e.latLng, map);
        });
      
        function placeMarker(latLng, map) {
          var mark= new google.maps.Marker({
            position: latLng,
            map: map,
          });
        
// dynamic array to store the markers placed by placeMarker
          arr1.push(mark);
  
//test print arr dynamic markers          
          console.log(arr1);
  
//event for START button
          var START = document.getElementById('start');
          START.addEventListener("click",  function spostaRover()
          {
//test print to see the length of the array
            console.log(arr1.length);
        
//for loop to set rover position on markers added dynamically  

              for(let i=0; i<arr1.length; i++)
                {
  
                  markerRover.setPosition(arr1[i].position);

//attempt to wait 5s and then move rover marker to new position
                    setTimeout(() =>  markerRover.setPosition(arr1[i].position),5000);
                    console.log('marcatore '+i+' fatto')
  
//in the Rover Coordinates input form, I add the new coordinates that the rover will have   
                      latitudine=document.getElementById('latitudine').value= markerRover.position.lat();
                      longitudine=document.getElementById('longitudine').value= markerRover.position.lng();
      
                }
  
          });
  
    /*
              //evento per tasto CONFIRM
              var CONFIRM = document.getElementById('confermaTappa');
              CONFIRM.addEventListener("click",  function addTappa(){
        
              
                
      
                // scrive in textArea le coordinate dell'ultimo marcatore creato
                let td1= document.getElementById("coordTry").textContent= "latitudine: "+mark.position.lat()+"\n" +"longitudine: " +mark.position.lng();
      
                //let td2= document.getElementById("coordTry").textContent=mark.position.lng();
            
              });
  
  
          //evento per tasto remove
          var REMOVE = document.getElementById('removeMarker');
          REMOVE.addEventListener("click", function removeMarker(){
        
            //leva da arr1 (array dei marcatori) ultimo marcatore da array
            arr1.pop(mark);
            //prova di stampa
            console.log(arr1);
            mark.setMap(null);
            //manca di togliere ultimo marcatore dalla mappa
          });
  */
      }//closing placemarker
     
      }
       
        window.initMap = initMap;

HTML代码

<!DOCTYPE html>
<!--
 @license
 Copyright 2019 Google LLC. All Rights Reserved.
 SPDX-License-Identifier: Apache-2.0
-->
<html>
  <head>
    <title>geo-rover</title>
    
    <script src="script.js"></script>


    <link rel="stylesheet" href="style.css">

    <!-- jsFiddle will insert css and js -->
  </head>

<body>

<div class="container1">
  
  <h1>GEO-ROVER</h1>

      <div id="map">

      </div>

    
    <div class="containerPulsanti1">

      <div class="containerPulsanti2">

      <button class="pulsante" 
        id="removeMarker"
        type="button">
        REMOVE
      </button>
    
      <button class="pulsante"
        id="stop"
        type="button">
        STOP
      </button>

      <button class="pulsante"
        id="start"
        type="button"> 
        START
    </button>

    
    
      <button class="pulsante"
        id="confermaTappa"
        type="button">
        CONFIRM
      </button>

    </div>

      </div>
   
    <!-- Container 2 per coordinate attuali e tabella tappe*/  -->
    <div class="container2">

      <!-- Container 3 per gestire in flex contenuto container2 -->
      <div class="container3">
        
     <!-- Container per label coordinate-->
        <div class="containerCoordinate">

          <h2>Coordinate rover</h2>

            <div id="coordinate">

              <label for="coordinate" class="coordinateLat" > Latitudine</label>
              <input type="text" class="coordinateGeo" id="latitudine" name="latitudine" disabled >

              <label for="coordinate" class="coordinateLong"> Longitudine</label>
              <input type="text" class="coordinateGeo" id="longitudine" name="longitudine" disabled >

            </div>
     
        </div>

      <div class="containerTable">

        <h2>Coordinate tappe Rover</h2>

            <label for="coordTry"></label>
            <textarea id="coordTry" name="story" rows="10" cols="45" >
            </textarea>
    
    
        
      <!-- <table class="table">

      <thead>

      <tr>
      <th>TAPPE</th>
      <th>LATITUDINE</th>
      <th>LONGITUDINE</th>
      </tr>

      </thead>

      <tbody class="bodyTable">

      <tr>
      <th>1</th>
      <td id="tappa1lat">-</td>
      <td id="tappa1lng">-</td>
      </tr>

      <tr>
      <th>2</th>
      <td id="tappa2lat">--</td>
      <td id="tappa2lng">--</td>
      </tr>

      <tr>
      <th>3</th>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      </tr>

      <tr>
      <th>4</th>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      </tr>

      </tbody>          
      </table>

  
      </div>
       -->

    </div>
  </div>
</div>
    <!-- 
     The `defer` attribute causes the callback to execute after the full HTML
     document has been parsed. For non-blocking uses, avoiding race conditions,
     and consistent behavior across browsers, consider loading using Promises
     with https://www.npmjs.com/package/@googlemaps/js-api-loader.
    -->
    
<!--<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAFkjhEDLfud-pZFUtE_wdfspot2IWnuXI&callback=initMap&libraries=drawing&v=weekly" defer>   </script>
-->
 
<!--  ,geometry,places  ---non mio-->

  <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&libraries=drawing&v=weekly" defer> </script>  

</body>

</html>

CSS样式

/* stile html e body*/
   
   @import url('https://fonts.googleapis.com/css?family=Coda');

   html,
   body {
     background: rgb(0,0,0);
   background: linear-gradient(180deg, rgba(0,0,0,1) 71%, rgba(168,167,0,1) 100%, rgba(204,209,0,1) 100%);
     margin: 0;
     padding: 0;
     height: 150vh;
     width: 100%
   }
   
   /*my rules*/
   
   /*TITOLI*/
   h1{
   
     font-family: Coda, cursive;
     font-style: italic;
       text-align: center;
       font-size: 35px;
       letter-spacing: 4px;
       word-spacing: 3px;
       color: rgb(247, 255, 0);
      
   }
   
   
   h2 {
    
     font-family: Coda, cursive;
     font-style: italic;
       text-align: center;
       
       letter-spacing: 4px;
       word-spacing: 3px;
       color: rgb(247, 255, 0);
   }

   
   /*container Principale che parte da sotto al titolo h1*/
   .container1 {
   
     display: flex;
     flex-direction: column;
     height: 100%;
   
   }
   /*mappa GOOGLE     div per contenere mappa*/
   #map  {
   
     flex: 6;
   }
   
   /*Container 2 per coordinate attuali e tabella tappe*/
   .container2 {
     
     flex: 3;
     padding-bottom: 1%;
     
   }
   /*container 3 per gestire in flexbox contenuto container 2*/
   .container3{
     display: flex;
     flex-direction: row;
     justify-content: space-around;
     
   }
   
   
   .containerPulsanti1{
   
     padding: 10px;
     flex:1;
   }
   .containerPulsanti2 {
     padding: 10px;
     margin: 10px;
     display: flex;
     flex-direction: row;
     justify-content: space-evenly;
     align-items: center;
   }
   .pulsante {
     
     cursor:pointer;
     color:#ffffff;
     font-family:Arial;
     font-size:17px ;
     padding:10px 25px;
     text-decoration:none;
   }
   
   .containerPulsanti2 {
     position:relative;
     top:1px;
   }
   #start{
     box-shadow: 0px 0px 5px 0px #3dc21b;
     background-color:#44c767;
     border-radius:28px;
     border:1px solid #18ab29;
   }
   
   #start:hover {
     background-color:#5cbf2a;
   }
   #start:active {
     background-color:#055509;
   }
   #stop{
     box-shadow: 0px 0px 5px 0px red;
     background-color:red;
     border-radius:28px;
     border:1px solid red;
   }
   #stop:hover {
     background-color: #f16161;
   }
   #stop:active {
     background-color:#890303;
   }
   #removeMarker{
     color: #000000;
     box-shadow: 0px 0px 5px 0px yellow;
     background-color:yellow;
     border-radius:28px;
     border:1px solid yellow;
   }
   
   #removeMarker:hover {
     background-color:#fcf288;
   }
   #removeMarker:active {
     background-color:#7b7100;
   }
   #confermaTappa{
     color: #000000;
     box-shadow: 0px 0px 5px 0px yellow;
     background-color:yellow;
     border-radius:28px;
     border:1px solid yellow;
   }
   #confermaTappa:hover {
     background-color:#fcf288;
   }
   
   #confermaTappa:active {
     background-color:#7b7100;
   }
   
   
   .coordinateGeo {
     padding: 5px;
     font-size: 16px;
     border-width: 2px;
     border-color: #fffb09;
     background-color: black;
     color: #ffffff;
     border-style: solid;
     border-radius: 10px;
     margin-top: 1vh;
     
   }
   /*.coordinateGeo:focus {
     outline:none;
   }*/
   #coordinate {
   
     display: flex;
     flex-direction: column;
   text-align: center;
   }
   .coordinateLong {
     margin-top: 2vh;
     font-family: verdana;
       text-align: center;
       font-size: 20px;
       color: rgb(255, 255, 255);
   
   }
   .coordinateLat {
    margin-top: 2vh;
     font-family: verdana;
       text-align: center;
       font-size: 20px;
       color: rgb(255, 255, 255);
   
   }
   #latitudine{
         text-align: center;
   
   }
   #longitudine{
         text-align: center;
   
   }

   
       
      
      
     
   

问题分析与修复方案

核心问题1:循环中setTimeout的闭包陷阱

for循环里的setTimeout会在循环完全结束后才执行,此时变量i已经变成了数组的最后一个索引值,所以所有延迟执行的setPosition都会指向最后一个航点。

核心问题2:同步代码直接覆盖位置

循环里直接执行markerRover.setPosition(arr1[i].position);会立刻把Rover的位置设置到当前循环的航点,循环瞬间跑完后,Rover已经被设置到最后一个航点,后续延迟执行的代码又会重复设置最后一个航点。

核心问题3:事件监听重复绑定

每次点击地图添加航点时,你都会给START按钮重新绑定一次点击事件,这会导致点击START时,之前添加的所有航点对应的移动逻辑都会重复执行,造成混乱。


修复后的核心代码示例

function initMap() {
  var arr1=[];
  let myLatLng = { lat: 44.525961, lng: 15.255119  };
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: myLatLng,
  });
  
  var markerRover = new google.maps.Marker({
    position: myLatLng,
    map: map,
    draggable: true,
    title: "ROVER",
    icon: "https://developers.google.com/maps/documentation/javascript/examples/full/images/beachflag.png"
  });

  // 更新初始坐标
  function updateRoverCoords() {
    document.getElementById('latitudine').value = markerRover.position.lat();
    document.getElementById('longitudine').value = markerRover.position.lng();
  }
  updateRoverCoords();

  // 把START事件监听移到外面,只绑定一次
  var START = document.getElementById('start');
  START.addEventListener("click", function spostaRover() {
    console.log(arr1.length);
    // 递归实现依次延迟移动
    function moveToNext(index) {
      if (index >= arr1.length) return;
      // 设置当前航点位置
      markerRover.setPosition(arr1[index].position);
      updateRoverCoords();
      console.log('marcatore ' + index + ' fatto');
      //
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 23:45:54