UNPKG

@babluroy/agm-snazzy-info-window

Version:

Angular Google Maps (AGM) extension for Snazzy Info Window

290 lines (252 loc) 8.61 kB
import { AgmMarker, GoogleMapsAPIWrapper, MapsAPILoader, MarkerManager } from '@babluroy/agm-core'; import { AfterViewInit, Component, ContentChild, ElementRef, EventEmitter, Host, Input, OnChanges, OnDestroy, Optional, Output, SimpleChanges, SkipSelf, TemplateRef, ViewChild, ViewContainerRef } from '@angular/core'; declare var require: any; @Component({ // tslint:disable-next-line:component-selector selector: 'agm-snazzy-info-window', standalone: true, template: '<div #outerWrapper><div #viewContainer></div></div><ng-content></ng-content>', }) export class AgmSnazzyInfoWindow implements AfterViewInit, OnDestroy, OnChanges { /** * The latitude and longitude where the info window is anchored. * The offset will default to 0px when using this option. Only required/used if you are not using a agm-marker. */ @Input() latitude!: number; /** * The longitude where the info window is anchored. * The offset will default to 0px when using this option. Only required/used if you are not using a agm-marker. */ @Input() longitude!: number; /** * Changes the open status of the snazzy info window. */ @Input() isOpen = false; /** * Emits when the open status changes. */ @Output() isOpenChange: EventEmitter<boolean> = new EventEmitter<boolean>(); /** * Choose where you want the info window to be displayed, relative to the marker. */ @Input() placement: 'top' | 'bottom' | 'left' | 'right' = 'top'; /** * The max width in pixels of the info window. */ @Input() maxWidth: number | string = 200; /** * The max height in pixels of the info window. */ @Input() maxHeight: number | string = 200; /** * The color to use for the background of the info window. */ @Input() backgroundColor!: string; /** * A custom padding size around the content of the info window. */ @Input() padding!: string; /** * A custom border around the info window. Set to false to completely remove the border. * The units used for border should be the same as pointer. */ @Input() border!: {width: string; color: string} | boolean; /** * A custom CSS border radius property to specify the rounded corners of the info window. */ @Input() borderRadius!: string; /** * The font color to use for the content inside the body of the info window. */ @Input() fontColor!: string; /** * The font size to use for the content inside the body of the info window. */ @Input() fontSize!: string; /** * The height of the pointer from the info window to the marker. * Set to false to completely remove the pointer. * The units used for pointer should be the same as border. */ @Input() pointer!: string | boolean; /** * The CSS properties for the shadow of the info window. * Set to false to completely remove the shadow. */ @Input() shadow!: boolean | {h?: string, v?: string, blur: string, spread: string, opacity: number, color: string}; /** * Determines if the info window will open when the marker is clicked. * An internal listener is added to the Google Maps click event which calls the open() method. */ @Input() openOnMarkerClick = true; /** * Determines if the info window will close when the map is clicked. An internal listener is added to * the Google Maps click event which calls the close() method. * This will not activate on the Google Maps drag event when the user is panning the map. */ @Input() closeOnMapClick = true; /** * An optional CSS class to assign to the wrapper container of the info window. * Can be used for applying custom CSS to the info window. */ @Input() wrapperClass!: string; /** * Determines if the info window will close when any other Snazzy Info Window is opened. */ @Input() closeWhenOthersOpen = false; /** * Determines if the info window will show a close button. */ @Input() showCloseButton = true; /** * Determines if the info window will be panned into view when opened. */ @Input() panOnOpen = true; /** * Emits before the info window opens. */ @Output() beforeOpen: EventEmitter<void> = new EventEmitter<void>(); /** * Emits before the info window closes. */ @Output() afterClose: EventEmitter<void> = new EventEmitter<void>(); /** * @internal */ @ViewChild('outerWrapper', {read: ElementRef, static: false}) _outerWrapper!: ElementRef; /** * @internal */ @ViewChild('viewContainer', {read: ViewContainerRef, static: false}) _viewContainerRef!: ViewContainerRef; /** * @internal */ @ContentChild(TemplateRef, {static: false}) _templateRef!: TemplateRef<any>; protected _nativeSnazzyInfoWindow: any; protected _snazzyInfoWindowInitialized: Promise<any> | null = null; constructor( @Optional() @Host() @SkipSelf() private _marker: AgmMarker, private _wrapper: GoogleMapsAPIWrapper, private _manager: MarkerManager, private _loader: MapsAPILoader, ) {} /** * @internal */ ngOnChanges(changes: SimpleChanges) { if (this._nativeSnazzyInfoWindow == null) { return; } if ('isOpen' in changes && this.isOpen) { this._openInfoWindow(); } else if ('isOpen' in changes && !this.isOpen) { this._closeInfoWindow(); } if (('latitude' in changes || 'longitude' in changes) && this._marker == null) { this._updatePosition(); } } /** * @internal */ ngAfterViewInit() { const m = this._manager != null ? this._manager.getNativeMarker(this._marker) : null; this._snazzyInfoWindowInitialized = this._loader.load() .then(() => require('snazzy-info-window')) .then((module: any) => Promise.all([module, m, this._wrapper.getNativeMap()])) .then((elems) => { const options: any = { map: elems[2], content: '', placement: this.placement, maxWidth: this.maxWidth, maxHeight: this.maxHeight, backgroundColor: this.backgroundColor, padding: this.padding, border: this.border, borderRadius: this.borderRadius, fontColor: this.fontColor, pointer: this.pointer, shadow: this.shadow, closeOnMapClick: this.closeOnMapClick, openOnMarkerClick: this.openOnMarkerClick, closeWhenOthersOpen: this.closeWhenOthersOpen, showCloseButton: this.showCloseButton, panOnOpen: this.panOnOpen, wrapperClass: this.wrapperClass, callbacks: { beforeOpen: () => { this._createViewContent(); this.beforeOpen.emit(); }, afterOpen: () => { this.isOpenChange.emit(this.openStatus()); }, afterClose: () => { this.afterClose.emit(); this.isOpenChange.emit(this.openStatus()); }, }, }; if (elems[1] != null) { options.marker = elems[1]; } else { options.position = { lat: this.latitude, lng: this.longitude, }; } this._nativeSnazzyInfoWindow = new elems[0](options); }); this._snazzyInfoWindowInitialized.then(() => { if (this.isOpen) { this._openInfoWindow(); } }); } protected _openInfoWindow() { if (this._snazzyInfoWindowInitialized) { this._snazzyInfoWindowInitialized.then(() => { this._nativeSnazzyInfoWindow.open(); }); } } protected _closeInfoWindow() { if (this._snazzyInfoWindowInitialized) { this._snazzyInfoWindowInitialized.then(() => { this._nativeSnazzyInfoWindow.close(); }); } } protected _createViewContent() { if (this._viewContainerRef.length === 1) { return; } const evr = this._viewContainerRef.createEmbeddedView(this._templateRef); this._nativeSnazzyInfoWindow.setContent(this._outerWrapper.nativeElement); // we have to run this in a separate cycle. setTimeout(() => { evr.detectChanges(); }); } protected _updatePosition() { this._nativeSnazzyInfoWindow.setPosition({ lat: this.latitude, lng: this.longitude, }); } /** * Returns true when the Snazzy Info Window is initialized and open. */ openStatus(): boolean { return this._nativeSnazzyInfoWindow && this._nativeSnazzyInfoWindow.isOpen(); } /** * @internal */ ngOnDestroy() { if (this._nativeSnazzyInfoWindow) { this._nativeSnazzyInfoWindow.destroy(); } } }