diff --git a/src/components.ts b/src/components.ts
index e800cdef1..0cfe0321d 100644
--- a/src/components.ts
+++ b/src/components.ts
@@ -1 +1,2 @@
export * from './components/google_map';
+export * from './components/google_map_marker';
diff --git a/src/components/google_map.ts b/src/components/google_map.ts
index e4b20bd7d..01c8aa0bd 100644
--- a/src/components/google_map.ts
+++ b/src/components/google_map.ts
@@ -1,20 +1,24 @@
-import {Component, Directive, Input, Output, ContentChild, ElementRef, ViewChild, SimpleChange, NgZone, Provider, EventEmitter} from 'angular2/angular2';
+import {Component, Directive, Provider, Input, Output, Renderer, ContentChildren, ElementRef, SimpleChange, NgZone, EventEmitter, QueryList, provide} from 'angular2/angular2';
import {GoogleMapsAPIWrapper, GoogleMapsAPIWrapperFactory} from '../services/google_maps_api_wrapper';
+import {SebmGoogleMapMarker} from './google_map_marker';
+import {MarkerManager} from '../services/marker_manager';
/**
* Todo: add docs
*/
@Component({
selector: 'sebm-google-map',
- providers: [GoogleMapsAPIWrapperFactory],
+ providers: [GoogleMapsAPIWrapperFactory, MarkerManager],
+ viewProviders: [MarkerManager],
styles: [`
- .sebm-google-map-container {
- width: 100%;
+ .sebm-google-map-container-inner {
+ width: inherit;
+ height: inherit;
display: block;
}
`],
template: `
-
+
`
})
@@ -24,8 +28,9 @@ export class SebmGoogleMap {
private _zoom: number = 8;
private _mapsWrapper: GoogleMapsAPIWrapper;
- constructor(private elem: ElementRef, private _zone: NgZone, mapsFactory: GoogleMapsAPIWrapperFactory) {
- this._initMapInstance(elem.nativeElement.querySelector('.sebm-google-map-container'), mapsFactory);
+ constructor(private elem: ElementRef, private _zone: NgZone, mapsFactory: GoogleMapsAPIWrapperFactory, renderer: Renderer) {
+ renderer.setElementClass(elem, 'sebm-google-map-container', true);
+ this._initMapInstance(elem.nativeElement.querySelector('.sebm-google-map-container-inner'), mapsFactory);
}
private _initMapInstance(el: HTMLElement, mapsFactory: GoogleMapsAPIWrapperFactory) {
@@ -36,8 +41,10 @@ export class SebmGoogleMap {
@Input()
set zoom(value: number|string) {
- this._zoom = this._convertToDecimal(value);
- this._mapsWrapper.setZoom(this._zoom);
+ this._zoom = this._convertToDecimal(value);
+ if (typeof this._zoom === 'number') {
+ this._mapsWrapper.setZoom(this._zoom);
+ }
}
@Input()
@@ -55,11 +62,16 @@ export class SebmGoogleMap {
private _convertToDecimal(value: string|number): number {
if (typeof value === 'string') {
return parseFloat(value);
+ } else if (typeof value === 'number') {
+ return value;
}
- return value;
+ return null;
}
private _updateCenter() {
+ if (typeof this._latitude !== 'number' || typeof this._longitude !== 'number') {
+ return;
+ }
this._mapsWrapper.setCenter({
lat: this._latitude,
lng: this._longitude,
diff --git a/src/components/google_map_marker.ts b/src/components/google_map_marker.ts
new file mode 100644
index 000000000..dc7ecf580
--- /dev/null
+++ b/src/components/google_map_marker.ts
@@ -0,0 +1,48 @@
+import {Directive, Input, provide, Host, Inject, SkipSelf, SimpleChange} from 'angular2/angular2';
+import {GoogleMapsAPIWrapper} from '../services/google_maps_api_wrapper';
+import {MarkerManager} from '../services/marker_manager';
+import {SebmGoogleMap} from './google_map';
+
+let markerId = 0;
+
+@Directive({
+ selector: 'sebm-google-map-marker'
+})
+export class SebmGoogleMapMarker {
+ @Input() latitude: number;
+ @Input() longitude: number;
+ @Input() title: string;
+
+ private _markerAddedToManger: boolean = false;
+ private _id: string;
+
+ constructor(@Host() @SkipSelf() private _map: SebmGoogleMap, private _markerManager: MarkerManager) {
+ this._id = (markerId++).toString();
+ }
+
+ onChanges(changes: {[key: string]: SimpleChange}) {
+ if (!this._markerAddedToManger && this.latitude && this.longitude) {
+ this._markerManager.addMarker(this);
+ this._markerAddedToManger = true;
+ return;
+ }
+ if (changes['latitude'] || changes['logitude']) {
+ this._markerManager.updateMarkerPosition(this);
+ }
+ if (changes['title']) {
+ this._markerManager.updateTitle(this);
+ }
+ }
+
+ id(): string {
+ return this._id;
+ }
+
+ toString(): string {
+ return 'SebmGoogleMapMarker-' + this._id.toString();
+ }
+
+ onDestroy() {
+ this._markerManager.deleteMarker(this);
+ }
+}
diff --git a/src/custom_typings/google_maps.d.ts b/src/custom_typings/google_maps.d.ts
index 2c52478bb..4efb8bf2b 100644
--- a/src/custom_typings/google_maps.d.ts
+++ b/src/custom_typings/google_maps.d.ts
@@ -15,6 +15,19 @@ declare module google.maps {
lng(): number;
}
+ export class Marker {
+ constructor(options?: MarkerOptions)
+ setMap(map:Map): void
+ setPosition(latLng: LatLng|LatLngLiteral): void
+ setTitle(title: string): void;
+ }
+
+ export interface MarkerOptions {
+ position: LatLng|LatLngLiteral;
+ title?: string;
+ map?: Map;
+ }
+
export interface LatLngLiteral {
lat: number;
lng: number;
diff --git a/src/services/google_maps_api_wrapper.ts b/src/services/google_maps_api_wrapper.ts
index 7c3f1e03c..310ca3ed2 100644
--- a/src/services/google_maps_api_wrapper.ts
+++ b/src/services/google_maps_api_wrapper.ts
@@ -8,13 +8,11 @@ import {Observable} from 'rx';
export class GoogleMapsAPIWrapper {
private _el: HTMLElement;
private _map: google.maps.Map;
- private _isInitialized: boolean;
private _centerChangeObservable: Observable;
private _zoomChangeObservable: Observable;
constructor(_el: HTMLElement, latitude: number, longitude: number, private _zone: NgZone) {
- this._isInitialized = true;
this._el = _el;
this._map = new google.maps.Map(this._el, {
center: {
@@ -28,9 +26,7 @@ export class GoogleMapsAPIWrapper {
createEventObservable(eventName: string, callback: (observer: Rx.Observer) => void): Observable {
return Observable.create((observer: Rx.Observer) => {
this._map.addListener(eventName, () => {
- this._zone.run(() => {
- callback(observer);
- });
+ callback(observer);
});
});
}
@@ -48,6 +44,14 @@ export class GoogleMapsAPIWrapper {
});
}
+ /**
+ * Creates a google map marker with the map context
+ */
+ createMarker(options: google.maps.MarkerOptions = {}): google.maps.Marker {
+ options.map = this._map;
+ return new google.maps.Marker(options);
+ }
+
getZoomChangeObserable(): Observable {
return this._zoomChangeObservable;
}
@@ -65,21 +69,27 @@ export class GoogleMapsAPIWrapper {
}
getCenter(): google.maps.LatLng {
- if (!this._isInitialized) {
- return;
- }
return this._map.getCenter();
}
-
- isInitialized(): boolean {
- return this._isInitialized;
- }
}
+// todo: change name, because it's not a real factory.
+// We have to create the instance with the component element and I don't see
+// any chances to modify the viewproviders for after the component instance is created.
@Injectable()
export class GoogleMapsAPIWrapperFactory {
+ private _instance: GoogleMapsAPIWrapper;
+
constructor(private _zone: NgZone) {}
+
create(el: HTMLElement, latitude: number, longitude: number): GoogleMapsAPIWrapper {
- return new GoogleMapsAPIWrapper(el, latitude, latitude, this._zone);
+ if (this._instance) {
+ throw new Error('instance already created');
+ }
+ return this._instance = new GoogleMapsAPIWrapper(el, latitude, latitude, this._zone);
+ }
+
+ getInstance(): GoogleMapsAPIWrapper {
+ return this._instance;
}
}
diff --git a/src/services/marker_manager.ts b/src/services/marker_manager.ts
new file mode 100644
index 000000000..515c61d39
--- /dev/null
+++ b/src/services/marker_manager.ts
@@ -0,0 +1,39 @@
+import {Injectable} from 'angular2/angular2';
+import {SebmGoogleMapMarker} from '../components/google_map_marker';
+import {GoogleMapsAPIWrapperFactory, GoogleMapsAPIWrapper} from './google_maps_api_wrapper';
+
+@Injectable()
+export class MarkerManager {
+ private _markers: Map = new Map();
+ private _mapsAPI: GoogleMapsAPIWrapper;
+
+ constructor(f: GoogleMapsAPIWrapperFactory) {
+ this._mapsAPI = f.getInstance();
+ }
+
+ deleteMarker(marker: SebmGoogleMapMarker) {
+ console.log(this._markers.values());
+ this._markers.get(marker).setMap(null);
+ this._markers.delete(marker);
+ }
+
+ updateMarkerPosition(marker: SebmGoogleMapMarker) {
+ this._markers.get(marker).setPosition({
+ lat: marker.latitude,
+ lng: marker.longitude
+ });
+ }
+
+ updateTitle(marker: SebmGoogleMapMarker) {
+ this._markers.get(marker).setTitle(marker.title);
+ }
+
+ addMarker(marker: SebmGoogleMapMarker) {
+ this._markers.set(marker, this._mapsAPI.createMarker({
+ position: {
+ lat: marker.latitude,
+ lng: marker.longitude
+ }
+ }));
+ }
+}