Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integrating Spiderfier JS into markerClusterer V3 to explode multi-markers with exact same long / lat

I am using markerCLusterer V3 on a db file from Filemaker to generate a (semi-live) map of current delivery locations, based off of addresses. Grabbing the lat/long from Google and populating those fields is no problem. Generating the map via markerClusterer is no problem. I am even hosting the JS locally so that I can change the maxZoom variable to break the clusters apart above max zoom, so that I can see multiple markers. However, with the markers at exactly the same lat / long, I can only see the last one entered. I would like to integrate OverlappingMarkerSpiderfier into this JS so that after I zoom in past the maxZoom, the markers would "spider" apart to see the markers (as an example, multiple pieces of equipment being delivered to the same address). I can't find any info here on on the web of how to do this. It's either that simple and I'm missing it or it hasn't been done yet. Thanks in advance for any help!

like image 721
Gary Gathright Avatar asked Mar 15 '12 19:03

Gary Gathright


4 Answers

I'm using: MarkerClustererPlus-2.0.14 and OverlappingMarkerSpiderfier-version-??

At first only the clustering works, clicking on a cluster, zooms in but 2 or more markers on the exact same point still stay a cluster even when zoomed in to the maximum. Unfortunately no spiderfier showed up :-(.

But than a noticed the setMaxZoom() method on markerClusterPlus. When setting this too your appropriate zoom level (15 for me) spiderfier takes over beyond the zoom level. It looks like markerClusters says it ain't my business anymore from here on it's up to spiderfier :-).

like image 185
ceasaro Avatar answered Oct 18 '22 20:10

ceasaro


Setting the max zoom will fix the problem:

minClusterZoom = 14;
markerCluster.setMaxZoom(minClusterZoom);

but for viewing purposes you may want to create a clusterclick listener to prevent it from zooming in really close on a cluster of points at the same location (clicking a cluster set the bounds of the map to cover the points in the cluster; if all points are at the same location it will zoom in all the way, which tends to look bad):

google.maps.event.addListener(markerCluster, 'clusterclick', function(cluster) {
    map.fitBounds(cluster.getBounds()); // Fit the bounds of the cluster clicked on
    if( map.getZoom() > minClusterZoom+1 ) // If zoomed in past 15 (first level without clustering), zoom out to 15
        map.setZoom(minClusterZoom+1);
});
like image 21
Cameron Avatar answered Oct 18 '22 18:10

Cameron


Integrating Spiderfier JS into markerClusterer

  • Download the oms.min.js file from here
  • Download the markerClusterer.js and the image folder from here

In order to make both work together you only need to add a maxZoom to the clusterMarker object

 new MarkerClusterer(map, clusterMarker, {imagePath: 'images/m', maxZoom: 15}); 

(Zoomlevel 0 is the complete earth, and 20 is pretty close to the ground). This means that if you zoom into the map further as zoom level 15 (for example if you click on a cluster) then the clusters are not shown anymore. If you now click on markers that are on the exact same location (or close to each other) Spiderfier JS will trigger.

It follows now a minimal working example. I made some comments in the code so I think its self-explanatory, but here are some things to mention:

  • Replace YOUR_API_KEY with your api key
  • Make sure to load oms.min.js after you loaded the google maps api

Example:

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
  <script     src="https://maps.googleapis.com/maps/apijs?key=YOUR_API_KEY">
  </script>
  <script src="oms.min.js"></script>
  <script src="markerclusterer.js"></script>
  <script>
    window.onload = function() {
      // cluster marker
      var clusterMarker = [];

      var map = new google.maps.Map(document.getElementById('map'), {
        center: new google.maps.LatLng( 50, 3),
        zoom: 6,
        mapTypeId: 'terrain'
      });

      // Create infowindow
      var infoWindow = new google.maps.InfoWindow();

      // Create OverlappingMarkerSpiderfier instsance
      var oms = new OverlappingMarkerSpiderfier(map,
        {markersWontMove: true, markersWontHide: true});

      // This is necessary to make the Spiderfy work
      oms.addListener('click', function(marker) {
        infoWindow.setContent(marker.desc);
        infoWindow.open(map, marker);
      });

      // Some sample data
      var sampleData = [{lat:50, lng:3}, {lat:50, lng:3}, {lat:50, lng:7}];


      for (var i = 0; i < sampleData.length; i ++) {

        var point = sampleData[i];
        var location = new google.maps.LatLng(point.lat, point.lng);

        // create marker at location
        var marker = new google.maps.Marker({
          position: location,
          map: map
        });

        // text to appear in window
        marker.desc = "Number "+i;

        // needed to make Spiderfy work
        oms.addMarker(marker);

        // needed to cluster marker
        clusterMarker.push(marker);
      }

      new MarkerClusterer(map, clusterMarker, {imagePath: 'images/m', maxZoom: 15});
    }
  </script>
</head>
<body><div id="map" style='width:400px;height:400px;'></div></body></html>

Recommendation

If you are starting from scratch, I would recommend to use the JS Libary Leaflet. Because this library provides you with the LeafletMarkerCluster plugin which is basically markercluster with Spiderfier integrated, and a lot of other cool stuff.

Advantage:

  • Cluster look really nice
  • Leaflet really easy to use and looks pretty
  • You do not need to customize the code, because Spiderfier and markerCluster already integrated
  • Some fancy other stuff: Like showing the border on hover of a region where marker are spread.
  • You can freely choose your map-tiles-provider and are no longer restricted to google maps (possible providers here)

Downsites:

  • You may need to invest 30min to learn and use the Leaflet API instead of the Google API
  • If you want to use Google Map Tiles, then you need to use this plugin, because you are only allowed to use the Google Tiles when using the Google API. This plugin is a wrapper for the Google API.

Here is an example code:

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
  <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
  <script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
  <link rel="stylesheet" href="leaflet/dist/MarkerCluster.css" />
  <link rel="stylesheet" href="leaflet/dist/MarkerCluster.Default.css" />
  <script src="leaflet/dist/leaflet.markercluster-src.js"></script>
  <script>
    $(document).ready(function(){

    var tiles = L.tileLayer(***);//Depending on your tile provider

    var map = new L.Map('map', {center: latlng, zoom: 1, layers: [tiles]});

    var markers = new L.MarkerClusterGroup({
      removeOutsideVisibleBounds: true,
      spiderfyDistanceMultiplier: 2,
      maxClusterRadius: 20
    });
    var markersList = [];

    var sampleData = [{lat:50, lng:3}, {lat:50, lng:3}, {lat:50, lng:7}];

    for (var i = 0; i < sampleData.length; i ++) {

      var point = sampleData[i];
      var location = new L.LatLng(point.lat, point.lng);

      // create marker at location

      var m = new L.Marker(location);
      m.bindPopup("Number" +i); //Text to appear in window
      markersList.push(m);
      markers.addLayer(m);
    }

    var bounds = markers.getBounds();
    map.fitBounds(bounds)
    map.addLayer(markers);
}    
</head>
<body><div id="map" style='width:400px;height:400px;'></div></body></html>
like image 8
Adam Avatar answered Oct 18 '22 18:10

Adam


I came across this post because I was looking for the exact same thing, but lucky for me I have made it work!

I honestly didn't do anything special, I followed the integration guide for MarkerClusterer, and then followed the integration guide for OverlappingMarkerSpiderfier and they work flawlessly together.

When I click/zoom in on a cluster of properties that are all at the same address, initially it just shows the "top" marker, but when I click it, they Spiderfy just like you'd want them too!

What specific result are you getting when you try to use the two scripts together?

like image 2
Phil Avatar answered Oct 18 '22 20:10

Phil