enriqg9
enriqg9

Reputation: 1507

Google Maps Custom HTML Marker and MarkerClustererPlus

I have a map with Custom HTML Markers and a MarkerClusterer, the clusterer works fine, but I want to filter markers by radius to a location, I am able to get the markers inside the given radius, however I am not able to hide the markers outside the given radius and show only the markers inside that radius from the MarkerClusterer.

I am defining my custom marker like this:

function CustomMarker(latlng, map, args)
{
    this.latlng = latlng;
    this.args = args;
    this.setMap(map);
    this.map = map;
}

CustomMarker.prototype = new google.maps.OverlayView();

CustomMarker.prototype.draw = function ()
{
    var self = this;

    if (!this.div)
    {
        var div = document.createElement('div');

        div.className = 'marker';
        div.style.position = 'absolute';
        div.style.cursor = 'pointer';

        var span = document.createElement('span');
        span.innerHTML = 'X';

        div.appendChild(span);

        var panes = this.getPanes();
        panes.overlayImage.appendChild(div);

        this.div = div;
    }

    var point = this.getProjection().fromLatLngToDivPixel(this.latlng);

    if (point)
    {
        this.div.style.left = (point.x - 20) + 'px';
        this.div.style.top = (point.y - 20) + 'px';
    }

    google.maps.event.addDomListener(this.div, "click", function (event)
    {
        google.maps.event.trigger(self, "click");
    });
};

CustomMarker.prototype.remove = function ()
{
    if (this.div)
    {
        this.div.parentNode.removeChild(this.div);
        this.div = null;
    }
};

CustomMarker.prototype.getPosition = function ()
{
    return this.latlng;
};

CustomMarker.prototype.getDraggable = function ()
{
    return false;
};

CustomMarker.prototype.setVisible = function (visible)
{
    if (this.div)
    {
        if (visible)
        {
            this.div.style.display = 'table';
            this.visible = true;
        }
        else
        {
            this.div.style.display = 'none';
            this.visible = false;
        }
    }
};

CustomMarker.prototype.getVisible = function ()
{
    return this.visible;
};

I am using MarkerClustererPlus and using setIgnoreHidden(true) will hide all the markers including the marker that is supposed to be visible.

I have noticed that marker.getVisible(), which is used by the MC+ when using setIgnoreHidden(true), returns false for the markers outside the given radius as expected, but undefined for the markers inside a cluster.

I think that it is because when a cluster is formed, the elements inside it get removed, not just hidden, hence setting them to null.

CustomMarker.prototype.remove = function ()
{
    if (this.div)
    {
        this.div.parentNode.removeChild(this.div);
        this.div = null;
    }
};

See Example JS Fiddle.

https://jsfiddle.net/enriqg9/az21h1b5/

Upvotes: 0

Views: 3170

Answers (1)

geocodezip
geocodezip

Reputation: 161334

If you want the marker to be visible, you need to set its map property:

for (var n = 0; n < this.markers.length; n++) {
  var marker = this.markers[n];
  var distance = google.maps.geometry.spherical.computeDistanceBetween(marker.getPosition(), location) / 1609;
  if (distance > radius) {
    // 4 Markers over 10 mile radius should be hidden
    marker.setVisible(false);
  } else {
    // Only 1 marker should be kept visible
    marker.setMap(this.map);
    visibleMarkers.push(marker);
  }
  console.log(marker.getVisible());
}

proof of concept fiddle

code snippet:

/* ==========================================================================
 Google Maps
 ========================================================================== */
