Skip to content
This repository was archived by the owner on Jun 23, 2025. It is now read-only.

Commit ec644a4

Browse files
committed
feat(marker): add basic marker support
Introduces a new directive <sebm-google-map-marker> that accepts three bindings: - latitude (required) - longitude (required) - title (optional)
1 parent 4b90bfb commit ec644a4

6 files changed

Lines changed: 146 additions & 23 deletions

File tree

src/components.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './components/google_map';
2+
export * from './components/google_map_marker';

src/components/google_map.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
1-
import {Component, Directive, Input, Output, ContentChild, ElementRef, ViewChild, SimpleChange, NgZone, Provider, EventEmitter} from 'angular2/angular2';
1+
import {Component, Directive, Provider, Input, Output, Renderer, ContentChildren, ElementRef, SimpleChange, NgZone, EventEmitter, QueryList, provide} from 'angular2/angular2';
22
import {GoogleMapsAPIWrapper, GoogleMapsAPIWrapperFactory} from '../services/google_maps_api_wrapper';
3+
import {SebmGoogleMapMarker} from './google_map_marker';
4+
import {MarkerManager} from '../services/marker_manager';
35

46
/**
57
* Todo: add docs
68
*/
79
@Component({
810
selector: 'sebm-google-map',
9-
providers: [GoogleMapsAPIWrapperFactory],
11+
providers: [GoogleMapsAPIWrapperFactory, MarkerManager],
12+
viewProviders: [MarkerManager],
1013
styles: [`
11-
.sebm-google-map-container {
12-
width: 100%;
14+
.sebm-google-map-container-inner {
15+
width: inherit;
16+
height: inherit;
1317
display: block;
1418
}
1519
`],
1620
template: `
17-
<div class="sebm-google-map-container"></div>
21+
<div class="sebm-google-map-container-inner"></div>
1822
<ng-content></ng-content>
1923
`
2024
})
@@ -24,8 +28,9 @@ export class SebmGoogleMap {
2428
private _zoom: number = 8;
2529
private _mapsWrapper: GoogleMapsAPIWrapper;
2630

27-
constructor(private elem: ElementRef, private _zone: NgZone, mapsFactory: GoogleMapsAPIWrapperFactory) {
28-
this._initMapInstance(elem.nativeElement.querySelector('.sebm-google-map-container'), mapsFactory);
31+
constructor(private elem: ElementRef, private _zone: NgZone, mapsFactory: GoogleMapsAPIWrapperFactory, renderer: Renderer) {
32+
renderer.setElementClass(elem, 'sebm-google-map-container', true);
33+
this._initMapInstance(elem.nativeElement.querySelector('.sebm-google-map-container-inner'), mapsFactory);
2934
}
3035

3136
private _initMapInstance(el: HTMLElement, mapsFactory: GoogleMapsAPIWrapperFactory) {
@@ -36,8 +41,10 @@ export class SebmGoogleMap {
3641

3742
@Input()
3843
set zoom(value: number|string) {
39-
this._zoom = this._convertToDecimal(value);
40-
this._mapsWrapper.setZoom(this._zoom);
44+
this._zoom = this._convertToDecimal(value);
45+
if (typeof this._zoom === 'number') {
46+
this._mapsWrapper.setZoom(this._zoom);
47+
}
4148
}
4249

4350
@Input()
@@ -55,11 +62,16 @@ export class SebmGoogleMap {
5562
private _convertToDecimal(value: string|number): number {
5663
if (typeof value === 'string') {
5764
return parseFloat(value);
65+
} else if (typeof value === 'number') {
66+
return <number> value;
5867
}
59-
return <number> value;
68+
return null;
6069
}
6170

6271
private _updateCenter() {
72+
if (typeof this._latitude !== 'number' || typeof this._longitude !== 'number') {
73+
return;
74+
}
6375
this._mapsWrapper.setCenter({
6476
lat: this._latitude,
6577
lng: this._longitude,
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import {Directive, Input, provide, Host, Inject, SkipSelf, SimpleChange} from 'angular2/angular2';
2+
import {GoogleMapsAPIWrapper} from '../services/google_maps_api_wrapper';
3+
import {MarkerManager} from '../services/marker_manager';
4+
import {SebmGoogleMap} from './google_map';
5+
6+
let markerId = 0;
7+
8+
@Directive({
9+
selector: 'sebm-google-map-marker'
10+
})
11+
export class SebmGoogleMapMarker {
12+
@Input() latitude: number;
13+
@Input() longitude: number;
14+
@Input() title: string;
15+
16+
private _markerAddedToManger: boolean = false;
17+
private _id: string;
18+
19+
constructor(@Host() @SkipSelf() private _map: SebmGoogleMap, private _markerManager: MarkerManager) {
20+
this._id = (markerId++).toString();
21+
}
22+
23+
onChanges(changes: {[key: string]: SimpleChange}) {
24+
if (!this._markerAddedToManger && this.latitude && this.longitude) {
25+
this._markerManager.addMarker(this);
26+
this._markerAddedToManger = true;
27+
return;
28+
}
29+
if (changes['latitude'] || changes['logitude']) {
30+
this._markerManager.updateMarkerPosition(this);
31+
}
32+
if (changes['title']) {
33+
this._markerManager.updateTitle(this);
34+
}
35+
}
36+
37+
id(): string {
38+
return this._id;
39+
}
40+
41+
toString(): string {
42+
return 'SebmGoogleMapMarker-' + this._id.toString();
43+
}
44+
45+
onDestroy() {
46+
this._markerManager.deleteMarker(this);
47+
}
48+
}

src/custom_typings/google_maps.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@ declare module google.maps {
1515
lng(): number;
1616
}
1717

18+
export class Marker {
19+
constructor(options?: MarkerOptions)
20+
setMap(map:Map): void
21+
setPosition(latLng: LatLng|LatLngLiteral): void
22+
setTitle(title: string): void;
23+
}
24+
25+
export interface MarkerOptions {
26+
position: LatLng|LatLngLiteral;
27+
title?: string;
28+
map?: Map;
29+
}
30+
1831
export interface LatLngLiteral {
1932
lat: number;
2033
lng: number;

src/services/google_maps_api_wrapper.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ import {Observable} from 'rx';
88
export class GoogleMapsAPIWrapper {
99
private _el: HTMLElement;
1010
private _map: google.maps.Map;
11-
private _isInitialized: boolean;
1211

1312
private _centerChangeObservable: Observable<google.maps.LatLngLiteral>;
1413
private _zoomChangeObservable: Observable<number>;
1514

1615
constructor(_el: HTMLElement, latitude: number, longitude: number, private _zone: NgZone) {
17-
this._isInitialized = true;
1816
this._el = _el;
1917
this._map = new google.maps.Map(this._el, {
2018
center: {
@@ -28,9 +26,7 @@ export class GoogleMapsAPIWrapper {
2826
createEventObservable<E>(eventName: string, callback: (observer: Rx.Observer<E>) => void): Observable<E> {
2927
return Observable.create((observer: Rx.Observer<E>) => {
3028
this._map.addListener(eventName, () => {
31-
this._zone.run(() => {
32-
callback(observer);
33-
});
29+
callback(observer);
3430
});
3531
});
3632
}
@@ -48,6 +44,14 @@ export class GoogleMapsAPIWrapper {
4844
});
4945
}
5046

47+
/**
48+
* Creates a google map marker with the map context
49+
*/
50+
createMarker(options: google.maps.MarkerOptions = <google.maps.MarkerOptions> {}): google.maps.Marker {
51+
options.map = this._map;
52+
return new google.maps.Marker(options);
53+
}
54+
5155
getZoomChangeObserable(): Observable<number> {
5256
return this._zoomChangeObservable;
5357
}
@@ -65,21 +69,27 @@ export class GoogleMapsAPIWrapper {
6569
}
6670

6771
getCenter(): google.maps.LatLng {
68-
if (!this._isInitialized) {
69-
return;
70-
}
7172
return this._map.getCenter();
7273
}
73-
74-
isInitialized(): boolean {
75-
return this._isInitialized;
76-
}
7774
}
7875

76+
// todo: change name, because it's not a real factory.
77+
// We have to create the instance with the component element and I don't see
78+
// any chances to modify the viewproviders for <sebm-google-map> after the component instance is created.
7979
@Injectable()
8080
export class GoogleMapsAPIWrapperFactory {
81+
private _instance: GoogleMapsAPIWrapper;
82+
8183
constructor(private _zone: NgZone) {}
84+
8285
create(el: HTMLElement, latitude: number, longitude: number): GoogleMapsAPIWrapper {
83-
return new GoogleMapsAPIWrapper(el, latitude, latitude, this._zone);
86+
if (this._instance) {
87+
throw new Error('instance already created');
88+
}
89+
return this._instance = new GoogleMapsAPIWrapper(el, latitude, latitude, this._zone);
90+
}
91+
92+
getInstance(): GoogleMapsAPIWrapper {
93+
return this._instance;
8494
}
8595
}

src/services/marker_manager.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import {Injectable} from 'angular2/angular2';
2+
import {SebmGoogleMapMarker} from '../components/google_map_marker';
3+
import {GoogleMapsAPIWrapperFactory, GoogleMapsAPIWrapper} from './google_maps_api_wrapper';
4+
5+
@Injectable()
6+
export class MarkerManager {
7+
private _markers: Map<SebmGoogleMapMarker, google.maps.Marker> = new Map<SebmGoogleMapMarker, google.maps.Marker>();
8+
private _mapsAPI: GoogleMapsAPIWrapper;
9+
10+
constructor(f: GoogleMapsAPIWrapperFactory) {
11+
this._mapsAPI = f.getInstance();
12+
}
13+
14+
deleteMarker(marker: SebmGoogleMapMarker) {
15+
console.log(this._markers.values());
16+
this._markers.get(marker).setMap(null);
17+
this._markers.delete(marker);
18+
}
19+
20+
updateMarkerPosition(marker: SebmGoogleMapMarker) {
21+
this._markers.get(marker).setPosition({
22+
lat: marker.latitude,
23+
lng: marker.longitude
24+
});
25+
}
26+
27+
updateTitle(marker: SebmGoogleMapMarker) {
28+
this._markers.get(marker).setTitle(marker.title);
29+
}
30+
31+
addMarker(marker: SebmGoogleMapMarker) {
32+
this._markers.set(marker, this._mapsAPI.createMarker({
33+
position: {
34+
lat: marker.latitude,
35+
lng: marker.longitude
36+
}
37+
}));
38+
}
39+
}

0 commit comments

Comments
 (0)