/* eslint-disable */
|
let __extends = (this && this.__extends) || (function () {
|
let extendStatics = Object.setPrototypeOf ||
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b }) ||
|
function (d, b) { for (let p in b) if (b.hasOwnProperty(p)) d[p] = b[p] }
|
return function (d, b) {
|
extendStatics(d, b)
|
function __() { this.constructor = d }
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __())
|
}
|
})()
|
export let PruneCluster;
|
(function (PruneCluster_1) {
|
let Point = (function () {
|
function Point() {
|
}
|
return Point
|
}())
|
PruneCluster_1.Point = Point
|
let ClusterObject = (function () {
|
function ClusterObject() {
|
}
|
return ClusterObject
|
}())
|
PruneCluster_1.ClusterObject = ClusterObject
|
let hashCodeCounter = 1
|
let maxHashCodeValue = Math.pow(2, 53) - 1
|
let Marker = (function (_super) {
|
__extends(Marker, _super)
|
function Marker(lat, lng, data, category, weight, filtered) {
|
if (data === void 0) { data = {} }
|
if (weight === void 0) { weight = 1 }
|
if (filtered === void 0) { filtered = false }
|
let _this = _super.call(this) || this
|
_this.data = data
|
_this.position = { lat: +lat, lng: +lng }
|
_this.weight = weight
|
_this.category = category
|
_this.filtered = filtered
|
_this.hashCode = hashCodeCounter++
|
return _this
|
}
|
Marker.prototype.Move = function (lat, lng) {
|
this.position.lat = +lat
|
this.position.lng = +lng
|
}
|
Marker.prototype.SetData = function (data) {
|
for (let key in data) {
|
this.data[key] = data[key]
|
}
|
}
|
return Marker
|
}(ClusterObject))
|
PruneCluster_1.Marker = Marker
|
let Cluster = (function (_super) {
|
__extends(Cluster, _super)
|
function Cluster(marker) {
|
let _this = _super.call(this) || this
|
_this.stats = [0, 0, 0, 0, 0, 0, 0, 0]
|
_this.data = {}
|
if (!marker) {
|
_this.hashCode = 1
|
if (Cluster.ENABLE_MARKERS_LIST) {
|
_this._clusterMarkers = []
|
}
|
return _this
|
}
|
if (Cluster.ENABLE_MARKERS_LIST) {
|
_this._clusterMarkers = [marker]
|
}
|
_this.lastMarker = marker
|
_this.hashCode = 31 + marker.hashCode
|
_this.population = 1
|
if (marker.category !== undefined) {
|
_this.stats[marker.category] = 1
|
}
|
_this.totalWeight = marker.weight
|
_this.position = {
|
lat: marker.position.lat,
|
lng: marker.position.lng
|
}
|
_this.averagePosition = {
|
lat: marker.position.lat,
|
lng: marker.position.lng
|
}
|
return _this
|
}
|
Cluster.prototype.AddMarker = function (marker) {
|
if (Cluster.ENABLE_MARKERS_LIST) {
|
this._clusterMarkers.push(marker)
|
}
|
let h = this.hashCode
|
h = ((h << 5) - h) + marker.hashCode
|
if (h >= maxHashCodeValue) {
|
this.hashCode = h % maxHashCodeValue
|
} else {
|
this.hashCode = h
|
}
|
this.lastMarker = marker
|
let weight = marker.weight, currentTotalWeight = this.totalWeight, newWeight = weight + currentTotalWeight
|
this.averagePosition.lat =
|
(this.averagePosition.lat * currentTotalWeight +
|
marker.position.lat * weight) / newWeight
|
this.averagePosition.lng =
|
(this.averagePosition.lng * currentTotalWeight +
|
marker.position.lng * weight) / newWeight
|
++this.population
|
this.totalWeight = newWeight
|
if (marker.category !== undefined) {
|
this.stats[marker.category] = (this.stats[marker.category] + 1) || 1
|
}
|
}
|
Cluster.prototype.Reset = function () {
|
this.hashCode = 1
|
this.lastMarker = undefined
|
this.population = 0
|
this.totalWeight = 0
|
this.stats = [0, 0, 0, 0, 0, 0, 0, 0]
|
if (Cluster.ENABLE_MARKERS_LIST) {
|
this._clusterMarkers = []
|
}
|
}
|
Cluster.prototype.ComputeBounds = function (cluster) {
|
let proj = cluster.Project(this.position.lat, this.position.lng)
|
let size = cluster.Size
|
let nbX = Math.floor(proj.x / size), nbY = Math.floor(proj.y / size), startX = nbX * size, startY = nbY * size
|
let a = cluster.UnProject(startX, startY), b = cluster.UnProject(startX + size, startY + size)
|
this.bounds = {
|
minLat: b.lat,
|
maxLat: a.lat,
|
minLng: a.lng,
|
maxLng: b.lng
|
}
|
}
|
Cluster.prototype.GetClusterMarkers = function () {
|
return this._clusterMarkers
|
}
|
Cluster.prototype.ApplyCluster = function (newCluster) {
|
this.hashCode = this.hashCode * 41 + newCluster.hashCode * 43
|
if (this.hashCode > maxHashCodeValue) {
|
this.hashCode = this.hashCode = maxHashCodeValue
|
}
|
let weight = newCluster.totalWeight, currentTotalWeight = this.totalWeight, newWeight = weight + currentTotalWeight
|
this.averagePosition.lat =
|
(this.averagePosition.lat * currentTotalWeight +
|
newCluster.averagePosition.lat * weight) / newWeight
|
this.averagePosition.lng =
|
(this.averagePosition.lng * currentTotalWeight +
|
newCluster.averagePosition.lng * weight) / newWeight
|
this.population += newCluster.population
|
this.totalWeight = newWeight
|
this.bounds.minLat = Math.min(this.bounds.minLat, newCluster.bounds.minLat)
|
this.bounds.minLng = Math.min(this.bounds.minLng, newCluster.bounds.minLng)
|
this.bounds.maxLat = Math.max(this.bounds.maxLat, newCluster.bounds.maxLat)
|
this.bounds.maxLng = Math.max(this.bounds.maxLng, newCluster.bounds.maxLng)
|
for (let category in newCluster.stats) {
|
if (newCluster.stats.hasOwnProperty(category)) {
|
if (this.stats.hasOwnProperty(category)) {
|
this.stats[category] += newCluster.stats[category]
|
} else {
|
this.stats[category] = newCluster.stats[category]
|
}
|
}
|
}
|
if (Cluster.ENABLE_MARKERS_LIST) {
|
this._clusterMarkers = this._clusterMarkers.concat(newCluster.GetClusterMarkers())
|
}
|
}
|
Cluster.ENABLE_MARKERS_LIST = false
|
return Cluster
|
}(ClusterObject))
|
PruneCluster_1.Cluster = Cluster
|
function checkPositionInsideBounds(a, b) {
|
return (a.lat >= b.minLat && a.lat <= b.maxLat) &&
|
a.lng >= b.minLng && a.lng <= b.maxLng
|
}
|
function insertionSort(list) {
|
for (let i = 1, j, tmp, tmpLng, length = list.length; i < length; ++i) {
|
tmp = list[i]
|
tmpLng = tmp.position.lng
|
for (j = i - 1; j >= 0 && list[j].position.lng > tmpLng; --j) {
|
list[j + 1] = list[j]
|
}
|
list[j + 1] = tmp
|
}
|
}
|
function shouldUseInsertionSort(total, nbChanges) {
|
if (nbChanges > 300) {
|
return false
|
} else {
|
return (nbChanges / total) < 0.2
|
}
|
}
|
let PruneCluster = (function () {
|
function PruneCluster() {
|
this._markers = []
|
this._nbChanges = 0
|
this._clusters = []
|
this.Size = 166
|
this.ViewPadding = 0.2
|
}
|
PruneCluster.prototype.RegisterMarker = function (marker) {
|
if (marker._removeFlag) {
|
delete marker._removeFlag
|
}
|
this._markers.push(marker)
|
this._nbChanges += 1
|
}
|
PruneCluster.prototype.RegisterMarkers = function (markers) {
|
let _this = this
|
markers.forEach(function (marker) {
|
_this.RegisterMarker(marker)
|
})
|
}
|
PruneCluster.prototype._sortMarkers = function () {
|
let markers = this._markers, length = markers.length
|
if (this._nbChanges && !shouldUseInsertionSort(length, this._nbChanges)) {
|
this._markers.sort(function (a, b) { return a.position.lng - b.position.lng })
|
} else {
|
insertionSort(markers)
|
}
|
this._nbChanges = 0
|
}
|
PruneCluster.prototype._sortClusters = function () {
|
insertionSort(this._clusters)
|
}
|
PruneCluster.prototype._indexLowerBoundLng = function (lng) {
|
let markers = this._markers, it, step, first = 0, count = markers.length
|
while (count > 0) {
|
step = Math.floor(count / 2)
|
it = first + step
|
if (markers[it].position.lng < lng) {
|
first = ++it
|
count -= step + 1
|
} else {
|
count = step
|
}
|
}
|
return first
|
}
|
PruneCluster.prototype._resetClusterViews = function () {
|
for (let i = 0, l = this._clusters.length; i < l; ++i) {
|
let cluster = this._clusters[i]
|
cluster.Reset()
|
cluster.ComputeBounds(this)
|
}
|
}
|
PruneCluster.prototype.ProcessView = function (bounds) {
|
let heightBuffer = Math.abs(bounds.maxLat - bounds.minLat) * this.ViewPadding, widthBuffer = Math.abs(bounds.maxLng - bounds.minLng) * this.ViewPadding
|
let extendedBounds = {
|
minLat: bounds.minLat - heightBuffer - heightBuffer,
|
maxLat: bounds.maxLat + heightBuffer + heightBuffer,
|
minLng: bounds.minLng - widthBuffer - widthBuffer,
|
maxLng: bounds.maxLng + widthBuffer + widthBuffer
|
}
|
this._sortMarkers()
|
this._resetClusterViews()
|
let firstIndex = this._indexLowerBoundLng(extendedBounds.minLng)
|
let markers = this._markers, clusters = this._clusters
|
let workingClusterList = clusters.slice(0)
|
for (let i = firstIndex, l = markers.length; i < l; ++i) {
|
let marker = markers[i], markerPosition = marker.position
|
if (markerPosition.lng > extendedBounds.maxLng) {
|
break
|
}
|
if (markerPosition.lat > extendedBounds.minLat &&
|
markerPosition.lat < extendedBounds.maxLat &&
|
!marker.filtered) {
|
let clusterFound = false, cluster
|
for (let j = 0, ll = workingClusterList.length; j < ll; ++j) {
|
cluster = workingClusterList[j]
|
if (cluster.bounds.maxLng < marker.position.lng) {
|
workingClusterList.splice(j, 1)
|
--j
|
--ll
|
continue
|
}
|
if (checkPositionInsideBounds(markerPosition, cluster.bounds)) {
|
cluster.AddMarker(marker)
|
clusterFound = true
|
break
|
}
|
}
|
if (!clusterFound) {
|
cluster = new Cluster(marker)
|
cluster.ComputeBounds(this)
|
clusters.push(cluster)
|
workingClusterList.push(cluster)
|
}
|
}
|
}
|
let newClustersList = []
|
for (i = 0, l = clusters.length; i < l; ++i) {
|
let cluster = clusters[i]
|
if (cluster.population > 0) {
|
newClustersList.push(cluster)
|
}
|
}
|
this._clusters = newClustersList
|
this._sortClusters()
|
return this._clusters
|
}
|
PruneCluster.prototype.RemoveMarkers = function (markers) {
|
if (!markers) {
|
this._markers = []
|
return
|
}
|
for (let i = 0, l = markers.length; i < l; ++i) {
|
markers[i]._removeFlag = true
|
}
|
let newMarkersList = []
|
for (i = 0, l = this._markers.length; i < l; ++i) {
|
if (!this._markers[i]._removeFlag) {
|
newMarkersList.push(this._markers[i])
|
} else {
|
delete this._markers[i]._removeFlag
|
}
|
}
|
this._markers = newMarkersList
|
}
|
PruneCluster.prototype.FindMarkersInArea = function (area) {
|
let aMinLat = area.minLat, aMaxLat = area.maxLat, aMinLng = area.minLng, aMaxLng = area.maxLng, markers = this._markers, result = []
|
let firstIndex = this._indexLowerBoundLng(aMinLng)
|
for (let i = firstIndex, l = markers.length; i < l; ++i) {
|
let pos = markers[i].position
|
if (pos.lng > aMaxLng) {
|
break
|
}
|
if (pos.lat >= aMinLat && pos.lat <= aMaxLat &&
|
pos.lng >= aMinLng) {
|
result.push(markers[i])
|
}
|
}
|
return result
|
}
|
PruneCluster.prototype.ComputeBounds = function (markers, withFiltered) {
|
if (withFiltered === void 0) { withFiltered = true }
|
if (!markers || !markers.length) {
|
return null
|
}
|
let rMinLat = Number.MAX_VALUE, rMaxLat = -Number.MAX_VALUE, rMinLng = Number.MAX_VALUE, rMaxLng = -Number.MAX_VALUE
|
for (let i = 0, l = markers.length; i < l; ++i) {
|
if (!withFiltered && markers[i].filtered) {
|
continue
|
}
|
let pos = markers[i].position
|
if (pos.lat < rMinLat) { rMinLat = pos.lat }
|
if (pos.lat > rMaxLat) { rMaxLat = pos.lat }
|
if (pos.lng < rMinLng) { rMinLng = pos.lng }
|
if (pos.lng > rMaxLng) { rMaxLng = pos.lng }
|
}
|
return {
|
minLat: rMinLat,
|
maxLat: rMaxLat,
|
minLng: rMinLng,
|
maxLng: rMaxLng
|
}
|
}
|
PruneCluster.prototype.FindMarkersBoundsInArea = function (area) {
|
return this.ComputeBounds(this.FindMarkersInArea(area))
|
}
|
PruneCluster.prototype.ComputeGlobalBounds = function (withFiltered) {
|
if (withFiltered === void 0) { withFiltered = true }
|
return this.ComputeBounds(this._markers, withFiltered)
|
}
|
PruneCluster.prototype.GetMarkers = function () {
|
return this._markers
|
}
|
PruneCluster.prototype.GetPopulation = function () {
|
return this._markers.length
|
}
|
PruneCluster.prototype.ResetClusters = function () {
|
this._clusters = []
|
}
|
return PruneCluster
|
}())
|
PruneCluster_1.PruneCluster = PruneCluster
|
})(PruneCluster || (PruneCluster = {}))
|
|
// let PruneCluster;
|
// (function (PruneCluster) {
|
// })(PruneCluster || (PruneCluster = {}));
|
|
export let PruneClusterForLeaflet = (L.Layer ? L.Layer : L.Class).extend({
|
initialize: function (size, clusterMargin) {
|
let _this = this
|
if (size === void 0) { size = 120 }
|
if (clusterMargin === void 0) { clusterMargin = 20 }
|
this.Cluster = new PruneCluster.PruneCluster()
|
this.Cluster.Size = size
|
this.clusterMargin = Math.min(clusterMargin, size / 4)
|
this.Cluster.Project = function (lat, lng) {
|
return _this._map.project(new L.LatLng(lat, lng), Math.floor(_this._map.getZoom()))
|
}
|
this.Cluster.UnProject = function (x, y) {
|
return _this._map.unproject(new L.Point(x, y), Math.floor(_this._map.getZoom()))
|
}
|
this._objectsOnMap = []
|
this.spiderfier = new PruneClusterLeafletSpiderfier(this)
|
this._hardMove = false
|
this._resetIcons = false
|
this._removeTimeoutId = 0
|
this._markersRemoveListTimeout = []
|
},
|
RegisterMarker: function (marker) {
|
this.Cluster.RegisterMarker(marker)
|
},
|
RegisterMarkers: function (markers) {
|
this.Cluster.RegisterMarkers(markers)
|
},
|
RemoveMarkers: function (markers) {
|
this.Cluster.RemoveMarkers(markers)
|
},
|
BuildLeafletCluster: function (cluster, position) {
|
let _this = this
|
let m = new L.Marker(position, {
|
icon: this.BuildLeafletClusterIcon(cluster)
|
})
|
m._leafletClusterBounds = cluster.bounds
|
m.on('click', function () {
|
let cbounds = m._leafletClusterBounds
|
let markersArea = _this.Cluster.FindMarkersInArea(cbounds)
|
let b = _this.Cluster.ComputeBounds(markersArea)
|
if (b) {
|
let bounds = new L.LatLngBounds(new L.LatLng(b.minLat, b.maxLng), new L.LatLng(b.maxLat, b.minLng))
|
let zoomLevelBefore = _this._map.getZoom(), zoomLevelAfter = _this._map.getBoundsZoom(bounds, false, new L.Point(20, 20))
|
if (zoomLevelAfter === zoomLevelBefore) {
|
let filteredBounds = []
|
for (let i = 0, l = _this._objectsOnMap.length; i < l; ++i) {
|
let o = _this._objectsOnMap[i]
|
if (o.data._leafletMarker !== m) {
|
if (o.bounds.minLat >= cbounds.minLat &&
|
o.bounds.maxLat <= cbounds.maxLat &&
|
o.bounds.minLng >= cbounds.minLng &&
|
o.bounds.maxLng <= cbounds.maxLng) {
|
filteredBounds.push(o.bounds)
|
}
|
}
|
}
|
if (filteredBounds.length > 0) {
|
let newMarkersArea = []
|
let ll = filteredBounds.length
|
for (i = 0, l = markersArea.length; i < l; ++i) {
|
let markerPos = markersArea[i].position
|
let isFiltered = false
|
for (let j = 0; j < ll; ++j) {
|
let currentFilteredBounds = filteredBounds[j]
|
if (markerPos.lat >= currentFilteredBounds.minLat &&
|
markerPos.lat <= currentFilteredBounds.maxLat &&
|
markerPos.lng >= currentFilteredBounds.minLng &&
|
markerPos.lng <= currentFilteredBounds.maxLng) {
|
isFiltered = true
|
break
|
}
|
}
|
if (!isFiltered) {
|
newMarkersArea.push(markersArea[i])
|
}
|
}
|
markersArea = newMarkersArea
|
}
|
if (markersArea.length < 200 || zoomLevelAfter >= _this._map.getMaxZoom()) {
|
_this._map.fire('overlappingmarkers', {
|
cluster: _this,
|
markers: markersArea,
|
center: m.getLatLng(),
|
marker: m
|
})
|
} else {
|
zoomLevelAfter++
|
}
|
_this._map.setView(m.getLatLng(), zoomLevelAfter)
|
} else {
|
_this._map.fitBounds(bounds)
|
}
|
}
|
})
|
return m
|
},
|
BuildLeafletClusterIcon: function (cluster) {
|
let c = 'prunecluster prunecluster-'
|
let iconSize = 38
|
let maxPopulation = this.Cluster.GetPopulation()
|
if (cluster.population < Math.max(10, maxPopulation * 0.01)) {
|
c += 'small'
|
} else if (cluster.population < Math.max(100, maxPopulation * 0.05)) {
|
c += 'medium'
|
iconSize = 40
|
} else {
|
c += 'large'
|
iconSize = 44
|
}
|
return new L.DivIcon({
|
html: '<div><span>' + cluster.population + '</span></div>',
|
className: c,
|
iconSize: L.point(iconSize, iconSize)
|
})
|
},
|
BuildLeafletMarker: function (marker, position) {
|
let m = new L.Marker(position)
|
this.PrepareLeafletMarker(m, marker.data, marker.category)
|
return m
|
},
|
PrepareLeafletMarker: function (marker, data, category) {
|
if (data.icon) {
|
if (typeof data.icon === 'function') {
|
marker.setIcon(data.icon(data, category))
|
} else {
|
marker.setIcon(data.icon)
|
}
|
}
|
if (data.popup) {
|
let content = typeof data.popup === 'function' ? data.popup(data, category) : data.popup
|
if (marker.getPopup()) {
|
marker.setPopupContent(content, data.popupOptions)
|
} else {
|
marker.bindPopup(content, data.popupOptions)
|
}
|
}
|
},
|
onAdd: function (map) {
|
this._map = map
|
map.on('movestart', this._moveStart, this)
|
map.on('moveend', this._moveEnd, this)
|
map.on('zoomend', this._zoomStart, this)
|
map.on('zoomend', this._zoomEnd, this)
|
this.ProcessView()
|
map.addLayer(this.spiderfier)
|
},
|
onRemove: function (map) {
|
map.off('movestart', this._moveStart, this)
|
map.off('moveend', this._moveEnd, this)
|
map.off('zoomend', this._zoomStart, this)
|
map.off('zoomend', this._zoomEnd, this)
|
for (let i = 0, l = this._objectsOnMap.length; i < l; ++i) {
|
map.removeLayer(this._objectsOnMap[i].data._leafletMarker)
|
}
|
this._objectsOnMap = []
|
this.Cluster.ResetClusters()
|
map.removeLayer(this.spiderfier)
|
this._map = null
|
},
|
_moveStart: function () {
|
this._moveInProgress = true
|
},
|
_moveEnd: function (e) {
|
this._moveInProgress = false
|
this._hardMove = e.hard
|
this.ProcessView()
|
},
|
_zoomStart: function () {
|
this._zoomInProgress = true
|
},
|
_zoomEnd: function () {
|
this._zoomInProgress = false
|
this.ProcessView()
|
},
|
ProcessView: function () {
|
let _this = this
|
if (!this._map || this._zoomInProgress || this._moveInProgress) {
|
return
|
}
|
let map = this._map, bounds = map.getBounds(), zoom = Math.floor(map.getZoom()), marginRatio = this.clusterMargin / this.Cluster.Size, resetIcons = this._resetIcons
|
let southWest = bounds.getSouthWest(), northEast = bounds.getNorthEast()
|
let clusters = this.Cluster.ProcessView({
|
minLat: southWest.lat,
|
minLng: southWest.lng,
|
maxLat: northEast.lat,
|
maxLng: northEast.lng
|
})
|
let objectsOnMap = this._objectsOnMap, newObjectsOnMap = [], markersOnMap = new Array(objectsOnMap.length)
|
for (let i = 0, l = objectsOnMap.length; i < l; ++i) {
|
let marker = objectsOnMap[i].data._leafletMarker
|
markersOnMap[i] = marker
|
marker._removeFromMap = true
|
}
|
let clusterCreationList = []
|
let clusterCreationListPopOne = []
|
let opacityUpdateList = []
|
let workingList = []
|
for (i = 0, l = clusters.length; i < l; ++i) {
|
let icluster = clusters[i], iclusterData = icluster.data
|
let latMargin = (icluster.bounds.maxLat - icluster.bounds.minLat) * marginRatio, lngMargin = (icluster.bounds.maxLng - icluster.bounds.minLng) * marginRatio
|
for (let j = 0, ll = workingList.length; j < ll; ++j) {
|
let c = workingList[j]
|
if (c.bounds.maxLng < icluster.bounds.minLng) {
|
workingList.splice(j, 1)
|
--j
|
--ll
|
continue
|
}
|
let oldMaxLng = c.averagePosition.lng + lngMargin, oldMinLat = c.averagePosition.lat - latMargin, oldMaxLat = c.averagePosition.lat + latMargin, newMinLng = icluster.averagePosition.lng - lngMargin, newMinLat = icluster.averagePosition.lat - latMargin, newMaxLat = icluster.averagePosition.lat + latMargin
|
if (oldMaxLng > newMinLng && oldMaxLat > newMinLat && oldMinLat < newMaxLat) {
|
iclusterData._leafletCollision = true
|
c.ApplyCluster(icluster)
|
break
|
}
|
}
|
if (!iclusterData._leafletCollision) {
|
workingList.push(icluster)
|
}
|
}
|
clusters.forEach(function (cluster) {
|
let m = undefined
|
let data = cluster.data
|
if (data._leafletCollision) {
|
data._leafletCollision = false
|
data._leafletOldPopulation = 0
|
data._leafletOldHashCode = 0
|
return
|
}
|
let position = new L.LatLng(cluster.averagePosition.lat, cluster.averagePosition.lng)
|
let oldMarker = data._leafletMarker
|
if (oldMarker) {
|
if (cluster.population === 1 && data._leafletOldPopulation === 1 && cluster.hashCode === oldMarker._hashCode) {
|
if (resetIcons || oldMarker._zoomLevel !== zoom || cluster.lastMarker.data.forceIconRedraw) {
|
_this.PrepareLeafletMarker(oldMarker, cluster.lastMarker.data, cluster.lastMarker.category)
|
if (cluster.lastMarker.data.forceIconRedraw) {
|
cluster.lastMarker.data.forceIconRedraw = false
|
}
|
}
|
oldMarker.setLatLng(position)
|
m = oldMarker
|
} else if (cluster.population > 1 && data._leafletOldPopulation > 1 && (oldMarker._zoomLevel === zoom ||
|
data._leafletPosition.equals(position))) {
|
oldMarker.setLatLng(position)
|
if (resetIcons || cluster.population != data._leafletOldPopulation ||
|
cluster.hashCode !== data._leafletOldHashCode) {
|
let boundsCopy = {}
|
L.Util.extend(boundsCopy, cluster.bounds)
|
oldMarker._leafletClusterBounds = boundsCopy
|
oldMarker.setIcon(_this.BuildLeafletClusterIcon(cluster))
|
}
|
data._leafletOldPopulation = cluster.population
|
data._leafletOldHashCode = cluster.hashCode
|
m = oldMarker
|
}
|
}
|
if (!m) {
|
if (cluster.population === 1) {
|
clusterCreationListPopOne.push(cluster)
|
} else {
|
clusterCreationList.push(cluster)
|
}
|
data._leafletPosition = position
|
data._leafletOldPopulation = cluster.population
|
data._leafletOldHashCode = cluster.hashCode
|
} else {
|
m._removeFromMap = false
|
newObjectsOnMap.push(cluster)
|
m._zoomLevel = zoom
|
m._hashCode = cluster.hashCode
|
m._population = cluster.population
|
data._leafletMarker = m
|
data._leafletPosition = position
|
}
|
})
|
clusterCreationList = clusterCreationListPopOne.concat(clusterCreationList)
|
for (i = 0, l = objectsOnMap.length; i < l; ++i) {
|
let icluster = objectsOnMap[i]
|
let idata = icluster.data
|
let marker = idata._leafletMarker
|
if (idata._leafletMarker._removeFromMap) {
|
let remove = true
|
if (marker._zoomLevel === zoom) {
|
let pa = icluster.averagePosition
|
let latMargin = (icluster.bounds.maxLat - icluster.bounds.minLat) * marginRatio,
|
lngMargin = (icluster.bounds.maxLng - icluster.bounds.minLng) * marginRatio
|
let ll= clusterCreationList.length
|
for (let j = 0; j < ll; ++j) {
|
let jcluster = clusterCreationList[j], jdata = jcluster.data
|
if (marker._population === 1 && jcluster.population === 1 &&
|
marker._hashCode === jcluster.hashCode) {
|
if (resetIcons || jcluster.lastMarker.data.forceIconRedraw) {
|
this.PrepareLeafletMarker(marker, jcluster.lastMarker.data, jcluster.lastMarker.category)
|
if (jcluster.lastMarker.data.forceIconRedraw) {
|
jcluster.lastMarker.data.forceIconRedraw = false
|
}
|
}
|
marker.setLatLng(jdata._leafletPosition)
|
remove = false
|
} else {
|
let pb = jcluster.averagePosition
|
let oldMinLng = pa.lng - lngMargin, newMaxLng = pb.lng + lngMargin
|
let oldMaxLng = pa.lng + lngMargin
|
let oldMinLat = pa.lat - latMargin
|
let oldMaxLat = pa.lat + latMargin
|
let newMinLng = pb.lng - lngMargin
|
let newMinLat = pb.lat - latMargin
|
let newMaxLat = pb.lat + latMargin
|
if ((marker._population > 1 && jcluster.population > 1) &&
|
(oldMaxLng > newMinLng && oldMinLng < newMaxLng && oldMaxLat > newMinLat && oldMinLat < newMaxLat)) {
|
marker.setLatLng(jdata._leafletPosition)
|
marker.setIcon(this.BuildLeafletClusterIcon(jcluster))
|
let poisson = {}
|
L.Util.extend(poisson, jcluster.bounds)
|
marker._leafletClusterBounds = poisson
|
jdata._leafletOldPopulation = jcluster.population
|
jdata._leafletOldHashCode = jcluster.hashCode
|
marker._population = jcluster.population
|
remove = false
|
}
|
}
|
if (!remove) {
|
jdata._leafletMarker = marker
|
marker._removeFromMap = false
|
newObjectsOnMap.push(jcluster)
|
clusterCreationList.splice(j, 1)
|
--j
|
--ll
|
break
|
}
|
}
|
}
|
if (remove) {
|
if (!marker._removeFromMap) { console.error('wtf') }
|
}
|
}
|
}
|
for (i = 0, l = clusterCreationList.length; i < l; ++i) {
|
let icluster = clusterCreationList[i]
|
let idata = icluster.data
|
let iposition = idata._leafletPosition
|
let creationMarker
|
if (icluster.population === 1) {
|
creationMarker = this.BuildLeafletMarker(icluster.lastMarker, iposition)
|
} else {
|
creationMarker = this.BuildLeafletCluster(icluster, iposition)
|
}
|
creationMarker.addTo(map)
|
creationMarker.setOpacity(0)
|
opacityUpdateList.push(creationMarker)
|
idata._leafletMarker = creationMarker
|
creationMarker._zoomLevel = zoom
|
creationMarker._hashCode = icluster.hashCode
|
creationMarker._population = icluster.population
|
newObjectsOnMap.push(icluster)
|
}
|
window.setTimeout(function () {
|
for (i = 0, l = opacityUpdateList.length; i < l; ++i) {
|
let m = opacityUpdateList[i]
|
if (m._icon) { L.DomUtil.addClass(m._icon, 'prunecluster-anim') }
|
if (m._shadow) { L.DomUtil.addClass(m._shadow, 'prunecluster-anim') }
|
m.setOpacity(1)
|
}
|
}, 1)
|
if (this._hardMove) {
|
for (i = 0, l = markersOnMap.length; i < l; ++i) {
|
let marker = markersOnMap[i]
|
if (marker._removeFromMap) {
|
map.removeLayer(marker)
|
}
|
}
|
} else {
|
if (this._removeTimeoutId !== 0) {
|
window.clearTimeout(this._removeTimeoutId)
|
for (i = 0, l = this._markersRemoveListTimeout.length; i < l; ++i) {
|
map.removeLayer(this._markersRemoveListTimeout[i])
|
}
|
}
|
let toRemove = []
|
for (i = 0, l = markersOnMap.length; i < l; ++i) {
|
let marker = markersOnMap[i]
|
if (marker._removeFromMap) {
|
marker.setOpacity(0)
|
toRemove.push(marker)
|
}
|
}
|
if (toRemove.length > 0) {
|
this._removeTimeoutId = window.setTimeout(function () {
|
for (i = 0, l = toRemove.length; i < l; ++i) {
|
map.removeLayer(toRemove[i])
|
}
|
_this._removeTimeoutId = 0
|
}, 300)
|
}
|
this._markersRemoveListTimeout = toRemove
|
}
|
this._objectsOnMap = newObjectsOnMap
|
this._hardMove = false
|
this._resetIcons = false
|
},
|
FitBounds: function (withFiltered) {
|
if (withFiltered === void 0) { withFiltered = true }
|
let bounds = this.Cluster.ComputeGlobalBounds(withFiltered)
|
if (bounds) {
|
this._map.fitBounds(new L.LatLngBounds(new L.LatLng(bounds.minLat, bounds.maxLng), new L.LatLng(bounds.maxLat, bounds.minLng)))
|
}
|
},
|
GetMarkers: function () {
|
return this.Cluster.GetMarkers()
|
},
|
RedrawIcons: function (processView) {
|
if (processView === void 0) { processView = true }
|
this._resetIcons = true
|
if (processView) {
|
this.ProcessView()
|
}
|
}
|
})
|
export let PruneClusterLeafletSpiderfier = (L.Layer ? L.Layer : L.Class).extend({
|
_2PI: Math.PI * 2,
|
_circleFootSeparation: 25,
|
_circleStartAngle: Math.PI / 6,
|
_spiralFootSeparation: 28,
|
_spiralLengthStart: 11,
|
_spiralLengthFactor: 5,
|
_spiralCountTrigger: 8,
|
spiderfyDistanceMultiplier: 1,
|
initialize: function (cluster) {
|
this._cluster = cluster
|
this._currentMarkers = []
|
this._multiLines = !!L.multiPolyline
|
this._lines = this._multiLines
|
? L.multiPolyline([], { weight: 1.5, color: '#222' })
|
: L.polyline([], { weight: 1.5, color: '#222' })
|
},
|
onAdd: function (map) {
|
this._map = map
|
this._map.on('overlappingmarkers', this.Spiderfy, this)
|
this._map.on('click', this.Unspiderfy, this)
|
this._map.on('zoomend', this.Unspiderfy, this)
|
},
|
Spiderfy: function (data) {
|
let _this = this
|
if (data.cluster !== this._cluster) {
|
return
|
}
|
this.Unspiderfy()
|
let markers = data.markers.filter(function (marker) {
|
return !marker.filtered
|
})
|
this._currentCenter = data.center
|
let centerPoint = this._map.latLngToLayerPoint(data.center)
|
let points
|
if (markers.length >= this._spiralCountTrigger) {
|
points = this._generatePointsSpiral(markers.length, centerPoint)
|
} else {
|
if (this._multiLines) {
|
centerPoint.y += 10
|
}
|
points = this._generatePointsCircle(markers.length, centerPoint)
|
}
|
let polylines = []
|
let leafletMarkers = []
|
let projectedPoints = []
|
for (let i = 0, l = points.length; i < l; ++i) {
|
let pos = this._map.layerPointToLatLng(points[i])
|
let m = this._cluster.BuildLeafletMarker(markers[i], data.center)
|
m.setZIndexOffset(5000)
|
m.setOpacity(0)
|
this._currentMarkers.push(m)
|
this._map.addLayer(m)
|
leafletMarkers.push(m)
|
projectedPoints.push(pos)
|
}
|
window.setTimeout(function () {
|
for (i = 0, l = points.length; i < l; ++i) {
|
leafletMarkers[i].setLatLng(projectedPoints[i])
|
.setOpacity(1)
|
}
|
let startTime = +new Date()
|
let interval = 42, duration = 290
|
let anim = window.setInterval(function () {
|
polylines = []
|
let now = +new Date()
|
let d = now - startTime
|
if (d >= duration) {
|
window.clearInterval(anim)
|
let stepRatio = 1.0
|
} else {
|
let stepRatio = d / duration
|
}
|
let center = data.center
|
for (i = 0, l = points.length; i < l; ++i) {
|
let p = projectedPoints[i], diffLat = p.lat - center.lat, diffLng = p.lng - center.lng
|
polylines.push([center, new L.LatLng(center.lat + diffLat * stepRatio, center.lng + diffLng * stepRatio)])
|
}
|
_this._lines.setLatLngs(polylines)
|
}, interval)
|
}, 1)
|
this._lines.setLatLngs(polylines)
|
this._map.addLayer(this._lines)
|
if (data.marker) {
|
this._clusterMarker = data.marker.setOpacity(0.3)
|
}
|
},
|
_generatePointsCircle: function (count, centerPt) {
|
let circumference = this.spiderfyDistanceMultiplier * this._circleFootSeparation * (2 + count), legLength = circumference / this._2PI, angleStep = this._2PI / count, res = [], i, angle
|
res.length = count
|
for (i = count - 1; i >= 0; i--) {
|
angle = this._circleStartAngle + i * angleStep
|
res[i] = new L.Point(Math.round(centerPt.x + legLength * Math.cos(angle)), Math.round(centerPt.y + legLength * Math.sin(angle)))
|
}
|
return res
|
},
|
_generatePointsSpiral: function (count, centerPt) {
|
let legLength = this.spiderfyDistanceMultiplier * this._spiralLengthStart, separation = this.spiderfyDistanceMultiplier * this._spiralFootSeparation, lengthFactor = this.spiderfyDistanceMultiplier * this._spiralLengthFactor, angle = 0, res = [], i
|
res.length = count
|
for (i = count - 1; i >= 0; i--) {
|
angle += separation / legLength + i * 0.0005
|
res[i] = new L.Point(Math.round(centerPt.x + legLength * Math.cos(angle)), Math.round(centerPt.y + legLength * Math.sin(angle)))
|
legLength += this._2PI * lengthFactor / angle
|
}
|
return res
|
},
|
Unspiderfy: function () {
|
let _this = this
|
for (let i = 0, l = this._currentMarkers.length; i < l; ++i) {
|
this._currentMarkers[i].setLatLng(this._currentCenter).setOpacity(0)
|
}
|
let markers = this._currentMarkers
|
window.setTimeout(function () {
|
for (i = 0, l = markers.length; i < l; ++i) {
|
_this._map.removeLayer(markers[i])
|
}
|
}, 300)
|
this._currentMarkers = []
|
this._map.removeLayer(this._lines)
|
if (this._clusterMarker) {
|
this._clusterMarker.setOpacity(1)
|
}
|
},
|
onRemove: function (map) {
|
this.Unspiderfy()
|
map.off('overlappingmarkers', this.Spiderfy, this)
|
map.off('click', this.Unspiderfy, this)
|
map.off('zoomend', this.Unspiderfy, this)
|
}
|
})
|