infusion-code/angular-maps

View on GitHub
src/services/bing/bing-layer-base.ts

Summary

Maintainability
C
1 day
Test Coverage
import { Injectable, NgZone } from '@angular/core';
import { IMarkerOptions } from '../../interfaces/imarker-options';
import { IMarkerIconInfo } from '../../interfaces/imarker-icon-info';
import { Marker } from '../../models/marker';
import { BingMarker } from '../../models/bing/bing-marker';
import { Layer } from '../../models/layer';
import { MarkerTypeId } from '../../models/marker-type-id';
import { MapService } from '../map.service';
import { MapLayerDirective } from '../../components/map-layer';
import { LayerService } from '../layer.service';
import { BingMapService } from './bing-map.service';
import { BingConversions } from './bing-conversions';

/**
 * This abstract partially implements the contract for the {@link LayerService}
 * and {@link ClusterService} for the Bing Maps V8 archtiecture. It serves
 * as the base class for basic layer ({@link BingLayerService}) and cluster layer ({@link BingClusterLayer}).
 *
 * @export
 * @abstract
 */
export abstract class BingLayerBase {

    ///
    /// Field declarations
    ///

    protected _layers: Map<number, Promise<Layer>> = new Map<number, Promise<Layer>>();

    ///
    /// Constructor
    ///

    /**
     * Creates an instance of BingLayerBase.
     * @param _mapService - Concrete {@link MapService} implementation for Bing Maps V8. An instance of {@link BingMapService}.
     *
     * @memberof BingLayerBase
     */
    constructor(protected _mapService: MapService, protected _zone: NgZone) { }

    ///
    /// Public methods
    ///

    /**
     * Adds a layer to the map.
     *
     * @abstract
     * @param layer - MapLayerDirective component object.
     * Generally, MapLayerDirective will be injected with an instance of the
     * LayerService and then self register on initialization.
     *
     * @memberof BingLayerBase
     */
    public abstract AddLayer(layer: MapLayerDirective): void;

    /**
     * Creates a marker in the layer.
     *
     * @param layer - The Id of the layer in which to create the marker.
     * @param options - {@link IMarkerOptions} object containing the marker properties.
     * @returns - A promise that when fullfilled contains the {@link Marker} model for the created marker.
     *
     * @memberof BingLayerBase
     */
    public CreateMarker(layer: number, options: IMarkerOptions): Promise<Marker> {
        const payload = (icon: string, l: Layer): BingMarker => {
            const loc: Microsoft.Maps.Location = BingConversions.TranslateLocation(options.position);
            const o: Microsoft.Maps.IPushpinOptions = BingConversions.TranslateMarkerOptions(options);
            if (icon && icon !== '') { o.icon = icon; }
            const pushpin: Microsoft.Maps.Pushpin = new Microsoft.Maps.Pushpin(loc, o);
            const marker: BingMarker = new BingMarker(pushpin, null, l.NativePrimitve);
            marker.IsFirst = options.isFirst;
            marker.IsLast = options.isLast;
            if (options.metadata) { options.metadata.forEach((v, k) => marker.Metadata.set(k, v)); }
            l.AddEntity(marker);
            return marker;
        };
        const p: Promise<Layer> = this.GetLayerById(layer);
        if (p == null) { throw (new Error(`Layer with id ${layer} not found in Layer Map`)); }
        return p.then((l: Layer) => {
            if (options.iconInfo && options.iconInfo.markerType) {
                const s = Marker.CreateMarker(options.iconInfo);
                if (typeof(s) === 'string') { return(payload(s, l)); }
                else {
                    return s.then(x => {
                        return(payload(x.icon, l));
                    });
                }
            }
            else {
                return (payload(null, l));
            }
        });
    }

    /**
     * Creates an array of unbound markers. Use this method to create arrays of markers to be used in bulk
     * operations.
     *
     * @param options - Marker options defining the markers.
     * @param markerIcon - Optional information to generate custom markers. This will be applied to all markers.
     * @returns - A promise that when fullfilled contains the an arrays of the Marker models.
     *
     * @memberof BingLayerBase
     */
    public CreateMarkers(options: Array<IMarkerOptions>, markerIcon?: IMarkerIconInfo): Promise<Array<Marker>> {
        const payload = (icon: string, op: Array<IMarkerOptions>): Array<BingMarker> => {
            const markers: Array<BingMarker> = op.map(mo => {
                let s: string;
                const o: Microsoft.Maps.IPushpinOptions = BingConversions.TranslateMarkerOptions(mo);
                if (icon && icon !== '' ) { s = icon; }
                else if (o.icon) {
                    s = o.icon;
                }
                if (o.icon) { delete o.icon; }
                const loc: Microsoft.Maps.Location = BingConversions.TranslateLocation(mo.position);
                const pushpin: Microsoft.Maps.Pushpin = new Microsoft.Maps.Pushpin(loc, o);
                const img = Marker.GetImageForMarker(s);
                if (img != null) { (<any>pushpin).image = img; }

                const marker: BingMarker = new BingMarker(pushpin, null, null);
                marker.IsFirst = mo.isFirst;
                marker.IsLast = mo.isLast;
                if (mo.metadata) { mo.metadata.forEach((v, k) => marker.Metadata.set(k, v)); }
                return marker;
            });
            return markers;
        };
        const p: Promise<Array<Marker>> = new Promise<Array<Marker>>((resolve, reject) => {
            if (markerIcon && markerIcon.markerType) {
                const s = Marker.CreateMarker(markerIcon);
                if (typeof(s) === 'string') { resolve(payload(s, options)); }
                else {
                    return s.then(x => {
                        resolve(payload(x.icon, options));
                    });
                }
            }
            else {
                resolve(payload(null, options));
            }
        });
        return p;
    }

    /**
     * Deletes the layer
     *
     * @param layer - MapLayerDirective component object for which to retrieve the layer.
     * @returns - A promise that is fullfilled when the layer has been removed.
     *
     * @memberof BingLayerBase
     */
    public DeleteLayer(layer: MapLayerDirective): Promise<void> {
        const l = this._layers.get(layer.Id);
        if (l == null) {
            return Promise.resolve();
        }
        return l.then((l1: Layer) => {
            return this._zone.run(() => {
                l1.Delete();
                this._layers.delete(layer.Id);
            });
        });
    }

    /**
     * Returns the Layer model represented by this layer.
     *
     * @param layer - MapLayerDirective component object or Layer Id for which to retrieve the layer model.
     * @returns - A promise that when resolved contains the Layer model.
     *
     * @memberof BingLayerBase
     */
    public GetNativeLayer(layer: MapLayerDirective|number): Promise<Layer> {
        let p: Promise<Layer> = null;
        if (typeof(layer) === 'number') {
            p = this._layers.get(layer);
        }
        else {
            p = this._layers.get((<MapLayerDirective>layer).Id);
        }
        return p;
    }

    ///
    /// Protected methods
    ///

    /**
     * Gets the layer based on its id.
     *
     * @protected
     * @param id - Layer Id.
     * @returns - A promise that when fullfilled contains the {@link Layer} model for the layer.
     *
     * @memberof BingLayerBase
     */
    protected GetLayerById(id: number): Promise<Layer> {
        let p: Promise<Layer>;
        this._layers.forEach((l: Promise<Layer>, k: number) => { if (k === id) { p = l; } });
        return p;
    }

}