var map = {
  'map': '',
  'markers': [],
  'lat': 31.862491,
  'lng': -106.3650707,
  'createMap': function() {
    this.map = new google.maps.Map(document.getElementById('map'), {
      center: {
        lat: this.lat,
        lng: this.lng
      },
      zoom: 6,
      maxZoom: 18,
      scrollwheel: false,
      disableDefaultUI: true,
      zoomControl: true
    });
    this.createMarkers($object);
  },
  'createMarkers': function(response) {
    var self = this;
    var infoWindow = new google.maps.InfoWindow({
      content: 'Loading'
    });
    var bounds = new google.maps.LatLngBounds();
    for (var n = 0; n < response.length; n++) {
      var el = response[n];
      var lat = parseFloat(el.lat);
      var lng = parseFloat(el.lng);
      var latLng = new google.maps.LatLng(lat, lng);
      var marker = new CustomMarker(latLng, this.map, {
        title: el.title
      });
      this.markers.push(marker);
      bounds.extend(marker.getPosition());
      google.maps.event.addListener(marker, 'click', function() {
        infoWindow.setContent('<b>' + this.args.title + '</b>');
        infoWindow.open(self.map, this);
        self.map.panTo(this.getPosition());
        self.map.setZoom(14);
      });
    }
    // New markerClustererPlus
    this.mc = new MarkerClusterer(this.map, this.markers, {imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'});
  },
  'filter': function(location) {
    var bounds = new google.maps.LatLngBounds();
    var visibleMarkers = [];
    // For testing purposes
    var radius = 10;
    var location = new google.maps.LatLng(this.lat, this.lng);
    // Hide Markers not inside given radius
    for (var n = 0; n < this.markers.length; n++) {
      var marker = this.markers[n];
      var distance = google.maps.geometry.spherical.computeDistanceBetween(marker.getPosition(), location) / 1609;
      if (distance > radius) {
        // 4 Markers over 10 mile radius should be hidden
        marker.setVisible(false);
      } else {
        // Only 1 marker should be kept visible
        marker.setMap(this.map);
        visibleMarkers.push(marker);
      }
      console.log(marker.getVisible());
    }
    for (var n = 0; n < visibleMarkers.length; n++) {
      bounds.extend(visibleMarkers[n].getPosition());
    }
    this.mc.setIgnoreHidden(true);
    this.map.fitBounds(bounds);
  }
};
var btn = document.getElementById('filter');
btn.addEventListener('click', function() {
  map.filter();
});
var $object = [{
  "lat": -20.823485,
  "lng": 23.24177,
  "title": "Explicabo voluptates voluptatibus quas sed laborum minus quia."
}, {
  "lat": -27.503418,
  "lng": 32.594705,
  "title": "Repellat ea reiciendis quae dolores sit facilis ut."
}, {
  "lat": -53.468797,
  "lng": -125.400102,
  "title": "Perspiciatis voluptates consectetur nulla inventore illo debitis delectus alias."
}, {
  "lat": "31.80666009999999",
  "lng": "-106.50467950000001",
  "title": "321 Mesa St"
}, {
  "lat": "31.831369",
  "lng": "-106.55140799999998",
  "title": "123 Main St"
}];
/* ==========================================================================
 Custom Maker
 ========================================================================== */
function CustomMarker(latlng, map, args) {
  this.latlng = latlng;
  this.args = args;
  this.setMap(map);
  this.map = map;
}
CustomMarker.prototype = new google.maps.OverlayView();
CustomMarker.prototype.draw = function() {
  var self = this;
  if (!this.div) {
    var div = document.createElement('div');
    div.className = 'marker';
    div.style.position = 'absolute';
    div.style.cursor = 'pointer';
    var span = document.createElement('span');
    span.innerHTML = 'X';
    div.appendChild(span);
    var panes = this.getPanes();
    panes.overlayImage.appendChild(div);
    this.div = div;
  }
  var point = this.getProjection().fromLatLngToDivPixel(this.latlng);
  if (point) {
    this.div.style.left = (point.x - 20) + 'px';
    this.div.style.top = (point.y - 20) + 'px';
  }
  google.maps.event.addDomListener(this.div, "click", function(event) {
    google.maps.event.trigger(self, "click");
  });
};
CustomMarker.prototype.remove = function() {
  if (this.div) {
    this.div.parentNode.removeChild(this.div);
    this.div = null;
  }
};
CustomMarker.prototype.getPosition = function() {
  return this.latlng;
};
CustomMarker.prototype.getDraggable = function() {
  return false;
};
CustomMarker.prototype.setVisible = function(visible) {
  if (this.div) {
    if (visible) {
      this.div.style.display = 'table';
      this.visible = true;
    } else {
      this.div.style.display = 'none';
      this.visible = false;
    }
  }
};
CustomMarker.prototype.getVisible = function() {
  return this.visible;
};
map.createMap();
#map {
  height: 400px;
}
.marker {
  display: table;
  width: 40px;
  height: 40px;
  background-color: #353535;
  border: 3px solid #FF9000;
  border-radius: 50px;
  color: #fff;
  font-size: 1em;
  font-weight: bold;
  text-align: center;
}
.marker span {
  display: table-cell;
  vertical-align: middle;
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&libraries=geometry"></script>
<script src="https://cdn.jsdelivr.net/gh/googlemaps/v3-utility-library@master/markerclustererplus/src/markerclusterer.js"></script>
<div id="map"></div>

<button id="filter">Filter</button>

<p>
  Clicking the Filter button should display 1 marker, bounds get properly set but marker is not visible.
</p>

<p>
  If you click on the cluster before clicking the filter button, the markers inside it get visible, and clicking filter will work as expected, as there are no markers inside a cluster.
</p>

Upvotes: 3

Related Questions