UNPKG

@ng-maps/core

Version:

**@ng-maps/core** is a simple, modular and tree-shakable library for displaying google-maps inside an angular application

2,504 lines 99.7 kB
import * as i0 from '@angular/core';
import { Injectable, EventEmitter, Component, Input, Output, ViewChild, QueryList, forwardRef, ContentChildren, Directive, Self, Inject, InjectionToken, NgModule } from '@angular/core';
import { BehaviorSubject, from, timer, Subscription, ReplaySubject } from 'rxjs';
import { mergeMap, sample, switchMap, map, shareReplay, distinctUntilChanged } from 'rxjs/operators';
import { __decorate, __param, __metadata } from 'tslib';
import { DOCUMENT } from '@angular/common';

class MapsAPILoader {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: MapsAPILoader, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: MapsAPILoader }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: MapsAPILoader, decorators: [{
            type: Injectable
        }] });

/**
 * 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 {
    constructor(loader) {
        this._boundsChangeSampleTime$ = new BehaviorSubject(200);
        this._includeInBounds$ = new BehaviorSubject(new Map());
        this.bounds$ = from(loader.load()).pipe(mergeMap(() => this._includeInBounds$), sample(this._boundsChangeSampleTime$.pipe(switchMap((time) => timer(0, time)))), map((includeInBounds) => this.generateBounds(includeInBounds)), shareReplay(1));
    }
    addToBounds(latLng) {
        const id = this._createIdentifier(latLng);
        if (this._includeInBounds$.value.has(id)) {
            return;
        }
        const bounds = this._includeInBounds$.value;
        bounds.set(id, latLng);
        this._includeInBounds$.next(bounds);
    }
    removeFromBounds(latLng) {
        const bounds = this._includeInBounds$.value;
        bounds.delete(this._createIdentifier(latLng));
        this._includeInBounds$.next(bounds);
    }
    changeFitBoundsChangeSampleTime(timeMs) {
        this._boundsChangeSampleTime$.next(timeMs);
    }
    getBounds$() {
        return this.bounds$;
    }
    _createIdentifier(latLng) {
        return `${latLng.lat}+${latLng.lng}`;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: FitBoundsService, deps: [{ token: MapsAPILoader }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: FitBoundsService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: FitBoundsService, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: MapsAPILoader }] });

class MapsApiWrapper {
    constructor(_loader, _zone) {
        this._loader = _loader;
        this._zone = _zone;
        this._api = new Promise((resolve) => {
            this._mapResolver = resolve;
        });
    }
    async getNativeMap() {
        return this._api;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: MapsApiWrapper, deps: [{ token: MapsAPILoader }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: MapsApiWrapper }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: MapsApiWrapper, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: MapsAPILoader }, { type: i0.NgZone }] });

/**
 * NgMapsViewComponent renders a Google Map.
 * **Important note**: To be able see a map in the browser, you have to define a height for the
 * element `map-view`.
 *
 * @example
 * <map-view [latitude]="lat" [longitude]="lng" [zoom]="zoom"></map-view>
 */
