import {Injectable, NgZone} from '@angular/core'; import {Observable} from 'rxjs/Observable'; import {Observer} from 'rxjs/Observer'; import * as mapTypes from './google-maps-types'; import {Polyline} from './google-maps-types'; import {PolylineOptions} from './google-maps-types'; import {MapsAPILoader} from './maps-api-loader/maps-api-loader'; // todo: add types for this declare var google: any; /** * Wrapper class that handles the communication with the Google Maps Javascript * API v3 */ @Injectable() export class GoogleMapsAPIWrapper { private _map: Promise; private _mapResolver: (value?: mapTypes.GoogleMap) => void; constructor(private _loader: MapsAPILoader, private _zone: NgZone) { this._map = new Promise((resolve: () => void) => { this._mapResolver = resolve; }); } createMap(el: HTMLElement, mapOptions: mapTypes.MapOptions): Promise { return this._loader.load().then(() => { const map = new google.maps.Map(el, mapOptions); this._mapResolver(map); return; }); } setMapOptions(options: mapTypes.MapOptions) { this._map.then((m: mapTypes.GoogleMap) => { m.setOptions(options); }); } /** * Creates a google map marker with the map context */ createMarker(options: mapTypes.MarkerOptions = {}): Promise { return this._map.then((map: mapTypes.GoogleMap) => { options.map = map; return new google.maps.Marker(options); }); } createInfoWindow(options?: mapTypes.InfoWindowOptions): Promise { return this._map.then(() => { return new google.maps.InfoWindow(options); }); } /** * Creates a google.map.Circle for the current map. */ createCircle(options: mapTypes.CircleOptions): Promise { return this._map.then((map: mapTypes.GoogleMap) => { options.map = map; return new google.maps.Circle(options); }); } createPolyline(options: PolylineOptions): Promise { return this.getNativeMap().then((map: mapTypes.GoogleMap) => { let line = new google.maps.Polyline(options); line.setMap(map); return line; }); } createPolygon(options: mapTypes.PolygonOptions): Promise { return this.getNativeMap().then((map: mapTypes.GoogleMap) => { let polygon = new google.maps.Polygon(options); polygon.setMap(map); return polygon; }); } /** * Determines if given coordinates are insite a Polygon path. */ containsLocation(latLng: mapTypes.LatLngLiteral, polygon: mapTypes.Polygon): Promise { return google.maps.geometry.poly.containsLocation(latLng, polygon); } subscribeToMapEvent(eventName: string): Observable { return Observable.create((observer: Observer) => { this._map.then((m: mapTypes.GoogleMap) => { m.addListener(eventName, (arg: E) => { this._zone.run(() => observer.next(arg)); }); }); }); } setCenter(latLng: mapTypes.LatLngLiteral): Promise { return this._map.then((map: mapTypes.GoogleMap) => map.setCenter(latLng)); } getZoom(): Promise { return this._map.then((map: mapTypes.GoogleMap) => map.getZoom()); } getBounds(): Promise { return this._map.then((map: mapTypes.GoogleMap) => map.getBounds()); } setZoom(zoom: number): Promise { return this._map.then((map: mapTypes.GoogleMap) => map.setZoom(zoom)); } getCenter(): Promise { return this._map.then((map: mapTypes.GoogleMap) => map.getCenter()); } panTo(latLng: mapTypes.LatLng|mapTypes.LatLngLiteral): Promise { return this._map.then((map) => map.panTo(latLng)); } fitBounds(latLng: mapTypes.LatLngBounds|mapTypes.LatLngBoundsLiteral): Promise { return this._map.then((map) => map.fitBounds(latLng)); } panToBounds(latLng: mapTypes.LatLngBounds|mapTypes.LatLngBoundsLiteral): Promise { return this._map.then((map) => map.panToBounds(latLng)); } /** * Returns the native Google Maps Map instance. Be careful when using this instance directly. */ getNativeMap(): Promise { return this._map; } /** * Triggers the given event name on the map instance. */ triggerMapEvent(eventName: string): Promise { return this._map.then((m) => google.maps.event.trigger(m, eventName)); } }