crowded-google-map
v2.0.0
Published
Display a lot of POIs on Google Map without sacrificing UX
Downloads
7
Readme
Crowded Google Map - because sometimes it gets crowded
Display a lot of POIs on Google Map without sacrificing UX
Prerequisites
Before initializing the crowded google map, make sure you have loaded Google Maps API.
Read how to do it at https://developers.google.com/maps/documentation/javascript/tutorial
Basic usage
new CrowdedGoogleMap({
container: document.querySelector(".google-map"),
googleMapsConfig: {
center: { lat: -34.397, lng: 150.644 },
zoom: 10
},
markersData: new Promise(resolve =>
resolve([
{
first_name: "Michael",
last_name: "Scott",
position: { lat: 34.210973, lng: -118.436232 }
},
{
first_name: "Kevin",
last_name: "Malone",
position: { lat: -25.363, lng: 131.044 }
}
])
)
});
Advanced Usage
const defaultClusterStyle = {
textColor: "white",
textSize: 12,
height: 50,
width: 50
};
new CrowdedGoogleMap({
container: document.querySelector(".google-map"),
googleMapsConfig: {
center: { lat: -34.397, lng: 150.644 },
zoom: 10,
mapTypeId: "satellite"
},
markersData: fetch("/api/getmarkers.json", {
credentials: "same-origin"
}).then(res => resolve(res.json())),
parseMarkerData: marker => {
return Object.assign({}, marker, {
name: `${marker.first_name} ${marker.last_name}`,
href: `http://google.com/?q=${marker.first_name}+${marker.last_name}`,
icon: {
url: `http://my.cdn.com/images/gmap/${marker.type}-icon.svg`,
size: new google.maps.Size(24, 24),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(0, 24)
}
});
},
infoWindowConfig: marker => {
return {
content: `<a href="${marker.href}">${marker.name}</a>`,
maxWidth: 640
};
},
clustererConfig: {
styles: [
Object.assign({}, defaultClusterStyle, {
url: `http://my.cdn.com/images/gmap/small.png`
}),
Object.assign({}, defaultClusterStyle, {
url: `http://my.cdn.com/images/gmap/big.png`
})
]
}
});
Options
container
Type: DOM Element
Example:
document.querySelector(".google-map");
googleMapsConfig
Type: Object
Example:
{
zoom: 6,
center: { lat: -34.397, lng: 150.644 },
mapTypeId: "satellite"
}
Config that will be passed to Google Maps constructor. You can use everything that Google Maps supports (ie. styling).
Read more about google maps api options at https://developers.google.com/maps/documentation/javascript/3.exp/reference
clustererConfig
Type: Object
Example:
{
gridSize: 30,
maxZoom: 12
}
Object that will extend/override default clusterer config that can be found in src/config
.
Read more about supported options at https://www.npmjs.com/package/node-js-marker-clusterer
spiderifyConfig
Type: Object
Example:
{
circleFootSeparation: 30,
nearbyDistance: 60
}
Object that will extend/override default spiderify config that can be found in src/config
.
Read more about supported options at https://www.npmjs.com/package/overlapping-marker-spiderfier
markersData
Type: Promise
(resolving to an array of objects)
Example:
fetch("/api/getmarkers.json", {
credentials: "same-origin"
}).then(res => resolve(res.json()));
Collection of objects that will be used on the map. They will be parsed later on if you pass parseMarkerData
.
parseMarkerData
Type: Function
Example:
const parseMarkerData = marker => {
return Object.assign({}, marker, {
// Take whatever has been passed as marker, extend using object passed below
name: `${marker.first_name} ${marker.last_name}`,
href: `https://google.com/?q=${marker.first_name}+${marker.last_name}`,
icon: {
url: `https://my.cdn.com/images/gmap/${marker.type}-icon.svg`,
size: new google.maps.Size(24, 24),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(0, 24)
}
});
};
Function that will be run on each marker (using .map
) object before turning it into google map marker. Make sure this function returns proper objects/structure/data to use in later life cycles (ie. creation of google markers, info windows)
infoWindowConfig
Type: Function
Example:
const infoWindowConfig = marker => {
return {
content: `<a href="${marker.href}">${marker.name}</a>`,
maxWidth: 640
};
};
Configuration of infoWindow based on currently created marker. Content key is required by Google.
Dependencies
This script includes two depencenies to handle crowded maps:
- node-js-marker-clusterer - Joins markers that are close by to prevent overlapping
- overlapping-marker-spiderfier - Allows user to spread pins that are very close together (after zooming in, where clustering is no longer available) see them better
Performance tips
If your markers are served by the API (which often is the case), start downloading them as soon as possible.
For example, you might want to use XHR to start downloading them in the <head>
. The benefits depend on weight/speed of loading other blocking assets, so your milage may vary. In my tests I have observed 2-2.5 seconds boost by starting request as a first request on the site.
window.mapMarkers = new Promise(function(resolve) {
return fetch("/getMarkers.json", { credentials: "same-origin" }).then(
function(res) {
return resolve(res.json());
}
);
});
Having this set up you can pass window.mapMarkers
as markersData
to the map constructor - it will initialize as much as possible without the markers, then continue when they arrive.
Testing
Run npm test
to open test page with (hopefully) working example.
Troubleshooting
My map isn't showing up at all
Remember to provide some kind of css to make sure the map has height. You can even do that inline.
<div data-crowded-google-map="container" style="height: 700px"></div>
My clusters are missing icons
Make sure you pass styles with proper urls to graphic icons. See Advanced Usage example.
Known bugs
Uncaught TypeError: Cannot read property 'fromLatLngToDivPixel' of undefined
in oms.js
. Everything works, if you have any idea why it throws error anyway please help me fix it :)