-
Notifications
You must be signed in to change notification settings - Fork 39
Expand file tree
/
Copy pathMarkerClusterer.tsx
More file actions
228 lines (214 loc) · 7.4 KB
/
MarkerClusterer.tsx
File metadata and controls
228 lines (214 loc) · 7.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
import React, {
useLayoutEffect,
useImperativeHandle,
useMemo,
useContext,
} from "react"
import { useKakaoEvent } from "../hooks/useKakaoEvent"
import { useMap } from "../hooks/useMap"
import { useIsomorphicLayoutEffect } from "../hooks/useIsomorphicLayoutEffect"
import { useKakaoMapsSetEffect } from "../hooks/useKakaoMapsSetEffect"
export const KakaoMapMarkerClustererContext =
React.createContext<kakao.maps.MarkerClusterer>(
undefined as unknown as kakao.maps.MarkerClusterer,
)
export type MarkerClustererProps = React.PropsWithChildren<{
/**
* 클러스터의 격자 크기. 화면 픽셀 단위이며 해당 격자 영역 안에 마커가 포함되면 클러스터에 포함시킨다
* @default 60
*/
gridSize?: number
/**
* 마커들의 좌표 평균을 클러스터 좌표 설정 여부
* @default false
*/
averageCenter?: boolean
/**
* 클러스터링 할 지도의 최소 레벨 값. 지정한 숫자에 해당하는 레벨 미만에서는 클러스터링 하지 않는다
* @default 0
*/
minLevel?: number
/**
* 클러스터링 할 최소 마커 수
* @default 2
*/
minClusterSize?: number
/**
* 클러스터의 스타일. 여러개를 선언하면 calculator 로 구분된 사이즈 구간마다 서로 다른 스타일을 적용시킬 수 있다
*/
styles?: React.CSSProperties[] | object[]
/**
* 클러스터에 표시할 문자열 또는 문자열 생성 함수.
* @default "클러스터에 포함된 숫자"
*/
texts?: string[] | ((size: number) => string)
/**
* 클러스터 크기를 구분하는 값을 가진 배열 또는 구분값 생성함수
* @default [10, 100, 1000, 10000]
*/
calculator?: number[] | ((size: number) => number[])
/**
* 클러스터 클릭 시 지도 확대 여부. true로 설정하면 클러스터 클릭 시 확대 되지 않는다
* @default false
*/
disableClickZoom?: boolean
/**
* 클러스터 클릭 가능 여부 지정 옵션. false일 경우 클러스터의 clusterclick, clusterdblclick, clusterrightclick 이벤트가 발생하지 않으며, 커서가 변경되지 않는다.
* @default true
*/
clickable?: boolean
/**
* 클러스터에 마우스 over/out 가능 여부 지정 옵션. false일 경우 클러스터의 clusterover, clusterout 이벤트가 발생하지 않는다.
* @default true
*/
hoverable?: boolean
/**
* 클러스터 마커를 클릭 했을 때 발생한다.
* 이벤트 핸들러 함수 인자로는 Cluster 객체가 넘어온다.
* 클러스터 마커 클릭 시 지도가 줌인 되는 경우 원하는 Cluster 객체를 얻지 못할 수도 있다.
* 때문에 MarkerClusterer 를 생성할 때 disableClickZoom 옵션을 true로 설정하여
* 클러스터 마커를 클릭했을 때 지도가 줌인되지 않도록 설정 후 사용한다.
*/
onClusterclick?: (
target: kakao.maps.MarkerClusterer,
cluster: kakao.maps.Cluster,
) => void
/**
* 클러스터 마커를 마우스 오버 했을 때 발생한다
* 이벤트 핸들러 함수 인자로는 마우스 오버한 Cluster 객체가 넘어온다.
*/
onClusterover?: (
target: kakao.maps.MarkerClusterer,
cluster: kakao.maps.Cluster,
) => void
/**
* 클러스터 마커를 마우스 아웃 했을 때 발생한다
* 이벤트 핸들러 함수 인자로는 마우스 아웃된 Cluster 객체가 넘어온다.
*/
onClusterout?: (
target: kakao.maps.MarkerClusterer,
cluster: kakao.maps.Cluster,
) => void
/**
* 클러스터 마커를 더블클릭 했을 때 발생한다
* 이벤트 핸들러 함수 인자로는 더블클릭한 Cluster 객체가 넘어온다.
* MarkerClusterer 를 생성할 때 disableClickZoom 옵션을 true로 설정해야만 이벤트가 발생한다.
*/
onClusterdblclick?: (
target: kakao.maps.MarkerClusterer,
cluster: kakao.maps.Cluster,
) => void
/**
* 클러스터 마커를 오른쪽 클릭 했을 때 발생한다
* 이벤트 핸들러 함수 인자로는 오른쪽 클릭한 Cluster 객체가 넘어온다.
*/
onClusterrightclick?: (
target: kakao.maps.MarkerClusterer,
cluster: kakao.maps.Cluster,
) => void
/**
* 클러스터링이 완료됐을 때 발생한다.
* 이벤트 핸들러 함수 인자로는 생성된 Cluster 객체 전체가 배열로 넘어온다.
*/
onClustered?: (
target: kakao.maps.MarkerClusterer,
clusters: kakao.maps.Cluster[],
) => void
/**
* MarkerClusterer 생성 후 해당 객체를 전달하는 함수
*/
onCreate?: (target: kakao.maps.MarkerClusterer) => void
}>
export const MarkerClusterer = React.forwardRef<
kakao.maps.MarkerClusterer,
MarkerClustererProps
>(function MarkerClusterer(
{
onClusterclick,
onClusterdblclick,
onClustered,
onClusterout,
onClusterover,
onClusterrightclick,
onCreate,
...props
},
ref,
) {
const {
children,
averageCenter,
calculator,
clickable,
disableClickZoom,
gridSize,
hoverable,
minClusterSize,
minLevel,
styles,
texts,
} = props
const map = useMap(`MarkerClusterer`)
const markerClusterer = useMemo(() => {
if (!window.kakao.maps.MarkerClusterer) {
console.warn(
"clusterer 라이브러리를 별도 로드 해야 사용 가능합니다. `https://apis.map.kakao.com/web/guide/#loadlibrary`",
)
return
}
return new kakao.maps.MarkerClusterer({
averageCenter,
calculator,
clickable,
disableClickZoom,
gridSize,
hoverable,
minClusterSize,
minLevel,
styles,
texts,
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
useImperativeHandle(ref, () => markerClusterer!, [markerClusterer])
useLayoutEffect(() => {
if (!markerClusterer) return
markerClusterer.setMap(map)
return () => {
markerClusterer.setMap(null)
}
}, [map, markerClusterer])
useLayoutEffect(() => {
if (markerClusterer && onCreate) onCreate(markerClusterer)
}, [markerClusterer, onCreate])
useKakaoMapsSetEffect(markerClusterer, "setGridSize", gridSize!)
useKakaoMapsSetEffect(markerClusterer, "setMinClusterSize", minClusterSize!)
useKakaoMapsSetEffect(markerClusterer, "setAverageCenter", averageCenter!)
useKakaoMapsSetEffect(markerClusterer, "setAverageCenter", averageCenter!)
useKakaoMapsSetEffect(markerClusterer, "setMinLevel", minLevel!)
useKakaoMapsSetEffect(markerClusterer, "setTexts", texts!)
useKakaoMapsSetEffect(markerClusterer, "setCalculator", calculator!)
useKakaoMapsSetEffect(markerClusterer, "setStyles", styles!)
useKakaoEvent(markerClusterer, "clustered", onClustered)
useKakaoEvent(markerClusterer, "clusterclick", onClusterclick)
useKakaoEvent(markerClusterer, "clusterover", onClusterover)
useKakaoEvent(markerClusterer, "clusterout", onClusterout)
useKakaoEvent(markerClusterer, "clusterdblclick", onClusterdblclick)
useKakaoEvent(markerClusterer, "clusterrightclick", onClusterrightclick)
if (!markerClusterer) {
return null
}
return (
<KakaoMapMarkerClustererContext.Provider value={markerClusterer}>
{children}
<MarkerClustererRedraw {...props} />
</KakaoMapMarkerClustererContext.Provider>
)
})
const MarkerClustererRedraw: React.FC<MarkerClustererProps> = () => {
const markerClusterer = useContext(KakaoMapMarkerClustererContext)
useIsomorphicLayoutEffect(() => {
markerClusterer.redraw()
})
return null
}