Skip to content

Commit

Permalink
feat(marker): add basic marker support
Browse files Browse the repository at this point in the history
Introduces a new directive <sebm-google-map-marker> that accepts three
bindings:

- latitude (required)
- longitude (required)
- title (optional)
  • Loading branch information
sebholstein committed Nov 6, 2015
1 parent 4b90bfb commit ec644a4
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 23 deletions.
1 change: 1 addition & 0 deletions src/components.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './components/google_map';
export * from './components/google_map_marker';
32 changes: 22 additions & 10 deletions src/components/google_map.ts
Original file line number Diff line number Diff line change
@@ -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: `
<div class="sebm-google-map-container"></div>
<div class="sebm-google-map-container-inner"></div>
<ng-content></ng-content>
`
})
Expand All @@ -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) {
Expand All @@ -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()
Expand All @@ -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 <number> value;
}
return <number> value;
return null;
}

private _updateCenter() {
if (typeof this._latitude !== 'number' || typeof this._longitude !== 'number') {
return;
}
this._mapsWrapper.setCenter({
lat: this._latitude,
lng: this._longitude,
Expand Down
48 changes: 48 additions & 0 deletions src/components/google_map_marker.ts
Original file line number Diff line number Diff line change
@@ -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);
}
}
13 changes: 13 additions & 0 deletions src/custom_typings/google_maps.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
36 changes: 23 additions & 13 deletions src/services/google_maps_api_wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<google.maps.LatLngLiteral>;
private _zoomChangeObservable: Observable<number>;

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: {
Expand All @@ -28,9 +26,7 @@ export class GoogleMapsAPIWrapper {
createEventObservable<E>(eventName: string, callback: (observer: Rx.Observer<E>) => void): Observable<E> {
return Observable.create((observer: Rx.Observer<E>) => {
this._map.addListener(eventName, () => {
this._zone.run(() => {
callback(observer);
});
callback(observer);
});
});
}
Expand All @@ -48,6 +44,14 @@ export class GoogleMapsAPIWrapper {
});
}

/**
* Creates a google map marker with the map context
*/
createMarker(options: google.maps.MarkerOptions = <google.maps.MarkerOptions> {}): google.maps.Marker {
options.map = this._map;
return new google.maps.Marker(options);
}

getZoomChangeObserable(): Observable<number> {
return this._zoomChangeObservable;
}
Expand All @@ -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 <sebm-google-map> 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;
}
}
39 changes: 39 additions & 0 deletions src/services/marker_manager.ts
Original file line number Diff line number Diff line change
@@ -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<SebmGoogleMapMarker, google.maps.Marker> = new Map<SebmGoogleMapMarker, google.maps.Marker>();
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
}
}));
}
}

0 comments on commit ec644a4

Please sign in to comment.