@react-google-maps/marker-clusterer
Version:
Marker Clusterer for React.js Google Maps API
1,013 lines (807 loc) • 31.7 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = global || self, factory(global.markerClusterer = {}));
}(this, function (exports) { 'use strict';
var ClusterIcon =
/*#__PURE__*/
function () {
function ClusterIcon(cluster, styles) {
cluster.getClusterer().extend(ClusterIcon, google.maps.OverlayView);
this.cluster = cluster;
this.className = this.cluster.getClusterer().getClusterClass();
this.styles = styles;
this.center = undefined;
this.div = null;
this.sums = null;
this.visible = false;
this.boundsChangedListener = null;
this.url = '';
this.height = 0;
this.width = 0;
this.anchorText = [0, 0];
this.anchorIcon = [0, 0];
this.textColor = 'black';
this.textSize = 11;
this.textDecoration = 'none';
this.fontWeight = 'bold';
this.fontStyle = 'normal';
this.fontFamily = 'Arial,sans-serif';
this.backgroundPosition = '0 0'; // @ts-ignore
this.setMap(cluster.getMap()); // Note: this causes onAdd to be called
}
var _proto = ClusterIcon.prototype;
_proto.onAdd = function onAdd() {
var _this = this;
var cMouseDownInCluster;
var cDraggingMapByCluster;
this.div = document.createElement("div");
this.div.className = this.className;
if (this.visible) {
this.show();
} // @ts-ignore
this.getPanes().overlayMouseTarget.appendChild(this.div); // Fix for Issue 157
this.boundsChangedListener = google.maps.event.addListener( // @ts-ignore
this.getMap(), "boundschanged", function boundsChabged() {
cDraggingMapByCluster = cMouseDownInCluster;
});
google.maps.event.addDomListener(this.div, "mousedown", function onMouseDown() {
cMouseDownInCluster = true;
cDraggingMapByCluster = false;
}); // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name
google.maps.event.addDomListener(this.div, "click", // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name
function (event) {
cMouseDownInCluster = false;
if (!cDraggingMapByCluster) {
var markerClusterer = _this.cluster.getClusterer();
/**
* This event is fired when a cluster marker is clicked.
* @name MarkerClusterer#click
* @param {Cluster} c The cluster that was clicked.
* @event
*/
google.maps.event.trigger(markerClusterer, "click", _this.cluster);
google.maps.event.trigger(markerClusterer, "clusterclick", _this.cluster); // deprecated name
// The default click handler follows. Disable it by setting
// the zoomOnClick property to false.
if (markerClusterer.getZoomOnClick()) {
// Zoom into the cluster.
var maxZoom = markerClusterer.getMaxZoom();
var bounds = _this.cluster.getBounds(); // @ts-ignore
markerClusterer.getMap().fitBounds(bounds); // There is a fix for Issue 170 here:
setTimeout(function timeout() {
// @ts-ignore
markerClusterer.getMap().fitBounds(bounds); // Don't zoom beyond the max zoom level
// @ts-ignore
if (maxZoom !== null && markerClusterer.getMap().getZoom() > maxZoom) {
// @ts-ignore
markerClusterer.getMap().setZoom(maxZoom + 1);
}
}, 100);
} // Prevent event propagation to the map:
event.cancelBubble = true;
if (event.stopPropagation) {
event.stopPropagation();
}
}
});
google.maps.event.addDomListener(this.div, "mouseover", // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name
function () {
/**
* This event is fired when the mouse moves over a cluster marker.
* @name MarkerClusterer#mouseover
* @param {Cluster} c The cluster that the mouse moved over.
* @event
*/
google.maps.event.trigger(_this.cluster.getClusterer(), "mouseover", _this.cluster);
}); // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name
google.maps.event.addDomListener(this.div, "mouseout", // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name
function () {
/**
* This event is fired when the mouse moves out of a cluster marker.
* @name MarkerClusterer#mouseout
* @param {Cluster} c The cluster that the mouse moved out of.
* @event
*/
google.maps.event.trigger(_this.cluster.getClusterer(), "mouseout", _this.cluster);
});
};
_proto.onRemove = function onRemove() {
if (this.div && this.div.parentNode) {
this.hide();
if (this.boundsChangedListener !== null) {
google.maps.event.removeListener(this.boundsChangedListener);
}
google.maps.event.clearInstanceListeners(this.div);
this.div.parentNode.removeChild(this.div);
this.div = null;
}
};
_proto.draw = function draw() {
if (this.visible && this.div !== null && this.center) {
var _this$getPosFromLatLn = this.getPosFromLatLng(this.center),
x = _this$getPosFromLatLn.x,
y = _this$getPosFromLatLn.y;
this.div.style.top = y + "px";
this.div.style.left = x + "px";
}
};
_proto.hide = function hide() {
if (this.div) {
this.div.style.display = "none";
}
this.visible = false;
};
_proto.show = function show() {
if (this.div && this.center) {
var img = ""; // NOTE: values must be specified in px units
var bp = this.backgroundPosition.split(" ");
var spriteH = parseInt(bp[0].replace(/^\s+|\s+$/g, ""), 10);
var spriteV = parseInt(bp[1].replace(/^\s+|\s+$/g, ""), 10);
var pos = this.getPosFromLatLng(this.center);
this.div.style.cssText = this.createCss(pos);
img = "<img src='" + this.url + "' style='position: absolute; top: " + spriteV + "px; left: " + spriteH + "px; "; //@ts-ignore
if (!this.cluster.getClusterer().enableRetinaIcons) {
img += "clip: rect(" + -1 * spriteV + "px, " + (-1 * spriteH + this.width) + "px, " + (-1 * spriteV + this.height) + "px, " + -1 * spriteH + "px);";
}
img += "'>";
this.div.innerHTML = img + "<div style='" + "position: absolute;" + "top: " + this.anchorText[0] + "px;" + "left: " + this.anchorText[1] + "px;" + "color: " + this.textColor + ";" + "font-size: " + this.textSize + "px;" + "font-family: " + this.fontFamily + ";" + "font-weight: " + this.fontWeight + ";" + "font-style: " + this.fontStyle + ";" + "text-decoration: " + this.textDecoration + ";" + "text-align: center;" + "width: " + this.width + "px;" + "line-height:" + this.height + "px;" + // @ts-ignore
"'>" + this.sums.text + "</div>"; // @ts-ignore
if (typeof this.sums.title === "undefined" || this.sums.title === "") {
this.div.title = this.cluster.getClusterer().getTitle();
} else {
// @ts-ignore
this.div.title = this.sums.title;
}
this.div.style.display = "";
}
this.visible = true;
};
_proto.useStyle = function useStyle(sums) {
this.sums = sums;
var style = this.styles[Math.min(this.styles.length - 1, Math.max(0, sums.index - 1))];
this.url = style.url;
this.height = style.height;
this.width = style.width;
this.anchorText = style.anchorText || [0, 0];
this.anchorIcon = style.anchorIcon || [this.height / 2, this.width / 2];
this.textColor = style.textColor || "black";
this.textSize = style.textSize || 11;
this.textDecoration = style.textDecoration || "none";
this.fontWeight = style.fontWeight || "bold";
this.fontStyle = style.fontStyle || "normal";
this.fontFamily = style.fontFamily || "Arial,sans-serif";
this.backgroundPosition = style.backgroundPosition || "0 0";
};
_proto.setCenter = function setCenter(center) {
this.center = center;
};
_proto.createCss = function createCss(pos) {
var style = [];
style.push("cursor: pointer;");
style.push("position: absolute; top: " + pos.y + "px; left: " + pos.x + "px;");
style.push("width: " + this.width + "px; height: " + this.height + "px;");
return style.join("");
};
_proto.getPosFromLatLng = function getPosFromLatLng(latlng) {
// @ts-ignore
var pos = this.getProjection().fromLatLngToDivPixel(latlng);
pos.x -= this.anchorIcon[1];
pos.y -= this.anchorIcon[0];
pos.x = pos.x;
pos.y = pos.y;
return pos;
};
return ClusterIcon;
}();
var Cluster =
/*#__PURE__*/
function () {
function Cluster(markerClusterer) {
this.markerClusterer = markerClusterer; // @ts-ignore
this.map = this.markerClusterer.getMap();
this.gridSize = this.markerClusterer.getGridSize();
this.minClusterSize = this.markerClusterer.getMinimumClusterSize();
this.averageCenter = this.markerClusterer.getAverageCenter();
this.markers = [];
this.center = undefined;
this.bounds = null;
this.clusterIcon = new ClusterIcon(this, this.markerClusterer.getStyles());
}
var _proto = Cluster.prototype;
_proto.getSize = function getSize() {
return this.markers.length;
};
_proto.getMarkers = function getMarkers() {
return this.markers;
};
_proto.getCenter = function getCenter() {
return this.center;
};
_proto.getMap = function getMap() {
return this.map;
};
_proto.getClusterer = function getClusterer() {
return this.markerClusterer;
};
_proto.getBounds = function getBounds() {
var bounds = new google.maps.LatLngBounds(this.center, this.center);
var markers = this.getMarkers();
for (var i = 0; i < markers.length; i++) {
var position = markers[i].getPosition();
if (position) {
bounds.extend(position);
}
}
return bounds;
};
_proto.remove = function remove() {
// @ts-ignore
this.clusterIcon.setMap(null);
this.markers = [];
delete this.markers;
};
_proto.addMarker = function addMarker(marker) {
if (this.isMarkerAlreadyAdded(marker)) {
return false;
}
if (!this.center) {
var position = marker.getPosition();
if (position) {
this.center = position;
this.calculateBounds();
}
} else {
if (this.averageCenter) {
var _position = marker.getPosition();
if (_position) {
var length = this.markers.length + 1;
this.center = new google.maps.LatLng((this.center.lat() * (length - 1) + _position.lat()) / length, (this.center.lng() * (length - 1) + _position.lng()) / length);
this.calculateBounds();
}
}
}
marker.isAdded = true;
this.markers.push(marker);
var mCount = this.markers.length;
var maxZoom = this.markerClusterer.getMaxZoom();
if (maxZoom !== null && this.map.getZoom() > maxZoom) {
// Zoomed in past max zoom, so show the marker.
if (marker.getMap() !== this.map) {
marker.setMap(this.map);
}
} else if (mCount < this.minClusterSize) {
// Min cluster size not reached so show the marker.
if (marker.getMap() !== this.map) {
marker.setMap(this.map);
}
} else if (mCount === this.minClusterSize) {
// Hide the markers that were showing.
for (var i = 0; i < mCount; i++) {
this.markers[i].setMap(null);
}
} else {
marker.setMap(null);
}
this.updateIcon();
return true;
};
_proto.isMarkerInClusterBounds = function isMarkerInClusterBounds(marker) {
if (this.bounds !== null) {
var position = marker.getPosition();
if (position) {
return this.bounds.contains(position);
}
}
return false;
};
_proto.calculateBounds = function calculateBounds() {
this.bounds = this.markerClusterer.getExtendedBounds(new google.maps.LatLngBounds(this.center, this.center));
};
_proto.updateIcon = function updateIcon() {
var mCount = this.markers.length;
var maxZoom = this.markerClusterer.getMaxZoom();
if (maxZoom !== null && this.map.getZoom() > maxZoom) {
this.clusterIcon.hide();
return;
}
if (mCount < this.minClusterSize) {
// Min cluster size not yet reached.
this.clusterIcon.hide();
return;
}
if (this.center) {
this.clusterIcon.setCenter(this.center);
}
this.clusterIcon.useStyle(this.markerClusterer.getCalculator()(this.markers, this.markerClusterer.getStyles().length));
this.clusterIcon.show();
};
_proto.isMarkerAlreadyAdded = function isMarkerAlreadyAdded(marker) {
if (this.markers.indexOf) {
return this.markers.includes(marker);
} else {
for (var i = 0; i < this.markers.length; i++) {
if (marker === this.markers[i]) {
return true;
}
}
}
return false;
};
return Cluster;
}();
/* eslint-disable filenames/match-regex */
var CALCULATOR = function CALCULATOR(markers, numStyles) {
var index = 0;
var title = "";
var count = markers.length.toString();
var dv = count;
while (dv !== 0) {
// @ts-ignore
dv = parseInt(dv, 10) / 10;
index++;
}
index = Math.min(index, numStyles);
return {
text: count,
index: index,
title: title
};
};
var BATCH_SIZE = 2000;
var BATCH_SIZE_IE = 500;
var IMAGE_PATH = "https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m";
var IMAGE_EXTENSION = "png";
var IMAGE_SIZES = [53, 56, 66, 78, 90];
var CLUSTERER_CLASS = "cluster";
var Clusterer =
/*#__PURE__*/
function () {
function Clusterer(map, optMarkers, optOptions) {
if (optMarkers === void 0) {
optMarkers = [];
}
if (optOptions === void 0) {
optOptions = {};
}
this.extend(Clusterer, google.maps.OverlayView);
this.markers = [];
this.clusters = [];
this.listeners = [];
this.activeMap = null;
this.ready = false;
this.gridSize = optOptions.gridSize || 60;
this.minClusterSize = optOptions.minimumClusterSize || 2;
this.maxZoom = optOptions.maxZoom || null;
this.styles = optOptions.styles || [];
this.title = optOptions.title || "";
this.zoomOnClick = true;
if (optOptions.zoomOnClick !== undefined) {
this.zoomOnClick = optOptions.zoomOnClick;
}
this.averageCenter = false;
if (optOptions.averageCenter !== undefined) {
this.averageCenter = optOptions.averageCenter;
}
this.ignoreHidden = false;
if (optOptions.ignoreHidden !== undefined) {
this.ignoreHidden = optOptions.ignoreHidden;
}
this.enableRetinaIcons = false;
if (optOptions.enableRetinaIcons !== undefined) {
this.enableRetinaIcons = optOptions.enableRetinaIcons;
}
this.imagePath = optOptions.imagePath || IMAGE_PATH;
this.imageExtension = optOptions.imageExtension || IMAGE_EXTENSION;
this.imageSizes = optOptions.imageSizes || IMAGE_SIZES;
this.calculator = optOptions.calculator || CALCULATOR;
this.batchSize = optOptions.batchSize || BATCH_SIZE;
this.batchSizeIE = optOptions.batchSizeIE || BATCH_SIZE_IE;
this.clusterClass = optOptions.clusterClass || CLUSTERER_CLASS;
if (navigator.userAgent.toLowerCase().indexOf("msie") !== -1) {
// Try to avoid IE timeout when processing a huge number of markers:
this.batchSize = this.batchSizeIE;
}
this.timerRefStatic = null;
this.setupStyles();
this.addMarkers(optMarkers, true); // @ts-ignore
this.setMap(map); // Note: this causes onAdd to be called
}
var _proto = Clusterer.prototype;
_proto.onAdd = function onAdd() {
var _this = this;
// @ts-ignore
this.activeMap = this.getMap();
this.ready = true;
this.repaint(); // Add the map event listeners
this.listeners = [google.maps.event.addListener( // @ts-ignore
this.getMap(), "zoom_changed", // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name
function () {
_this.resetViewport(false); // Workaround for this Google bug: when map is at level 0 and "-" of
// zoom slider is clicked, a "zoom_changed" event is fired even though
// the map doesn't zoom out any further. In this situation, no "idle"
// event is triggered so the cluster markers that have been removed
// do not get redrawn. Same goes for a zoom in at maxZoom.
if ( // @ts-ignore
_this.getMap().getZoom() === (_this.get("minZoom") || 0) || // @ts-ignore
_this.getMap().getZoom() === _this.get("maxZoom")) {
google.maps.event.trigger(_this, "idle");
}
}), google.maps.event.addListener( // @ts-ignore
this.getMap(), "idle", // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name
function () {
_this.redraw();
})];
} // eslint-disable-next-line @getify/proper-arrows/this
;
_proto.onRemove = function onRemove() {
// Put all the managed markers back on the map:
for (var i = 0; i < this.markers.length; i++) {
if (this.markers[i].getMap() !== this.activeMap) {
this.markers[i].setMap(this.activeMap);
}
} // Remove all clusters:
for (var _i = 0; _i < this.clusters.length; _i++) {
this.clusters[_i].remove();
}
this.clusters = []; // Remove map event listeners:
for (var _i2 = 0; _i2 < this.listeners.length; _i2++) {
google.maps.event.removeListener(this.listeners[_i2]);
}
this.listeners = [];
this.activeMap = null;
this.ready = false;
};
_proto.draw = function draw() {};
_proto.setupStyles = function setupStyles() {
if (this.styles.length > 0) {
return;
}
for (var i = 0; i < this.imageSizes.length; i++) {
this.styles.push({
url: this.imagePath + (i + 1) + "." + this.imageExtension,
height: this.imageSizes[i],
width: this.imageSizes[i]
});
}
};
_proto.fitMapToMarkers = function fitMapToMarkers() {
var markers = this.getMarkers();
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < markers.length; i++) {
var position = markers[i].getPosition();
if (position) {
bounds.extend(position);
}
} // @ts-ignore
this.getMap().fitBounds(bounds);
};
_proto.getGridSize = function getGridSize() {
return this.gridSize;
};
_proto.setGridSize = function setGridSize(gridSize) {
this.gridSize = gridSize;
};
_proto.getMinimumClusterSize = function getMinimumClusterSize() {
return this.minClusterSize;
};
_proto.setMinimumClusterSize = function setMinimumClusterSize(minimumClusterSize) {
this.minClusterSize = minimumClusterSize;
};
_proto.getMaxZoom = function getMaxZoom() {
return this.maxZoom;
};
_proto.setMaxZoom = function setMaxZoom(maxZoom) {
this.maxZoom = maxZoom;
};
_proto.getStyles = function getStyles() {
return this.styles;
};
_proto.setStyles = function setStyles(styles) {
this.styles = styles;
};
_proto.getTitle = function getTitle() {
return this.title;
};
_proto.setTitle = function setTitle(title) {
this.title = title;
};
_proto.getZoomOnClick = function getZoomOnClick() {
return this.zoomOnClick;
};
_proto.setZoomOnClick = function setZoomOnClick(zoomOnClick) {
this.zoomOnClick = zoomOnClick;
};
_proto.getAverageCenter = function getAverageCenter() {
return this.averageCenter;
};
_proto.setAverageCenter = function setAverageCenter(averageCenter) {
this.averageCenter = averageCenter;
};
_proto.getIgnoreHidden = function getIgnoreHidden() {
return this.ignoreHidden;
};
_proto.setIgnoreHidden = function setIgnoreHidden(ignoreHidden) {
this.ignoreHidden = ignoreHidden;
};
_proto.getEnableRetinaIcons = function getEnableRetinaIcons() {
return this.enableRetinaIcons;
};
_proto.setEnableRetinaIcons = function setEnableRetinaIcons(enableRetinaIcons) {
this.enableRetinaIcons = enableRetinaIcons;
};
_proto.getImageExtension = function getImageExtension() {
return this.imageExtension;
};
_proto.setImageExtension = function setImageExtension(imageExtension) {
this.imageExtension = imageExtension;
};
_proto.getImagePath = function getImagePath() {
return this.imagePath;
};
_proto.setImagePath = function setImagePath(imagePath) {
this.imagePath = imagePath;
};
_proto.getImageSizes = function getImageSizes() {
return this.imageSizes;
};
_proto.setImageSizes = function setImageSizes(imageSizes) {
this.imageSizes = imageSizes;
};
_proto.getCalculator = function getCalculator() {
return this.calculator;
};
_proto.setCalculator = function setCalculator(calculator) {
this.calculator = calculator;
};
_proto.getBatchSizeIE = function getBatchSizeIE() {
return this.batchSizeIE;
};
_proto.setBatchSizeIE = function setBatchSizeIE(batchSizeIE) {
this.batchSizeIE = batchSizeIE;
};
_proto.getClusterClass = function getClusterClass() {
return this.clusterClass;
};
_proto.setClusterClass = function setClusterClass(clusterClass) {
this.clusterClass = clusterClass;
};
_proto.getMarkers = function getMarkers() {
return this.markers;
};
_proto.getTotalMarkers = function getTotalMarkers() {
return this.markers.length;
};
_proto.getClusters = function getClusters() {
return this.clusters;
};
_proto.getTotalClusters = function getTotalClusters() {
return this.clusters.length;
};
_proto.addMarker = function addMarker(marker, optNoDraw) {
this.pushMarkerTo(marker);
if (!optNoDraw) {
this.redraw();
}
};
_proto.addMarkers = function addMarkers(markers, optNoDraw) {
for (var key in markers) {
if (markers.hasOwnProperty(key)) {
this.pushMarkerTo(markers[key]);
}
}
if (!optNoDraw) {
this.redraw();
}
};
_proto.pushMarkerTo = function pushMarkerTo(marker) {
var _this2 = this;
// If the marker is draggable add a listener so we can update the clusters on the dragend:
if (marker.getDraggable()) {
// eslint-disable-next-line @getify/proper-arrows/name, @getify/proper-arrows/this
google.maps.event.addListener(marker, "dragend", function () {
if (_this2.ready) {
marker.isAdded = false;
_this2.repaint();
}
});
}
marker.isAdded = false;
this.markers.push(marker);
};
_proto.removeMarker_ = function removeMarker_(marker) {
var index = -1;
if (this.markers.indexOf) {
index = this.markers.indexOf(marker);
} else {
for (var i = 0; i < this.markers.length; i++) {
if (marker === this.markers[i]) {
index = i;
break;
}
}
}
if (index === -1) {
// Marker is not in our list of markers, so do nothing:
return false;
}
marker.setMap(null);
this.markers.splice(index, 1); // Remove the marker from the list of managed markers
return true;
};
_proto.removeMarker = function removeMarker(marker, optNoDraw) {
var removed = this.removeMarker_(marker);
if (!optNoDraw && removed) {
this.repaint();
}
return removed;
};
_proto.removeMarkers = function removeMarkers(markers, optNoDraw) {
var removed = false;
for (var i = 0; i < markers.length; i++) {
removed = removed || this.removeMarker_(markers[i]);
}
if (!optNoDraw && removed) {
this.repaint();
}
return removed;
};
_proto.clearMarkers = function clearMarkers() {
this.resetViewport(true);
this.markers = [];
};
_proto.repaint = function repaint() {
var oldClusters = this.clusters.slice();
this.clusters = [];
this.resetViewport(false);
this.redraw(); // Remove the old clusters.
// Do it in a timeout to prevent blinking effect.
setTimeout(function timeout() {
for (var i = 0; i < oldClusters.length; i++) {
oldClusters[i].remove();
}
}, 0);
};
_proto.getExtendedBounds = function getExtendedBounds(bounds) {
// @ts-ignore
var projection = this.getProjection(); // Convert the points to pixels and the extend out by the grid size.
var trPix = projection.fromLatLngToDivPixel( // Turn the bounds into latlng.
new google.maps.LatLng(bounds.getNorthEast().lat(), bounds.getNorthEast().lng()));
trPix.x += this.gridSize;
trPix.y -= this.gridSize;
var blPix = projection.fromLatLngToDivPixel( // Turn the bounds into latlng.
new google.maps.LatLng(bounds.getSouthWest().lat(), bounds.getSouthWest().lng()));
blPix.x -= this.gridSize;
blPix.y += this.gridSize; // Extend the bounds to contain the new bounds.
bounds.extend( // Convert the pixel points back to LatLng nw
projection.fromDivPixelToLatLng(trPix));
bounds.extend( // Convert the pixel points back to LatLng sw
projection.fromDivPixelToLatLng(blPix));
return bounds;
};
_proto.redraw = function redraw() {
// Redraws all the clusters.
this.createClusters(0);
};
_proto.resetViewport = function resetViewport(optHide) {
// Remove all the clusters
for (var i = 0; i < this.clusters.length; i++) {
this.clusters[i].remove();
}
this.clusters = []; // Reset the markers to not be added and to be removed from the map.
for (var _i3 = 0; _i3 < this.markers.length; _i3++) {
var marker = this.markers[_i3];
marker.isAdded = false;
if (optHide) {
marker.setMap(null);
}
}
};
_proto.distanceBetweenPoints = function distanceBetweenPoints(p1, p2) {
var R = 6371; // Radius of the Earth in km
var dLat = (p2.lat() - p1.lat()) * Math.PI / 180;
var dLon = (p2.lng() - p1.lng()) * Math.PI / 180;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
return R * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)));
};
_proto.isMarkerInBounds = function isMarkerInBounds(marker, bounds) {
var position = marker.getPosition();
if (position) {
return bounds.contains(position);
}
return false;
};
_proto.addToClosestCluster = function addToClosestCluster(marker) {
var cluster;
var distance = 40000; // Some large number
var clusterToAddTo = null;
for (var i = 0; i < this.clusters.length; i++) {
cluster = this.clusters[i];
var center = cluster.getCenter();
var position = marker.getPosition();
if (center && position) {
var d = this.distanceBetweenPoints(center, position);
if (d < distance) {
distance = d;
clusterToAddTo = cluster;
}
}
}
if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)) {
clusterToAddTo.addMarker(marker);
} else {
cluster = new Cluster(this);
cluster.addMarker(marker);
this.clusters.push(cluster);
}
};
_proto.createClusters = function createClusters(iFirst) {
var _this3 = this;
if (!this.ready) {
return;
} // Cancel previous batch processing if we're working on the first batch:
if (iFirst === 0) {
/**
* This event is fired when the <code>Clusterer</code> begins
* clustering markers.
* @name Clusterer#clusteringbegin
* @param {Clusterer} mc The Clusterer whose markers are being clustered.
* @event
*/
google.maps.event.trigger(this, "clusteringbegin", this);
if (this.timerRefStatic !== null) {
window.clearTimeout(this.timerRefStatic);
delete this.timerRefStatic;
}
} // Get our current map view bounds.
// Create a new bounds object so we don't affect the map.
//
// See Comments 9 & 11 on Issue 3651 relating to this workaround for a Google Maps bug:
// @ts-ignore
var mapBounds = this.getMap().getZoom() > 3 ? new google.maps.LatLngBounds( // @ts-ignore
this.getMap().getBounds().getSouthWest(), // @ts-ignore
this.getMap().getBounds().getNorthEast()) : new google.maps.LatLngBounds(new google.maps.LatLng(85.02070771743472, -178.48388434375), new google.maps.LatLng(-85.08136444384544, 178.00048865625));
var bounds = this.getExtendedBounds(mapBounds);
var iLast = Math.min(iFirst + this.batchSize, this.markers.length);
for (var i = iFirst; i < iLast; i++) {
var marker = this.markers[i];
if (!marker.isAdded && this.isMarkerInBounds(marker, bounds)) {
if (!this.ignoreHidden || this.ignoreHidden && marker.getVisible()) {
this.addToClosestCluster(marker);
}
}
}
if (iLast < this.markers.length) {
this.timerRefStatic = window.setTimeout( // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name
function () {
_this3.createClusters(iLast);
}, 0);
} else {
this.timerRefStatic = null;
/**
* This event is fired when the <code>Clusterer</code> stops
* clustering markers.
* @name Clusterer#clusteringend
* @param {Clusterer} mc The Clusterer whose markers are being clustered.
* @event
*/
google.maps.event.trigger(this, "clusteringend", this);
}
};
_proto.extend = function extend(obj1, obj2) {
return function applyExtend(object) {
// eslint-disable-next-line guard-for-in
for (var property in object.prototype) {
// @ts-ignore
this.prototype[property] = object.prototype[property];
} // @ts-ignore
return this;
}.apply(obj1, [obj2]);
};
return Clusterer;
}();
exports.Cluster = Cluster;
exports.ClusterIcon = ClusterIcon;
exports.Clusterer = Clusterer;
}));
//# sourceMappingURL=markerclusterer.umd.development.js.map