使用 @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);
}
...
这将绘制地图并按预期填充数组,但不会更新地图上的标记位置。
我和你有同样的问题。 我找到了一种更新 html 中第一个标记的方法。
在组件中添加一个ViewChild:
@ViewChild(MapMarker, { static: false }) myMarker!: MapMarker;
然后您将能够像这样更新标记:
this.myMarker?.marker?.setPosition({lat: 0, lng: 0});
这仍然是一种解决方法,但我无法选择特定标记并更新它。
我也遇到了同样的情况。无法通过绑定和更改检测获取地图反映的标记对象的更新。然后阅读有关角度变化检测的更多信息,以及如果我们绑定的对象是不可变的,它如何更好地工作。默认的更改检测策略检查对象引用是否相同,或者它是一个不同对象。
因此,您应该对对象进行深层复制,而不是更改
marker.position.lat
。要么通过对象扩展运算符(但请注意,它是浅复制),要么通过创建标记对象的新实例。
此外,如果您将
markers
作为 Array
类型的字段绑定,则对象的引用是相同的,除非您将列表的新深层副本分配给该字段。我不是专家,但我看到其他人添加了 Observable<Marker[]>
字段(或者更好的是 Subject<Marker[]>
),并在列表更新后显式发送更新。
角度变化检测文章中的示例完整地展示了这种模式。