@react-google-maps/marker-clusterer 2.9.0 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs.js +260 -201
- package/dist/cjs.js.map +1 -1
- package/dist/cjs.min.js +1 -1
- package/dist/cjs.min.js.map +1 -1
- package/dist/esm.js +260 -201
- package/dist/esm.js.map +1 -1
- package/dist/esm.min.js +1 -1
- package/dist/esm.min.js.map +1 -1
- package/dist/index.d.ts +14 -4
- package/dist/umd.js +260 -201
- package/dist/umd.js.map +1 -1
- package/dist/umd.min.js +1 -1
- package/dist/umd.min.js.map +1 -1
- package/package.json +10 -47
- package/src/Cluster.tsx +9 -5
- package/src/ClusterIcon.tsx +171 -110
- package/src/Clusterer.tsx +88 -66
- package/src/index.ts +5 -5
- package/src/setup-tests.js +0 -356
package/src/ClusterIcon.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import { Cluster } from './Cluster'
|
|
|
4
4
|
|
|
5
5
|
import { ClusterIconStyle, ClusterIconInfo } from './types'
|
|
6
6
|
|
|
7
|
-
export class ClusterIcon {
|
|
7
|
+
export class ClusterIcon extends google.maps.OverlayView {
|
|
8
8
|
cluster: Cluster
|
|
9
9
|
className: string
|
|
10
10
|
clusterClassName: string
|
|
@@ -25,144 +25,179 @@ export class ClusterIcon {
|
|
|
25
25
|
fontStyle: string
|
|
26
26
|
fontFamily: string
|
|
27
27
|
backgroundPosition: string
|
|
28
|
+
cMouseDownInCluster: boolean | null
|
|
29
|
+
cDraggingMapByCluster: boolean | null
|
|
30
|
+
timeOut: number | null
|
|
28
31
|
|
|
29
32
|
boundsChangedListener: google.maps.MapsEventListener | null
|
|
30
33
|
|
|
31
34
|
constructor(cluster: Cluster, styles: ClusterIconStyle[]) {
|
|
35
|
+
super()
|
|
32
36
|
cluster.getClusterer().extend(ClusterIcon, google.maps.OverlayView)
|
|
37
|
+
|
|
33
38
|
this.cluster = cluster
|
|
39
|
+
|
|
34
40
|
this.clusterClassName = this.cluster.getClusterer().getClusterClass()
|
|
41
|
+
|
|
35
42
|
this.className = this.clusterClassName
|
|
43
|
+
|
|
36
44
|
this.styles = styles
|
|
45
|
+
|
|
37
46
|
this.center = undefined
|
|
47
|
+
|
|
38
48
|
this.div = null
|
|
49
|
+
|
|
39
50
|
this.sums = null
|
|
51
|
+
|
|
40
52
|
this.visible = false
|
|
53
|
+
|
|
41
54
|
this.boundsChangedListener = null
|
|
55
|
+
|
|
42
56
|
this.url = ''
|
|
57
|
+
|
|
43
58
|
this.height = 0
|
|
44
59
|
this.width = 0
|
|
60
|
+
|
|
45
61
|
this.anchorText = [0, 0]
|
|
46
62
|
this.anchorIcon = [0, 0]
|
|
63
|
+
|
|
47
64
|
this.textColor = 'black'
|
|
48
65
|
this.textSize = 11
|
|
49
66
|
this.textDecoration = 'none'
|
|
50
67
|
this.fontWeight = 'bold'
|
|
51
68
|
this.fontStyle = 'normal'
|
|
52
69
|
this.fontFamily = 'Arial,sans-serif'
|
|
70
|
+
|
|
53
71
|
this.backgroundPosition = '0 0'
|
|
54
|
-
|
|
72
|
+
|
|
73
|
+
this.cMouseDownInCluster = null
|
|
74
|
+
this.cDraggingMapByCluster = null
|
|
75
|
+
this.timeOut = null
|
|
76
|
+
|
|
77
|
+
|
|
55
78
|
this.setMap(cluster.getMap()) // Note: this causes onAdd to be called
|
|
56
79
|
}
|
|
57
80
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
81
|
+
onBoundsChanged() {
|
|
82
|
+
this.cDraggingMapByCluster = this.cMouseDownInCluster
|
|
83
|
+
}
|
|
61
84
|
|
|
85
|
+
onMouseDown() {
|
|
86
|
+
this.cMouseDownInCluster = true
|
|
87
|
+
|
|
88
|
+
this.cDraggingMapByCluster = false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
onClick(event: Event) {
|
|
92
|
+
this.cMouseDownInCluster = false
|
|
93
|
+
|
|
94
|
+
if (!this.cDraggingMapByCluster) {
|
|
95
|
+
const markerClusterer = this.cluster.getClusterer()
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* This event is fired when a cluster marker is clicked.
|
|
99
|
+
* @name MarkerClusterer#click
|
|
100
|
+
* @param {Cluster} c The cluster that was clicked.
|
|
101
|
+
* @event
|
|
102
|
+
*/
|
|
103
|
+
google.maps.event.trigger(markerClusterer, 'click', this.cluster)
|
|
104
|
+
google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster) // deprecated name
|
|
105
|
+
|
|
106
|
+
// The default click handler follows. Disable it by setting
|
|
107
|
+
// the zoomOnClick property to false.
|
|
108
|
+
if (markerClusterer.getZoomOnClick()) {
|
|
109
|
+
// Zoom into the cluster.
|
|
110
|
+
const maxZoom = markerClusterer.getMaxZoom()
|
|
111
|
+
|
|
112
|
+
const bounds = this.cluster.getBounds()
|
|
113
|
+
|
|
114
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
115
|
+
// @ts-ignore
|
|
116
|
+
markerClusterer.getMap().fitBounds(bounds)
|
|
117
|
+
|
|
118
|
+
// There is a fix for Issue 170 here:
|
|
119
|
+
this.timeOut = window.setTimeout(() => {
|
|
120
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
121
|
+
// @ts-ignore
|
|
122
|
+
markerClusterer.getMap().fitBounds(bounds)
|
|
123
|
+
|
|
124
|
+
// Don't zoom beyond the max zoom level
|
|
125
|
+
if (
|
|
126
|
+
maxZoom !== null &&
|
|
127
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
128
|
+
// @ts-ignore
|
|
129
|
+
markerClusterer.getMap().getZoom() > maxZoom
|
|
130
|
+
) {
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
132
|
+
// @ts-ignore
|
|
133
|
+
markerClusterer.getMap().setZoom(maxZoom + 1)
|
|
134
|
+
}
|
|
135
|
+
}, 100)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Prevent event propagation to the map:
|
|
139
|
+
event.cancelBubble = true
|
|
140
|
+
|
|
141
|
+
if (event.stopPropagation) {
|
|
142
|
+
event.stopPropagation()
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
onMouseOver() {
|
|
148
|
+
/**
|
|
149
|
+
* This event is fired when the mouse moves over a cluster marker.
|
|
150
|
+
* @name MarkerClusterer#mouseover
|
|
151
|
+
* @param {Cluster} c The cluster that the mouse moved over.
|
|
152
|
+
* @event
|
|
153
|
+
*/
|
|
154
|
+
google.maps.event.trigger(
|
|
155
|
+
this.cluster.getClusterer(),
|
|
156
|
+
'mouseover',
|
|
157
|
+
this.cluster
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
onMouseOut() {
|
|
162
|
+
/**
|
|
163
|
+
* This event is fired when the mouse moves out of a cluster marker.
|
|
164
|
+
* @name MarkerClusterer#mouseout
|
|
165
|
+
* @param {Cluster} c The cluster that the mouse moved out of.
|
|
166
|
+
* @event
|
|
167
|
+
*/
|
|
168
|
+
google.maps.event.trigger(
|
|
169
|
+
this.cluster.getClusterer(),
|
|
170
|
+
'mouseout',
|
|
171
|
+
this.cluster
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
onAdd() {
|
|
62
176
|
this.div = document.createElement('div')
|
|
63
177
|
this.div.className = this.className
|
|
64
178
|
if (this.visible) {
|
|
65
179
|
this.show()
|
|
66
180
|
}
|
|
67
181
|
|
|
182
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
68
183
|
// @ts-ignore
|
|
69
184
|
this.getPanes().overlayMouseTarget.appendChild(this.div)
|
|
70
|
-
|
|
71
185
|
// Fix for Issue 157
|
|
72
186
|
this.boundsChangedListener = google.maps.event.addListener(
|
|
187
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
73
188
|
// @ts-ignore
|
|
74
189
|
this.getMap(),
|
|
75
|
-
'
|
|
76
|
-
|
|
77
|
-
cDraggingMapByCluster = cMouseDownInCluster
|
|
78
|
-
}
|
|
190
|
+
'bounds_changed',
|
|
191
|
+
this.onBoundsChanged
|
|
79
192
|
)
|
|
80
193
|
|
|
81
|
-
|
|
82
|
-
cMouseDownInCluster = true
|
|
83
|
-
cDraggingMapByCluster = false
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
google.maps.event.addDomListener(
|
|
87
|
-
this.div,
|
|
88
|
-
'click',
|
|
89
|
-
(event: Event) => {
|
|
90
|
-
cMouseDownInCluster = false
|
|
91
|
-
|
|
92
|
-
if (!cDraggingMapByCluster) {
|
|
93
|
-
const markerClusterer = this.cluster.getClusterer()
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* This event is fired when a cluster marker is clicked.
|
|
97
|
-
* @name MarkerClusterer#click
|
|
98
|
-
* @param {Cluster} c The cluster that was clicked.
|
|
99
|
-
* @event
|
|
100
|
-
*/
|
|
101
|
-
google.maps.event.trigger(markerClusterer, 'click', this.cluster)
|
|
102
|
-
google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster) // deprecated name
|
|
103
|
-
|
|
104
|
-
// The default click handler follows. Disable it by setting
|
|
105
|
-
// the zoomOnClick property to false.
|
|
106
|
-
if (markerClusterer.getZoomOnClick()) {
|
|
107
|
-
// Zoom into the cluster.
|
|
108
|
-
const maxZoom = markerClusterer.getMaxZoom()
|
|
109
|
-
|
|
110
|
-
const bounds = this.cluster.getBounds()
|
|
194
|
+
this.div.addEventListener('mousedown', this.onMouseDown)
|
|
111
195
|
|
|
112
|
-
|
|
113
|
-
markerClusterer.getMap().fitBounds(bounds)
|
|
114
|
-
|
|
115
|
-
// There is a fix for Issue 170 here:
|
|
116
|
-
setTimeout(function timeout() {
|
|
117
|
-
// @ts-ignore
|
|
118
|
-
markerClusterer.getMap().fitBounds(bounds)
|
|
119
|
-
|
|
120
|
-
// Don't zoom beyond the max zoom level
|
|
121
|
-
// @ts-ignore
|
|
122
|
-
if (maxZoom !== null && markerClusterer.getMap().getZoom() > maxZoom) {
|
|
123
|
-
// @ts-ignore
|
|
124
|
-
markerClusterer.getMap().setZoom(maxZoom + 1)
|
|
125
|
-
}
|
|
126
|
-
}, 100)
|
|
127
|
-
}
|
|
196
|
+
this.div.addEventListener('click', this.onClick)
|
|
128
197
|
|
|
129
|
-
|
|
130
|
-
event.cancelBubble = true
|
|
198
|
+
this.div.addEventListener('mouseover', this.onMouseOver)
|
|
131
199
|
|
|
132
|
-
|
|
133
|
-
event.stopPropagation()
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
google.maps.event.addDomListener(
|
|
140
|
-
this.div,
|
|
141
|
-
'mouseover',
|
|
142
|
-
() => {
|
|
143
|
-
/**
|
|
144
|
-
* This event is fired when the mouse moves over a cluster marker.
|
|
145
|
-
* @name MarkerClusterer#mouseover
|
|
146
|
-
* @param {Cluster} c The cluster that the mouse moved over.
|
|
147
|
-
* @event
|
|
148
|
-
*/
|
|
149
|
-
google.maps.event.trigger(this.cluster.getClusterer(), 'mouseover', this.cluster)
|
|
150
|
-
}
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
google.maps.event.addDomListener(
|
|
154
|
-
this.div,
|
|
155
|
-
'mouseout',
|
|
156
|
-
() => {
|
|
157
|
-
/**
|
|
158
|
-
* This event is fired when the mouse moves out of a cluster marker.
|
|
159
|
-
* @name MarkerClusterer#mouseout
|
|
160
|
-
* @param {Cluster} c The cluster that the mouse moved out of.
|
|
161
|
-
* @event
|
|
162
|
-
*/
|
|
163
|
-
google.maps.event.trigger(this.cluster.getClusterer(), 'mouseout', this.cluster)
|
|
164
|
-
}
|
|
165
|
-
)
|
|
200
|
+
this.div.addEventListener('mouseout', this.onMouseOut)
|
|
166
201
|
}
|
|
167
202
|
|
|
168
203
|
onRemove() {
|
|
@@ -173,20 +208,32 @@ export class ClusterIcon {
|
|
|
173
208
|
google.maps.event.removeListener(this.boundsChangedListener)
|
|
174
209
|
}
|
|
175
210
|
|
|
176
|
-
|
|
211
|
+
this.div.removeEventListener('mousedown', this.onMouseDown)
|
|
212
|
+
|
|
213
|
+
this.div.removeEventListener('click', this.onClick)
|
|
214
|
+
|
|
215
|
+
this.div.removeEventListener('mouseover', this.onMouseOver)
|
|
216
|
+
|
|
217
|
+
this.div.removeEventListener('mouseout', this.onMouseOut)
|
|
177
218
|
|
|
178
219
|
this.div.parentNode.removeChild(this.div)
|
|
179
220
|
|
|
221
|
+
if (this.timeOut !== null) {
|
|
222
|
+
window.clearTimeout(this.timeOut)
|
|
223
|
+
|
|
224
|
+
this.timeOut = null
|
|
225
|
+
}
|
|
226
|
+
|
|
180
227
|
this.div = null
|
|
181
228
|
}
|
|
182
229
|
}
|
|
183
230
|
|
|
184
231
|
draw() {
|
|
185
232
|
if (this.visible && this.div !== null && this.center) {
|
|
186
|
-
const
|
|
233
|
+
const pos = this.getPosFromLatLng(this.center)
|
|
187
234
|
|
|
188
|
-
this.div.style.top = y
|
|
189
|
-
this.div.style.left = x
|
|
235
|
+
this.div.style.top = pos !== null ? `${pos.y}px` : '0'
|
|
236
|
+
this.div.style.left = pos !== null ? `${pos.x}px` : '0'
|
|
190
237
|
}
|
|
191
238
|
}
|
|
192
239
|
|
|
@@ -210,7 +257,11 @@ export class ClusterIcon {
|
|
|
210
257
|
|
|
211
258
|
const pos = this.getPosFromLatLng(this.center)
|
|
212
259
|
|
|
213
|
-
if (
|
|
260
|
+
if (
|
|
261
|
+
this.sums === null ||
|
|
262
|
+
typeof this.sums.title === 'undefined' ||
|
|
263
|
+
this.sums.title === ''
|
|
264
|
+
) {
|
|
214
265
|
divTitle = this.cluster.getClusterer().getTitle()
|
|
215
266
|
} else {
|
|
216
267
|
divTitle = this.sums.title
|
|
@@ -218,12 +269,15 @@ export class ClusterIcon {
|
|
|
218
269
|
|
|
219
270
|
this.div.style.cursor = 'pointer'
|
|
220
271
|
this.div.style.position = 'absolute'
|
|
221
|
-
|
|
222
|
-
this.div.style.
|
|
272
|
+
|
|
273
|
+
this.div.style.top = pos !== null ? `${pos.y}px` : '0'
|
|
274
|
+
this.div.style.left = pos !== null ? `${pos.x}px` : '0'
|
|
275
|
+
|
|
223
276
|
this.div.style.width = `${this.width}px`
|
|
224
277
|
this.div.style.height = `${this.height}px`
|
|
225
278
|
|
|
226
279
|
const img = document.createElement('img')
|
|
280
|
+
|
|
227
281
|
img.alt = divTitle
|
|
228
282
|
img.src = this.url
|
|
229
283
|
img.style.position = 'absolute'
|
|
@@ -231,10 +285,13 @@ export class ClusterIcon {
|
|
|
231
285
|
img.style.left = `${spriteH}px`
|
|
232
286
|
|
|
233
287
|
if (!this.cluster.getClusterer().enableRetinaIcons) {
|
|
234
|
-
img.style.clip = `rect(-${spriteV}px, -${spriteH + this.width}px, -${
|
|
288
|
+
img.style.clip = `rect(-${spriteV}px, -${spriteH + this.width}px, -${
|
|
289
|
+
spriteV + this.height
|
|
290
|
+
}, -${spriteH})`
|
|
235
291
|
}
|
|
236
292
|
|
|
237
293
|
const textElm = document.createElement('div')
|
|
294
|
+
|
|
238
295
|
textElm.style.position = 'absolute'
|
|
239
296
|
textElm.style.top = `${this.anchorText[0]}px`
|
|
240
297
|
textElm.style.left = `${this.anchorText[1]}px`
|
|
@@ -250,9 +307,12 @@ export class ClusterIcon {
|
|
|
250
307
|
textElm.innerText = `${this.sums?.text}`
|
|
251
308
|
|
|
252
309
|
this.div.innerHTML = ''
|
|
310
|
+
|
|
253
311
|
this.div.appendChild(img)
|
|
254
312
|
this.div.appendChild(textElm)
|
|
313
|
+
|
|
255
314
|
this.div.title = divTitle
|
|
315
|
+
|
|
256
316
|
this.div.style.display = ''
|
|
257
317
|
}
|
|
258
318
|
|
|
@@ -261,14 +321,18 @@ export class ClusterIcon {
|
|
|
261
321
|
|
|
262
322
|
useStyle(sums: ClusterIconInfo) {
|
|
263
323
|
this.sums = sums
|
|
324
|
+
|
|
264
325
|
const styles = this.cluster.getClusterer().getStyles()
|
|
265
|
-
|
|
326
|
+
|
|
327
|
+
const style =
|
|
328
|
+
styles[Math.min(styles.length - 1, Math.max(0, sums.index - 1))]
|
|
266
329
|
|
|
267
330
|
this.url = style.url
|
|
268
331
|
this.height = style.height
|
|
269
332
|
this.width = style.width
|
|
270
333
|
|
|
271
|
-
if (style.className)
|
|
334
|
+
if (style.className)
|
|
335
|
+
this.className = `${this.clusterClassName} ${style.className}`
|
|
272
336
|
|
|
273
337
|
this.anchorText = style.anchorText || [0, 0]
|
|
274
338
|
this.anchorIcon = style.anchorIcon || [this.height / 2, this.width / 2]
|
|
@@ -292,17 +356,14 @@ export class ClusterIcon {
|
|
|
292
356
|
this.center = center
|
|
293
357
|
}
|
|
294
358
|
|
|
295
|
-
getPosFromLatLng(latlng: google.maps.LatLng): google.maps.Point {
|
|
296
|
-
// @ts-ignore
|
|
359
|
+
getPosFromLatLng(latlng: google.maps.LatLng): google.maps.Point | null {
|
|
297
360
|
const pos = this.getProjection().fromLatLngToDivPixel(latlng)
|
|
298
361
|
|
|
299
|
-
pos
|
|
300
|
-
|
|
301
|
-
pos.y -= this.anchorIcon[0]
|
|
362
|
+
if (pos !== null) {
|
|
363
|
+
pos.x -= this.anchorIcon[1]
|
|
302
364
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
// pos.y = pos.y
|
|
365
|
+
pos.y -= this.anchorIcon[0]
|
|
366
|
+
}
|
|
306
367
|
|
|
307
368
|
return pos
|
|
308
369
|
}
|
package/src/Clusterer.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* global google */
|
|
2
2
|
/* eslint-disable filenames/match-regex */
|
|
3
3
|
import { Cluster } from './Cluster'
|
|
4
|
+
import { ClusterIcon } from './ClusterIcon'
|
|
4
5
|
|
|
5
6
|
import {
|
|
6
7
|
MarkerExtended,
|
|
@@ -44,7 +45,7 @@ const IMAGE_SIZES = [53, 56, 66, 78, 90]
|
|
|
44
45
|
|
|
45
46
|
const CLUSTERER_CLASS = 'cluster'
|
|
46
47
|
|
|
47
|
-
export class Clusterer {
|
|
48
|
+
export class Clusterer extends google.maps.OverlayView {
|
|
48
49
|
markers: MarkerExtended[]
|
|
49
50
|
clusters: Cluster[]
|
|
50
51
|
listeners: google.maps.MapsEventListener[]
|
|
@@ -73,6 +74,8 @@ export class Clusterer {
|
|
|
73
74
|
optMarkers: MarkerExtended[] = [],
|
|
74
75
|
optOptions: ClustererOptions = {}
|
|
75
76
|
) {
|
|
77
|
+
super()
|
|
78
|
+
|
|
76
79
|
this.extend(Clusterer, google.maps.OverlayView)
|
|
77
80
|
|
|
78
81
|
this.markers = []
|
|
@@ -134,50 +137,56 @@ export class Clusterer {
|
|
|
134
137
|
this.setupStyles()
|
|
135
138
|
|
|
136
139
|
this.addMarkers(optMarkers, true)
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
137
141
|
// @ts-ignore
|
|
138
142
|
this.setMap(map) // Note: this causes onAdd to be called
|
|
139
143
|
}
|
|
140
144
|
|
|
145
|
+
onZoomChanged() {
|
|
146
|
+
this.resetViewport(false)
|
|
147
|
+
|
|
148
|
+
// Workaround for this Google bug: when map is at level 0 and "-" of
|
|
149
|
+
// zoom slider is clicked, a "zoom_changed" event is fired even though
|
|
150
|
+
// the map doesn't zoom out any further. In this situation, no "idle"
|
|
151
|
+
// event is triggered so the cluster markers that have been removed
|
|
152
|
+
// do not get redrawn. Same goes for a zoom in at maxZoom.
|
|
153
|
+
if (
|
|
154
|
+
this.getMap()?.getZoom() === (this.get('minZoom') || 0) ||
|
|
155
|
+
|
|
156
|
+
this.getMap()?.getZoom() === this.get('maxZoom')
|
|
157
|
+
) {
|
|
158
|
+
google.maps.event.trigger(this, 'idle')
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
onIdle() {
|
|
163
|
+
this.redraw()
|
|
164
|
+
}
|
|
165
|
+
|
|
141
166
|
onAdd() {
|
|
142
|
-
|
|
143
|
-
|
|
167
|
+
const map = this.getMap()
|
|
168
|
+
|
|
169
|
+
this.activeMap = map
|
|
144
170
|
|
|
145
171
|
this.ready = true
|
|
146
172
|
|
|
147
173
|
this.repaint()
|
|
148
174
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
this.getMap().getZoom() === (this.get('minZoom') || 0) ||
|
|
165
|
-
// @ts-ignore
|
|
166
|
-
this.getMap().getZoom() === this.get('maxZoom')
|
|
167
|
-
) {
|
|
168
|
-
google.maps.event.trigger(this, 'idle')
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
),
|
|
172
|
-
google.maps.event.addListener(
|
|
173
|
-
// @ts-ignore
|
|
174
|
-
this.getMap(),
|
|
175
|
-
'idle',
|
|
176
|
-
() => {
|
|
177
|
-
this.redraw()
|
|
178
|
-
}
|
|
179
|
-
),
|
|
180
|
-
]
|
|
175
|
+
if (map !== null) {
|
|
176
|
+
// Add the map event listeners
|
|
177
|
+
this.listeners = [
|
|
178
|
+
google.maps.event.addListener(
|
|
179
|
+
map,
|
|
180
|
+
'zoom_changed',
|
|
181
|
+
this.onZoomChanged
|
|
182
|
+
),
|
|
183
|
+
google.maps.event.addListener(
|
|
184
|
+
map,
|
|
185
|
+
'idle',
|
|
186
|
+
this.onIdle
|
|
187
|
+
),
|
|
188
|
+
]
|
|
189
|
+
}
|
|
181
190
|
}
|
|
182
191
|
|
|
183
192
|
onRemove() {
|
|
@@ -236,6 +245,7 @@ export class Clusterer {
|
|
|
236
245
|
}
|
|
237
246
|
}
|
|
238
247
|
|
|
248
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
239
249
|
// @ts-ignore
|
|
240
250
|
this.getMap().fitBounds(bounds)
|
|
241
251
|
}
|
|
@@ -489,6 +499,7 @@ export class Clusterer {
|
|
|
489
499
|
}
|
|
490
500
|
|
|
491
501
|
getExtendedBounds(bounds: google.maps.LatLngBounds): google.maps.LatLngBounds {
|
|
502
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
492
503
|
// @ts-ignore
|
|
493
504
|
const projection = this.getProjection()
|
|
494
505
|
// Convert the points to pixels and the extend out by the grid size.
|
|
@@ -497,27 +508,43 @@ export class Clusterer {
|
|
|
497
508
|
new google.maps.LatLng(bounds.getNorthEast().lat(), bounds.getNorthEast().lng())
|
|
498
509
|
)
|
|
499
510
|
|
|
500
|
-
trPix
|
|
501
|
-
|
|
511
|
+
if (trPix !== null) {
|
|
512
|
+
trPix.x += this.gridSize
|
|
513
|
+
trPix.y -= this.gridSize
|
|
514
|
+
}
|
|
502
515
|
|
|
503
516
|
const blPix = projection.fromLatLngToDivPixel(
|
|
504
517
|
// Turn the bounds into latlng.
|
|
505
518
|
new google.maps.LatLng(bounds.getSouthWest().lat(), bounds.getSouthWest().lng())
|
|
506
519
|
)
|
|
507
520
|
|
|
508
|
-
blPix
|
|
509
|
-
|
|
521
|
+
if (blPix !== null) {
|
|
522
|
+
blPix.x -= this.gridSize
|
|
523
|
+
blPix.y += this.gridSize
|
|
524
|
+
}
|
|
525
|
+
|
|
510
526
|
|
|
511
527
|
// Extend the bounds to contain the new bounds.
|
|
512
|
-
|
|
528
|
+
if (trPix !== null) {
|
|
513
529
|
// Convert the pixel points back to LatLng nw
|
|
514
|
-
projection.fromDivPixelToLatLng(trPix)
|
|
515
|
-
)
|
|
530
|
+
const point1 = projection.fromDivPixelToLatLng(trPix)
|
|
516
531
|
|
|
517
|
-
|
|
532
|
+
if (point1 !== null) {
|
|
533
|
+
bounds.extend(point1)
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
if (blPix !== null) {
|
|
518
538
|
// Convert the pixel points back to LatLng sw
|
|
519
|
-
projection.fromDivPixelToLatLng(blPix)
|
|
520
|
-
|
|
539
|
+
const point2 = projection.fromDivPixelToLatLng(blPix)
|
|
540
|
+
|
|
541
|
+
if (point2 !== null) {
|
|
542
|
+
bounds.extend(
|
|
543
|
+
point2
|
|
544
|
+
)
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
521
548
|
|
|
522
549
|
return bounds
|
|
523
550
|
}
|
|
@@ -628,44 +655,42 @@ export class Clusterer {
|
|
|
628
655
|
if (this.timerRefStatic !== null) {
|
|
629
656
|
window.clearTimeout(this.timerRefStatic)
|
|
630
657
|
|
|
658
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
631
659
|
// @ts-ignore
|
|
632
660
|
delete this.timerRefStatic
|
|
633
661
|
}
|
|
634
662
|
}
|
|
635
663
|
|
|
664
|
+
const map = this.getMap()
|
|
665
|
+
|
|
666
|
+
const bounds = map !== null && 'getBounds' in map ? map.getBounds() : null
|
|
667
|
+
|
|
636
668
|
// Get our current map view bounds.
|
|
637
669
|
// Create a new bounds object so we don't affect the map.
|
|
638
670
|
//
|
|
639
671
|
// See Comments 9 & 11 on Issue 3651 relating to this workaround for a Google Maps bug:
|
|
640
672
|
const mapBounds =
|
|
673
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
641
674
|
// @ts-ignore
|
|
642
|
-
|
|
675
|
+
map.getZoom() > 3
|
|
643
676
|
? new google.maps.LatLngBounds(
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
.getBounds()
|
|
647
|
-
.getSouthWest(),
|
|
648
|
-
// @ts-ignore
|
|
649
|
-
this.getMap()
|
|
650
|
-
.getBounds()
|
|
651
|
-
.getNorthEast()
|
|
677
|
+
bounds?.getSouthWest(),
|
|
678
|
+
bounds?.getNorthEast()
|
|
652
679
|
)
|
|
653
680
|
: new google.maps.LatLngBounds(
|
|
654
681
|
new google.maps.LatLng(85.02070771743472, -178.48388434375),
|
|
655
682
|
new google.maps.LatLng(-85.08136444384544, 178.00048865625)
|
|
656
683
|
)
|
|
657
684
|
|
|
658
|
-
const
|
|
685
|
+
const extendedMapBounds = this.getExtendedBounds(mapBounds)
|
|
659
686
|
|
|
660
687
|
const iLast = Math.min(iFirst + this.batchSize, this.markers.length)
|
|
661
688
|
|
|
662
689
|
for (let i = iFirst; i < iLast; i++) {
|
|
663
690
|
const marker = this.markers[i]
|
|
664
691
|
|
|
665
|
-
if (!marker.isAdded && this.isMarkerInBounds(marker,
|
|
666
|
-
|
|
667
|
-
this.addToClosestCluster(marker)
|
|
668
|
-
}
|
|
692
|
+
if (!marker.isAdded && this.isMarkerInBounds(marker, extendedMapBounds) && (!this.ignoreHidden || (this.ignoreHidden && marker.getVisible()))) {
|
|
693
|
+
this.addToClosestCluster(marker)
|
|
669
694
|
}
|
|
670
695
|
}
|
|
671
696
|
|
|
@@ -694,16 +719,13 @@ export class Clusterer {
|
|
|
694
719
|
}
|
|
695
720
|
}
|
|
696
721
|
|
|
697
|
-
extend(obj1:
|
|
698
|
-
return function applyExtend(object:
|
|
699
|
-
// eslint-disable-next-line guard-for-in
|
|
722
|
+
extend<A extends typeof ClusterIcon | typeof Clusterer>(obj1: A, obj2: typeof google.maps.OverlayView) {
|
|
723
|
+
return function applyExtend(this: A, object: typeof google.maps.OverlayView) {
|
|
700
724
|
for (const property in object.prototype) {
|
|
701
|
-
|
|
702
|
-
this.prototype[property] = object.prototype[property]
|
|
725
|
+
this.prototype.set(property, object.prototype.get(property))
|
|
703
726
|
}
|
|
704
727
|
|
|
705
|
-
// @ts-ignore
|
|
706
728
|
return this
|
|
707
|
-
}.apply(obj1, [obj2])
|
|
729
|
+
}.apply<A, [typeof google.maps.OverlayView], any>(obj1, [obj2])
|
|
708
730
|
}
|
|
709
731
|
}
|
package/src/index.ts
CHANGED
|
@@ -43,9 +43,9 @@ export { Cluster } from './Cluster'
|
|
|
43
43
|
export { ClusterIcon } from './ClusterIcon'
|
|
44
44
|
|
|
45
45
|
export {
|
|
46
|
-
ClusterIconInfo,
|
|
47
|
-
ClusterIconStyle,
|
|
48
|
-
MarkerExtended,
|
|
49
|
-
TCalculator,
|
|
50
|
-
ClustererOptions,
|
|
46
|
+
type ClusterIconInfo,
|
|
47
|
+
type ClusterIconStyle,
|
|
48
|
+
type MarkerExtended,
|
|
49
|
+
type TCalculator,
|
|
50
|
+
type ClustererOptions,
|
|
51
51
|
} from './types'
|