UNPKG

ng-agm-core-lib

Version:
1,288 lines (1,271 loc) 173 kB
import * as i0 from '@angular/core'; import { Injectable, InjectionToken, LOCALE_ID, Optional, Inject, Directive, Input, EventEmitter, Output, Self, Component, PLATFORM_ID, ContentChildren, QueryList, forwardRef, NgModule } from '@angular/core'; import { Observable, BehaviorSubject, from, timer, ReplaySubject, bindCallback, of, throwError, fromEventPattern, merge, Subject } from 'rxjs'; import { flatMap, sample, switchMap, map, shareReplay, multicast, startWith, skip, distinctUntilChanged, takeUntil } from 'rxjs/operators'; import { isPlatformServer } from '@angular/common'; class MapsAPILoader { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MapsAPILoader, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MapsAPILoader }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MapsAPILoader, decorators: [{ type: Injectable }] }); /** * Wrapper class that handles the communication with the Google Maps Javascript * API v3 */ class GoogleMapsAPIWrapper { _loader; _zone; _map; _mapResolver; constructor(_loader, _zone) { this._loader = _loader; this._zone = _zone; this._map = new Promise((resolve) => { this._mapResolver = resolve; }); } createMap(el, mapOptions) { return this._zone.runOutsideAngular(() => { return this._loader.load().then(() => { const map = new google.maps.Map(el, mapOptions); this._mapResolver(map); return; }); }); } setMapOptions(options) { return this._zone.runOutsideAngular(() => { this._map.then((m) => { m.setOptions(options); }); }); } /** * Creates a google map marker with the map context */ createMarker(options = {}, addToMap = true) { return this._zone.runOutsideAngular(() => { return this._map.then((map) => { if (addToMap) { options.map = map; } return new google.maps.Marker(options); }); }); } createInfoWindow(options) { return this._zone.runOutsideAngular(() => { return this._map.then(() => new google.maps.InfoWindow(options)); }); } /** * Creates a google.map.Circle for the current map. */ createCircle(options) { return this._zone.runOutsideAngular(() => { return this._map.then((map) => { options.map = map; return new google.maps.Circle(options); }); }); } /** * Creates a google.map.Rectangle for the current map. */ createRectangle(options) { return this._zone.runOutsideAngular(() => { return this._map.then((map) => { options.map = map; return new google.maps.Rectangle(options); }); }); } createPolyline(options) { return this._zone.runOutsideAngular(() => { return this.getNativeMap().then((map) => { const line = new google.maps.Polyline(options); line.setMap(map); return line; }); }); } createPolygon(options) { return this._zone.runOutsideAngular(() => { return this.getNativeMap().then((map) => { const polygon = new google.maps.Polygon(options); polygon.setMap(map); return polygon; }); }); } /** * Creates a new google.map.Data layer for the current map */ createDataLayer(options) { return this._zone.runOutsideAngular(() => { return this._map.then(m => { const data = new google.maps.Data(options); data.setMap(m); return data; }); }); } /** * Creates a TransitLayer instance for a map * @returns a new transit layer object */ createTransitLayer() { return this._zone.runOutsideAngular(() => { return this._map.then((map) => { const newLayer = new google.maps.TransitLayer(); newLayer.setMap(map); return newLayer; }); }); } /** * Creates a BicyclingLayer instance for a map * @returns a new bicycling layer object */ createBicyclingLayer() { return this._zone.runOutsideAngular(() => { return this._map.then((map) => { const newLayer = new google.maps.BicyclingLayer(); newLayer.setMap(map); return newLayer; }); }); } /** * Determines if given coordinates are insite a Polygon path. */ containsLocation(latLng, polygon) { return this._map.then(() => google.maps.geometry.poly.containsLocation(latLng, polygon)); } subscribeToMapEvent(eventName) { return new Observable((observer) => { this._map.then(m => m.addListener(eventName, (...evArgs) => this._zone.run(() => observer.next(evArgs)))); }); } clearInstanceListeners() { return this._zone.runOutsideAngular(() => { this._map.then((map) => { google.maps.event.clearInstanceListeners(map); }); }); } setCenter(latLng) { return this._zone.runOutsideAngular(() => { return this._map.then((map) => map.setCenter(latLng)); }); } getZoom() { return this._zone.runOutsideAngular(() => { return this._map.then((map) => map.getZoom()); }); } getBounds() { return this._zone.runOutsideAngular(() => { return this._map.then((map) => map.getBounds()); }); } getMapTypeId() { return this._zone.runOutsideAngular(() => { return this._map.then((map) => map.getMapTypeId()); }); } setZoom(zoom) { return this._zone.runOutsideAngular(() => { return this._map.then((map) => map.setZoom(zoom)); }); } getCenter() { return this._zone.runOutsideAngular(() => { return this._map.then((map) => map.getCenter()); }); } panTo(latLng) { return this._zone.runOutsideAngular(() => { return this._map.then((map) => map.panTo(latLng)); }); } panBy(x, y) { return this._zone.runOutsideAngular(() => { return this._map.then((map) => map.panBy(x, y)); }); } fitBounds(latLng, padding) { return this._zone.runOutsideAngular(() => { return this._map.then((map) => map.fitBounds(latLng, padding)); }); } panToBounds(latLng, padding) { return this._zone.runOutsideAngular(() => { return this._map.then((map) => map.panToBounds(latLng, padding)); }); } /** * Returns the native Google Maps Map instance. Be careful when using this instance directly. */ getNativeMap() { return this._map; } /** * Triggers the given event name on the map instance. */ triggerMapEvent(eventName) { return this._map.then((m) => google.maps.event.trigger(m, eventName)); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: GoogleMapsAPIWrapper, deps: [{ token: MapsAPILoader }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: GoogleMapsAPIWrapper }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: GoogleMapsAPIWrapper, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: MapsAPILoader }, { type: i0.NgZone }] }); class CircleManager { _apiWrapper; _zone; _circles = new Map(); constructor(_apiWrapper, _zone) { this._apiWrapper = _apiWrapper; this._zone = _zone; } addCircle(circle) { this._circles.set(circle, this._apiWrapper.getNativeMap().then(() => this._apiWrapper.createCircle({ center: { lat: circle.latitude, lng: circle.longitude }, clickable: circle.clickable, draggable: circle.draggable, editable: circle.editable, fillColor: circle.fillColor, fillOpacity: circle.fillOpacity, radius: circle.radius, strokeColor: circle.strokeColor, strokeOpacity: circle.strokeOpacity, strokePosition: google.maps.StrokePosition[circle.strokePosition], strokeWeight: circle.strokeWeight, visible: circle.visible, zIndex: circle.zIndex, }))); } /** * Removes the given circle from the map. */ removeCircle(circle) { return this._circles.get(circle).then((c) => { c.setMap(null); this._circles.delete(circle); }); } async setOptions(circle, options) { return this._circles.get(circle).then((c) => { const actualParam = options.strokePosition; options.strokePosition = google.maps.StrokePosition[actualParam]; c.setOptions(options); }); } getBounds(circle) { return this._circles.get(circle).then((c) => c.getBounds()); } getCenter(circle) { return this._circles.get(circle).then((c) => c.getCenter()); } getRadius(circle) { return this._circles.get(circle).then((c) => c.getRadius()); } setCenter(circle) { return this._circles.get(circle).then(c => c.setCenter({ lat: circle.latitude, lng: circle.longitude })); } setEditable(circle) { return this._circles.get(circle).then(c => c.setEditable(circle.editable)); } setDraggable(circle) { return this._circles.get(circle).then(c => c.setDraggable(circle.draggable)); } setVisible(circle) { return this._circles.get(circle).then(c => c.setVisible(circle.visible)); } setRadius(circle) { return this._circles.get(circle).then(c => c.setRadius(circle.radius)); } getNativeCircle(circle) { return this._circles.get(circle); } createEventObservable(eventName, circle) { return new Observable((observer) => { let listener = null; this._circles.get(circle).then((c) => { listener = c.addListener(eventName, (e) => this._zone.run(() => observer.next(e))); }); return () => { if (listener !== null) { listener.remove(); } }; }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CircleManager, deps: [{ token: GoogleMapsAPIWrapper }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CircleManager }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CircleManager, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: GoogleMapsAPIWrapper }, { type: i0.NgZone }] }); /** * Manages all Data Layers for a Google Map instance. */ class DataLayerManager { _wrapper; _zone; _layers = new Map(); constructor(_wrapper, _zone) { this._wrapper = _wrapper; this._zone = _zone; } /** * Adds a new Data Layer to the map. */ addDataLayer(layer) { const newLayer = this._wrapper.createDataLayer({ style: layer.style, }) .then(d => { if (layer.geoJson) { // NOTE: accessing "features" on google.maps.Data is undocumented this.getDataFeatures(d, layer.geoJson).then(features => d.features = features); } return d; }); this._layers.set(layer, newLayer); } deleteDataLayer(layer) { this._layers.get(layer).then(l => { l.setMap(null); this._layers.delete(layer); }); } updateGeoJson(layer, geoJson) { this._layers.get(layer).then(l => { l.forEach(feature => { l.remove(feature); // NOTE: accessing "features" on google.maps.Data is undocumented const index = l.features.indexOf(feature, 0); if (index > -1) { l.features.splice(index, 1); } }); this.getDataFeatures(l, geoJson).then(features => l.features = features); }); } setDataOptions(layer, options) { this._layers.get(layer).then(l => { l.setControlPosition(options.controlPosition); l.setControls(options.controls); l.setDrawingMode(options.drawingMode); l.setStyle(options.style); }); } /** * Creates a Google Maps event listener for the given DataLayer as an Observable */ createEventObservable(eventName, layer) { return new Observable((observer) => { this._layers.get(layer).then((d) => { d.addListener(eventName, (e) => this._zone.run(() => observer.next(e))); }); }); } /** * Extract features from a geoJson using google.maps Data Class * @param d : google.maps.Data class instance * @param geoJson : url or geojson object */ getDataFeatures(d, geoJson) { return new Promise((resolve, reject) => { if (typeof geoJson === 'object') { try { const features = d.addGeoJson(geoJson); resolve(features); } catch (e) { reject(e); } } else if (typeof geoJson === 'string') { d.loadGeoJson(geoJson, null, resolve); } else { reject(`Impossible to extract features from geoJson: wrong argument type`); } }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DataLayerManager, deps: [{ token: GoogleMapsAPIWrapper }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DataLayerManager }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DataLayerManager, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: GoogleMapsAPIWrapper }, { type: i0.NgZone }] }); /** * Class to implement when you what to be able to make it work with the auto fit bounds feature * of AGM. */ class FitBoundsAccessor { } /** * The FitBoundsService is responsible for computing the bounds of the a single map. */ class FitBoundsService { bounds$; _boundsChangeSampleTime$ = new BehaviorSubject(200); _includeInBounds$ = new BehaviorSubject(new Map()); constructor(loader) { this.bounds$ = from(loader.load()).pipe(flatMap(() => this._includeInBounds$), sample(this._boundsChangeSampleTime$.pipe(switchMap(time => timer(0, time)))), map(includeInBounds => this._generateBounds(includeInBounds)), shareReplay(1)); } _generateBounds(includeInBounds) { const bounds = new google.maps.LatLngBounds(); includeInBounds.forEach(b => bounds.extend(b)); return bounds; } addToBounds(latLng) { const id = this._createIdentifier(latLng); if (this._includeInBounds$.value.has(id)) { return; } const boundsMap = this._includeInBounds$.value; boundsMap.set(id, latLng); this._includeInBounds$.next(boundsMap); } removeFromBounds(latLng) { const boundsMap = this._includeInBounds$.value; boundsMap.delete(this._createIdentifier(latLng)); this._includeInBounds$.next(boundsMap); } changeFitBoundsChangeSampleTime(timeMs) { this._boundsChangeSampleTime$.next(timeMs); } getBounds$() { return this.bounds$; } _createIdentifier(latLng) { return `${latLng.lat}+${latLng.lng}`; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FitBoundsService, deps: [{ token: MapsAPILoader }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FitBoundsService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FitBoundsService, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: MapsAPILoader }] }); class AgmGeocoder { geocoder$; constructor(loader) { const connectableGeocoder$ = new Observable(subscriber => { loader.load().then(() => subscriber.next()); }) .pipe(map(() => this._createGeocoder()), multicast(new ReplaySubject(1))); connectableGeocoder$.connect(); // ignore the subscription // since we will remain subscribed till application exits this.geocoder$ = connectableGeocoder$; } geocode(request) { return this.geocoder$.pipe(switchMap((geocoder) => this._getGoogleResults(geocoder, request))); } _getGoogleResults(geocoder, request) { const geocodeObservable = bindCallback(geocoder.geocode); return geocodeObservable(request).pipe(switchMap(([results, status]) => { if (status === google.maps.GeocoderStatus.OK) { return of(results); } return throwError(status); })); } _createGeocoder() { return new google.maps.Geocoder(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AgmGeocoder, deps: [{ token: MapsAPILoader }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AgmGeocoder, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AgmGeocoder, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: MapsAPILoader }] }); class WindowRef { getNativeWindow() { return window; } } class DocumentRef { getNativeDocument() { return document; } } const BROWSER_GLOBALS_PROVIDERS = [WindowRef, DocumentRef]; var GoogleMapsScriptProtocol; (function (GoogleMapsScriptProtocol) { GoogleMapsScriptProtocol[GoogleMapsScriptProtocol["HTTP"] = 1] = "HTTP"; GoogleMapsScriptProtocol[GoogleMapsScriptProtocol["HTTPS"] = 2] = "HTTPS"; GoogleMapsScriptProtocol[GoogleMapsScriptProtocol["AUTO"] = 3] = "AUTO"; })(GoogleMapsScriptProtocol || (GoogleMapsScriptProtocol = {})); /** * Token for the config of the LazyMapsAPILoader. Please provide an object of type {@link * LazyMapsAPILoaderConfig}. */ const LAZY_MAPS_API_CONFIG = new InjectionToken('angular-google-maps LAZY_MAPS_API_CONFIG'); class LazyMapsAPILoader extends MapsAPILoader { localeId; _scriptLoadingPromise; _config; _windowRef; _documentRef; _SCRIPT_ID = 'agmGoogleMapsApiScript'; callbackName = `agmLazyMapsAPILoader`; constructor(config = null, w, d, localeId) { super(); this.localeId = localeId; this._config = config || {}; this._windowRef = w; this._documentRef = d; } load() { const window = this._windowRef.getNativeWindow(); if (window.google && window.google.maps) { // Google maps already loaded on the page. return Promise.resolve(); } if (this._scriptLoadingPromise) { return this._scriptLoadingPromise; } // this can happen in HMR situations or Stackblitz.io editors. const scriptOnPage = this._documentRef.getNativeDocument().getElementById(this._SCRIPT_ID); if (scriptOnPage) { this._assignScriptLoadingPromise(scriptOnPage); return this._scriptLoadingPromise; } const script = this._documentRef.getNativeDocument().createElement('script'); script.type = 'text/javascript'; script.async = true; script.defer = true; script.id = this._SCRIPT_ID; script.src = this._getScriptSrc(this.callbackName); this._assignScriptLoadingPromise(script); this._documentRef.getNativeDocument().body.appendChild(script); return this._scriptLoadingPromise; } _assignScriptLoadingPromise(scriptElem) { this._scriptLoadingPromise = new Promise((resolve, reject) => { this._windowRef.getNativeWindow()[this.callbackName] = () => { resolve(); }; scriptElem.onerror = (error) => { reject(error); }; }); } _getScriptSrc(callbackName) { const protocolType = (this._config && this._config.protocol) || GoogleMapsScriptProtocol.HTTPS; let protocol; switch (protocolType) { case GoogleMapsScriptProtocol.AUTO: protocol = ''; break; case GoogleMapsScriptProtocol.HTTP: protocol = 'http:'; break; case GoogleMapsScriptProtocol.HTTPS: protocol = 'https:'; break; } const hostAndPath = this._config.hostAndPath || 'maps.googleapis.com/maps/api/js'; const queryParams = { v: this._config.apiVersion || 'quarterly', callback: callbackName, key: this._config.apiKey, client: this._config.clientId, channel: this._config.channel, libraries: this._config.libraries, region: this._config.region, language: this._config.language || (this.localeId !== 'en-US' ? this.localeId : null), }; const params = Object.keys(queryParams) .filter((k) => queryParams[k] != null) .filter((k) => { // remove empty arrays return !Array.isArray(queryParams[k]) || (Array.isArray(queryParams[k]) && queryParams[k].length > 0); }) .map((k) => { // join arrays as comma seperated strings const i = queryParams[k]; if (Array.isArray(i)) { return { key: k, value: i.join(',') }; } return { key: k, value: queryParams[k] }; }) .map((entry) => { return `${entry.key}=${entry.value}`; }) .join('&'); return `${protocol}//${hostAndPath}?${params}`; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LazyMapsAPILoader, deps: [{ token: LAZY_MAPS_API_CONFIG, optional: true }, { token: WindowRef }, { token: DocumentRef }, { token: LOCALE_ID }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LazyMapsAPILoader }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LazyMapsAPILoader, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [LAZY_MAPS_API_CONFIG] }] }, { type: WindowRef }, { type: DocumentRef }, { type: undefined, decorators: [{ type: Inject, args: [LOCALE_ID] }] }] }); class MarkerManager { _mapsWrapper; _zone; _markers = new Map(); constructor(_mapsWrapper, _zone) { this._mapsWrapper = _mapsWrapper; this._zone = _zone; } async convertAnimation(uiAnim) { if (uiAnim === null) { return null; } else { return this._mapsWrapper.getNativeMap().then(() => google.maps.Animation[uiAnim]); } } deleteMarker(markerDirective) { const markerPromise = this._markers.get(markerDirective); if (markerPromise == null) { // marker already deleted return Promise.resolve(); } return markerPromise.then((marker) => { return this._zone.run(() => { marker.setMap(null); this._markers.delete(markerDirective); }); }); } updateMarkerPosition(marker) { return this._markers.get(marker).then((m) => m.setPosition({ lat: marker.latitude, lng: marker.longitude })); } updateTitle(marker) { return this._markers.get(marker).then((m) => m.setTitle(marker.title)); } updateLabel(marker) { return this._markers.get(marker).then((m) => { m.setLabel(marker.label); }); } updateDraggable(marker) { return this._markers.get(marker).then((m) => m.setDraggable(marker.draggable)); } updateIcon(marker) { return this._markers.get(marker).then((m) => m.setIcon(marker.iconUrl)); } updateOpacity(marker) { return this._markers.get(marker).then((m) => m.setOpacity(marker.opacity)); } updateVisible(marker) { return this._markers.get(marker).then((m) => m.setVisible(marker.visible)); } updateZIndex(marker) { return this._markers.get(marker).then((m) => m.setZIndex(marker.zIndex)); } updateClickable(marker) { return this._markers.get(marker).then((m) => m.setClickable(marker.clickable)); } async updateAnimation(marker) { const m = await this._markers.get(marker); m.setAnimation(await this.convertAnimation(marker.animation)); } addMarker(marker) { const markerPromise = new Promise(async (resolve) => this._mapsWrapper.createMarker({ position: { lat: marker.latitude, lng: marker.longitude }, label: marker.label, draggable: marker.draggable, icon: marker.iconUrl, opacity: marker.opacity, visible: marker.visible, zIndex: marker.zIndex, title: marker.title, clickable: marker.clickable, animation: await this.convertAnimation(marker.animation), }).then(resolve)); this._markers.set(marker, markerPromise); } getNativeMarker(marker) { return this._markers.get(marker); } createEventObservable(eventName, marker) { return new Observable(observer => { this._markers.get(marker).then(m => m.addListener(eventName, e => this._zone.run(() => observer.next(e)))); }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MarkerManager, deps: [{ token: GoogleMapsAPIWrapper }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MarkerManager }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MarkerManager, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: GoogleMapsAPIWrapper }, { type: i0.NgZone }] }); class InfoWindowManager { _mapsWrapper; _zone; _markerManager; _infoWindows = new Map(); constructor(_mapsWrapper, _zone, _markerManager) { this._mapsWrapper = _mapsWrapper; this._zone = _zone; this._markerManager = _markerManager; } deleteInfoWindow(infoWindow) { const iWindow = this._infoWindows.get(infoWindow); if (iWindow == null) { // info window already deleted return Promise.resolve(); } return iWindow.then((i) => { return this._zone.run(() => { i.close(); this._infoWindows.delete(infoWindow); }); }); } setPosition(infoWindow) { return this._infoWindows.get(infoWindow).then((i) => i.setPosition({ lat: infoWindow.latitude, lng: infoWindow.longitude, })); } setZIndex(infoWindow) { return this._infoWindows.get(infoWindow) .then((i) => i.setZIndex(infoWindow.zIndex)); } open(infoWindow) { return this._infoWindows.get(infoWindow).then((w) => { if (infoWindow.hostMarker != null) { return this._markerManager.getNativeMarker(infoWindow.hostMarker).then((marker) => { return this._mapsWrapper.getNativeMap().then((map) => w.open(map, marker)); }); } return this._mapsWrapper.getNativeMap().then((map) => w.open(map)); }); } close(infoWindow) { return this._infoWindows.get(infoWindow).then((w) => w.close()); } setOptions(infoWindow, options) { return this._infoWindows.get(infoWindow).then((i) => i.setOptions(options)); } addInfoWindow(infoWindow) { const options = { content: infoWindow.content, maxWidth: infoWindow.maxWidth, zIndex: infoWindow.zIndex, disableAutoPan: infoWindow.disableAutoPan, }; if (typeof infoWindow.latitude === 'number' && typeof infoWindow.longitude === 'number') { options.position = { lat: infoWindow.latitude, lng: infoWindow.longitude }; } const infoWindowPromise = this._mapsWrapper.createInfoWindow(options); this._infoWindows.set(infoWindow, infoWindowPromise); } /** * Creates a Google Maps event listener for the given InfoWindow as an Observable */ createEventObservable(eventName, infoWindow) { return new Observable((observer) => { this._infoWindows.get(infoWindow).then((i) => { i.addListener(eventName, (e) => this._zone.run(() => observer.next(e))); }); }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: InfoWindowManager, deps: [{ token: GoogleMapsAPIWrapper }, { token: i0.NgZone }, { token: MarkerManager }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: InfoWindowManager }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: InfoWindowManager, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: GoogleMapsAPIWrapper }, { type: i0.NgZone }, { type: MarkerManager }] }); /** * Manages all KML Layers for a Google Map instance. */ class KmlLayerManager { _wrapper; _zone; _layers = new Map(); constructor(_wrapper, _zone) { this._wrapper = _wrapper; this._zone = _zone; } /** * Adds a new KML Layer to the map. */ addKmlLayer(layer) { const newLayer = this._wrapper.getNativeMap().then(m => { return new google.maps.KmlLayer({ clickable: layer.clickable, map: m, preserveViewport: layer.preserveViewport, screenOverlays: layer.screenOverlays, suppressInfoWindows: layer.suppressInfoWindows, url: layer.url, zIndex: layer.zIndex, }); }); this._layers.set(layer, newLayer); } setOptions(layer, options) { this._layers.get(layer).then(l => l.setOptions(options)); } deleteKmlLayer(layer) { this._layers.get(layer).then(l => { l.setMap(null); this._layers.delete(layer); }); } /** * Creates a Google Maps event listener for the given KmlLayer as an Observable */ createEventObservable(eventName, layer) { return new Observable((observer) => { this._layers.get(layer).then((m) => { m.addListener(eventName, (e) => this._zone.run(() => observer.next(e))); }); }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: KmlLayerManager, deps: [{ token: GoogleMapsAPIWrapper }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: KmlLayerManager }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: KmlLayerManager, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: GoogleMapsAPIWrapper }, { type: i0.NgZone }] }); /** * This class manages Transit and Bicycling Layers for a Google Map instance. */ class LayerManager { _wrapper; _layers = new Map(); constructor(_wrapper) { this._wrapper = _wrapper; } /** * Adds a transit layer to a map instance. * @param layer - a TransitLayer object * @param _options - TransitLayerOptions options * @returns void */ addTransitLayer(layer) { const newLayer = this._wrapper.createTransitLayer(); this._layers.set(layer, newLayer); } /** * Adds a bicycling layer to a map instance. * @param layer - a bicycling layer object * @param _options - BicyclingLayer options * @returns void */ addBicyclingLayer(layer) { const newLayer = this._wrapper.createBicyclingLayer(); this._layers.set(layer, newLayer); } /** * Deletes a map layer * @param layer - the layer to delete */ deleteLayer(layer) { return this._layers.get(layer).then(currentLayer => { currentLayer.setMap(null); this._layers.delete(layer); }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LayerManager, deps: [{ token: GoogleMapsAPIWrapper }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LayerManager }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LayerManager, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: GoogleMapsAPIWrapper }] }); /** * When using the NoOpMapsAPILoader, the Google Maps API must be added to the page via a `<script>` * Tag. * It's important that the Google Maps API script gets loaded first on the page. */ class NoOpMapsAPILoader { load() { if (!window.google || !window.google.maps) { throw new Error('Google Maps API not loaded on page. Make sure window.google.maps is available!'); } return Promise.resolve(); } } function createMVCEventObservable(array) { const eventNames = ['insert_at', 'remove_at', 'set_at']; return fromEventPattern(handler => eventNames.map(eventName => array.addListener(eventName, (index, previous) => handler.apply(array, [{ newArr: array.getArray(), eventName, index, previous }]))), (_handler, evListeners) => evListeners.forEach(evListener => evListener.remove())); } class MvcArrayMock { vals = []; listeners = { remove_at: [], insert_at: [], set_at: [], }; clear() { for (let i = this.vals.length - 1; i >= 0; i--) { this.removeAt(i); } } getArray() { return [...this.vals]; } getAt(i) { return this.vals[i]; } getLength() { return this.vals.length; } insertAt(i, elem) { this.vals.splice(i, 0, elem); this.listeners.insert_at.forEach(listener => listener(i)); } pop() { const deleted = this.vals.pop(); this.listeners.remove_at.forEach(listener => listener(this.vals.length, deleted)); return deleted; } push(elem) { this.vals.push(elem); this.listeners.insert_at.forEach(listener => listener(this.vals.length - 1)); return this.vals.length; } removeAt(i) { const deleted = this.vals.splice(i, 1)[0]; this.listeners.remove_at.forEach(listener => listener(i, deleted)); return deleted; } setAt(i, elem) { const deleted = this.vals[i]; this.vals[i] = elem; this.listeners.set_at.forEach(listener => listener(i, deleted)); } forEach(callback) { this.vals.forEach(callback); } addListener(eventName, handler) { const listenerArr = this.listeners[eventName]; listenerArr.push(handler); return { remove: () => { listenerArr.splice(listenerArr.indexOf(handler), 1); }, }; } bindTo() { throw new Error('Not implemented'); } changed() { throw new Error('Not implemented'); } get() { throw new Error('Not implemented'); } notify() { throw new Error('Not implemented'); } set() { throw new Error('Not implemented'); } setValues() { throw new Error('Not implemented'); } unbind() { throw new Error('Not implemented'); } unbindAll() { throw new Error('Not implemented'); } } class PolygonManager { _mapsWrapper; _zone; _polygons = new Map(); constructor(_mapsWrapper, _zone) { this._mapsWrapper = _mapsWrapper; this._zone = _zone; } addPolygon(path) { const polygonPromise = this._mapsWrapper.createPolygon({ clickable: path.clickable, draggable: path.draggable, editable: path.editable, fillColor: path.fillColor, fillOpacity: path.fillOpacity, geodesic: path.geodesic, paths: path.paths, strokeColor: path.strokeColor, strokeOpacity: path.strokeOpacity, strokeWeight: path.strokeWeight, visible: path.visible, zIndex: path.zIndex, }); this._polygons.set(path, polygonPromise); } updatePolygon(polygon) { const m = this._polygons.get(polygon); if (m == null) { return Promise.resolve(); } return m.then((l) => this._zone.run(() => { l.setPaths(polygon.paths); })); } setPolygonOptions(path, options) { return this._polygons.get(path).then((l) => { l.setOptions(options); }); } deletePolygon(paths) { const m = this._polygons.get(paths); if (m == null) { return Promise.resolve(); } return m.then((l) => { return this._zone.run(() => { l.setMap(null); this._polygons.delete(paths); }); }); } getPath(polygonDirective) { return this._polygons.get(polygonDirective) .then((polygon) => polygon.getPath().getArray()); } getPaths(polygonDirective) { return this._polygons.get(polygonDirective) .then((polygon) => polygon.getPaths().getArray().map((p) => p.getArray())); } createEventObservable(eventName, path) { return new Observable((observer) => { this._polygons.get(path).then((l) => { l.addListener(eventName, (e) => this._zone.run(() => observer.next(e))); }); }); } async createPathEventObservable(agmPolygon) { const polygon = await this._polygons.get(agmPolygon); const paths = polygon.getPaths(); const pathsChanges$ = createMVCEventObservable(paths); return pathsChanges$.pipe(startWith({ newArr: paths.getArray() }), // in order to subscribe to them all switchMap(parentMVEvent => merge(... // rest parameter parentMVEvent.newArr.map((chMVC, index) => createMVCEventObservable(chMVC) .pipe(map(chMVCEvent => ({ parentMVEvent, chMVCEvent, pathIndex: index }))))) .pipe(// start the merged ob with an event signinifing change to parent startWith({ parentMVEvent, chMVCEvent: null, pathIndex: null }))), skip(1), // skip the manually added event map(({ parentMVEvent, chMVCEvent, pathIndex }) => { let retVal; if (!chMVCEvent) { retVal = { newArr: parentMVEvent.newArr.map(subArr => subArr.getArray().map(latLng => latLng.toJSON())), eventName: parentMVEvent.eventName, index: parentMVEvent.index, }; if (parentMVEvent.previous) { retVal.previous = parentMVEvent.previous.getArray(); } } else { retVal = { newArr: parentMVEvent.newArr.map(subArr => subArr.getArray().map(latLng => latLng.toJSON())), pathIndex, eventName: chMVCEvent.eventName, index: chMVCEvent.index, }; if (chMVCEvent.previous) { retVal.previous = chMVCEvent.previous; } } return retVal; })); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PolygonManager, deps: [{ token: GoogleMapsAPIWrapper }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PolygonManager }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PolygonManager, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: GoogleMapsAPIWrapper }, { type: i0.NgZone }] }); class PolylineManager { _mapsWrapper; _zone; _polylines = new Map(); constructor(_mapsWrapper, _zone) { this._mapsWrapper = _mapsWrapper; this._zone = _zone; } static _convertPoints(line) { const path = line._getPoints().map((point) => { return { lat: point.latitude, lng: point.longitude }; }); return path; } static _convertPath(path) { const symbolPath = google.maps.SymbolPath[path]; if (typeof symbolPath === 'number') { return symbolPath; } else { return path; } } static _convertIcons(line) { const icons = line._getIcons().map(agmIcon => ({ fixedRotation: agmIcon.fixedRotation, offset: agmIcon.offset, repeat: agmIcon.repeat, icon: { anchor: new google.maps.Point(agmIcon.anchorX, agmIcon.anchorY), fillColor: agmIcon.fillColor, fillOpacity: agmIcon.fillOpacity, path: PolylineManager._convertPath(agmIcon.path), rotation: agmIcon.rotation, scale: agmIcon.scale, strokeColor: agmIcon.strokeColor, strokeOpacity: agmIcon.strokeOpacity, strokeWeight: agmIcon.strokeWeight, }, })); // prune undefineds; icons.forEach(icon => { Object.entries(icon).forEach(([key, val]) => { if (typeof val === 'undefined') { delete icon[key]; } }); if (typeof icon.icon.anchor.x === 'undefined' || typeof icon.icon.anchor.y === 'undefined') { delete icon.icon.anchor; } }); return icons; } addPolyline(line) { const polylinePromise = this._mapsWrapper.getNativeMap() .then(() => [PolylineManager._convertPoints(line), PolylineManager._convertIcons(line)]) .then(([path, icons]) => this._mapsWrapper.createPolyline({ clickable: line.clickable, draggable: line.draggable, editable: line.editable, geodesic: line.geodesic, strokeColor: line.strokeColor, strokeOpacity: line.strokeOpacity, strokeWeight: line.strokeWeight, visible: line.visible, zIndex: line.zIndex, path, icons, })); this._polylines.set(line, polylinePromise); } updatePolylinePoints(line) { const path = PolylineManager._convertPoints(line); const m = this._polylines.get(line); if (m == null) { return Promise.resolve(); } return m.then((l) => this._zone.run(() => l.setPath(path))); } async updateIconSequences(line) { await this._mapsWrapper.getNativeMap(); const icons = PolylineManager._convertIcons(line); const m = this._polylines.get(line); if (m == null) { return; } return m.then(l => this._zone.run(() => l.setOptions({ icons }))); } setPolylineOptions(line, options) { return this._polylines.get(line).then((l) => { l.setOptions(options); }); } deletePolyline(line) { const m = this._polylines.get(line); if (m == null) { return Promise.resolve(); } return m.then((l) => { return this._zone.run(() => { l.setMap(null); this._polylines.delete(line); }); }); } async getMVCPath(agmPolyline) { const polyline = await this._polylines.get(agmPolyline); return polyline.getPath(); } async getPath(agmPolyline) { return (await this.getMVCPath(agmPolyline)).getArray(); } createEventObservable(eventName, line) { return new Observable((observer) => { this._polylines.get(line).then((l) => { l.addListener(eventName, (e) => this._zone.run(() => observer.next(e))); }); }); } async createPathEventObservable(line) { const mvcPath = await this.getMVCPath(line); return createMVCEventObservable(mvcPath); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PolylineManager, deps: [{ token: GoogleMapsAPIWrapper }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PolylineManager }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PolylineManager, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: GoogleMapsAPIWrapper }, { type: i0.NgZone }] }); class RectangleManager { _apiWrapper; _zone; _rectangles = new Map(); constructor(_apiWrapper, _zone) { this._apiWrapper = _apiWrapper; this._zone = _zone; } addRectangle(rectangle) { this._rectangles.set(rectangle, this._apiWrapper.getNativeMap().then(() => this._apiWrapper.createRectangle({ bounds: { north: rectangle.north, east: rectangle.east, south: rectangle.south, west: rectangle.west, }, clickable: rectangle.clickable, draggable: rectangle.draggable, editable: rectangle.editable, fillColor: rectangle.fillColor, fillOpacity: rectangle.fillOpacity, strokeColor: rectangle.strokeColor, strokeOpacity: rectangle.strokeOpacity, strokePosition: google.maps.StrokePosition[rectangle.strokePosition], strokeWeight: rectangle.strokeWeight, visible: rectangle.visible, zIndex: rectangle.zIndex, }))); } /** * Removes the given rectangle from the map. */ removeRectangle(rectangle) { return this._rectangles.get(rectangle).then((r) => { r.setMap(null); this._rectangles.delete(rectangle); }); } setOptions(rectangle, options) { return this._rectangles.get(rectangle).then((r) => { const actualStrokePosition = options.strokePosition; options.strokePosition = google.maps.StrokePosition[actualStrokePosition]; r.setOptions(options); }); } getBounds(rectangle) { return this._rectangles.get(rectangle).then((r) => r.getBounds()); } setBounds(rectangle) { return this._rectangles.get(rectangle).then((r) => { return r.setBounds({ north: rectangle.north, east: rectangle.east, south: rectangle.south, west: rectangle.west, }); }); } setEditable(rectangle) { return this._rectangles.get(rectangle).then((r) => { return r.setEditable(rectangle.editable); }); } setDraggable(rectangle) { return this._rectangles.get(rectangle).then((r) => { return r.setDraggable(rectangle.draggable); }); } setVisible(rectangle) { return this._rectangles.get(rectangle).then((r) => { return r.setVisible(rectangle.visible); }); } createEventObservable(eventName, rectangle) { return new Observable((subsrciber) => { let listener = null; this._rectangles.get(rectangle)