diff --git a/README.md b/README.md
index b64f549..795b77c 100644
--- a/README.md
+++ b/README.md
@@ -44,6 +44,12 @@ export function configure(aurelia) {
options: { panControl: true, panControlOptions: { position: 9 } }, //add google.maps.MapOptions on construct (https://developers.google.com/maps/documentation/javascript/3.exp/reference#MapOptions)
language:'' | 'en', // default: uses browser configuration (recommended). Set this parameter to set another language (https://developers.google.com/maps/documentation/javascript/localization)
region: '' | 'US' // default: it applies a default bias for application behavior towards the United States. (https://developers.google.com/maps/documentation/javascript/localization)
+ markerCluster: {
+ enable: false,
+ src: 'https://cdn.rawgit.com/googlemaps/v3-utility-library/99a385c1/markerclusterer/src/markerclusterer.js', // self-hosting this file is highly recommended. (https://developers.google.com/maps/documentation/javascript/marker-clustering)
+ imagePath: 'https://cdn.rawgit.com/googlemaps/v3-utility-library/tree/master/markerclusterer/images/m', // the base URL where the images representing the clusters will be found. The full URL will be: `{imagePath}{[1-5]}`.`{imageExtension}` e.g. `foo/1.png`. Self-hosting these images is highly recommended. (https://developers.google.com/maps/documentation/javascript/marker-clustering)
+ imageExtension: 'png',
+ }
});
})
}
@@ -195,6 +201,12 @@ var myMarkers = [
* `custom` (optional) - store arbitrary data (e.g. an `id` field) in this object, retrieve it from the `googlemap:marker:click` event payload
* `infoWindow` (optional) - object - If set, the `googlemap:marker:click` evetn will not be called, instead an infowindow containing the given content will show up - see [docs](https://developers.google.com/maps/documentation/javascript/infowindows)
+
+### Marker clustering
+
+This options allows the clustering of markers that are near each other.
+All the config and styling options can be found [here](https://github.com/googlemaps/v3-utility-library/blob/master/markerclusterer/src/markerclusterer.js#L40).
+
### Drawing Mode
Allows usage of Google Maps' Drawing API to add Markers, Polylines, Polygons, Rectangles and Circles to the map instance. To allow this, simply set the defaults as below:
diff --git a/src/configure.ts b/src/configure.ts
index 6e63174..fb92a81 100644
--- a/src/configure.ts
+++ b/src/configure.ts
@@ -3,6 +3,7 @@ export interface ConfigInterface {
apiKey: string;
apiLibraries: string;
options: any;
+ markerCluster: {enable: boolean, src?: string, imagePath?: string, imageExtension?: string}
}
export class Configure {
@@ -15,12 +16,20 @@ export class Configure {
apiLibraries: '',
region: '',
language: '',
- options: {}
+ options: {},
+ markerCluster: {
+ enable: false,
+ src: 'https://cdn.rawgit.com/googlemaps/v3-utility-library/99a385c1/markerclusterer/src/markerclusterer.js',
+ imagePath: 'https://raw.githubusercontent.com/googlemaps/v3-utility-library/99a385c1/markerclusterer/images/m',
+ imageExtension: 'png',
+ }
};
}
options(obj: ConfigInterface) {
- Object.assign(this._config, obj);
+ Object.assign(this._config, obj, {
+ markerCluster: Object.assign({}, this._config.markerCluster, obj.markerCluster)
+ });
}
get(key: string) {
diff --git a/src/google-maps-api.ts b/src/google-maps-api.ts
index 88b4048..1856912 100644
--- a/src/google-maps-api.ts
+++ b/src/google-maps-api.ts
@@ -20,10 +20,18 @@ export class GoogleMapsAPI {
// google has not been defined yet
let script = document.createElement('script');
+ let params = [
+ this.config.get('apiKey') ? `key=${this.config.get('apiKey')}&` : '',
+ this.config.get('apiLibraries') ? `libraries=${this.config.get('apiLibraries')}` : '',
+ this.config.get('language') ? `language=${this.config.get('language')}` : '',
+ this.config.get('region') ? `region=${this.config.get('region')}` : '',
+ 'callback=aureliaGoogleMapsCallback',
+ ];
+
script.type = 'text/javascript';
script.async = true;
script.defer = true;
- script.src = `${this.config.get('apiScript')}?key=${this.config.get('apiKey')}&libraries=${this.config.get('apiLibraries')}&language=${this.config.get('language')}®ion=${this.config.get('region')}&callback=aureliaGoogleMapsCallback`;
+ script.src = `${this.config.get('apiScript')}?${params.join('&')}`;
document.body.appendChild(script);
this._scriptPromise = new Promise((resolve, reject) => {
diff --git a/src/google-maps.ts b/src/google-maps.ts
index f378c78..2290891 100644
--- a/src/google-maps.ts
+++ b/src/google-maps.ts
@@ -6,6 +6,7 @@ import { getLogger } from 'aurelia-logging';
import { Configure } from './configure';
import { GoogleMapsAPI } from './google-maps-api';
+import { MarkerClustering } from './marker-clustering';
import { Events } from './events';
@@ -26,13 +27,14 @@ export interface Marker {
@noView()
@customElement('google-map')
-@inject(Element, TaskQueue, Configure, BindingEngine, GoogleMapsAPI)
+@inject(Element, TaskQueue, Configure, BindingEngine, GoogleMapsAPI, MarkerClustering)
export class GoogleMaps {
private element: Element;
private taskQueue: TaskQueue;
private config: any;
private bindingEngine: BindingEngine;
private googleMapsApi: GoogleMapsAPI;
+ private markerClustering: MarkerClustering;
private _currentInfoWindow: any = null;
@bindable longitude: number = 0;
@@ -61,12 +63,20 @@ export class GoogleMaps {
public _renderedPolygons: any = [];
public _polygonsSubscription: any = null;
- constructor(element: Element, taskQueue: TaskQueue, config: Configure, bindingEngine: BindingEngine, googleMapsApi: GoogleMapsAPI) {
+ constructor(
+ element: Element,
+ taskQueue: TaskQueue,
+ config: Configure,
+ bindingEngine: BindingEngine,
+ googleMapsApi: GoogleMapsAPI,
+ markerClustering: MarkerClustering,
+ ) {
this.element = element;
this.taskQueue = taskQueue;
this.config = config;
this.bindingEngine = bindingEngine;
this.googleMapsApi = googleMapsApi;
+ this.markerClustering = markerClustering;
if (!config.get('apiScript')) {
logger.error('No API script is defined.');
@@ -75,7 +85,8 @@ export class GoogleMaps {
if (!config.get('apiKey') && config.get('apiKey') !== false) {
logger.error('No API key has been specified.');
}
-
+
+ this.markerClustering.loadScript();
this._scriptPromise = this.googleMapsApi.getMapsInstance();
let self: GoogleMaps = this;
@@ -120,6 +131,7 @@ export class GoogleMaps {
});
this._renderedMarkers = [];
+ this.markerClustering.renderClusters(this.map, []);
}
attached() {
@@ -289,6 +301,8 @@ export class GoogleMaps {
// Send up and event to let the parent know a new marker has been rendered
dispatchEvent(Events.MARKERRENDERED, { createdMarker, marker }, this.element);
+ }).then(() => {
+ this.markerClustering.renderClusters(this.map, this._renderedMarkers);
});
});
}
@@ -389,6 +403,8 @@ export class GoogleMaps {
// Wait until all of the renderMarker calls have been resolved
return Promise.all(markerPromises);
}).then(() => {
+ this.markerClustering.renderClusters(this.map, this._renderedMarkers);
+
/**
* We queue up a task to update the bounds, because in the case of multiple bound properties changing all at once,
* we need to let Aurelia handle updating the other properties before we actually trigger a re-render of the map
@@ -457,6 +473,8 @@ export class GoogleMaps {
* Wait for all of the promises to resolve for rendering markers
*/
Promise.all(renderPromises).then(() => {
+ this.markerClustering.renderClusters(this.map, this._renderedMarkers);
+
/**
* We queue up a task to update the bounds, because in the case of multiple bound properties changing all at once,
* we need to let Aurelia handle updating the other properties before we actually trigger a re-render of the map
@@ -568,7 +586,7 @@ export class GoogleMaps {
/**
* Get the given constant that Google's library uses. Defaults to MARKER
- * @param type
+ * @param type
*/
getOverlayType(type: any = '') {
switch (type.toUpperCase()) {
@@ -605,7 +623,7 @@ export class GoogleMaps {
/**
* Update the drawing mode, called by aurelia binding
- * @param newval
+ * @param newval
*/
drawModeChanged(newval: any = '') {
this.initDrawingManager()
@@ -821,4 +839,4 @@ function dispatchEvent(name: string, detail: any, target: Element, bubbles = tru
}
target.dispatchEvent(changeEvent);
-}
\ No newline at end of file
+}
diff --git a/src/marker-clustering.ts b/src/marker-clustering.ts
new file mode 100644
index 0000000..d383fe5
--- /dev/null
+++ b/src/marker-clustering.ts
@@ -0,0 +1,35 @@
+import { inject } from 'aurelia-dependency-injection';
+import { Configure } from './configure';
+
+@inject(Configure)
+export class MarkerClustering {
+ private config: Configure;
+
+ constructor(config) {
+ this.config = config;
+ }
+
+ isEnabled() {
+ return this.config.get('markerCluster') && this.config.get('markerCluster').enable;
+ }
+
+ loadScript() {
+ if (!this.isEnabled()) {
+ return;
+ }
+
+ let script = document.createElement('script');
+
+ script.type = 'text/javascript';
+ script.src = this.config.get('markerCluster').src;
+ document.body.appendChild(script);
+ }
+
+ renderClusters(map, markers) {
+ if (!this.isEnabled()) {
+ return;
+ }
+
+ new (window).MarkerClusterer(map, markers, this.config.get('markerCluster'));
+ }
+}