Я использую Карты Azure и пытаюсь создать многоразовую библиотеку вокруг своих карт. Я хочу предоставить пользователю способ передать свое собственное всплывающее окно вместе с массивом строго типизированных объектов для добавления маркеров на страницу. У меня есть карта и маркеры работают, но я застрял на том, как передать данные во всплывающее окно. В настоящее время у меня есть:
аз-map.component.html
<div class="map-wrapper">
<div id="az-map"></div>
</div>
<ng-template #defaultMarker>
<div>
<img alt="" src="https://maps.gstatic.com/mapfiles/api-3/images/spotlight-poi2.png" />
</div>
</ng-template>
<ng-template #defaultPopup>
<div>
<h2>~name~</h2>
</div>
</ng-template>
<div style="display:none">
<div id="marker" #marker>
<ng-container *ngTemplateOutlet="markerTemplate ? markerTemplate : defaultMarkerTemplate"></ng-container>
</div>
<div id="popup" #popup>
<ng-content select="[popupTemplate]"></ng-content>
</div>
</div>
Az-map.component.ts
@Component({
selector: 'az-map',
templateUrl: './azure-map.component.html',
styleUrls: ['./azure-map.component.scss']
})
export class AzureMapComponent implements OnInit {
@Input() locations: Location[];
@Input() mapConfig: AzureMapConfig;
@Input() markerTemplate: TemplateRef<any>;
@ViewChild('defaultMarker') defaultMarkerTemplate: TemplateRef<any>;
@ViewChild("popup") popupElement: ElementRef;
@ViewChild("marker") marker: ElementRef;
/* These are the map components we can interact with */
public map: any;
public popup: atlas.Popup;
public symbolLayer: atlas.layer.SymbolLayer;
private dataSource: atlas.source.DataSource;
constructor(private configService: ConfigurationService) { }
ngOnInit() {
const centerPosition: any = this.mapConfig.center.length
? this.mapConfig.center
: ( this.locations && this.locations.length > 0 ? [this.locations[0].longitude, this.locations[0].latitude] : [-95, 38]);
this.map = new atlas.Map('az-map', {
center: centerPosition,
zoom: this.mapConfig.zoom,
authOptions: {
authType: atlas.AuthenticationType.subscriptionKey,
subscriptionKey: this.configService.get().azureMapKey
}
});
this.map.events.add('ready', () => {
this.dataSource = new atlas.source.DataSource();
this.map.sources.add(this.dataSource);
this.addMarkers();
this.symbolLayer = new atlas.layer.SymbolLayer(this.dataSource, null)
this.map.layers.add(this.symbolLayer);
if (this.mapConfig.showControls) {
this.map.controls.add(new atlas.control.ZoomControl(), {
position: "top-right"
});
}
if(this.mapConfig.showPopups){
this.popup = new atlas.Popup({
pixelOffset: [0, -18],
closeButton: false
});
const _this = this;
this.map.events.add('mouseover', this.symbolLayer, (e) => {
if (e.shapes && e.shapes.length > 0) {
var coordinate;
const popupHtml = _this.popupElement.nativeElement.innerHTML;
var props = e.shapes[0].getProperties();
coordinate = e.shapes[0].getCoordinates();
_this.popup.setOptions({
//Update the content of the popup.
content: popupHtml,
//Update the popup's position with the symbol's coordinate.
position: coordinate
});
//Open the popup.
_this.popup.open(_this.map);
}
});
this.map.events.add('mouseleave', this.symbolLayer, (e) => {
this.popup.close()
});
}
});
}
private addMarkers(): void {
const html = this.marker.nativeElement.innerHTML;
this.locations.forEach(l => {
const point = new atlas.Shape( new atlas.data.Point([l.longitude, l.latitude]));
this.dataSource.add(point);
});
}
}
и пример его использования здесь:
<h1>Account Coverage</h1>
<div class="map-wrapper col-12">
<az-map [mapConfig]="mapConfig" [locations]="locations" class="col-12 h-50">
<coverage-popup popupTemplate></coverage-popup>
</az-map>
</div>
Это работает и показывает всплывающее окно, но мне нужно найти способ передачи данных в CoveragePopupComponent в событии mouseover в az-maps.component.ts
Один метод, который мы пытались использовать, который работает хорошо, когда у вас есть только один тип всплывающих окон, который должен быть обработан, - это использование ComponentFactoryResolver следующим образом:
const factory = this.componentFactoryResolver.resolveComponentFactory(PopupComponent);
const component = factory.create(this.injector);
component.instance.machine = shape.getProperties();
component.changeDetectorRef.detectChanges();
const popupContent = component.location.nativeElement;
this.map.setCamera({
center: shape.getCoordinates(),
type: 'ease',
});
this.popup.setOptions({
position: shape.getCoordinates(),
content: popupContent,
pixelOffset: [0, -20]
});
this.popup.open(this.map);
но тогда вы всегда должны использовать тип PopupComponent и не можете использовать материал ng-content, который мы имеем в шаблоне карты.