@react-google-maps/marker-clusterer 2.10.0 → 2.11.1
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 +262 -223
- 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 +262 -223
- 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 +16 -6
- package/dist/umd.js +262 -223
- 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 +7 -7
- package/src/Cluster.tsx +4 -8
- package/src/ClusterIcon.tsx +183 -114
- package/src/Clusterer.tsx +92 -82
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,146 +25,189 @@ 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
|
|
|
62
|
-
|
|
63
|
-
this.
|
|
64
|
-
if (this.visible) {
|
|
65
|
-
this.show()
|
|
66
|
-
}
|
|
85
|
+
onMouseDown() {
|
|
86
|
+
this.cMouseDownInCluster = true
|
|
67
87
|
|
|
68
|
-
|
|
69
|
-
|
|
88
|
+
this.cDraggingMapByCluster = false
|
|
89
|
+
}
|
|
70
90
|
|
|
71
|
-
|
|
72
|
-
this.
|
|
73
|
-
// @ts-ignore
|
|
74
|
-
this.getMap(),
|
|
75
|
-
'boundschanged',
|
|
76
|
-
function boundsChanged() {
|
|
77
|
-
cDraggingMapByCluster = cMouseDownInCluster
|
|
78
|
-
}
|
|
79
|
-
)
|
|
91
|
+
onClick(event: Event) {
|
|
92
|
+
this.cMouseDownInCluster = false
|
|
80
93
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
cDraggingMapByCluster = false
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
google.maps.event.addListener(
|
|
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()
|
|
111
|
-
|
|
112
|
-
// @ts-ignore
|
|
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
|
-
}
|
|
94
|
+
if (!this.cDraggingMapByCluster) {
|
|
95
|
+
const markerClusterer = this.cluster.getClusterer()
|
|
128
96
|
|
|
129
|
-
|
|
130
|
-
|
|
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
|
|
131
105
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
+
const map = markerClusterer.getMap()
|
|
115
|
+
|
|
116
|
+
if (map !== null && 'fitBounds' in map) {
|
|
117
|
+
map.fitBounds(bounds)
|
|
135
118
|
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
// There is a fix for Issue 170 here:
|
|
122
|
+
this.timeOut = window.setTimeout(() => {
|
|
123
|
+
const map = markerClusterer.getMap()
|
|
124
|
+
|
|
125
|
+
if (map !== null) {
|
|
126
|
+
if ('fitBounds' in map) {
|
|
127
|
+
map.fitBounds(bounds)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const zoom = map.getZoom() || 0
|
|
131
|
+
|
|
132
|
+
// Don't zoom beyond the max zoom level
|
|
133
|
+
if (
|
|
134
|
+
maxZoom !== null &&
|
|
135
|
+
zoom > maxZoom
|
|
136
|
+
) {
|
|
137
|
+
map.setZoom(maxZoom + 1)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}, 100)
|
|
136
141
|
}
|
|
137
|
-
)
|
|
138
142
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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)
|
|
143
|
+
// Prevent event propagation to the map:
|
|
144
|
+
event.cancelBubble = true
|
|
145
|
+
|
|
146
|
+
if (event.stopPropagation) {
|
|
147
|
+
event.stopPropagation()
|
|
150
148
|
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
onMouseOver() {
|
|
153
|
+
/**
|
|
154
|
+
* This event is fired when the mouse moves over a cluster marker.
|
|
155
|
+
* @name MarkerClusterer#mouseover
|
|
156
|
+
* @param {Cluster} c The cluster that the mouse moved over.
|
|
157
|
+
* @event
|
|
158
|
+
*/
|
|
159
|
+
google.maps.event.trigger(
|
|
160
|
+
this.cluster.getClusterer(),
|
|
161
|
+
'mouseover',
|
|
162
|
+
this.cluster
|
|
151
163
|
)
|
|
164
|
+
}
|
|
152
165
|
|
|
153
|
-
|
|
154
|
-
|
|
166
|
+
onMouseOut() {
|
|
167
|
+
/**
|
|
168
|
+
* This event is fired when the mouse moves out of a cluster marker.
|
|
169
|
+
* @name MarkerClusterer#mouseout
|
|
170
|
+
* @param {Cluster} c The cluster that the mouse moved out of.
|
|
171
|
+
* @event
|
|
172
|
+
*/
|
|
173
|
+
google.maps.event.trigger(
|
|
174
|
+
this.cluster.getClusterer(),
|
|
155
175
|
'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
|
-
}
|
|
176
|
+
this.cluster
|
|
165
177
|
)
|
|
166
178
|
}
|
|
167
179
|
|
|
180
|
+
onAdd() {
|
|
181
|
+
this.div = document.createElement('div')
|
|
182
|
+
|
|
183
|
+
this.div.className = this.className
|
|
184
|
+
|
|
185
|
+
if (this.visible) {
|
|
186
|
+
this.show()
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
this.getPanes()?.overlayMouseTarget.appendChild(this.div)
|
|
190
|
+
|
|
191
|
+
const map = this.getMap()
|
|
192
|
+
|
|
193
|
+
if (map !== null) {
|
|
194
|
+
// Fix for Issue 157
|
|
195
|
+
this.boundsChangedListener = google.maps.event.addListener(
|
|
196
|
+
map,
|
|
197
|
+
'bounds_changed',
|
|
198
|
+
this.onBoundsChanged
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
this.div.addEventListener('mousedown', this.onMouseDown)
|
|
202
|
+
|
|
203
|
+
this.div.addEventListener('click', this.onClick)
|
|
204
|
+
|
|
205
|
+
this.div.addEventListener('mouseover', this.onMouseOver)
|
|
206
|
+
|
|
207
|
+
this.div.addEventListener('mouseout', this.onMouseOut)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
168
211
|
onRemove() {
|
|
169
212
|
if (this.div && this.div.parentNode) {
|
|
170
213
|
this.hide()
|
|
@@ -173,20 +216,32 @@ export class ClusterIcon {
|
|
|
173
216
|
google.maps.event.removeListener(this.boundsChangedListener)
|
|
174
217
|
}
|
|
175
218
|
|
|
176
|
-
|
|
219
|
+
this.div.removeEventListener('mousedown', this.onMouseDown)
|
|
220
|
+
|
|
221
|
+
this.div.removeEventListener('click', this.onClick)
|
|
222
|
+
|
|
223
|
+
this.div.removeEventListener('mouseover', this.onMouseOver)
|
|
224
|
+
|
|
225
|
+
this.div.removeEventListener('mouseout', this.onMouseOut)
|
|
177
226
|
|
|
178
227
|
this.div.parentNode.removeChild(this.div)
|
|
179
228
|
|
|
229
|
+
if (this.timeOut !== null) {
|
|
230
|
+
window.clearTimeout(this.timeOut)
|
|
231
|
+
|
|
232
|
+
this.timeOut = null
|
|
233
|
+
}
|
|
234
|
+
|
|
180
235
|
this.div = null
|
|
181
236
|
}
|
|
182
237
|
}
|
|
183
238
|
|
|
184
239
|
draw() {
|
|
185
240
|
if (this.visible && this.div !== null && this.center) {
|
|
186
|
-
const
|
|
241
|
+
const pos = this.getPosFromLatLng(this.center)
|
|
187
242
|
|
|
188
|
-
this.div.style.top = y
|
|
189
|
-
this.div.style.left = x
|
|
243
|
+
this.div.style.top = pos !== null ? `${pos.y}px` : '0'
|
|
244
|
+
this.div.style.left = pos !== null ? `${pos.x}px` : '0'
|
|
190
245
|
}
|
|
191
246
|
}
|
|
192
247
|
|
|
@@ -210,7 +265,11 @@ export class ClusterIcon {
|
|
|
210
265
|
|
|
211
266
|
const pos = this.getPosFromLatLng(this.center)
|
|
212
267
|
|
|
213
|
-
if (
|
|
268
|
+
if (
|
|
269
|
+
this.sums === null ||
|
|
270
|
+
typeof this.sums.title === 'undefined' ||
|
|
271
|
+
this.sums.title === ''
|
|
272
|
+
) {
|
|
214
273
|
divTitle = this.cluster.getClusterer().getTitle()
|
|
215
274
|
} else {
|
|
216
275
|
divTitle = this.sums.title
|
|
@@ -218,12 +277,15 @@ export class ClusterIcon {
|
|
|
218
277
|
|
|
219
278
|
this.div.style.cursor = 'pointer'
|
|
220
279
|
this.div.style.position = 'absolute'
|
|
221
|
-
|
|
222
|
-
this.div.style.
|
|
280
|
+
|
|
281
|
+
this.div.style.top = pos !== null ? `${pos.y}px` : '0'
|
|
282
|
+
this.div.style.left = pos !== null ? `${pos.x}px` : '0'
|
|
283
|
+
|
|
223
284
|
this.div.style.width = `${this.width}px`
|
|
224
285
|
this.div.style.height = `${this.height}px`
|
|
225
286
|
|
|
226
287
|
const img = document.createElement('img')
|
|
288
|
+
|
|
227
289
|
img.alt = divTitle
|
|
228
290
|
img.src = this.url
|
|
229
291
|
img.style.position = 'absolute'
|
|
@@ -231,10 +293,13 @@ export class ClusterIcon {
|
|
|
231
293
|
img.style.left = `${spriteH}px`
|
|
232
294
|
|
|
233
295
|
if (!this.cluster.getClusterer().enableRetinaIcons) {
|
|
234
|
-
img.style.clip = `rect(-${spriteV}px, -${spriteH + this.width}px, -${
|
|
296
|
+
img.style.clip = `rect(-${spriteV}px, -${spriteH + this.width}px, -${
|
|
297
|
+
spriteV + this.height
|
|
298
|
+
}, -${spriteH})`
|
|
235
299
|
}
|
|
236
300
|
|
|
237
301
|
const textElm = document.createElement('div')
|
|
302
|
+
|
|
238
303
|
textElm.style.position = 'absolute'
|
|
239
304
|
textElm.style.top = `${this.anchorText[0]}px`
|
|
240
305
|
textElm.style.left = `${this.anchorText[1]}px`
|
|
@@ -250,9 +315,12 @@ export class ClusterIcon {
|
|
|
250
315
|
textElm.innerText = `${this.sums?.text}`
|
|
251
316
|
|
|
252
317
|
this.div.innerHTML = ''
|
|
318
|
+
|
|
253
319
|
this.div.appendChild(img)
|
|
254
320
|
this.div.appendChild(textElm)
|
|
321
|
+
|
|
255
322
|
this.div.title = divTitle
|
|
323
|
+
|
|
256
324
|
this.div.style.display = ''
|
|
257
325
|
}
|
|
258
326
|
|
|
@@ -261,14 +329,18 @@ export class ClusterIcon {
|
|
|
261
329
|
|
|
262
330
|
useStyle(sums: ClusterIconInfo) {
|
|
263
331
|
this.sums = sums
|
|
332
|
+
|
|
264
333
|
const styles = this.cluster.getClusterer().getStyles()
|
|
265
|
-
|
|
334
|
+
|
|
335
|
+
const style =
|
|
336
|
+
styles[Math.min(styles.length - 1, Math.max(0, sums.index - 1))]
|
|
266
337
|
|
|
267
338
|
this.url = style.url
|
|
268
339
|
this.height = style.height
|
|
269
340
|
this.width = style.width
|
|
270
341
|
|
|
271
|
-
if (style.className)
|
|
342
|
+
if (style.className)
|
|
343
|
+
this.className = `${this.clusterClassName} ${style.className}`
|
|
272
344
|
|
|
273
345
|
this.anchorText = style.anchorText || [0, 0]
|
|
274
346
|
this.anchorIcon = style.anchorIcon || [this.height / 2, this.width / 2]
|
|
@@ -292,17 +364,14 @@ export class ClusterIcon {
|
|
|
292
364
|
this.center = center
|
|
293
365
|
}
|
|
294
366
|
|
|
295
|
-
getPosFromLatLng(latlng: google.maps.LatLng): google.maps.Point {
|
|
296
|
-
// @ts-ignore
|
|
367
|
+
getPosFromLatLng(latlng: google.maps.LatLng): google.maps.Point | null {
|
|
297
368
|
const pos = this.getProjection().fromLatLngToDivPixel(latlng)
|
|
298
369
|
|
|
299
|
-
pos
|
|
300
|
-
|
|
301
|
-
pos.y -= this.anchorIcon[0]
|
|
370
|
+
if (pos !== null) {
|
|
371
|
+
pos.x -= this.anchorIcon[1]
|
|
302
372
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
// pos.y = pos.y
|
|
373
|
+
pos.y -= this.anchorIcon[0]
|
|
374
|
+
}
|
|
306
375
|
|
|
307
376
|
return pos
|
|
308
377
|
}
|