class NgMapsViewComponent {
    constructor(_mapsWrapper, _fitBoundsService, _zone) {
        this._mapsWrapper = _mapsWrapper;
        this._fitBoundsService = _fitBoundsService;
        this._zone = _zone;
        /**
         * The longitude that defines the center of the map.
         */
        this.longitude = 0;
        /**
         * The latitude that defines the center of the map.
         */
        this.latitude = 0;
        /**
         * The zoom level of the map. The default zoom level is 8.
         */
        this.zoom = 8;
        /**
         * Enables/disables if map is draggable.
         */
        this.draggable = true;
        /**
         * Enables/disables zoom and center on double click. Enabled by default.
         */
        this.disableDoubleClickZoom = false;
        /**
         * Enables/disables all default UI of the Google map. Please note: When the map is created, this
         * value cannot get updated.
         */
        this.disableDefaultUI = false;
        /**
         * If false, disables scrollwheel zooming on the map. The scrollwheel is enabled by default.
         */
        this.scrollwheel = true;
        /**
         * If false, prevents the map from being controlled by the keyboard. Keyboard shortcuts are
         * enabled by default.
         */
        this.keyboardShortcuts = true;
        /**
         * The enabled/disabled state of the Zoom control.
         */
        this.zoomControl = true;
        /**
         * Styles to apply to each of the default map types. Note that for Satellite/Hybrid and Terrain
         * modes, these styles will only apply to labels and geometry.
         */
        this.styles = [];
        /**
         * When true and the latitude and/or longitude values changes, the Google Maps panTo method is
         * used to
         * center the map. See: https://developers.google.com/maps/documentation/javascript/reference#Map
         */
        this.usePanning = false;
        /**
         * Sets the viewport to contain the given bounds.
         * If this option to `true`, the bounds get automatically computed from all elements that use the {@link NgMapsFitBounds} directive.
         */
        this.fitBounds = false;
        /**
         * The initial enabled/disabled state of the Scale control. This is disabled by default.
         */
        this.scaleControl = true;
        /**
         * The initial enabled/disabled state of the Map type control.
         */
        this.mapTypeControl = true;
        /**
         * The initial enabled/disabled state of the Pan control.
         */
        this.panControl = false;
        /**
         * The initial enabled/disabled state of the Rotate control.
         */
        this.rotateControl = false;
        /**
         * The initial enabled/disabled state of the Fullscreen control.
         */
        this.fullscreenControl = false;
        /**
         * The map mapTypeId. Defaults to 'roadmap'.
         */
        this.mapTypeId = 'roadmap';
        this._layerInstance = new Map();
        /**
         * When false, map icons are not clickable. A map icon represents a point of interest,
         * also known as a POI. By default map icons are clickable.
         */
        this.clickableIcons = true;
        /**
         * This setting controls how gestures on the map are handled.
         * Allowed values:
         * - 'cooperative' (Two-finger touch gestures pan and zoom the map. One-finger touch gestures are not handled by the map.)
         * - 'greedy'      (All touch gestures pan or zoom the map.)
         * - 'none'        (The map cannot be panned or zoomed by user gestures.)
         * - 'auto'        [default] (Gesture handling is either cooperative or greedy, depending on whether the page is scrollable or not.
         */
        this.gestureHandling = 'auto';
        /**
         * Controls the automatic switching behavior for the angle of incidence of
         * the map. The only allowed values are 0 and 45. The value 0 causes the map
         * to always use a 0° overhead view regardless of the zoom level and
         * viewport. The value 45 causes the tilt angle to automatically switch to
         * 45 whenever 45° imagery is available for the current zoom level and
         * viewport, and switch back to 0 whenever 45° imagery is not available
         * (this is the default behavior). 45° imagery is only available for
         * satellite and hybrid map types, within some locations, and at some zoom
         * levels. Note: getTilt returns the current tilt angle, not the value
         * specified by this option. Because getTilt and this option refer to
         * different things, do not bind() the tilt property; doing so may yield
         * unpredictable effects. (Default of AGM is 0 (disabled). Enable it with value 45.)
         */
        this.tilt = 0;
        this.subscription = new Subscription();
        /**
         * This event emitter gets emitted when the user clicks on the map (but not when they click on a
         * marker or infoWindow).
         */
        this.mapClick = new EventEmitter();
        /**
         * This event emitter gets emitted when the user right-clicks on the map (but not when they click
         * on a marker or infoWindow).
         */
        this.mapRightClick = new EventEmitter();
        /**
         * This event emitter gets emitted when the user double-clicks on the map (but not when they click
         * on a marker or infoWindow).
         */
        this.mapDblClick = new EventEmitter();
        /**
         * This event emitter is fired when the map center changes.
         */
        this.centerChange = new EventEmitter();
        /**
         * This event is fired when the viewport bounds have changed.
         */
        this.boundsChange = new EventEmitter();
        /**
         * This event is fired when the mapTypeId property changes.
         */
        this.mapTypeIdChange = new EventEmitter();
        /**
         * This event is fired when the map becomes idle after panning or zooming.
         */
        this.idle = new EventEmitter();
        /**
         * This event is fired when the zoom level has changed.
         */
        this.zoomChange = new EventEmitter();
        /**
         * This event is fired when the google map is fully initialized.
         * You get the google.maps.Map instance as a result of this EventEmitter.
         */
        this.mapReady = new EventEmitter();
        /**
         * This event is fired when the visible tiles have finished loading.
         */
        this.tilesLoaded = new EventEmitter();
    }
    /**
     * Map option attributes that can change over time
     */
    static { this._mapOptionsAttributes = [
        'disableDoubleClickZoom',
        'scrollwheel',
        'draggable',
        'draggableCursor',
        'draggingCursor',
        'keyboardShortcuts',
        'zoomControl',
        'zoomControlOptions',
        'styles',
        'streetViewControl',
        'streetViewControlOptions',
        'zoom',
        'mapTypeControl',
        'mapTypeControlOptions',
        'minZoom',
        'maxZoom',
        'panControl',
        'panControlOptions',
        'rotateControl',
        'rotateControlOptions',
        'fullscreenControl',
        'fullscreenControlOptions',
        'scaleControl',
        'scaleControlOptions',
        'mapTypeId',
        'clickableIcons',
        'gestureHandling',
        'tilt',
    ]; }
    /** @internal */
    ngOnInit() {
        this._initMapInstance(this.container?.nativeElement);
    }
    async _initMapInstance(el) {
        await this._mapsWrapper.createMap(el, { lat: this.latitude || 0, lng: this.longitude || 0 }, {
            zoom: this.zoom,
            minZoom: this.minZoom,
            maxZoom: this.maxZoom,
            disableDefaultUI: this.disableDefaultUI,
            disableDoubleClickZoom: this.disableDoubleClickZoom,
            scrollwheel: this.scrollwheel,
            backgroundColor: this.backgroundColor,
            draggable: this.draggable,
            draggableCursor: this.draggableCursor,
            draggingCursor: this.draggingCursor,
            keyboardShortcuts: this.keyboardShortcuts,
            styles: this.styles,
            zoomControl: this.zoomControl,
            zoomControlOptions: this.zoomControlOptions,
            streetViewControl: this.streetViewControl,
            streetViewControlOptions: this.streetViewControlOptions,
            scaleControl: this.scaleControl,
            scaleControlOptions: this.scaleControlOptions,
            mapTypeControl: this.mapTypeControl,
            mapTypeControlOptions: this.mapTypeControlOptions,
            panControl: this.panControl,
            panControlOptions: this.panControlOptions,
            rotateControl: this.rotateControl,
            rotateControlOptions: this.rotateControlOptions,
            fullscreenControl: this.fullscreenControl,
            fullscreenControlOptions: this.fullscreenControlOptions,
            mapTypeId: this.mapTypeId,
            clickableIcons: this.clickableIcons,
            gestureHandling: this.gestureHandling,
            tilt: this.tilt,
        });
        const map = await this._mapsWrapper.getNativeMap();
        this.mapReady.emit(map);
        // register event listeners
        this._handleMapCenterChange();
        this._handleMapZoomChange();
        this._handleMapMouseEvents();
        this._handleBoundsChange();
        this._handleMapTypeIdChange();
        this._handleTilesLoadedEvent();
        this._handleIdleEvent();
    }
    _handleIdleEvent() {
        throw new Error('Method not implemented.');
    }
    _handleTilesLoadedEvent() {
        throw new Error('Method not implemented.');
    }
    _handleMapTypeIdChange() {
        throw new Error('Method not implemented.');
    }
    _handleBoundsChange() {
        throw new Error('Method not implemented.');
    }
    _handleMapMouseEvents() {
        throw new Error('Method not implemented.');
    }
    _handleMapZoomChange() {
        throw new Error('Method not implemented.');
    }
    _handleMapCenterChange() {
        throw new Error('Method not implemented.');
    }
    /** @internal */
    ngOnDestroy() {
        // unsubscribe all registered observable subscriptions
        this.subscription.unsubscribe();
        // remove all listeners from the map instance
        this._mapsWrapper.clearInstanceListeners();
        if (this._fitBoundsSubscription) {
            this._fitBoundsSubscription.unsubscribe();
        }
    }
    /* @internal */
    ngOnChanges(changes) {
        this._updateMapOptionsChanges(changes);
        this._updatePosition(changes);
        this._layerChanges(changes);
    }
    _updateMapOptionsChanges(changes) {
        const options = {};
        const optionKeys = Object.keys(changes).filter((k) => NgMapsViewComponent._mapOptionsAttributes.includes(k));
        optionKeys.forEach((k) => {
            options[k] = changes[k].currentValue;
        });
        return this._mapsWrapper.setMapOptions(options);
    }
    /**
     * @todo google specific
     * @param changes
     * @protected
     */
    async _layerChanges(changes) {
        if (changes.layers) {
            const map = await this._mapsWrapper.getNativeMap();
            const layers = Array.isArray(this.layers) ? this.layers : [this.layers];
            layers.forEach((layer) => {
                if (layer && !this._layerInstance.has(layer)) {
                    const i = new google.maps[layer]();
                    // @todo typings
                    i.setMap(map);
                    this._layerInstance.set(layer, i);
                }
            });
            Array.from(this._layerInstance.keys()).forEach((layer) => {
                if (!layers.includes(layer)) {
                    const i = this._layerInstance.get(layer);
                    i?.setMap(null);
                    this._layerInstance.delete(layer);
                }
            });
        }
    }
    /**
     * Triggers a resize event on the google map instance.
     * When recenter is true, the of the google map gets called with the current lat/lng values or fitBounds value to recenter the map.
     * Returns a promise that gets resolved after the event was triggered.
     */
    triggerResize(recenter = true) {
        // Note: When we would trigger the resize event and show the map in the same turn (which is a
        // common case for triggering a resize event), then the resize event would not
        // work (to show the map), so we trigger the event in a timeout.
        return new Promise((resolve) => {
            setTimeout(async () => {
                await this._mapsWrapper.triggerMapEvent('resize');
                if (recenter) {
                    this.fitBounds != null ? this._fitBounds() : this._setCenter();
                }
                resolve();
            });
        });
    }
    async _updatePosition(changes) {
        if (changes.latitude == null &&
            changes.longitude == null &&
            !changes.fitBounds) {
            // no position update needed
            return;
        }
        // we prefer fitBounds in changes
        if ('fitBounds' in changes) {
            await this._fitBounds();
            return;
        }
        if (typeof this.latitude === 'string') {
            this.latitude = parseFloat(this.latitude);
        }
        if (typeof this.longitude === 'string') {
            this.longitude = parseFloat(this.longitude);
        }
        const center = await this._mapsWrapper.getCenter();
        if (!(typeof this.latitude !== 'number' || typeof this.longitude !== 'number') &&
            this.latitude !== center?.lat &&
            this.longitude !== center?.lng) {
            await this._setCenter();
            return;
        }
    }
    _setCenter() {
        const newCenter = {
            lat: this.latitude,
            lng: this.longitude,
        };
        if (this.usePanning) {
            return this._mapsWrapper.panTo(newCenter);
        }
        else {
            return this._mapsWrapper.setCenter(newCenter);
        }
    }
    async _fitBounds() {
        switch (this.fitBounds) {
            case true:
                this._subscribeToFitBoundsUpdates();
                break;
            case false:
                if (this._fitBoundsSubscription) {
                    this._fitBoundsSubscription.unsubscribe();
                }
                break;
            default:
                if (this._fitBoundsSubscription) {
                    this._fitBoundsSubscription.unsubscribe();
                }
                return this._updateBounds(this.fitBounds);
        }
    }
    _subscribeToFitBoundsUpdates() {
        this._zone.runOutsideAngular(() => {
            this._fitBoundsSubscription = this._fitBoundsService
                .getBounds$()
                .subscribe((b) => this._zone.run(() => this._updateBounds(b)));
        });
    }
    async _updateBounds(bounds) {
        if (bounds != null) {
            /**
             * await map to not update bounds till map is initialized
             */
            await this._mapsWrapper.getNativeMap();
            if (this.usePanning) {
                return this._mapsWrapper.panToBounds(bounds, this.boundsPadding);
            }
            else {
                return this._mapsWrapper.fitBounds(bounds, this.boundsPadding);
            }
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsViewComponent, deps: [{ token: MapsApiWrapper }, { token: FitBoundsService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.8", type: NgMapsViewComponent, selector: "ng-component", inputs: { longitude: "longitude", latitude: "latitude", zoom: "zoom", minZoom: "minZoom", maxZoom: "maxZoom", draggable: "draggable", disableDoubleClickZoom: "disableDoubleClickZoom", disableDefaultUI: "disableDefaultUI", scrollwheel: "scrollwheel", backgroundColor: "backgroundColor", draggableCursor: "draggableCursor", draggingCursor: "draggingCursor", keyboardShortcuts: "keyboardShortcuts", zoomControl: "zoomControl", zoomControlOptions: "zoomControlOptions", styles: "styles", usePanning: "usePanning", streetViewControl: "streetViewControl", streetViewControlOptions: "streetViewControlOptions", fitBounds: "fitBounds", boundsPadding: "boundsPadding", scaleControl: "scaleControl", scaleControlOptions: "scaleControlOptions", mapTypeControl: "mapTypeControl", mapTypeControlOptions: "mapTypeControlOptions", panControl: "panControl", panControlOptions: "panControlOptions", rotateControl: "rotateControl", rotateControlOptions: "rotateControlOptions", fullscreenControl: "fullscreenControl", fullscreenControlOptions: "fullscreenControlOptions", mapTypeId: "mapTypeId", layers: "layers", clickableIcons: "clickableIcons", gestureHandling: "gestureHandling", tilt: "tilt" }, outputs: { mapClick: "mapClick", mapRightClick: "mapRightClick", mapDblClick: "mapDblClick", centerChange: "centerChange", boundsChange: "boundsChange", mapTypeIdChange: "mapTypeIdChange", idle: "idle", zoomChange: "zoomChange", mapReady: "mapReady", tilesLoaded: "tilesLoaded" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `
    <div class="map-container-inner" #container></div>
    <div class="map-content">
      <ng-content></ng-content>
    </div>
  `, isInline: true, styles: [".map-container-inner{width:inherit;height:inherit}.map-content{display:none}\n"] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsViewComponent, decorators: [{
            type: Component,
            args: [{ template: `
    <div class="map-container-inner" #container></div>
    <div class="map-content">
      <ng-content></ng-content>
    </div>
  `, styles: [".map-container-inner{width:inherit;height:inherit}.map-content{display:none}\n"] }]
        }], ctorParameters: () => [{ type: MapsApiWrapper }, { type: FitBoundsService }, { type: i0.NgZone }], propDecorators: { longitude: [{
                type: Input
            }], latitude: [{
                type: Input
            }], zoom: [{
                type: Input
            }], minZoom: [{
                type: Input
            }], maxZoom: [{
                type: Input
            }], draggable: [{
                type: Input
            }], disableDoubleClickZoom: [{
                type: Input
            }], disableDefaultUI: [{
                type: Input
            }], scrollwheel: [{
                type: Input
            }], backgroundColor: [{
                type: Input
            }], draggableCursor: [{
                type: Input
            }], draggingCursor: [{
                type: Input
            }], keyboardShortcuts: [{
                type: Input
            }], zoomControl: [{
                type: Input
            }], zoomControlOptions: [{
                type: Input
            }], styles: [{
                type: Input
            }], usePanning: [{
                type: Input
            }], streetViewControl: [{
                type: Input
            }], streetViewControlOptions: [{
                type: Input
            }], fitBounds: [{
                type: Input
            }], boundsPadding: [{
                type: Input
            }], scaleControl: [{
                type: Input
            }], scaleControlOptions: [{
                type: Input
            }], mapTypeControl: [{
                type: Input
            }], mapTypeControlOptions: [{
                type: Input
            }], panControl: [{
                type: Input
            }], panControlOptions: [{
                type: Input
            }], rotateControl: [{
                type: Input
            }], rotateControlOptions: [{
                type: Input
            }], fullscreenControl: [{
                type: Input
            }], fullscreenControlOptions: [{
                type: Input
            }], mapTypeId: [{
                type: Input
            }], layers: [{
                type: Input
            }], clickableIcons: [{
                type: Input
            }], gestureHandling: [{
                type: Input
            }], tilt: [{
                type: Input
            }], mapClick: [{
                type: Output
            }], mapRightClick: [{
                type: Output
            }], mapDblClick: [{
                type: Output
            }], centerChange: [{
                type: Output
            }], boundsChange: [{
                type: Output
            }], mapTypeIdChange: [{
                type: Output
            }], idle: [{
                type: Output
            }], zoomChange: [{
                type: Output
            }], mapReady: [{
                type: Output
            }], tilesLoaded: [{
                type: Output
            }], container: [{
                type: ViewChild,
                args: ['container', { static: true }]
            }] } });

class MarkerManager {
    constructor(_mapsWrapper, _zone) {
        this._mapsWrapper = _mapsWrapper;
        this._zone = _zone;
        this._markers = new Map();
    }
    async addMarker(marker) {
        if (typeof marker.latitude !== 'number' ||
            typeof marker.longitude !== 'number') {
            return;
        }
        const m = await this._mapsWrapper.createMarker({ lat: marker.latitude, lng: marker.longitude }, 
        // TODO typings
        {
            label: marker.label,
            draggable: marker.draggable,
            icon: marker.icon ?? marker.iconUrl,
            opacity: marker.opacity,
            optimized: marker.optimized,
            visible: marker.visible,
            zIndex: marker.zIndex,
            title: marker.title,
            clickable: marker.clickable,
            animation: typeof marker.animation === 'string'
                ? google.maps.Animation[marker.animation]
                : marker.animation,
        });
        this._markers.set(marker, m);
    }
    getNativeMarker(marker) {
        return this._markers.get(marker);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: MarkerManager, deps: [{ token: MapsApiWrapper }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: MarkerManager }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: MarkerManager, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: MapsApiWrapper }, { type: i0.NgZone }] });

class InfoWindowManager {
    constructor(_mapsWrapper, _zone, _markerManager) {
        this._mapsWrapper = _mapsWrapper;
        this._zone = _zone;
        this._markerManager = _markerManager;
        this._infoWindows = new Map();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: InfoWindowManager, deps: [{ token: MapsApiWrapper }, { token: i0.NgZone }, { token: MarkerManager }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: InfoWindowManager }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: InfoWindowManager, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: MapsApiWrapper }, { type: i0.NgZone }, { type: MarkerManager }] });

let infoWindowId = 0;
/**
 * NgMapsInfoWindowComponent renders a info window inside a {@link NgMapsMarkerComponent} or standalone.
 *
 * ### Example
 * ```typescript
 * import { Component } from '@angular/core';
 *
 * @Component({
 *  selector: 'my-map-cmp',
 *  styles: [`
 *    map-view {
 *      height: 300px;
 *    }
 * `],
 *  template: `
 *    <map-view [latitude]="lat" [longitude]="lng" [zoom]="zoom">
 *      <map-marker [latitude]="lat" [longitude]="lng" [label]="'M'">
 *        <map-info-window [disableAutoPan]="true">
 *          Hi, this is the content of the <strong>info window</strong>
 *        </map-info-window>
 *      </map-marker>
 *    </map-view>
 *  `
 * })
 * ```
 */
class NgMapsInfoWindowComponent {
    // @todo how to add correct typings?
    constructor(_infoWindowManager, elementRef) {
        this._infoWindowManager = _infoWindowManager;
        this.elementRef = elementRef;
        /**
         * Sets the open state for the InfoWindow. You can also call the open() and close() methods.
         */
        this.isOpen = false;
        /**
         * Emits an event when the info window is closed.
         */
        this.infoWindowClose = new EventEmitter();
        this._infoWindowAddedToManager = false;
        this._id = (infoWindowId++).toString();
    }
    static { this._infoWindowOptionsInputs = [
        'disableAutoPan',
        'maxWidth',
    ]; }
    ngOnInit() {
        this._infoWindowManager.addInfoWindow(this).then(() => {
            this._infoWindowAddedToManager = true;
            this._updateOpenState();
            this._registerEventListeners();
        });
    }
    /** @internal */
    ngOnChanges(changes) {
        if (!this._infoWindowAddedToManager) {
            return;
        }
        if ((changes.latitude || changes.longitude) &&
            typeof this.latitude === 'number' &&
            typeof this.longitude === 'number') {
            this._infoWindowManager.setPosition(this);
        }
        if (changes.zIndex) {
            this._infoWindowManager.setZIndex(this);
        }
        if (changes.isOpen) {
            this._updateOpenState();
        }
        this._setInfoWindowOptions(changes);
    }
    _registerEventListeners() {
        this._infoWindowManager
            .createEventObservable('closeclick', this)
            .subscribe(() => {
            this.isOpen = false;
            this.infoWindowClose.emit();
        });
    }
    _updateOpenState() {
        this.isOpen ? this.open() : this.close();
    }
    _setInfoWindowOptions(changes) {
        const options = {};
        const optionKeys = Object.keys(changes).filter((k) => NgMapsInfoWindowComponent._infoWindowOptionsInputs.includes(k));
        optionKeys.forEach((k) => {
            options[k] = changes[k].currentValue;
        });
        this._infoWindowManager.setOptions(this, options);
    }
    /**
     * Opens the info window.
     */
    open(event) {
        return this._infoWindowManager.open(this, event);
    }
    /**
     * Closes the info window.
     */
    async close() {
        await this._infoWindowManager.close(this);
        return this.infoWindowClose.emit();
    }
    /** @internal */
    id() {
        return this._id;
    }
    /** @internal */
    toString() {
        return `NgMapsInfoWindowComponent-${this._id.toString()}`;
    }
    /** @internal */
    ngOnDestroy() {
        this._infoWindowManager.deleteInfoWindow(this);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsInfoWindowComponent, deps: [{ token: InfoWindowManager }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.8", type: NgMapsInfoWindowComponent, selector: "map-info-window", inputs: { latitude: "latitude", longitude: "longitude", disableAutoPan: "disableAutoPan", zIndex: "zIndex", maxWidth: "maxWidth", isOpen: "isOpen" }, outputs: { infoWindowClose: "infoWindowClose" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `
    <div class="info-window-content" #content>
      <ng-content></ng-content>
    </div>
  `, isInline: true }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsInfoWindowComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'map-info-window',
                    template: `
    <div class="info-window-content" #content>
      <ng-content></ng-content>
    </div>
  `,
                }]
        }], ctorParameters: () => [{ type: InfoWindowManager }, { type: i0.ElementRef }], propDecorators: { latitude: [{
                type: Input
            }], longitude: [{
                type: Input
            }], disableAutoPan: [{
                type: Input
            }], zIndex: [{
                type: Input
            }], maxWidth: [{
                type: Input
            }], content: [{
                type: ViewChild,
                args: ['content', { static: true }]
            }], isOpen: [{
                type: Input
            }], infoWindowClose: [{
                type: Output
            }] } });

let markerId = 0;
/**
 * NgMapsMarkerComponent renders a map marker inside a {@link NgMapsViewComponent}.
 *
 * @example
 * <agm-map [latitude]="lat" [longitude]="lng" [zoom]="zoom">
 *               <agm-marker [latitude]="lat" [longitude]="lng" label="M"></agm-marker>
 * </agm-map>
 */
class NgMapsMarkerComponent {
    constructor(markerManager) {
        this.markerManager = markerManager;
        /**
         * If true, the marker can be dragged. Default value is false.
         */
        // eslint-disable-next-line @angular-eslint/no-input-rename
        this.draggable = false;
        this.icon = null;
        /**
         * If true, the marker is visible
         */
        this.visible = true;
        /**
         * Whether to automatically open the child info window when the marker is clicked.
         */
        this.openInfoWindow = true;
        /**
         * The marker's opacity between 0.0 and 1.0.
         */
        this.opacity = 1;
        /**
         * Marker optimize flag. If it is false then it prevent duplicate rendering.
         * Default it is true
         */
        this.optimized = true;
        /**
         * All markers are displayed on the map in order of their zIndex, with higher values displaying in
         * front of markers with lower values. By default, markers are displayed according to their
         * vertical position on screen, with lower markers appearing in front of markers further up the
         * screen.
         */
        this.zIndex = 1;
        /**
         * If true, the marker can be clicked. Default value is true.
         */
        // eslint-disable-next-line @angular-eslint/no-input-rename
        this.clickable = true;
        /**
         * This event emitter gets emitted when the user clicks on the marker.
         */
        this.markerClick = new EventEmitter();
        /**
         * This event is fired when the user rightclicks on the marker.
         */
        this.markerRightClick = new EventEmitter();
        /**
         * This event is fired when the user starts dragging the marker.
         */
        this.dragStart = new EventEmitter();
        /**
         * This event is repeatedly fired while the user drags the marker.
         */
        this.drag = new EventEmitter();
        /**
         * This event is fired when the user stops dragging the marker.
         */
        this.dragEnd = new EventEmitter();
        /**
         * This event is fired when the user mouses over the marker.
         */
        this.mouseOver = new EventEmitter();
        /**
         * This event is fired when the user mouses outside the marker.
         */
        this.mouseOut = new EventEmitter();
        /**
         * @internal
         */
        this.infoWindow = new QueryList();
        this._markerAddedToManger = false;
        this.subscription = new Subscription();
        this._fitBoundsDetails$ = new ReplaySubject(1);
        this._id = (markerId++).toString();
    }
    /**
     *  @internal
     */
    ngAfterContentInit() {
        this.handleInfoWindowUpdate();
        this.infoWindow.changes.subscribe(() => this.handleInfoWindowUpdate());
    }
    handleInfoWindowUpdate() {
        if (this.infoWindow.length > 1) {
            throw new Error('Expected no more than one info window.');
        }
        this.infoWindow.forEach((marker) => {
            marker.hostMarker = this;
        });
    }
    /**
     * @internal
     */
    ngOnChanges(changes) {
        if (typeof this.latitude === 'string') {
            this.latitude = Number(this.latitude);
        }
        if (typeof this.longitude === 'string') {
            this.longitude = Number(this.longitude);
        }
        if (typeof this.latitude !== 'number' ||
            typeof this.longitude !== 'number') {
            return;
        }
        if (!this._markerAddedToManger) {
            this.markerManager.addMarker(this).then(() => {
                this._updateFitBoundsDetails();
                this._markerAddedToManger = true;
                this._addEventListeners();
            });
            return;
        }
        if (changes.latitude || changes.longitude) {
            this.markerManager.updateMarkerPosition(this);
            this._updateFitBoundsDetails();
        }
        if (changes.title) {
            this.markerManager.updateTitle(this);
        }
        if (changes.label) {
            this.markerManager.updateLabel(this);
        }
        if (changes.draggable) {
            this.markerManager.updateDraggable(this);
        }
        if (changes.iconUrl) {
            this.markerManager.updateIconLegacy(this);
        }
        if (changes.icon) {
            this.markerManager.updateIcon(this);
        }
        if (changes.opacity) {
            this.markerManager.updateOpacity(this);
        }
        if (changes.visible) {
            this.markerManager.updateVisible(this);
        }
        if (changes.zIndex) {
            this.markerManager.updateZIndex(this);
        }
        if (changes.clickable) {
            this.markerManager.updateClickable(this);
        }
        if (changes.animation) {
            this.markerManager.updateAnimation(this);
        }
    }
    /**
     * @internal
     */
    getFitBoundsDetails$() {
        return this._fitBoundsDetails$.asObservable();
    }
    _updateFitBoundsDetails() {
        if (this.latitude && this.longitude) {
            this._fitBoundsDetails$.next({
                latLng: { lat: this.latitude, lng: this.longitude },
            });
        }
    }
    _addEventListeners() {
        const cs = this.markerManager
            .createEventObservable(['click', 'pointerdown'], this)
            .subscribe({
            next: (event) => {
                if (this.openInfoWindow) {
                    this.infoWindow.forEach((infoWindow) => infoWindow.open(event));
                }
                this.markerClick.emit(this);
            },
        });
        this.subscription.add(cs);
        const rc = this.markerManager
            .createEventObservable('rightclick', this)
            .subscribe(() => {
            this.markerRightClick.emit();
        });
        this.subscription.add(rc);
        const ds = this.markerManager
            .createEventObservable('dragstart', this)
            .subscribe((e) => {
            this.dragStart.emit(e);
        });
        this.subscription.add(ds);
        const d = this.markerManager
            .createEventObservable('drag', this)
            .subscribe((e) => {
            this.drag.emit(e);
        });
        this.subscription.add(d);
        const dragend = this.markerManager
            .createEventObservable('dragend', this)
            .subscribe((e) => {
            this.dragEnd.emit(e);
        });
        this.subscription.add(dragend);
        const mouseover = this.markerManager
            .createEventObservable(['mouseover', 'pointerenter'], this)
            .subscribe((e) => {
            this.mouseOver.emit(e);
        });
        this.subscription.add(mouseover);
        const mouseout = this.markerManager
            .createEventObservable(['mouseout', 'pointerleave'], this)
            .subscribe((e) => {
            this.mouseOut.emit(e);
        });
        this.subscription.add(mouseout);
    }
    /** @internal */
    id() {
        return this._id;
    }
    /** @internal */
    toString() {
        return `NgMapsMarker-${this._id}`;
    }
    /** @internal */
    ngOnDestroy() {
        this.markerManager.deleteMarker(this);
        // unsubscribe all registered observable subscription
        this.subscription.unsubscribe();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsMarkerComponent, deps: [{ token: MarkerManager }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.8", type: NgMapsMarkerComponent, selector: "map-marker", inputs: { latitude: "latitude", longitude: "longitude", title: "title", label: "label", draggable: ["markerDraggable", "draggable"], iconUrl: "iconUrl", icon: "icon", openInfoWindow: "openInfoWindow", opacity: "opacity", optimized: "optimized", visible: "visible", zIndex: "zIndex", animation: "animation", clickable: ["markerClickable", "clickable"] }, outputs: { markerClick: "markerClick", dragStart: "dragStart", drag: "drag", dragEnd: "dragEnd", mouseOver: "mouseOver", mouseOut: "mouseOut", markerRightClick: "markerRightClick" }, providers: [
            {
                provide: FitBoundsAccessor,
                useExisting: forwardRef(() => NgMapsMarkerComponent),
            },
        ], queries: [{ propertyName: "infoWindow", predicate: NgMapsInfoWindowComponent }], usesOnChanges: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsMarkerComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'map-marker',
                    providers: [
                        {
                            provide: FitBoundsAccessor,
                            useExisting: forwardRef(() => NgMapsMarkerComponent),
                        },
                    ],
                    // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
                    inputs: [
                        'latitude',
                        'longitude',
                        'title',
                        'label',
                        // eslint-disable-next-line @angular-eslint/no-input-rename
                        'draggable: markerDraggable',
                        'iconUrl',
                        'icon',
                        'openInfoWindow',
                        'opacity',
                        'optimized',
                        'visible',
                        'zIndex',
                        'animation',
                    ],
                    // eslint-disable-next-line @angular-eslint/no-outputs-metadata-property
                    outputs: [
                        'markerClick',
                        'dragStart',
                        // eslint-disable-next-line @angular-eslint/no-output-native
                        'drag',
                        'dragEnd',
                        'mouseOver',
                        'mouseOut',
                    ],
                    template: '<ng-content></ng-content>',
                }]
        }], ctorParameters: () => [{ type: MarkerManager }], propDecorators: { latitude: [{
                type: Input
            }], longitude: [{
                type: Input
            }], title: [{
                type: Input
            }], label: [{
                type: Input
            }], draggable: [{
                type: Input,
                args: ['markerDraggable']
            }], iconUrl: [{
                type: Input
            }], icon: [{
                type: Input
            }], visible: [{
                type: Input
            }], openInfoWindow: [{
                type: Input
            }], opacity: [{
                type: Input
            }], optimized: [{
                type: Input
            }], zIndex: [{
                type: Input
            }], clickable: [{
                type: Input,
                args: ['markerClickable']
            }], markerClick: [{
                type: Output
            }], markerRightClick: [{
                type: Output
            }], dragStart: [{
                type: Output
            }], drag: [{
                type: Output
            }], dragEnd: [{
                type: Output
            }], mouseOver: [{
                type: Output
            }], mouseOut: [{
                type: Output
            }], infoWindow: [{
                type: ContentChildren,
                args: [NgMapsInfoWindowComponent]
            }] } });

/**
 * Adds the given directive to the auto fit bounds feature when the value is true.
 * To make it work with you custom AGM component, you also have to implement the {@link FitBoundsAccessor} abstract class.
 *
 * @example
 * <map-marker [mapFitBounds]="true"></map-marker>
 */
class NgMapsFitBoundsDirective {
    constructor(_fitBoundsAccessor, _fitBoundsService) {
        this._fitBoundsAccessor = _fitBoundsAccessor;
        this._fitBoundsService = _fitBoundsService;
        /**
         * If the value is true, the element gets added to the bounds of the map.
         * Default: true.
         */
        this.mapFitBounds = true;
        this._latestFitBoundsDetails = null;
        this.subscription = new Subscription();
    }
    /**
     * @internal
     */
    ngOnChanges(changes) {
        this._updateBounds();
    }
    /**
     * @internal
     */
    ngOnInit() {
        this.subscription.add(this._fitBoundsAccessor
            .getFitBoundsDetails$()
            .pipe(distinctUntilChanged((x, y) => x.latLng.lat === y.latLng.lat && x.latLng.lng === y.latLng.lng))
            .subscribe({
            next: (details) => this._updateBounds(details),
            complete: () => this._updateBounds(),
        }));
    }
    /**
     * Either the location changed, or visible status changed.
     * Possible state changes are
     * invisible -> visible
     * visible -> invisible
     * visible -> visible (new location)
     */
    _updateBounds(newFitBoundsDetails) {
        // either visibility will change, or location, so remove the old one anyway
        if (this._latestFitBoundsDetails) {
            this._fitBoundsService.removeFromBounds(this._latestFitBoundsDetails.latLng);
            // don't set latestFitBoundsDetails to null, because we can toggle visibility from
            // true -> false -> true, in which case we still need old value cached here
        }
        if (newFitBoundsDetails) {
            this._latestFitBoundsDetails = newFitBoundsDetails;
        }
        if (this._latestFitBoundsDetails) {
            if (this.mapFitBounds === true) {
                this._fitBoundsService.addToBounds(this._latestFitBoundsDetails.latLng);
            }
            else {
                this._fitBoundsService.removeFromBounds(this._latestFitBoundsDetails.latLng);
            }
        }
    }
    /**
     * @internal
     */
    ngOnDestroy() {
        this.subscription.unsubscribe();
        if (this._latestFitBoundsDetails !== null) {
            this._fitBoundsService.removeFromBounds(this._latestFitBoundsDetails.latLng);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsFitBoundsDirective, deps: [{ token: FitBoundsAccessor, self: true }, { token: FitBoundsService }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.8", type: NgMapsFitBoundsDirective, selector: "[mapFitBounds]", inputs: { mapFitBounds: "mapFitBounds" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsFitBoundsDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[mapFitBounds]',
                }]
        }], ctorParameters: () => [{ type: FitBoundsAccessor, decorators: [{
                    type: Self
                }] }, { type: FitBoundsService }], propDecorators: { mapFitBounds: [{
                type: Input
            }] } });

class CircleManager {
    constructor(_apiWrapper, _zone) {
        this._apiWrapper = _apiWrapper;
        this._zone = _zone;
        this._circles = new Map();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: CircleManager, deps: [{ token: MapsApiWrapper }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: CircleManager }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: CircleManager, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: MapsApiWrapper }, { type: i0.NgZone }] });

class NgMapsCircleDirective {
    constructor(_manager) {
        this._manager = _manager;
        /**
         * Indicates whether this Circle handles mouse events. Defaults to true.
         */
        this.clickable = true;
        /**
         * If set to true, the user can drag this circle over the map. Defaults to false.
         */
        this.draggable = false;
        /**
         * If set to true, the user can edit this circle by dragging the control points shown at
         * the center and around the circumference of the circle. Defaults to false.
         */
        this.editable = false;
        /**
         * The radius in meters on the Earth's surface.
         */
        this.radius = 0;
        /**
         * The stroke position. Defaults to CENTER.
         * This property is not supported on Internet Explorer 8 and earlier.
         *
         * @fixme
         */
        // @Input() strokePosition: google.maps.StrokePosition =
        //   google.maps.StrokePosition.CENTER;
        /**
         * The stroke width in pixels.
         */
        this.strokeWeight = 0;
        /**
         * Whether this circle is visible on the map. Defaults to true.
         */
        this.visible = true;
        /**
         * This event is fired when the circle's center is changed.
         */
        this.centerChange = new EventEmitter();
        /**
         * This event emitter gets emitted when the user clicks on the circle.
         */
        this.circleClick = new EventEmitter();
        /**
         * This event emitter gets emitted when the user clicks on the circle.
         */
        this.circleDblClick = new EventEmitter();
        /**
         * This event is repeatedly fired while the user drags the circle.
         */
        this.drag = new EventEmitter();
        /**
         * This event is fired when the user stops dragging the circle.
         */
        this.dragEnd = new EventEmitter();
        /**
         * This event is fired when the user starts dragging the circle.
         */
        this.dragStart = new EventEmitter();
        /**
         * This event is fired when the DOM mousedown event is fired on the circle.
         */
        this.mouseDown = new EventEmitter();
        /**
         * This event is fired when the DOM mousemove event is fired on the circle.
         */
        this.mouseMove = new EventEmitter();
        /**
         * This event is fired on circle mouseout.
         */
        this.mouseOut = new EventEmitter();
        /**
         * This event is fired on circle mouseover.
         */
        this.mouseOver = new EventEmitter();
        /**
         * This event is fired when the DOM mouseup event is fired on the circle.
         */
        this.mouseUp = new EventEmitter();
        /**
         * This event is fired when the circle's radius is changed.
         */
        this.radiusChange = new EventEmitter();
        /**
         * This event is fired when the circle is right-clicked on.
         */
        this.rightClick = new EventEmitter();
        this._circleAddedToManager = false;
        this.subscription = new Subscription();
    }
    static { this._mapOptions = [
        'fillColor',
        'fillOpacity',
        'strokeColor',
        'strokeOpacity',
        'strokePosition',
        'strokeWeight',
        'visible',
        'zIndex',
        'clickable',
    ]; }
    /** @internal */
    ngOnInit() {
        this._manager.addCircle(this);
        this._circleAddedToManager = true;
        this._registerEventListeners();
    }
    /** @internal */
    ngOnChanges(changes) {
        if (!this._circleAddedToManager) {
            return;
        }
        if (changes.latitude || changes.longitude) {
            this._manager.setCenter(this);
        }
        if (changes.editable) {
            this._manager.setEditable(this);
        }
        if (changes.draggable) {
            this._manager.setDraggable(this);
        }
        if (changes.visible) {
            this._manager.setVisible(this);
        }
        if (changes.radius) {
            this._manager.setRadius(this);
        }
        this._updateCircleOptionsChanges(changes);
    }
    _updateCircleOptionsChanges(changes) {
        const options = {};
        const optionKeys = Object.keys(changes).filter((k) => NgMapsCircleDirective._mapOptions.indexOf(k) !== -1);
        optionKeys.forEach((k) => {
            options[k] = changes[k].currentValue;
        });
        if (optionKeys.length > 0) {
            this._manager.setOptions(this, options);
        }
    }
    _registerEventListeners() {
        const events = new Map();
        events.set('center_changed', this.centerChange);
        events.set('click', this.circleClick);
        events.set('dblclick', this.circleDblClick);
        events.set('drag', this.drag);
        events.set('dragend', this.dragEnd);
        events.set('dragstart', this.dragStart);
        events.set('mousedown', this.mouseDown);
        events.set('mousemove', this.mouseMove);
        events.set('mouseout', this.mouseOut);
        events.set('mouseover', this.mouseOver);
        events.set('mouseup', this.mouseUp);
        events.set('radius_changed', this.radiusChange);
        events.set('rightclick', this.rightClick);
        events.forEach((eventEmitter, eventName) => {
            this.subscription.add(this._manager
                .createEventObservable(eventName, this)
                .subscribe((value) => {
                switch (eventName) {
                    case 'radius_changed':
                        this._manager
                            .getRadius(this)
                            .then((radius) => eventEmitter.emit(radius));
                        break;
                    case 'center_changed':
                        this._manager.getCenter(this).then((center) => eventEmitter.emit({
                            ...center,
                        }));
                        break;
                    default:
                        eventEmitter.emit(value);
                }
            }));
        });
    }
    /** @internal */
    ngOnDestroy() {
        this.subscription.unsubscribe();
        this._manager.removeCircle(this);
    }
    /**
     * Gets the LatLngBounds of this Circle.
     */
    async getBounds() {
        return this._manager.getBounds(this);
    }
    async getCenter() {
        return this._manager.getCenter(this);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsCircleDirective, deps: [{ token: CircleManager }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.8", type: NgMapsCircleDirective, selector: "map-circle", inputs: { latitude: "latitude", longitude: "longitude", clickable: "clickable", draggable: "draggable", editable: "editable", fillColor: "fillColor", fillOpacity: "fillOpacity", radius: "radius", strokeColor: "strokeColor", strokeOpacity: "strokeOpacity", strokeWeight: "strokeWeight", visible: "visible", zIndex: "zIndex" }, outputs: { centerChange: "centerChange", circleClick: "circleClick", circleDblClick: "circleDblClick", drag: "drag", dragEnd: "dragEnd", dragStart: "dragStart", mouseDown: "mouseDown", mouseMove: "mouseMove", mouseOut: "mouseOut", mouseOver: "mouseOver", mouseUp: "mouseUp", radiusChange: "radiusChange", rightClick: "rightClick" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsCircleDirective, decorators: [{
            type: Directive,
            args: [{
                    // eslint-disable-next-line @angular-eslint/directive-selector
                    selector: 'map-circle',
                }]
        }], ctorParameters: () => [{ type: CircleManager }], propDecorators: { latitude: [{
                type: Input
            }], longitude: [{
                type: Input
            }], clickable: [{
                type: Input
            }], draggable: [{
                type: Input
            }], editable: [{
                type: Input
            }], fillColor: [{
                type: Input
            }], fillOpacity: [{
                type: Input
            }], radius: [{
                type: Input
            }], strokeColor: [{
                type: Input
            }], strokeOpacity: [{
                type: Input
            }], strokeWeight: [{
                type: Input
            }], visible: [{
                type: Input
            }], zIndex: [{
                type: Input
            }], centerChange: [{
                type: Output
            }], circleClick: [{
                type: Output
            }], circleDblClick: [{
                type: Output
            }], drag: [{
                type: Output
            }], dragEnd: [{
                type: Output
            }], dragStart: [{
                type: Output
            }], mouseDown: [{
                type: Output
            }], mouseMove: [{
                type: Output
            }], mouseOut: [{
                type: Output
            }], mouseOver: [{
                type: Output
            }], mouseUp: [{
                type: Output
            }], radiusChange: [{
                type: Output
            }], rightClick: [{
                type: Output
            }] } });

class PolygonManager {
    constructor(_mapsWrapper, _zone) {
        this._mapsWrapper = _mapsWrapper;
        this._zone = _zone;
        this._polygons = new Map();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: PolygonManager, deps: [{ token: MapsApiWrapper }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: PolygonManager }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: PolygonManager, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: MapsApiWrapper }, { type: i0.NgZone }] });

/**
 * NgMapsPolygon renders a polygon on a {@link https://ng-maps.github.io/core/components/NgMapsViewComponent.html|NgMapsView}
 */
class NgMapsPolygonDirective {
    constructor(_polygonManager) {
        this._polygonManager = _polygonManager;
        /**
         * Indicates whether this Polygon handles mouse events. Defaults to true.
         */
        this.clickable = true;
        /**
         * If set to true, the user can drag this shape over the map. The geodesic
         * property defines the mode of dragging. Defaults to false.
         */
        // eslint-disable-next-line @angular-eslint/no-input-rename
        this.draggable = false;
        /**
         * If set to true, the user can edit this shape by dragging the control
         * points shown at the vertices and on each segment. Defaults to false.
         */
        this.editable = false;
        /**
         * When true, edges of the polygon are interpreted as geodesic and will
         * follow the curvature of the Earth. When false, edges of the polygon are
         * rendered as straight lines in screen space. Note that the shape of a
         * geodesic polygon may appear to change when dragged, as the dimensions
         * are maintained relative to the surface of the earth. Defaults to false.
         */
        this.geodesic = false;
        /**
         * The ordered sequence of coordinates that designates a closed loop.
         * Unlike polylines, a polygon may consist of one or more paths.
         *  As a result, the paths property may specify one or more arrays of
         * LatLng coordinates. Paths are closed automatically; do not repeat the
         * first vertex of the path as the last vertex. Simple polygons may be
         * defined using a single array of LatLngs. More complex polygons may
         * specify an array of arrays. Any simple arrays are converted into Arrays.
         * Inserting or removing LatLngs from the Array will automatically update
         * the polygon on the map.
         */
        this.paths = [];
        /**
         * This event is fired when the DOM click event is fired on the Polygon.
         */
        this.polyClick = new EventEmitter();
        /**
         * This event is fired when the DOM dblclick event is fired on the Polygon.
         */
        this.polyDblClick = new EventEmitter();
        /**
         * This event is repeatedly fired while the user drags the polygon.
         */
        this.polyDrag = new EventEmitter();
        /**
         * This event is fired when the user stops dragging the polygon.
         */
        this.polyDragEnd = new EventEmitter();
        /**
         * This event is fired when the user starts dragging the polygon.
         */
        this.polyDragStart = new EventEmitter();
        /**
         * This event is fired when the DOM mousedown event is fired on the Polygon.
         */
        this.polyMouseDown = new EventEmitter();
        /**
         * This event is fired when the DOM mousemove event is fired on the Polygon.
         */
        this.polyMouseMove = new EventEmitter();
        /**
         * This event is fired on Polygon mouseout.
         */
        this.polyMouseOut = new EventEmitter();
        /**
         * This event is fired on Polygon mouseover.
         */
        this.polyMouseOver = new EventEmitter();
        /**
         * This event is fired whe the DOM mouseup event is fired on the Polygon
         */
        this.polyMouseUp = new EventEmitter();
        /**
         * This even is fired when the Polygon is right-clicked on.
         */
        this.polyRightClick = new EventEmitter();
        this._polygonAddedToManager = false;
        this.subscription = new Subscription();
    }
    static { this._polygonOptionsAttributes = [
        'clickable',
        'draggable',
        'editable',
        'fillColor',
        'fillOpacity',
        'geodesic',
        'icon',
        'map',
        'paths',
        'strokeColor',
        'strokeOpacity',
        'strokeWeight',
        'visible',
        'zIndex',
        'draggable',
        'editable',
        'visible',
    ]; }
    /** @internal */
    ngAfterContentInit() {
        if (!this._polygonAddedToManager) {
            this._init();
        }
    }
    ngOnChanges(changes) {
        if (!this._polygonAddedToManager) {
            this._init();
            return;
        }
        this._polygonManager.setPolygonOptions(this, this._updatePolygonOptions(changes));
    }
    _init() {
        this._polygonManager.addPolygon(this);
        this._polygonAddedToManager = true;
        this._addEventListeners();
    }
    _addEventListeners() {
        const handlers = [
            {
                name: 'click',
                handler: (ev) => this.polyClick.emit(ev),
            },
            {
                name: 'dblclick',
                handler: (ev) => this.polyDblClick.emit(ev),
            },
            { name: 'drag', handler: (ev) => this.polyDrag.emit(ev) },
            {
                name: 'dragend',
                handler: (ev) => this.polyDragEnd.emit(ev),
            },
            {
                name: 'dragstart',
                handler: (ev) => this.polyDragStart.emit(ev),
            },
            {
                name: 'mousedown',
                handler: (ev) => this.polyMouseDown.emit(ev),
            },
            {
                name: 'mousemove',
                handler: (ev) => this.polyMouseMove.emit(ev),
            },
            {
                name: 'mouseout',
                handler: (ev) => this.polyMouseOut.emit(ev),
            },
            {
                name: 'mouseover',
                handler: (ev) => this.polyMouseOver.emit(ev),
            },
            {
                name: 'mouseup',
                handler: (ev) => this.polyMouseUp.emit(ev),
            },
            {
                name: 'rightclick',
                handler: (ev) => this.polyRightClick.emit(ev),
            },
        ];
        handlers.forEach((obj) => {
            const os = this._polygonManager
                .createEventObservable(obj.name, this)
                // FIXME
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                .subscribe(obj.handler);
            this.subscription.add(os);
        });
    }
    _updatePolygonOptions(changes) {
        return Object.keys(changes)
            .filter((k) => NgMapsPolygonDirective._polygonOptionsAttributes.indexOf(k) !== -1)
            .reduce((obj, k) => {
            obj[k] = changes[k].currentValue;
            return obj;
        }, {});
    }
    /** @internal */
    id() {
        return this._id;
    }
    /** @internal */
    ngOnDestroy() {
        this._polygonManager.deletePolygon(this);
        // unsubscribe all registered observable subscriptions
        this.subscription.unsubscribe();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsPolygonDirective, deps: [{ token: PolygonManager }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.8", type: NgMapsPolygonDirective, selector: "map-polygon", inputs: { clickable: "clickable", draggable: ["polyDraggable", "draggable"], editable: "editable", fillColor: "fillColor", fillOpacity: "fillOpacity", geodesic: "geodesic", paths: "paths", strokeColor: "strokeColor", strokeOpacity: "strokeOpacity", strokeWeight: "strokeWeight", visible: "visible", zIndex: "zIndex" }, outputs: { polyClick: "polyClick", polyDblClick: "polyDblClick", polyDrag: "polyDrag", polyDragEnd: "polyDragEnd", polyDragStart: "polyDragStart", polyMouseDown: "polyMouseDown", polyMouseMove: "polyMouseMove", polyMouseOut: "polyMouseOut", polyMouseOver: "polyMouseOver", polyMouseUp: "polyMouseUp", polyRightClick: "polyRightClick" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsPolygonDirective, decorators: [{
            type: Directive,
            args: [{
                    // eslint-disable-next-line @angular-eslint/directive-selector
                    selector: 'map-polygon',
                }]
        }], ctorParameters: () => [{ type: PolygonManager }], propDecorators: { clickable: [{
                type: Input
            }], draggable: [{
                type: Input,
                args: ['polyDraggable']
            }], editable: [{
                type: Input
            }], fillColor: [{
                type: Input
            }], fillOpacity: [{
                type: Input
            }], geodesic: [{
                type: Input
            }], paths: [{
                type: Input
            }], strokeColor: [{
                type: Input
            }], strokeOpacity: [{
                type: Input
            }], strokeWeight: [{
                type: Input
            }], visible: [{
                type: Input
            }], zIndex: [{
                type: Input
            }], polyClick: [{
                type: Output
            }], polyDblClick: [{
                type: Output
            }], polyDrag: [{
                type: Output
            }], polyDragEnd: [{
                type: Output
            }], polyDragStart: [{
                type: Output
            }], polyMouseDown: [{
                type: Output
            }], polyMouseMove: [{
                type: Output
            }], polyMouseOut: [{
                type: Output
            }], polyMouseOver: [{
                type: Output
            }], polyMouseUp: [{
                type: Output
            }], polyRightClick: [{
                type: Output
            }] } });

class PolylineManager {
    constructor(_mapsWrapper, _zone) {
        this._mapsWrapper = _mapsWrapper;
        this._zone = _zone;
        this._polylines = new Map();
    }
    _convertPoints(line) {
        return line._getPoints().map((point) => ({
            lat: point.latitude,
            lng: point.longitude,
        }));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: PolylineManager, deps: [{ token: MapsApiWrapper }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: PolylineManager }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: PolylineManager, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: MapsApiWrapper }, { type: i0.NgZone }] });

/**
 * NgMapsPolylinePoint represents one element of a polyline within a  {@link
 * NgMapsPolyline}
 */
// eslint-disable-next-line @angular-eslint/directive-class-suffix
class NgMapsPolylinePoint {
    constructor() {
        /**
         * This event emitter gets emitted when the position of the point changed.
         */
        this.positionChanged = new EventEmitter();
    }
    ngOnChanges(changes) {
        if (changes.latitude || changes.longitude) {
            const position = {
                lat: changes.latitude ? changes.latitude.currentValue : this.latitude,
                lng: changes.longitude
                    ? changes.longitude.currentValue
                    : this.longitude,
            };
            this.positionChanged.emit(position);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsPolylinePoint, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.8", type: NgMapsPolylinePoint, selector: "map-polyline-point", inputs: { latitude: "latitude", longitude: "longitude" }, outputs: { positionChanged: "positionChanged" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsPolylinePoint, decorators: [{
            type: Directive,
            args: [{
                    // eslint-disable-next-line @angular-eslint/directive-selector
                    selector: 'map-polyline-point',
                }]
        }], propDecorators: { latitude: [{
                type: Input
            }], longitude: [{
                type: Input
            }], positionChanged: [{
                type: Output
            }] } });

let polylineId = 0;
/**
 * NgMapsPolyline renders a polyline on a {@link https://ng-maps.github.io/core/components/NgMapsViewComponent.html|NgMapsView}
 */
// eslint-disable-next-line @angular-eslint/directive-class-suffix
class NgMapsPolyline {
    constructor(_polylineManager) {
        this._polylineManager = _polylineManager;
        /**
         * Indicates whether this Polyline handles mouse events. Defaults to true.
         */
        this.clickable = true;
        /**
         * If set to true, the user can drag this shape over the map. The geodesic property defines the
         * mode of dragging. Defaults to false.
         */
        // eslint-disable-next-line @angular-eslint/no-input-rename
        this.draggable = false;
        /**
         * If set to true, the user can edit this shape by dragging the control points shown at the
         * vertices and on each segment. Defaults to false.
         */
        this.editable = false;
        /**
         * When true, edges of the polygon are interpreted as geodesic and will follow the curvature of
         * the Earth. When false, edges of the polygon are rendered as straight lines in screen space.
         * Note that the shape of a geodesic polygon may appear to change when dragged, as the dimensions
         * are maintained relative to the surface of the earth. Defaults to false.
         */
        this.geodesic = false;
        /**
         * Whether this polyline is visible on the map. Defaults to true.
         */
        this.visible = true;
        /**
         * This event is fired when the DOM click event is fired on the Polyline.
         */
        this.lineClick = new EventEmitter();
        /**
         * This event is fired when the DOM dblclick event is fired on the Polyline.
         */
        this.lineDblClick = new EventEmitter();
        /**
         * This event is repeatedly fired while the user drags the polyline.
         */
        this.lineDrag = new EventEmitter();
        /**
         * This event is fired when the user stops dragging the polyline.
         */
        this.lineDragEnd = new EventEmitter();
        /**
         * This event is fired when the user starts dragging the polyline.
         */
        this.lineDragStart = new EventEmitter();
        /**
         * This event is fired when the DOM mousedown event is fired on the Polyline.
         */
        this.lineMouseDown = new EventEmitter();
        /**
         * This event is fired when the DOM mousemove event is fired on the Polyline.
         */
        this.lineMouseMove = new EventEmitter();
        /**
         * This event is fired on Polyline mouseout.
         */
        this.lineMouseOut = new EventEmitter();
        /**
         * This event is fired on Polyline mouseover.
         */
        this.lineMouseOver = new EventEmitter();
        /**
         * This event is fired whe the DOM mouseup event is fired on the Polyline
         */
        this.lineMouseUp = new EventEmitter();
        /**
         * This even is fired when the Polyline is right-clicked on.
         */
        this.lineRightClick = new EventEmitter();
        this._polylineAddedToManager = false;
        this.subscription = new Subscription();
        this._id = (polylineId++).toString();
    }
    static { this._polylineOptionsAttributes = [
        'draggable',
        'editable',
        'visible',
        'geodesic',
        'strokeColor',
        'strokeOpacity',
        'strokeWeight',
        'zIndex',
        'icons',
    ]; }
    /** @internal */
    ngAfterContentInit() {
        if (this.points) {
            this.points.forEach((point) => {
                const subscription = point.positionChanged.subscribe(() => {
                    this._polylineManager.updatePolylinePoints(this);
                });
                this.subscription.add(subscription);
            });
            const s = this.points.changes.subscribe(() => this._polylineManager.updatePolylinePoints(this));
            this.subscription.add(s);
        }
        if (!this._polylineAddedToManager) {
            this._init();
        }
        this._polylineManager.updatePolylinePoints(this);
    }
    ngOnChanges(changes) {
        if (!this._polylineAddedToManager) {
            this._init();
            return;
        }
        const options = {};
        const optionKeys = Object.keys(changes).filter((k) => NgMapsPolyline._polylineOptionsAttributes.indexOf(k) !== -1);
        optionKeys.forEach((k) => (options[k] = changes[k].currentValue));
        this._polylineManager.setPolylineOptions(this, options);
    }
    _init() {
        this._polylineManager.addPolyline(this);
        this._polylineAddedToManager = true;
        this._addEventListeners();
    }
    _addEventListeners() {
        const handlers = [
            {
                name: 'click',
                handler: (ev) => this.lineClick.emit(ev),
            },
            {
                name: 'dblclick',
                handler: (ev) => this.lineDblClick.emit(ev),
            },
            { name: 'drag', handler: (ev) => this.lineDrag.emit(ev) },
            {
                name: 'dragend',
                handler: (ev) => this.lineDragEnd.emit(ev),
            },
            {
                name: 'dragstart',
                handler: (ev) => this.lineDragStart.emit(ev),
            },
            {
                name: 'mousedown',
                handler: (ev) => this.lineMouseDown.emit(ev),
            },
            {
                name: 'mousemove',
                handler: (ev) => this.lineMouseMove.emit(ev),
            },
            {
                name: 'mouseout',
                handler: (ev) => this.lineMouseOut.emit(ev),
            },
            {
                name: 'mouseover',
                handler: (ev) => this.lineMouseOver.emit(ev),
            },
            {
                name: 'mouseup',
                handler: (ev) => this.lineMouseUp.emit(ev),
            },
            {
                name: 'rightclick',
                handler: (ev) => this.lineRightClick.emit(ev),
            },
        ];
        handlers.forEach((obj) => {
            const os = this._polylineManager
                .createEventObservable(obj.name, this)
                // FIXME
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                .subscribe(obj.handler);
            this.subscription.add(os);
        });
    }
    /** @internal */
    _getPoints() {
        if (this.points) {
            return this.points.toArray();
        }
        else {
            return [];
        }
    }
    /** @internal */
    id() {
        return this._id;
    }
    /** @internal */
    ngOnDestroy() {
        this._polylineManager.deletePolyline(this);
        // unsubscribe all registered observable subscriptions
        this.subscription.unsubscribe();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsPolyline, deps: [{ token: PolylineManager }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.8", type: NgMapsPolyline, selector: "map-polyline", inputs: { clickable: "clickable", draggable: ["polylineDraggable", "draggable"], editable: "editable", geodesic: "geodesic", strokeColor: "strokeColor", strokeOpacity: "strokeOpacity", strokeWeight: "strokeWeight", icons: "icons", visible: "visible", zIndex: "zIndex" }, outputs: { lineClick: "lineClick", lineDblClick: "lineDblClick", lineDrag: "lineDrag", lineDragEnd: "lineDragEnd", lineDragStart: "lineDragStart", lineMouseDown: "lineMouseDown", lineMouseMove: "lineMouseMove", lineMouseOut: "lineMouseOut", lineMouseOver: "lineMouseOver", lineMouseUp: "lineMouseUp", lineRightClick: "lineRightClick" }, queries: [{ propertyName: "points", predicate: NgMapsPolylinePoint }], usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsPolyline, decorators: [{
            type: Directive,
            args: [{
                    // eslint-disable-next-line @angular-eslint/directive-selector
                    selector: 'map-polyline',
                }]
        }], ctorParameters: () => [{ type: PolylineManager }], propDecorators: { clickable: [{
                type: Input
            }], draggable: [{
                type: Input,
                args: ['polylineDraggable']
            }], editable: [{
                type: Input
            }], geodesic: [{
                type: Input
            }], strokeColor: [{
                type: Input
            }], strokeOpacity: [{
                type: Input
            }], strokeWeight: [{
                type: Input
            }], icons: [{
                type: Input
            }], visible: [{
                type: Input
            }], zIndex: [{
                type: Input
            }], lineClick: [{
                type: Output
            }], lineDblClick: [{
                type: Output
            }], lineDrag: [{
                type: Output
            }], lineDragEnd: [{
                type: Output
            }], lineDragStart: [{
                type: Output
            }], lineMouseDown: [{
                type: Output
            }], lineMouseMove: [{
                type: Output
            }], lineMouseOut: [{
                type: Output
            }], lineMouseOver: [{
                type: Output
            }], lineMouseUp: [{
                type: Output
            }], lineRightClick: [{
                type: Output
            }], points: [{
                type: ContentChildren,
                args: [NgMapsPolylinePoint]
            }] } });

class RectangleManager {
    constructor(_apiWrapper, _zone) {
        this._apiWrapper = _apiWrapper;
        this._zone = _zone;
        this._rectangles = new Map();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: RectangleManager, deps: [{ token: MapsApiWrapper }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: RectangleManager }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: RectangleManager, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: MapsApiWrapper }, { type: i0.NgZone }] });

class NgMapsRectangleDirective {
    constructor(_manager) {
        this._manager = _manager;
        /**
         * Indicates whether this Rectangle handles mouse events. Defaults to true.
         */
        this.clickable = true;
        /**
         * If set to true, the user can drag this rectangle over the map. Defaults to false.
         */
        // eslint-disable-next-line @angular-eslint/no-input-rename
        this.draggable = false;
        /**
         * If set to true, the user can edit this rectangle by dragging the control points shown at
         * the center and around the circumference of the rectangle. Defaults to false.
         */
        this.editable = false;
        /**
         * The stroke position. Defaults to CENTER.
         * This property is not supported on Internet Explorer 8 and earlier.
         */
        this.strokePosition = 'CENTER';
        /**
         * The stroke width in pixels.
         */
        this.strokeWeight = 0;
        /**
         * Whether this rectangle is visible on the map. Defaults to true.
         */
        this.visible = true;
        /**
         * This event is fired when the rectangle's is changed.
         */
        this.boundsChange = new EventEmitter();
        /**
         * This event emitter gets emitted when the user clicks on the rectangle.
         */
        this.rectangleClick = new EventEmitter();
        /**
         * This event emitter gets emitted when the user clicks on the rectangle.
         */
        this.rectangleDblClick = new EventEmitter();
        /**
         * This event is repeatedly fired while the user drags the rectangle.
         */
        this.drag = new EventEmitter();
        /**
         * This event is fired when the user stops dragging the rectangle.
         */
        this.dragEnd = new EventEmitter();
        /**
         * This event is fired when the user starts dragging the rectangle.
         */
        this.dragStart = new EventEmitter();
        /**
         * This event is fired when the DOM mousedown event is fired on the rectangle.
         */
        this.mouseDown = new EventEmitter();
        /**
         * This event is fired when the DOM mousemove event is fired on the rectangle.
         */
        this.mouseMove = new EventEmitter();
        /**
         * This event is fired on rectangle mouseout.
         */
        this.mouseOut = new EventEmitter();
        /**
         * This event is fired on rectangle mouseover.
         */
        this.mouseOver = new EventEmitter();
        /**
         * This event is fired when the DOM mouseup event is fired on the rectangle.
         */
        this.mouseUp = new EventEmitter();
        /**
         * This event is fired when the rectangle is right-clicked on.
         */
        this.rightClick = new EventEmitter();
        this._rectangleAddedToManager = false;
        this.subscription = new Subscription();
    }
    static { this._mapOptions = [
        'fillColor',
        'fillOpacity',
        'strokeColor',
        'strokeOpacity',
        'strokePosition',
        'strokeWeight',
        'visible',
        'zIndex',
        'clickable',
    ]; }
    /** @internal */
    ngOnInit() {
        this._manager.addRectangle(this);
        this._rectangleAddedToManager = true;
        this._registerEventListeners();
    }
    /** @internal */
    ngOnChanges(changes) {
        if (!this._rectangleAddedToManager) {
            return;
        }
        if (changes.north || changes.east || changes.south || changes.west) {
            this._manager.setBounds(this);
        }
        if (changes.editable) {
            this._manager.setEditable(this);
        }
        if (changes.draggable) {
            this._manager.setDraggable(this);
        }
        if (changes.visible) {
            this._manager.setVisible(this);
        }
        this._updateRectangleOptionsChanges(changes);
    }
    _updateRectangleOptionsChanges(changes) {
        const options = {};
        const optionKeys = Object.keys(changes).filter((k) => NgMapsRectangleDirective._mapOptions.indexOf(k) !== -1);
        optionKeys.forEach((k) => {
            options[k] = changes[k].currentValue;
        });
        if (optionKeys.length > 0) {
            this._manager.setOptions(this, options);
        }
    }
    _registerEventListeners() {
        const events = new Map();
        events.set('bounds_changed', this.boundsChange);
        events.set('click', this.rectangleClick);
        events.set('dblclick', this.rectangleDblClick);
        events.set('drag', this.drag);
        events.set('dragend', this.dragEnd);
        events.set('dragStart', this.dragStart);
        events.set('mousedown', this.mouseDown);
        events.set('mousemove', this.mouseMove);
        events.set('mouseout', this.mouseOut);
        events.set('mouseover', this.mouseOver);
        events.set('mouseup', this.mouseUp);
        events.set('rightclick', this.rightClick);
        events.forEach((eventEmitter, eventName) => {
            this.subscription.add(this._manager
                .createEventObservable(eventName, this)
                .subscribe((value) => {
                switch (eventName) {
                    case 'bounds_changed':
                        this._manager
                            .getBounds(this)
                            .then((bounds) => eventEmitter.emit(bounds));
                        break;
                    default:
                        eventEmitter.emit(value);
                }
            }));
        });
    }
    /** @internal */
    ngOnDestroy() {
        this.subscription.unsubscribe();
        this._manager.removeRectangle(this);
    }
    /**
     * Gets the LatLngBounds of this Rectangle.
     */
    getBounds() {
        return this._manager.getBounds(this);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsRectangleDirective, deps: [{ token: RectangleManager }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.8", type: NgMapsRectangleDirective, selector: "map-rectangle", inputs: { north: "north", east: "east", south: "south", west: "west", clickable: "clickable", draggable: ["rectangleDraggable", "draggable"], editable: "editable", fillColor: "fillColor", fillOpacity: "fillOpacity", strokeColor: "strokeColor", strokeOpacity: "strokeOpacity", strokePosition: "strokePosition", strokeWeight: "strokeWeight", visible: "visible", zIndex: "zIndex" }, outputs: { boundsChange: "boundsChange", rectangleClick: "rectangleClick", rectangleDblClick: "rectangleDblClick", drag: "drag", dragEnd: "dragEnd", dragStart: "dragStart", mouseDown: "mouseDown", mouseMove: "mouseMove", mouseOut: "mouseOut", mouseOver: "mouseOver", mouseUp: "mouseUp", rightClick: "rightClick" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsRectangleDirective, decorators: [{
            type: Directive,
            args: [{
                    // eslint-disable-next-line @angular-eslint/directive-selector
                    selector: 'map-rectangle',
                }]
        }], ctorParameters: () => [{ type: RectangleManager }], propDecorators: { north: [{
                type: Input
            }], east: [{
                type: Input
            }], south: [{
                type: Input
            }], west: [{
                type: Input
            }], clickable: [{
                type: Input
            }], draggable: [{
                type: Input,
                args: ['rectangleDraggable']
            }], editable: [{
                type: Input
            }], fillColor: [{
                type: Input
            }], fillOpacity: [{
                type: Input
            }], strokeColor: [{
                type: Input
            }], strokeOpacity: [{
                type: Input
            }], strokePosition: [{
                type: Input
            }], strokeWeight: [{
                type: Input
            }], visible: [{
                type: Input
            }], zIndex: [{
                type: Input
            }], boundsChange: [{
                type: Output
            }], rectangleClick: [{
                type: Output
            }], rectangleDblClick: [{
                type: Output
            }], drag: [{
                type: Output
            }], dragEnd: [{
                type: Output
            }], dragStart: [{
                type: Output
            }], mouseDown: [{
                type: Output
            }], mouseMove: [{
                type: Output
            }], mouseOut: [{
                type: Output
            }], mouseOver: [{
                type: Output
            }], mouseUp: [{
                type: Output
            }], rightClick: [{
                type: Output
            }] } });

/**
 * 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.
 */
let NoOpMapsAPILoader = class NoOpMapsAPILoader extends MapsAPILoader {
    constructor(document) {
        super();
        this._document = document;
        this._window = this._document.defaultView;
    }
    load() {
        return Promise.resolve();
    }
    // eslint-disable-next-line @typescript-eslint/no-empty-function
    configure(config) { }
};
NoOpMapsAPILoader = __decorate([
    __param(0, Inject(DOCUMENT)),
    __metadata("design:paramtypes", [Object])
], NoOpMapsAPILoader);

class ScriptLoaderService {
    constructor(document) {
        this.alreadyLoaded = new Map();
        this.document = document;
        this.head = this.document.head;
    }
    observeLoad(element) {
        return new Promise((resolve, reject) => {
            function successHandler(event) {
                const readyState = element.readyState;
                // For IE we have readyState, other browsers just call the load event and we proccede
                if (readyState === 'complete' ||
                    readyState === 'loaded' ||
                    event.type === 'load') {
                    resolve(event);
                }
            }
            function errorHandler(event) {
                reject(event);
            }
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            element.addEventListener('readystatechange', successHandler);
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            element.addEventListener('load', successHandler);
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            element.addEventListener('error', errorHandler);
        });
    }
    createScriptElement(src) {
        const script = document.createElement('script');
        script.src = src;
        script.type = 'text/javascript';
        script.async = true;
        script.defer = true;
        return script;
    }
    // eslint-disable-next-line
    createCSSElement(href) {
        const style = document.createElement('link');
        style.rel = 'stylesheet';
        style.type = 'text/css';
        style.href = href;
        return style;
    }
    /**
     * Dynamically loads the given script
     *
     * @param src The url of the script to load dynamically
     * @param integrity set integrity check value
     * @returns Observable<UIEvent> Observable that will be resolved once the script has been loaded.
     */
    loadScript(src, integrity) {
        if (this.alreadyLoaded.has(src)) {
            return this.alreadyLoaded.get(src);
        }
        else {
            const script = this.createScriptElement(src);
            const promise = this.observeLoad(script);
            this.head.appendChild(script);
            this.alreadyLoaded.set(src, promise);
            return promise;
        }
    }
    /**
     * Dynamically loads the given CSS file
     *
     * @param href The url of the CSS to load dynamically
     * @returns Observable<UIEvent> Promise that will be resolved once the CSS file has been loaded.
     */
    loadCSS(href) {
        // eslint-disable-line
        if (this.alreadyLoaded.has(href)) {
            return this.alreadyLoaded.get(href);
        }
        else {
            const style = this.createCSSElement(href);
            const promise = this.observeLoad(style);
            this.head.appendChild(style);
            this.alreadyLoaded.set(href, promise);
            return promise;
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: ScriptLoaderService, deps: [{ token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: ScriptLoaderService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: ScriptLoaderService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root',
                }]
        }], ctorParameters: () => [{ type: undefined, decorators: [{
                    type: Inject,
                    args: [DOCUMENT]
                }] }] });

const MAP_PROVIDER = new InjectionToken('Map Provider');
function isGoogleMaps(token) {
    return token === 'GoogleMaps';
}
function isHereMaps(token) {
    return token === 'HereMaps';
}
/**
 * @internal
 */
function coreDirectives() {
    return [
        NgMapsViewComponent,
        NgMapsMarkerComponent,
        NgMapsInfoWindowComponent,
        NgMapsFitBoundsDirective,
        NgMapsCircleDirective,
        NgMapsPolygonDirective,
        NgMapsPolyline,
        NgMapsPolylinePoint,
        NgMapsRectangleDirective,
    ];
}
/**
 * The ng-maps core module. Contains all Directives/Services/Pipes
 */
class NgMapsCoreModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsCoreModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.8", ngImport: i0, type: NgMapsCoreModule, declarations: [NgMapsViewComponent,
            NgMapsMarkerComponent,
            NgMapsInfoWindowComponent,
            NgMapsFitBoundsDirective,
            NgMapsCircleDirective,
            NgMapsPolygonDirective,
            NgMapsPolyline,
            NgMapsPolylinePoint,
            NgMapsRectangleDirective], exports: [NgMapsViewComponent,
            NgMapsMarkerComponent,
            NgMapsInfoWindowComponent,
            NgMapsFitBoundsDirective,
            NgMapsCircleDirective,
            NgMapsPolygonDirective,
            NgMapsPolyline,
            NgMapsPolylinePoint,
            NgMapsRectangleDirective] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsCoreModule }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsCoreModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: coreDirectives(),
                    exports: coreDirectives(),
                }]
        }] });

/*
 * Public API Surface of core
 */
// interfaces

/**
 * Generated bundle index. Do not edit.
 */

export { CircleManager, FitBoundsAccessor, FitBoundsService, InfoWindowManager, MAP_PROVIDER, MapsAPILoader, MapsApiWrapper, MarkerManager, NgMapsCircleDirective, NgMapsCoreModule, NgMapsFitBoundsDirective, NgMapsInfoWindowComponent, NgMapsMarkerComponent, NgMapsPolygonDirective, NgMapsPolyline, NgMapsPolylinePoint, NgMapsRectangleDirective, NgMapsViewComponent, NoOpMapsAPILoader, PolygonManager, PolylineManager, RectangleManager, ScriptLoaderService, isGoogleMaps, isHereMaps };
//# sourceMappingURL=ng-maps-core.mjs.map