From c417d82226b90a63568f025daa2378ebc808863b Mon Sep 17 00:00:00 2001 From: Wykks Date: Fri, 11 May 2018 19:02:02 +0200 Subject: [PATCH] feat(popup): add open event (from mapbox-gl v0.45.0) Also refactor a bit PopupComponent --- src/app/lib/map/map.service.ts | 50 +++++++++++++++++++++++- src/app/lib/popup/popup.component.ts | 57 ++++++++++++++++------------ 2 files changed, 81 insertions(+), 26 deletions(-) diff --git a/src/app/lib/map/map.service.ts b/src/app/lib/map/map.service.ts index bbd66b718..293cb2f0b 100644 --- a/src/app/lib/map/map.service.ts +++ b/src/app/lib/map/map.service.ts @@ -31,6 +31,14 @@ export interface SetupLayer { }; } +export interface SetupPopup { + popupOptions: MapboxGl.PopupOptions; + popupEvents: { + open: EventEmitter; + close: EventEmitter; + }; +} + export type AllSource = MapboxGl.VectorSource | MapboxGl.RasterSource | MapboxGl.GeoJSONSource | @@ -249,16 +257,54 @@ export class MapService { this.markersToRemove.push(marker); } - addPopup(popup: MapboxGl.Popup) { + createPopup(popup: SetupPopup, element: Node) { + return this.zone.runOutsideAngular(() => { + Object.keys(popup.popupOptions) + .forEach((key) => + (popup.popupOptions)[key] === undefined && delete (popup.popupOptions)[key]); + const popupInstance = new MapboxGl.Popup(popup.popupOptions); + popupInstance.setDOMContent(element); + if (popup.popupEvents.close.observers.length) { + popupInstance.on('close', () => { + this.zone.run(() => { + popup.popupEvents.close.emit(); + }); + }); + } + if (popup.popupEvents.open.observers.length) { + popupInstance.on('open', () => { + this.zone.run(() => { + popup.popupEvents.open.emit(); + }); + }); + } + return popupInstance; + }); + } + + addPopupToMap(popup: MapboxGl.Popup, lngLat: MapboxGl.LngLatLike) { return this.zone.runOutsideAngular(() => { + popup.setLngLat(lngLat); popup.addTo(this.mapInstance); }); } - removePopup(popup: MapboxGl.Popup) { + addPopupToMarker(marker: MapboxGl.Marker, popup: MapboxGl.Popup) { + return this.zone.runOutsideAngular(() => { + marker.setPopup(popup); + }); + } + + removePopupFromMap(popup: MapboxGl.Popup) { this.popupsToRemove.push(popup); } + removePopupFromMarker(marker: MapboxGl.Marker) { + return this.zone.runOutsideAngular(() => { + marker.setPopup(undefined); + }); + } + addControl(control: MapboxGl.Control | MapboxGl.IControl, position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left') { return this.zone.runOutsideAngular(() => { this.mapInstance.addControl(control, position); diff --git a/src/app/lib/popup/popup.component.ts b/src/app/lib/popup/popup.component.ts index 36698ba6d..bb811a2c4 100644 --- a/src/app/lib/popup/popup.component.ts +++ b/src/app/lib/popup/popup.component.ts @@ -33,6 +33,7 @@ export class PopupComponent implements OnChanges, OnDestroy, AfterViewInit, OnIn @Input() marker?: MarkerComponent; @Output() close = new EventEmitter(); + @Output() open = new EventEmitter(); @ViewChild('content') content: ElementRef; @@ -50,54 +51,62 @@ export class PopupComponent implements OnChanges, OnDestroy, AfterViewInit, OnIn ngOnChanges(changes: SimpleChanges) { if (changes.lngLat && !changes.lngLat.isFirstChange()) { - this.MapService.removePopup(this.popupInstance!); + this.MapService.removePopupFromMap(this.popupInstance!); const popupInstanceTmp = this.createPopup(); - this.MapService.addPopup(popupInstanceTmp); + this.MapService.addPopupToMap(popupInstanceTmp, changes.lngLat.currentValue); this.popupInstance = popupInstanceTmp; } if (changes.marker && !changes.marker.isFirstChange()) { const previousMarker: MarkerComponent = changes.marker.previousValue; if (previousMarker.markerInstance) { - previousMarker.markerInstance.setPopup(undefined); + this.MapService.removePopupFromMarker(previousMarker.markerInstance); } - if (this.marker && this.marker.markerInstance) { - this.marker.markerInstance.setPopup(this.popupInstance); + if (this.marker && this.marker.markerInstance && this.popupInstance) { + this.MapService.addPopupToMarker(this.marker.markerInstance, this.popupInstance); } } } ngAfterViewInit() { this.popupInstance = this.createPopup(); + this.addPopup(this.popupInstance); } ngOnDestroy() { - this.MapService.removePopup(this.popupInstance!); + if (this.popupInstance) { + if (this.lngLat) { + this.MapService.removePopupFromMap(this.popupInstance); + } else if (this.marker && this.marker.markerInstance) { + this.MapService.removePopupFromMarker(this.marker.markerInstance); + } + } this.popupInstance = undefined; } private createPopup() { - const options = { - closeButton: this.closeButton, - closeOnClick: this.closeOnClick, - anchor: this.anchor, - offset: this.offset - }; - Object.keys(options) - .forEach((key) => - (options)[key] === undefined && delete (options)[key]); - const popupInstance = new Popup(options); - popupInstance.once('close', () => { - this.close.emit(); - }); - popupInstance.setDOMContent(this.content.nativeElement); + return this.MapService.createPopup({ + popupOptions: { + closeButton: this.closeButton, + closeOnClick: this.closeOnClick, + anchor: this.anchor, + offset: this.offset + }, + popupEvents: { + open: this.open, + close: this.close + } + }, this.content.nativeElement); + } + + private addPopup(popup: Popup) { this.MapService.mapCreated$.subscribe(() => { if (this.lngLat) { - popupInstance.setLngLat(this.lngLat); - this.MapService.addPopup(popupInstance); + this.MapService.addPopupToMap(popup, this.lngLat); } else if (this.marker && this.marker.markerInstance) { - this.marker.markerInstance.setPopup(popupInstance); + this.MapService.addPopupToMarker(this.marker.markerInstance, popup); + } else { + throw new Error('mgl-popup need either lngLat or marker to be set'); } }); - return popupInstance; } }