Angular 15 Google 地图实时更新标记位置

问题描述 投票:0回答:2

使用 @angular/google-maps 使用新南威尔士州 openData 的交通创建实时公共交通地图。

我可以成功创建初始地图,并将标记放置到地图上(在本例中为轮渡位置),但更新标记数组不会更新地图上的标记位置。

确实,但是,当我通过组件中的

*ngFor
循环输出到文本时,会更新视图中的数据。

我的问题:当标记数组更新时,如何更新 Angular Google Map 中的标记位置?

Angular 15 代码:

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 } from '@angular/core';
import { MapService} from '../../../services/map.service';

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

  public options: google.maps.MapOptions = {
    center: {lat: -33.853759, lng: 151.212803}, // Sydney Harbour center
    zoom: 14,
  };

  constructor(
      private mapService: MapService
    ) { }

  ngAfterViewInit(): void {
    
    // Load the maps API after view is init
    this.mapService.loadGoogleMapsAPI().subscribe(data => {
      
      this.apiLoaded = data;

      if(this.apiLoaded === true) {
        // Once it's loaded start getting live data
        setInterval(this.updateMarkers, this.period);
      }
    });

    // Initial marker setup on map
    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 => {
          // Only update markers with new positions
          if(marker.tripId === positionDataItem.vehicle.trip.tripId && (marker.position.lat !== positionDataItem.vehicle.position.latitude || marker.position.lng !== positionDataItem.vehicle.position.longitude)){
            marker.position.lat = positionDataItem.vehicle.position.latitude;
            marker.position.lng = positionDataItem.vehicle.position.longitude;
          }
        });
      });

      this.cd.detectChanges();

    });
  }
}

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);
  }
...

这将绘制地图并按预期填充数组,但不会更新地图上的标记位置。

IMAGE: the Angular 15 Material Google Maps with ferry position markers working

javascript angular angular-google-maps angular15
2个回答
0
投票

我和你有同样的问题。 我找到了一种更新 html 中第一个标记的方法。

在组件中添加一个ViewChild:

    @ViewChild(MapMarker, { static: false }) myMarker!: MapMarker;

然后您将能够像这样更新标记:

this.myMarker?.marker?.setPosition({lat: 0, lng: 0});

这仍然是一种解决方法,但我无法选择特定标记并更新它。


0
投票

我也遇到了同样的情况。无法通过绑定和更改检测获取地图反映的标记对象的更新。然后阅读有关角度变化检测的更多信息,以及如果我们绑定的对象是不可变的,它如何更好地工作。默认的更改检测策略检查对象引用是否相同,或者它是一个不同对象。

因此,您应该对对象进行深层复制,而不是更改

marker.position.lat
。要么通过对象扩展运算符(但请注意,它是浅复制),要么通过创建标记对象的新实例。

此外,如果您将

markers
作为
Array
类型的字段绑定,则对象的引用是相同的,除非您将列表的新深层副本分配给该字段。我不是专家,但我看到其他人添加了
Observable<Marker[]>
字段(或者更好的是
Subject<Marker[]>
),并在列表更新后显式发送更新。

角度变化检测文章中的示例完整地展示了这种模式。

© www.soinside.com 2019 - 2024. All rights reserved.