Overlapping Marker Spiderfier
npm install ts-overlapping-marker-spiderfier#Overlapping Marker Spiderfier for Google Maps API v3
This is a fork of jawj's OverlappingMarkerSpiderfier rewritten
into typescript, for use with (for example) Angular and other (webpack) based systems.
Instead of binding itself to window you canimport {OverlappingMarkerSpiderfier} from 'ts-overlapping-marker-spiderfier' and use the module as you would normally.
Other variants (umd, cjs, amd and browser) are provided using rollup and can be found in the dist folder. Forumd and browser the module will bind itself to the OMS namespace, so accessing the module code can be done usingnew OMS.OverlappingMarkerSpiderfier... instead of new OverlappingMarkerSpiderfier....
*Ever noticed how, in Google Earth, marker pins that overlap each other spring apart
gracefully when you click them, so you can pick the one you wanted?*
*Ever noticed how, when using the Google Maps API, the
same thing doesn't happen?*
This library makes map markers in the Google Maps API (version 3) behave in that Google Earth way (minus the animation).
Small numbers of markers (yes, up to 8) spiderfy into a circle. Larger numbers fan out into a more space-efficient
spiral.
The compiled code has no dependencies beyond Google Maps. Compiled out of
CoffeeScript, minified with Google's
Closure Compiler and gzipped, it's under 4KB.
I originally wrote it as part of Mappiness. There is also
a port for the Leaflet maps API,
which has fewer features.
You may have seen the
marker clustering library,
which also helps deal with markers that are close together.
That might be what you want. However, it probably isn't what you want (or isn't the only thing you want) if you have
markers that could be in the exact same location, or close enough to overlap even at maximum zoom. In that case,
clustering won't help your users see and/or click on the marker they're looking for.
OverlappingMarkerSpiderfier plays nice with clustering, and you can use them together. Once you get down to a zoom level
where individual markers are shown, these markers then spiderfy happily. But you may need to set the maxZoom
parameter on the clusterer to ensure that it doesn't cluster identical points all the way to the map's maximum zoom
level (14 or 15 have been
suggested
as sensible values).
Version 1.0 brings three key enhancements:
* Easy differential formatting of markers that will and won't spiderfy on click (via a new event listener). Thanks go to
Graphileon for sponsoring this much-requested feature.
* Simplified integration, via a per-marker spider_click listener that's a direct replacement for the standardclick listener.
* Support for async/deferred loading in parallel with Google Maps. We no longer require the Google Maps API to be loaded
first.
Also, a few potentially breaking changes:
* The methods addMarker(), removeMarker() and clearMarkers() have been renamed to trackMarker(),forgetMarker() and forgetAllMarkers(). This better reflects what they do. At the same time, new shortcut methodsaddMarker(), removeMarker() and removeAllMarkers() have been added — these call trackMarker(), forgetMarker()
or forgetAllMarkers() respectively and also add or remove the relevant marker(s) from the Google Map itself.
If you've only been using addMarker() and removeMarker(), and you always add or remove your markers from the map at
the same time as the spiderfier, you won't need to do anything new.
Breaking changes:
* The willSpiderfy(marker) and markersThatWillAndWontSpiderfy() methods were replaced by the (similar, but
different) markersNearMarker(marker) and markersNearAnyOtherMarker() methods. This should only worry advanced users.
There are three demo maps, showing increasing levels of functionality and complexity. Studying the source of these may
well be the best way to understand how to use this library.
* Simple demo
* Standard demo
* Fancy demo
In all cases, the data is randomised: reload the map to reposition the markers.
Or use it straight from cdnjs:.
See the source of the demo maps, or follow along here for a slightly simpler usage with commentary.
* Simple demo source
* Standard demo source
* Fancy demo source
Create a map and an InfoWindow as per usual:
``js`
var mapElement = document.getElementById('map_element');
var map = new google.maps.Map(mapElement, { center: new google.maps.LatLng(50, 0), zoom: 6 });
var iw = new google.maps.InfoWindow();
Now create an OverlappingMarkerSpiderfier instance associated with the map (the three options set here are not`
required, but will save some memory and CPU in simple use cases like this one):js`
var oms = new OverlappingMarkerSpiderfier(map, {
markersWontMove: true,
markersWontHide: true,
basicFormatEvents: true
});
As you create your markers, instead of attaching click listeners, attach spider_click listeners.
And, instead of adding them to the map with marker.setMap(map), add them to your OverlappingMarkerSpiderfier instance (and the map too) with oms.addMarker(marker).
`js`
for (var i = 0, len = window.mapData.length; i < len; i ++) {
(function() { // make a closure over the marker and marker data
var markerData = window.mapData[i]; // e.g. { lat: 50.123, lng: 0.123, text: 'XYZ' }
var marker = new google.maps.Marker({ position: markerData }); // markerData works here as a LatLngLiteral
google.maps.event.addListener(marker, 'spider_click', function(e) { // 'spider_click', not plain 'click'
iw.setContent(markerData.text);
iw.open(map, marker);
});
oms.addMarker(marker); // adds the marker to the spiderfier _and_ the map
})();
}
New in version 1.0, you can add marker formatting listeners to differentiate between markers that will and won't spiderfy (and that are and aren't spiderfied).
You can either add a format listener to the spiderfier instance (simplest if all your markers look the same, aside from their spiderfying status), or a spider_format listener to each individual marker (useful if you independently have different marker styles).
The first of these options, as seen in the
standard demo source, looks something
like this:
`js``
oms.addListener('format', function(marker, status) {
var iconURL = status == OverlappingMarkerSpiderfier.markerStatus.SPIDERFIED ? 'marker-highlight.svg' :
status == OverlappingMarkerSpiderfier.markerStatus.SPIDERFIABLE ? 'marker-plus.svg' :
status == OverlappingMarkerSpiderfier.markerStatus.UNSPIDERFIABLE ? 'marker.svg' :
null;
marker.setIcon({
url: iconURL,
scaledSize: new google.maps.Size(23, 32) // makes SVG icons work in IE
});
});
For an example of the second, per-marker option, see the
fancy demo source.
Again, thanks to Graphileon for sponsoring this feature.
The Google Maps API code changes frequently. Some earlier versions had broken support for z-indices, and the 'frozen' versions appear not to be as frozen as you'd like. At this moment, the 'stable' version 3.27 seems to work well, but do test with whatever version you fix on. Sometimes, glitches can be fixed by setting the optimized: false on your markers.
To enable async/deferred loading, as used by the Google Maps library itself, you can either provide a top-level function named spiderfier_callback, or specify a spiderfier_callback parameter that names some other top-level function in the script src attribute (i.e.