infusion-code/angular-maps

View on GitHub
src/services/bing/bing-polyline.service.ts

Summary

Maintainability
F
4 days
Test Coverage
import { Injectable, NgZone } from '@angular/core';
import { Observable, Observer, Subject } from 'rxjs';
import { IPolylineOptions } from '../../interfaces/ipolyline-options';
import { ILatLong } from '../../interfaces/ilatlong';
import { Polyline } from '../../models/polyline';
import { MapPolylineDirective } from '../../components/map-polyline';
import { PolylineService } from '../polyline.service';
import { MapService } from '../map.service';
import { LayerService } from '../layer.service';

/**
 * Concrete implementation of the Polyline Service abstract class for Bing Maps V8.
 *
 * @export
 */
@Injectable()
export class BingPolylineService implements PolylineService {

    ///
    /// Field declarations
    ///
    private _polylines: Map<MapPolylineDirective, Promise<Polyline|Array<Polyline>>> =
    new Map<MapPolylineDirective, Promise<Polyline|Array<Polyline>>>();

    ///
    /// Constructor
    ///

    /**
     * Creates an instance of BingPolylineService.
     * @param _mapService - {@link MapService} instance. The concrete {@link BingMapService} implementation is expected.
     * @param _layerService - {@link LayerService} instance.
     * The concrete {@link BingLayerService} implementation is expected.
     * @param _zone - NgZone instance to support zone aware promises.
     *
     * @memberof BingPolylineService
     */
    constructor(private _mapService: MapService,
        private _layerService: LayerService,
        private _zone: NgZone) {
    }

    ///
    /// Public members and MarkerService implementation
    ///

    /**
     * Adds a polyline to a map. Depending on the polyline context, the polyline will either by added to the map or a
     * corresponding layer.
     *
     * @param polyline - The {@link MapPolylineDirective} to be added.
     *
     * @memberof BingPolylineService
     */
    public AddPolyline(polyline: MapPolylineDirective): void {
        const o: IPolylineOptions = {
            id: polyline.Id,
            clickable: polyline.Clickable,
            draggable: polyline.Draggable,
            editable: polyline.Editable,
            geodesic: polyline.Geodesic,
            path: polyline.Path,
            showTooltip: polyline.ShowTooltip,
            strokeColor: polyline.StrokeColor,
            strokeOpacity: polyline.StrokeOpacity,
            strokeWeight: polyline.StrokeWeight,
            title: polyline.Title,
            visible: polyline.Visible,
            zIndex: polyline.zIndex,
        };
        let polylinePromise: Promise<Polyline|Array<Polyline>>;
        if (polyline.InCustomLayer) {
            polylinePromise = this._layerService.CreatePolyline(polyline.LayerId, o);
        } else {
            polylinePromise = this._mapService.CreatePolyline(o);
        }
        this._polylines.set(polyline, polylinePromise);
    }

    /**
      * Registers an event delegate for a line.
      *
      * @param eventName - The name of the event to register (e.g. 'click')
      * @param polyline - The {@link MapPolylineDirective} for which to register the event.
      * @returns - Observable emiting an instance of T each time the event occurs.
      *
      * @memberof BingPolylineService
      */
    public CreateEventObservable<T>(eventName: string, polyline: MapPolylineDirective): Observable<T> {
        const b: Subject<T> = new Subject<T>();
        if (eventName === 'mousemove') {
            return b.asObservable();
        }
        if (eventName === 'rightclick') {
            return b.asObservable();
        }
        ///
        /// mousemove and rightclick are not supported by bing polygons.
        ///
        return Observable.create((observer: Observer<T>) => {
            this._polylines.get(polyline).then(p => {
                const x: Array<Polyline> = Array.isArray(p) ? p : [p];
                x.forEach(line => line.AddListener(eventName, (e: T) => this._zone.run(() => observer.next(e))));
            });
        });
    }

    /**
      * Deletes a polyline.
      *
      * @param polyline - {@link MapPolylineDirective} to be deleted.
      * @returns - A promise fullfilled once the polyline has been deleted.
      *
      * @memberof BingPolylineService
      */
    public DeletePolyline(polyline: MapPolylineDirective): Promise<void> {
        const m = this._polylines.get(polyline);
        if (m == null) {
            return Promise.resolve();
        }
        return m.then((l: Polyline) => {
            return this._zone.run(() => {
                const x: Array<Polyline> = Array.isArray(l) ? l : [l];
                x.forEach(line =>  line.Delete());
                this._polylines.delete(polyline);
            });
        });

    }

    /**
     * Obtains geo coordinates for the marker on the click location
     *
     * @abstract
     * @param e - The mouse event.
     * @returns - {@link ILatLong} containing the geo coordinates of the clicked marker.
     *
     * @memberof BingPolylineService
     */
    public GetCoordinatesFromClick(e: Microsoft.Maps.IMouseEventArgs): ILatLong {
        if (!e) { return null; }
        if (!e.location) { return null; }
        return { latitude: e.location.latitude, longitude: e.location.longitude };
    }

    /**
     * Obtains the marker model for the marker allowing access to native implementation functionatiliy.
     *
     * @param polyline - The {@link MapPolylineDirective} for which to obtain the polyline model.
     * @returns - A promise that when fullfilled contains the {@link Polyline}
     * implementation of the underlying platform. For complex paths, returns an array of polylines.
     *
     * @memberof BingPolylineService
     */
    public GetNativePolyline(polyline: MapPolylineDirective): Promise<Polyline|Array<Polyline>> {
        return this._polylines.get(polyline);
    }

    /**
     * Set the polyline options.
     *
     * @param polyline - {@link MapPolylineDirective} to be updated.
     * @param options - {@link IPolylineOptions} object containing the options. Options will be merged with the
     * options already on the underlying object.
     * @returns - A promise fullfilled once the polyline options have been set.
     *
     * @memberof BingPolylineService
     */
    public SetOptions(polyline: MapPolylineDirective, options: IPolylineOptions): Promise<void> {
        return this._polylines.get(polyline).then(l => {
            const x: Array<Polyline> = Array.isArray(l) ? l : [l];
            x.forEach(line => line.SetOptions(options));
        });
    }

    /**
     * Updates the Polyline path
     *
     * @param polyline - {@link MapPolylineDirective} to be updated.
     * @returns - A promise fullfilled once the polyline has been updated.
     *
     * @memberof BingPolylineService
     */
    public UpdatePolyline(polyline: MapPolylineDirective): Promise<void> {
        const m = this._polylines.get(polyline);
        if (m == null) {
            return Promise.resolve();
        }
        return m.then(l => this._zone.run(() => {
            const x: Array<Polyline> = Array.isArray(l) ? l : [l];
            const p: Array<Array<ILatLong>> =
                polyline.Path.length > 0 && Array.isArray(polyline.Path[0]) ? <Array<Array<ILatLong>>>polyline.Path :
                <Array<Array<ILatLong>>>[polyline.Path];
             x.forEach((line, index) => {
                 if (p.length > index) { line.SetPath(p[index]); }
            });
            if (Array.isArray(l) && l.length > p.length) {
                l.splice(p.length - 1).forEach(line => line.Delete());
            }
        }));
    }
}