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

Angular 15 Google Maps标记位置无法实时更新的解决方案求助

问题:Angular Google Map标记位置无法随数组更新

我用@angular/google-maps结合新南威尔士州交通开放数据搭建了公共交通实时地图,已成功初始化地图并添加渡轮位置标记,但更新标记数组后,地图上的标记位置未同步变化。不过通过组件内的*ngFor循环输出文本时,视图中的数据能正常更新。

核心疑问:标记数组更新时,如何让Angular Google Map中的标记位置同步更新?

当前实现代码

livedata-map-content.component.html

<div class="live-transport-map">
    <div *ngIf="apiLoaded" class="google-maps-container">
        <google-map width="100%" height="100%" [options]="options">
              <map-marker  *ngFor="let marker of markers"
              [position]="marker.position"
              [label]="marker.label"
              [title]="marker.title"
              [options]="marker.options">
          </map-marker>
            
  <span *ngFor="let marker of markers">NAME:  {{marker.title}} LAT: {{marker.position.lat}} LNG: {{marker.position.lng}}!!!! </span>
        </google-map>
    </div>
</div>

livedata-map-content.component.ts

import { ChangeDetectorRef, Component, AfterViewInit, OnDestroy } from '@angular/core';
import { MapService} from '../../../services/map.service';
import { interval, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

@Component({
  selector: 'app-livedata-map-content',
  templateUrl: './livedata-map-content.component.html',
  styleUrls: ['./livedata-map-content.component.scss']
})
export class LivedataMapContentComponent implements AfterViewInit, OnDestroy {
  
  public apiLoaded: any = false;
  public markers: Array<any> = [];
  public period = 10000;
  public iconStr = "http://maps.google.com/mapfiles/ms/icons/green-dot.png";
  private destroy$ = new Subject<void>();

  public options: google.maps.MapOptions = {
    center: {lat: -33.853759, lng: 151.212803}, // 悉尼港中心
    zoom: 14,
  };

  constructor(
      private mapService: MapService,
      private cd: ChangeDetectorRef
    ) { }

  ngAfterViewInit(): void {
    
    // 视图初始化后加载地图API
    this.mapService.loadGoogleMapsAPI().subscribe(data => {
      
      this.apiLoaded = data;

      if(this.apiLoaded === true) {
        // API加载完成后启动实时数据更新
        interval(this.period)
          .pipe(takeUntil(this.destroy$))
          .subscribe(() => this.updateMarkers());
      }
    });

    // 初始化地图标记
    this.mapService.getLivePositionData('ferry').subscribe(positionData => {

      let transportEntitiesArray = positionData.data.entity;

      transportEntitiesArray.forEach((transportEntity: any) => {

        this.markers.push({
          tripId: transportEntity.vehicle.trip.tripId,
          position: {
            lat: transportEntity.vehicle.position.latitude,
            lng: transportEntity.vehicle.position.longitude,
          },
          title: transportEntity.vehicle.vehicle.id + '\n' + transportEntity.vehicle.vehicle.label,
          options: {
            icon: this.iconStr,
          }
        });
      });

      this.cd.detectChanges();
    });
  }
    
  updateMarkers = () => {

    this.mapService.getLivePositionData('ferry').subscribe(positionData => {

      positionData.data.entity.forEach(positionDataItem => {
        
        this.markers.forEach(marker => {
          // 仅更新有位置变化的标记
          if(marker.tripId === positionDataItem.vehicle.trip.tripId && 
             (marker.position.lat !== positionDataItem.vehicle.position.latitude || marker.position.lng !== positionDataItem.vehicle.position.longitude)){
            // 创建新的position对象替换旧引用,触发变更检测
            marker.position = {
              lat: positionDataItem.vehicle.position.latitude,
              lng: positionDataItem.vehicle.position.longitude
            };
          }
        });
      });

      this.cd.detectChanges();

    });
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
}

map.service.ts

...

  public loadGoogleMapsAPI = () => {

    const mapsAPIURL = `https://maps.googleapis.com/maps/api/js?key=${environment.tempGoogleMapsID}`
    console.log('mapsAPIURL ',mapsAPIURL);

    return this.http.jsonp<any>(mapsAPIURL, 'callback').pipe(
      map((data) => {
        console.log('DATA ',data);
        return true}),
      catchError((error) => {
        console.log('error ',error);
        return of(false)}),
    );

  }

...

  getLivePositionData = (transportMode: any) => {

    const getLivePositionDataObject = {
      transportMode: transportMode
    }
    
    const getLivePositionDataDataURL = this.openDataAPI + 'positiondata';

    return this.http.post<any>(getLivePositionDataDataURL, getLivePositionDataObject);
  }
...

当前地图可正常绘制并填充标记数组,但标记位置无法在地图上更新:

正常显示渡轮位置标记的Angular 15 Material Google Maps

问题原因及解决方案

问题根源

Angular的变更检测默认通过引用比较判断值是否变化,而你直接修改了marker.position对象内部的lat和lng属性,没有改变position对象的引用。@angular/google-maps的map-marker组件依赖输入属性的引用变化来触发更新,因此不会同步位置变更。

修复步骤

修改updateMarkers方法中更新位置的逻辑,创建新的position对象替换旧引用:

marker.position = {
  lat: positionDataItem.vehicle.position.latitude,
  lng: positionDataItem.vehicle.position.longitude
};

额外优化

  1. 替换setInterval为RxJS interval:避免内存泄漏,方便组件销毁时清理定时任务(已在代码示例中实现)。
  2. 补全ChangeDetectorRef注入:原代码构造函数中缺失该依赖注入,需添加(已修正)。

内容的提问来源于stack exchange,提问作者CVL

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 13:59:55