@react-google-maps/marker-clusterer
Version:
Marker Clusterer for React.js Google Maps API
996 lines (990 loc) • 46.1 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.markerClusterer = {}));
})(this, (function (exports) { 'use strict';
var ClusterIcon = /** @class */ (function () {
function ClusterIcon(cluster, styles) {
cluster.getClusterer().extend(ClusterIcon, google.maps.OverlayView);
this.cluster = cluster;
this.clusterClassName = this.cluster.getClusterer().getClusterClass();
this.className = this.clusterClassName;
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';
this.cMouseDownInCluster = null;
this.cDraggingMapByCluster = null;
this.timeOut = null;
this.setMap(cluster.getMap()); // Note: this causes onAdd to be called
this.onBoundsChanged = this.onBoundsChanged.bind(this);
this.onMouseDown = this.onMouseDown.bind(this);
this.onClick = this.onClick.bind(this);
this.onMouseOver = this.onMouseOver.bind(this);
this.onMouseOut = this.onMouseOut.bind(this);
this.onAdd = this.onAdd.bind(this);
this.onRemove = this.onRemove.bind(this);
this.draw = this.draw.bind(this);
this.hide = this.hide.bind(this);
this.show = this.show.bind(this);
this.useStyle = this.useStyle.bind(this);
this.setCenter = this.setCenter.bind(this);
this.getPosFromLatLng = this.getPosFromLatLng.bind(this);
}
ClusterIcon.prototype.onBoundsChanged = function () {
this.cDraggingMapByCluster = this.cMouseDownInCluster;
};
ClusterIcon.prototype.onMouseDown = function () {
this.cMouseDownInCluster = true;
this.cDraggingMapByCluster = false;
};
ClusterIcon.prototype.onClick = function (event) {
this.cMouseDownInCluster = false;
if (!this.cDraggingMapByCluster) {
var markerClusterer_1 = 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_1, 'click', this.cluster);
google.maps.event.trigger(markerClusterer_1, 'clusterclick', this.cluster); // deprecated name
// The default click handler follows. Disable it by setting
// the zoomOnClick property to false.
if (markerClusterer_1.getZoomOnClick()) {
// Zoom into the cluster.
var maxZoom_1 = markerClusterer_1.getMaxZoom();
var bounds_1 = this.cluster.getBounds();
var map = markerClusterer_1.getMap();
if (map !== null && 'fitBounds' in map) {
map.fitBounds(bounds_1);
}
// There is a fix for Issue 170 here:
this.timeOut = window.setTimeout(function () {
var map = markerClusterer_1.getMap();
if (map !== null) {
if ('fitBounds' in map) {
map.fitBounds(bounds_1);
}
var zoom = map.getZoom() || 0;
// Don't zoom beyond the max zoom level
if (maxZoom_1 !== null &&
zoom > maxZoom_1) {
map.setZoom(maxZoom_1 + 1);
}
}
}, 100);
}
// Prevent event propagation to the map:
event.cancelBubble = true;
if (event.stopPropagation) {
event.stopPropagation();
}
}
};
ClusterIcon.prototype.onMouseOver = 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);
};
ClusterIcon.prototype.onMouseOut = 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);
};
ClusterIcon.prototype.onAdd = function () {
var _a;
this.div = document.createElement('div');
this.div.className = this.className;
if (this.visible) {
this.show();
}
(_a = this.getPanes()) === null || _a === void 0 ? void 0 : _a.overlayMouseTarget.appendChild(this.div);
var map = this.getMap();
if (map !== null) {
// Fix for Issue 157
this.boundsChangedListener = google.maps.event.addListener(map, 'bounds_changed', this.onBoundsChanged);
this.div.addEventListener('mousedown', this.onMouseDown);
this.div.addEventListener('click', this.onClick);
this.div.addEventListener('mouseover', this.onMouseOver);
this.div.addEventListener('mouseout', this.onMouseOut);
}
};
ClusterIcon.prototype.onRemove = function () {
if (this.div && this.div.parentNode) {
this.hide();
if (this.boundsChangedListener !== null) {
google.maps.event.removeListener(this.boundsChangedListener);
}
this.div.removeEventListener('mousedown', this.onMouseDown);
this.div.removeEventListener('click', this.onClick);
this.div.removeEventListener('mouseover', this.onMouseOver);
this.div.removeEventListener('mouseout', this.onMouseOut);
this.div.parentNode.removeChild(this.div);
if (this.timeOut !== null) {
window.clearTimeout(this.timeOut);
this.timeOut = null;
}
this.div = null;
}
};
ClusterIcon.prototype.draw = function () {
if (this.visible && this.div !== null && this.center) {
var pos = this.getPosFromLatLng(this.center);
this.div.style.top = pos !== null ? "".concat(pos.y, "px") : '0';
this.div.style.left = pos !== null ? "".concat(pos.x, "px") : '0';
}
};
ClusterIcon.prototype.hide = function () {
if (this.div) {
this.div.style.display = 'none';
}
this.visible = false;
};
ClusterIcon.prototype.show = function () {
var _a, _b, _c, _d, _e, _f;
if (this.div && this.center) {
var divTitle = this.sums === null ||
typeof this.sums.title === 'undefined' ||
this.sums.title === '' ? this.cluster.getClusterer().getTitle() : this.sums.title;
// NOTE: values must be specified in px units
var bp = this.backgroundPosition.split(' ');
var spriteH = parseInt(((_a = bp[0]) === null || _a === void 0 ? void 0 : _a.replace(/^\s+|\s+$/g, '')) || '0', 10);
var spriteV = parseInt(((_b = bp[1]) === null || _b === void 0 ? void 0 : _b.replace(/^\s+|\s+$/g, '')) || '0', 10);
var pos = this.getPosFromLatLng(this.center);
this.div.className = this.className;
this.div.setAttribute('style', "cursor: pointer; position: absolute; top: ".concat(pos !== null ? "".concat(pos.y, "px") : '0', "; left: ").concat(pos !== null ? "".concat(pos.x, "px") : '0', "; width: ").concat(this.width, "px; height: ").concat(this.height, "px; "));
var img = document.createElement('img');
img.alt = divTitle;
img.src = this.url;
img.width = this.width;
img.height = this.height;
img.setAttribute('style', "position: absolute; top: ".concat(spriteV, "px; left: ").concat(spriteH, "px"));
if (!this.cluster.getClusterer().enableRetinaIcons) {
img.style.clip = "rect(-".concat(spriteV, "px, -").concat(spriteH + this.width, "px, -").concat(spriteV + this.height, ", -").concat(spriteH, ")");
}
var textElm = document.createElement('div');
textElm.setAttribute('style', "position: absolute; top: ".concat(this.anchorText[0], "px; left: ").concat(this.anchorText[1], "px; color: ").concat(this.textColor, "; font-size: ").concat(this.textSize, "px; font-family: ").concat(this.fontFamily, "; font-weight: ").concat(this.fontWeight, "; fontStyle: ").concat(this.fontStyle, "; text-decoration: ").concat(this.textDecoration, "; text-align: center; width: ").concat(this.width, "px; line-height: ").concat(this.height, "px"));
if ((_c = this.sums) === null || _c === void 0 ? void 0 : _c.text)
textElm.innerText = "".concat((_d = this.sums) === null || _d === void 0 ? void 0 : _d.text);
if ((_e = this.sums) === null || _e === void 0 ? void 0 : _e.html)
textElm.innerHTML = "".concat((_f = this.sums) === null || _f === void 0 ? void 0 : _f.html);
this.div.innerHTML = '';
this.div.appendChild(img);
this.div.appendChild(textElm);
this.div.title = divTitle;
this.div.style.display = '';
}
this.visible = true;
};
ClusterIcon.prototype.useStyle = function (sums) {
this.sums = sums;
var styles = this.cluster.getClusterer().getStyles();
var style = styles[Math.min(styles.length - 1, Math.max(0, sums.index - 1))];
if (style) {
this.url = style.url;
this.height = style.height;
this.width = style.width;
if (style.className) {
this.className = "".concat(this.clusterClassName, " ").concat(style.className);
}
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';
}
};
ClusterIcon.prototype.setCenter = function (center) {
this.center = center;
};
ClusterIcon.prototype.getPosFromLatLng = function (latlng) {
var pos = this.getProjection().fromLatLngToDivPixel(latlng);
if (pos !== null) {
pos.x -= this.anchorIcon[1];
pos.y -= this.anchorIcon[0];
}
return pos;
};
return ClusterIcon;
}());
/* global google */
var Cluster = /** @class */ (function () {
function Cluster(markerClusterer) {
this.markerClusterer = markerClusterer;
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());
this.getSize = this.getSize.bind(this);
this.getMarkers = this.getMarkers.bind(this);
this.getCenter = this.getCenter.bind(this);
this.getMap = this.getMap.bind(this);
this.getClusterer = this.getClusterer.bind(this);
this.getBounds = this.getBounds.bind(this);
this.remove = this.remove.bind(this);
this.addMarker = this.addMarker.bind(this);
this.isMarkerInClusterBounds = this.isMarkerInClusterBounds.bind(this);
this.calculateBounds = this.calculateBounds.bind(this);
this.updateIcon = this.updateIcon.bind(this);
this.isMarkerAlreadyAdded = this.isMarkerAlreadyAdded.bind(this);
}
Cluster.prototype.getSize = function () {
return this.markers.length;
};
Cluster.prototype.getMarkers = function () {
return this.markers;
};
Cluster.prototype.getCenter = function () {
return this.center;
};
Cluster.prototype.getMap = function () {
return this.map;
};
Cluster.prototype.getClusterer = function () {
return this.markerClusterer;
};
Cluster.prototype.getBounds = function () {
var bounds = new google.maps.LatLngBounds(this.center, this.center);
var markers = this.getMarkers();
for (var _i = 0, markers_1 = markers; _i < markers_1.length; _i++) {
var marker = markers_1[_i];
var position = marker.getPosition();
if (position) {
bounds.extend(position);
}
}
return bounds;
};
Cluster.prototype.remove = function () {
this.clusterIcon.setMap(null);
this.markers = [];
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
delete this.markers;
};
Cluster.prototype.addMarker = function (marker) {
var _a;
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_1 = this.markers.length + 1;
this.center = new google.maps.LatLng((this.center.lat() * (length_1 - 1) + position.lat()) / length_1, (this.center.lng() * (length_1 - 1) + position.lng()) / length_1);
this.calculateBounds();
}
}
}
marker.isAdded = true;
this.markers.push(marker);
var mCount = this.markers.length;
var maxZoom = this.markerClusterer.getMaxZoom();
var zoom = (_a = this.map) === null || _a === void 0 ? void 0 : _a.getZoom();
if (maxZoom !== null && typeof zoom !== 'undefined' && zoom > 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, _b = this.markers; _i < _b.length; _i++) {
var markerElement = _b[_i];
markerElement.setMap(null);
}
}
else {
marker.setMap(null);
}
return true;
};
Cluster.prototype.isMarkerInClusterBounds = function (marker) {
if (this.bounds !== null) {
var position = marker.getPosition();
if (position) {
return this.bounds.contains(position);
}
}
return false;
};
Cluster.prototype.calculateBounds = function () {
this.bounds = this.markerClusterer.getExtendedBounds(new google.maps.LatLngBounds(this.center, this.center));
};
Cluster.prototype.updateIcon = function () {
var _a;
var mCount = this.markers.length;
var maxZoom = this.markerClusterer.getMaxZoom();
var zoom = (_a = this.map) === null || _a === void 0 ? void 0 : _a.getZoom();
if (maxZoom !== null && typeof zoom !== 'undefined' && zoom > 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();
};
Cluster.prototype.isMarkerAlreadyAdded = function (marker) {
if (this.markers.includes) {
return this.markers.includes(marker);
}
for (var i = 0; i < this.markers.length; i++) {
if (marker === this.markers[i]) {
return true;
}
}
return false;
};
return Cluster;
}());
/* global google */
/* eslint-disable filenames/match-regex */
/**
* Supports up to 9007199254740991 (Number.MAX_SAFE_INTEGER) markers
* which is not a problem as max array length is 4294967296 (2**32)
*/
function CALCULATOR(markers, numStyles) {
var count = markers.length;
var numberOfDigits = count.toString().length;
var index = Math.min(numberOfDigits, numStyles);
return {
text: count.toString(),
index: index,
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 = /** @class */ (function () {
function Clusterer(map, optMarkers, optOptions) {
if (optMarkers === void 0) { optMarkers = []; }
if (optOptions === void 0) { optOptions = {}; }
this.getMinimumClusterSize = this.getMinimumClusterSize.bind(this);
this.setMinimumClusterSize = this.setMinimumClusterSize.bind(this);
this.getEnableRetinaIcons = this.getEnableRetinaIcons.bind(this);
this.setEnableRetinaIcons = this.setEnableRetinaIcons.bind(this);
this.addToClosestCluster = this.addToClosestCluster.bind(this);
this.getImageExtension = this.getImageExtension.bind(this);
this.setImageExtension = this.setImageExtension.bind(this);
this.getExtendedBounds = this.getExtendedBounds.bind(this);
this.getAverageCenter = this.getAverageCenter.bind(this);
this.setAverageCenter = this.setAverageCenter.bind(this);
this.getTotalClusters = this.getTotalClusters.bind(this);
this.fitMapToMarkers = this.fitMapToMarkers.bind(this);
this.getIgnoreHidden = this.getIgnoreHidden.bind(this);
this.setIgnoreHidden = this.setIgnoreHidden.bind(this);
this.getClusterClass = this.getClusterClass.bind(this);
this.setClusterClass = this.setClusterClass.bind(this);
this.getTotalMarkers = this.getTotalMarkers.bind(this);
this.getZoomOnClick = this.getZoomOnClick.bind(this);
this.setZoomOnClick = this.setZoomOnClick.bind(this);
this.getBatchSizeIE = this.getBatchSizeIE.bind(this);
this.setBatchSizeIE = this.setBatchSizeIE.bind(this);
this.createClusters = this.createClusters.bind(this);
this.onZoomChanged = this.onZoomChanged.bind(this);
this.getImageSizes = this.getImageSizes.bind(this);
this.setImageSizes = this.setImageSizes.bind(this);
this.getCalculator = this.getCalculator.bind(this);
this.setCalculator = this.setCalculator.bind(this);
this.removeMarkers = this.removeMarkers.bind(this);
this.resetViewport = this.resetViewport.bind(this);
this.getImagePath = this.getImagePath.bind(this);
this.setImagePath = this.setImagePath.bind(this);
this.pushMarkerTo = this.pushMarkerTo.bind(this);
this.removeMarker = this.removeMarker.bind(this);
this.clearMarkers = this.clearMarkers.bind(this);
this.setupStyles = this.setupStyles.bind(this);
this.getGridSize = this.getGridSize.bind(this);
this.setGridSize = this.setGridSize.bind(this);
this.getClusters = this.getClusters.bind(this);
this.getMaxZoom = this.getMaxZoom.bind(this);
this.setMaxZoom = this.setMaxZoom.bind(this);
this.getMarkers = this.getMarkers.bind(this);
this.addMarkers = this.addMarkers.bind(this);
this.getStyles = this.getStyles.bind(this);
this.setStyles = this.setStyles.bind(this);
this.addMarker = this.addMarker.bind(this);
this.onRemove = this.onRemove.bind(this);
this.getTitle = this.getTitle.bind(this);
this.setTitle = this.setTitle.bind(this);
this.repaint = this.repaint.bind(this);
this.onIdle = this.onIdle.bind(this);
this.redraw = this.redraw.bind(this);
this.onAdd = this.onAdd.bind(this);
this.draw = this.draw.bind(this);
this.extend = this.extend.bind(this);
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);
this.setMap(map); // Note: this causes onAdd to be called
}
Clusterer.prototype.onZoomChanged = function () {
var _a, _b;
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 (((_a = this.getMap()) === null || _a === void 0 ? void 0 : _a.getZoom()) === (this.get('minZoom') || 0) ||
((_b = this.getMap()) === null || _b === void 0 ? void 0 : _b.getZoom()) === this.get('maxZoom')) {
google.maps.event.trigger(this, 'idle');
}
};
Clusterer.prototype.onIdle = function () {
this.redraw();
};
Clusterer.prototype.onAdd = function () {
var map = this.getMap();
this.activeMap = map;
this.ready = true;
this.repaint();
if (map !== null) {
// Add the map event listeners
this.listeners = [
google.maps.event.addListener(map, 'zoom_changed', this.onZoomChanged),
google.maps.event.addListener(map, 'idle', this.onIdle),
];
}
};
Clusterer.prototype.onRemove = function () {
// Put all the managed markers back on the map:
for (var _i = 0, _a = this.markers; _i < _a.length; _i++) {
var marker = _a[_i];
if (marker.getMap() !== this.activeMap) {
marker.setMap(this.activeMap);
}
}
// Remove all clusters:
for (var _b = 0, _c = this.clusters; _b < _c.length; _b++) {
var cluster = _c[_b];
cluster.remove();
}
this.clusters = [];
// Remove map event listeners:
for (var _d = 0, _e = this.listeners; _d < _e.length; _d++) {
var listener = _e[_d];
google.maps.event.removeListener(listener);
}
this.listeners = [];
this.activeMap = null;
this.ready = false;
};
Clusterer.prototype.draw = function () { return; };
Clusterer.prototype.getMap = function () { return null; };
Clusterer.prototype.getPanes = function () { return null; };
Clusterer.prototype.getProjection = function () {
return {
fromContainerPixelToLatLng: function () { return null; },
fromDivPixelToLatLng: function () { return null; },
fromLatLngToContainerPixel: function () { return null; },
fromLatLngToDivPixel: function () { return null; },
getVisibleRegion: function () { return null; },
getWorldWidth: function () { return 0; }
};
};
Clusterer.prototype.setMap = function () { return; };
Clusterer.prototype.addListener = function () {
return {
remove: function () { return; }
};
};
Clusterer.prototype.bindTo = function () { return; };
Clusterer.prototype.get = function () { return; };
Clusterer.prototype.notify = function () { return; };
Clusterer.prototype.set = function () { return; };
Clusterer.prototype.setValues = function () { return; };
Clusterer.prototype.unbind = function () { return; };
Clusterer.prototype.unbindAll = function () { return; };
Clusterer.prototype.setupStyles = function () {
if (this.styles.length > 0) {
return;
}
for (var i = 0; i < this.imageSizes.length; i++) {
this.styles.push({
url: "".concat(this.imagePath + (i + 1), ".").concat(this.imageExtension),
height: this.imageSizes[i] || 0,
width: this.imageSizes[i] || 0,
});
}
};
Clusterer.prototype.fitMapToMarkers = function () {
var markers = this.getMarkers();
var bounds = new google.maps.LatLngBounds();
for (var _i = 0, markers_1 = markers; _i < markers_1.length; _i++) {
var marker = markers_1[_i];
var position = marker.getPosition();
if (position) {
bounds.extend(position);
}
}
var map = this.getMap();
if (map !== null && 'fitBounds' in map) {
map.fitBounds(bounds);
}
};
Clusterer.prototype.getGridSize = function () {
return this.gridSize;
};
Clusterer.prototype.setGridSize = function (gridSize) {
this.gridSize = gridSize;
};
Clusterer.prototype.getMinimumClusterSize = function () {
return this.minClusterSize;
};
Clusterer.prototype.setMinimumClusterSize = function (minimumClusterSize) {
this.minClusterSize = minimumClusterSize;
};
Clusterer.prototype.getMaxZoom = function () {
return this.maxZoom;
};
Clusterer.prototype.setMaxZoom = function (maxZoom) {
this.maxZoom = maxZoom;
};
Clusterer.prototype.getStyles = function () {
return this.styles;
};
Clusterer.prototype.setStyles = function (styles) {
this.styles = styles;
};
Clusterer.prototype.getTitle = function () {
return this.title;
};
Clusterer.prototype.setTitle = function (title) {
this.title = title;
};
Clusterer.prototype.getZoomOnClick = function () {
return this.zoomOnClick;
};
Clusterer.prototype.setZoomOnClick = function (zoomOnClick) {
this.zoomOnClick = zoomOnClick;
};
Clusterer.prototype.getAverageCenter = function () {
return this.averageCenter;
};
Clusterer.prototype.setAverageCenter = function (averageCenter) {
this.averageCenter = averageCenter;
};
Clusterer.prototype.getIgnoreHidden = function () {
return this.ignoreHidden;
};
Clusterer.prototype.setIgnoreHidden = function (ignoreHidden) {
this.ignoreHidden = ignoreHidden;
};
Clusterer.prototype.getEnableRetinaIcons = function () {
return this.enableRetinaIcons;
};
Clusterer.prototype.setEnableRetinaIcons = function (enableRetinaIcons) {
this.enableRetinaIcons = enableRetinaIcons;
};
Clusterer.prototype.getImageExtension = function () {
return this.imageExtension;
};
Clusterer.prototype.setImageExtension = function (imageExtension) {
this.imageExtension = imageExtension;
};
Clusterer.prototype.getImagePath = function () {
return this.imagePath;
};
Clusterer.prototype.setImagePath = function (imagePath) {
this.imagePath = imagePath;
};
Clusterer.prototype.getImageSizes = function () {
return this.imageSizes;
};
Clusterer.prototype.setImageSizes = function (imageSizes) {
this.imageSizes = imageSizes;
};
Clusterer.prototype.getCalculator = function () {
return this.calculator;
};
Clusterer.prototype.setCalculator = function (calculator) {
this.calculator = calculator;
};
Clusterer.prototype.getBatchSizeIE = function () {
return this.batchSizeIE;
};
Clusterer.prototype.setBatchSizeIE = function (batchSizeIE) {
this.batchSizeIE = batchSizeIE;
};
Clusterer.prototype.getClusterClass = function () {
return this.clusterClass;
};
Clusterer.prototype.setClusterClass = function (clusterClass) {
this.clusterClass = clusterClass;
};
Clusterer.prototype.getMarkers = function () {
return this.markers;
};
Clusterer.prototype.getTotalMarkers = function () {
return this.markers.length;
};
Clusterer.prototype.getClusters = function () {
return this.clusters;
};
Clusterer.prototype.getTotalClusters = function () {
return this.clusters.length;
};
Clusterer.prototype.addMarker = function (marker, optNoDraw) {
this.pushMarkerTo(marker);
if (!optNoDraw) {
this.redraw();
}
};
Clusterer.prototype.addMarkers = function (markers, optNoDraw) {
for (var key in markers) {
if (Object.prototype.hasOwnProperty.call(markers, key)) {
var marker = markers[key];
if (marker) {
this.pushMarkerTo(marker);
}
}
}
if (!optNoDraw) {
this.redraw();
}
};
Clusterer.prototype.pushMarkerTo = function (marker) {
var _this = this;
// If the marker is draggable add a listener so we can update the clusters on the dragend:
if (marker.getDraggable()) {
google.maps.event.addListener(marker, 'dragend', function () {
if (_this.ready) {
marker.isAdded = false;
_this.repaint();
}
});
}
marker.isAdded = false;
this.markers.push(marker);
};
Clusterer.prototype.removeMarker_ = function (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;
};
Clusterer.prototype.removeMarker = function (marker, optNoDraw) {
var removed = this.removeMarker_(marker);
if (!optNoDraw && removed) {
this.repaint();
}
return removed;
};
Clusterer.prototype.removeMarkers = function (markers, optNoDraw) {
var removed = false;
for (var _i = 0, markers_2 = markers; _i < markers_2.length; _i++) {
var marker = markers_2[_i];
removed = removed || this.removeMarker_(marker);
}
if (!optNoDraw && removed) {
this.repaint();
}
return removed;
};
Clusterer.prototype.clearMarkers = function () {
this.resetViewport(true);
this.markers = [];
};
Clusterer.prototype.repaint = function () {
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, oldClusters_1 = oldClusters; _i < oldClusters_1.length; _i++) {
var oldCluster = oldClusters_1[_i];
oldCluster.remove();
}
}, 0);
};
Clusterer.prototype.getExtendedBounds = function (bounds) {
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()));
if (trPix !== null) {
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()));
if (blPix !== null) {
blPix.x -= this.gridSize;
blPix.y += this.gridSize;
}
// Extend the bounds to contain the new bounds.
if (trPix !== null) {
// Convert the pixel points back to LatLng nw
var point1 = projection.fromDivPixelToLatLng(trPix);
if (point1 !== null) {
bounds.extend(point1);
}
}
if (blPix !== null) {
// Convert the pixel points back to LatLng sw
var point2 = projection.fromDivPixelToLatLng(blPix);
if (point2 !== null) {
bounds.extend(point2);
}
}
return bounds;
};
Clusterer.prototype.redraw = function () {
// Redraws all the clusters.
this.createClusters(0);
};
Clusterer.prototype.resetViewport = function (optHide) {
// Remove all the clusters
for (var _i = 0, _a = this.clusters; _i < _a.length; _i++) {
var cluster = _a[_i];
cluster.remove();
}
this.clusters = [];
// Reset the markers to not be added and to be removed from the map.
for (var _b = 0, _c = this.markers; _b < _c.length; _b++) {
var marker = _c[_b];
marker.isAdded = false;
if (optHide) {
marker.setMap(null);
}
}
};
Clusterer.prototype.distanceBetweenPoints = function (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)));
};
Clusterer.prototype.isMarkerInBounds = function (marker, bounds) {
var position = marker.getPosition();
if (position) {
return bounds.contains(position);
}
return false;
};
Clusterer.prototype.addToClosestCluster = function (marker) {
var cluster;
var distance = 40000; // Some large number
var clusterToAddTo = null;
for (var _i = 0, _a = this.clusters; _i < _a.length; _i++) {
var clusterElement = _a[_i];
cluster = clusterElement;
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);
}
};
Clusterer.prototype.createClusters = function (iFirst) {
var _this = 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);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
delete this.timerRefStatic;
}
}
var map = this.getMap();
var bounds = map !== null && 'getBounds' in map ? map.getBounds() : null;
var zoom = (map === null || map === void 0 ? void 0 : map.getZoom()) || 0;
// 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:
var mapBounds = zoom > 3
? new google.maps.LatLngBounds(bounds === null || bounds === void 0 ? void 0 : bounds.getSouthWest(), bounds === null || bounds === void 0 ? void 0 : bounds.getNorthEast())
: new google.maps.LatLngBounds(new google.maps.LatLng(85.02070771743472, -178.48388434375), new google.maps.LatLng(-85.08136444384544, 178.00048865625));
var extendedMapBounds = 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 && !marker.isAdded && this.isMarkerInBounds(marker, extendedMapBounds) && (!this.ignoreHidden || (this.ignoreHidden && marker.getVisible()))) {
this.addToClosestCluster(marker);
}
}
if (iLast < this.markers.length) {
this.timerRefStatic = window.setTimeout(function () {
_this.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);
for (var _i = 0, _a = this.clusters; _i < _a.length; _i++) {
var cluster = _a[_i];
cluster.updateIcon();
}
}
};
Clusterer.prototype.extend = function (obj1, obj2) {
return function applyExtend(object) {
for (var property in object.prototype) {
// eslint-disable-next-line @typescript-eslint/ban-types
var prop = property;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
this.prototype[prop] = object.prototype[prop];
}
return this;
}.apply(obj1, [obj2]);
};
return Clusterer;
}());
exports.Cluster = Cluster;
exports.ClusterIcon = ClusterIcon;
exports.Clusterer = Clusterer;
}));
//# sourceMappingURL=umd.js.map