korea-drilldown-svg-map 0.1.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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +393 -0
  3. package/data/boundaries/dong/all.topo.json +1 -0
  4. package/data/boundaries/regions.json +3158 -0
  5. package/data/boundaries/sgg/all.topo.json +1 -0
  6. package/data/boundaries/sgg/by-sido/11.topo.json +1 -0
  7. package/data/boundaries/sgg/by-sido/26.topo.json +1 -0
  8. package/data/boundaries/sgg/by-sido/27.topo.json +1 -0
  9. package/data/boundaries/sgg/by-sido/28.topo.json +1 -0
  10. package/data/boundaries/sgg/by-sido/29.topo.json +1 -0
  11. package/data/boundaries/sgg/by-sido/30.topo.json +1 -0
  12. package/data/boundaries/sgg/by-sido/31.topo.json +1 -0
  13. package/data/boundaries/sgg/by-sido/36.topo.json +1 -0
  14. package/data/boundaries/sgg/by-sido/41.topo.json +1 -0
  15. package/data/boundaries/sgg/by-sido/43.topo.json +1 -0
  16. package/data/boundaries/sgg/by-sido/44.topo.json +1 -0
  17. package/data/boundaries/sgg/by-sido/46.topo.json +1 -0
  18. package/data/boundaries/sgg/by-sido/47.topo.json +1 -0
  19. package/data/boundaries/sgg/by-sido/48.topo.json +1 -0
  20. package/data/boundaries/sgg/by-sido/50.topo.json +1 -0
  21. package/data/boundaries/sgg/by-sido/51.topo.json +1 -0
  22. package/data/boundaries/sgg/by-sido/52.topo.json +1 -0
  23. package/data/boundaries/sido/all.topo.json +1 -0
  24. package/dist/components/KoreaAdministrativeMap.d.ts +3 -0
  25. package/dist/components/KoreaAdministrativeMap.d.ts.map +1 -0
  26. package/dist/components/KoreaAdministrativeMap.js +1173 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +6 -0
  30. package/dist/lib/choropleth.d.ts +11 -0
  31. package/dist/lib/choropleth.d.ts.map +1 -0
  32. package/dist/lib/choropleth.js +72 -0
  33. package/dist/lib/geometry.d.ts +17 -0
  34. package/dist/lib/geometry.d.ts.map +1 -0
  35. package/dist/lib/geometry.js +86 -0
  36. package/dist/lib/labels.d.ts +10 -0
  37. package/dist/lib/labels.d.ts.map +1 -0
  38. package/dist/lib/labels.js +36 -0
  39. package/dist/lib/loaders.d.ts +7 -0
  40. package/dist/lib/loaders.d.ts.map +1 -0
  41. package/dist/lib/loaders.js +65 -0
  42. package/dist/lib/theme.d.ts +6 -0
  43. package/dist/lib/theme.d.ts.map +1 -0
  44. package/dist/lib/theme.js +45 -0
  45. package/dist/types.d.ts +295 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +1 -0
  48. package/package.json +56 -0
  49. package/scripts/copy-boundaries.mjs +26 -0
  50. package/scripts/preprocess-boundaries.mjs +287 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,393 @@
1
+ # korea-drilldown-svg-map
2
+
3
+ 대한민국 행정구역 경계를 기반으로 `시/도 -> 시/군/구` 드릴다운 지도를 만들기 위한 React 패키지입니다.
4
+
5
+ 기본 제공 범위는 다음과 같습니다.
6
+
7
+ - `시/도`, `시/군/구` TopoJSON 자산
8
+ - 메타데이터 로더와 경계 fetch 유틸
9
+ - 선택 상태와 드릴다운
10
+ - 확대/축소와 포커스 이동
11
+ - 라벨 폰트, 크기, halo, 포맷 커스터마이징
12
+ - 선 굵기와 hover/selected 스타일 제어
13
+ - choropleth 기반 데이터 시각화
14
+ - 정적 지역별 색상 맵
15
+ - tooltip, legend, overlay, 커스텀 SVG 라벨 렌더
16
+
17
+ ## 지도 데이터 기준
18
+
19
+ - 원본 버전: `ver20260201/HangJeongDong_ver20260201.geojson`
20
+ - 지도 정보 업데이트 기준일: `2026-02-01`
21
+ - 참조 데이터 저장소: [vuski/admdongkor](https://github.com/vuski/admdongkor)
22
+
23
+ ## 설치
24
+
25
+ ```bash
26
+ pnpm add korea-drilldown-svg-map
27
+ ```
28
+
29
+ ## 의존성
30
+
31
+ peer dependency:
32
+
33
+ - `react 18` 또는 `react 19`
34
+ - `react-dom 18` 또는 `react-dom 19`
35
+
36
+ runtime dependency:
37
+
38
+ - `d3-geo`
39
+ - `react-simple-maps`
40
+ - `topojson-client`
41
+
42
+ 위 runtime dependency는 패키지 설치 시 자동으로 함께 설치됩니다.
43
+
44
+ ## 저장소 예제 앱
45
+
46
+ Vite 예제는 npm tarball에는 포함되지 않고, 저장소의 `examples/vite-demo` 디렉터리에서만 제공합니다.
47
+
48
+ ## 빠른 시작
49
+
50
+ ### 1. 내장 경계 자산으로 바로 사용
51
+
52
+ 기본 권장 방식입니다. 패키지 안에 포함된 경계 자산을 자동으로 읽기 때문에 `public` 디렉터리에 파일을 따로 복사할 필요가 없습니다.
53
+
54
+ ```tsx
55
+ "use client";
56
+
57
+ import { useEffect, useMemo, useState } from "react";
58
+ import {
59
+ KoreaAdministrativeMap,
60
+ createBundledBoundaryLoaders,
61
+ loadBundledRegionsMetadata,
62
+ type KoreaMapSelection,
63
+ type KoreaRegionsDataset,
64
+ } from "korea-drilldown-svg-map";
65
+
66
+ export function KoreaMapExample() {
67
+ const [metadata, setMetadata] = useState<KoreaRegionsDataset | null>(null);
68
+ const [selection, setSelection] = useState<KoreaMapSelection>({
69
+ sidoCode: null,
70
+ sggCode: null,
71
+ });
72
+
73
+ const loaders = useMemo(() => createBundledBoundaryLoaders(), []);
74
+
75
+ useEffect(() => {
76
+ loadBundledRegionsMetadata().then(setMetadata);
77
+ }, []);
78
+
79
+ if (!metadata) {
80
+ return <p>지도를 준비하는 중입니다...</p>;
81
+ }
82
+
83
+ return (
84
+ <KoreaAdministrativeMap
85
+ metadata={metadata}
86
+ loaders={loaders}
87
+ selection={selection}
88
+ onSelectionChange={setSelection}
89
+ />
90
+ );
91
+ }
92
+ ```
93
+
94
+ ### 2. 직접 `public` 경로로 호스팅하고 싶다면
95
+
96
+ 자산 URL을 직접 관리하거나 CDN 경로를 쓰고 싶으면 기존 방식도 사용할 수 있습니다.
97
+
98
+ ```bash
99
+ node ./node_modules/korea-drilldown-svg-map/scripts/copy-boundaries.mjs ./public/boundaries
100
+ ```
101
+
102
+ ```tsx
103
+ import {
104
+ createAssetBoundaryLoaders,
105
+ loadRegionsMetadata,
106
+ } from "korea-drilldown-svg-map";
107
+
108
+ const loaders = createAssetBoundaryLoaders("/boundaries");
109
+ const metadata = await loadRegionsMetadata("/boundaries");
110
+ ```
111
+
112
+ ## 핵심 기능
113
+
114
+ ### 1. 선 굵기와 경계선 제어
115
+
116
+ `strokes`로 시도/시군구별 기본선, 선택선, hover 선을 조절할 수 있습니다.
117
+
118
+ ```tsx
119
+ <KoreaAdministrativeMap
120
+ strokes={{
121
+ borderColor: "#ffffff",
122
+ sido: {
123
+ base: 1.4,
124
+ selected: 2.4,
125
+ hover: 2.2,
126
+ scaleWithZoom: true,
127
+ zoomAttenuation: 0.68,
128
+ },
129
+ sgg: {
130
+ base: 0.9,
131
+ selected: 1.8,
132
+ hover: 1.6,
133
+ },
134
+ }}
135
+ />
136
+ ```
137
+
138
+ ### 2. 라벨 폰트, 크기, halo, 텍스트 포맷
139
+
140
+ `labelOptions`로 라벨 스타일과 텍스트를 제어합니다.
141
+
142
+ ```tsx
143
+ <KoreaAdministrativeMap
144
+ labelOptions={{
145
+ sido: {
146
+ fontFamily: "'IBM Plex Sans KR', sans-serif",
147
+ fontWeight: 700,
148
+ baseSize: 24,
149
+ halo: true,
150
+ haloWidth: 5.6,
151
+ formatter: (summary) => summary.name,
152
+ secondaryFormatter: (summary) => `${summary.sggCount}개 시군구`,
153
+ },
154
+ sgg: {
155
+ fontFamily: "'IBM Plex Sans KR', sans-serif",
156
+ baseSize: 13.5,
157
+ minZoom: 2.5,
158
+ halo: false,
159
+ formatter: (summary) => summary.name,
160
+ },
161
+ }}
162
+ />
163
+ ```
164
+
165
+ 주요 옵션:
166
+
167
+ - `fontFamily`, `fontWeight`
168
+ - `baseSize`, `sizeAttenuation`
169
+ - `fill`, `selectedFill`
170
+ - `halo`, `haloColor`, `haloWidth`
171
+ - `minZoom`
172
+ - `formatter`
173
+ - `secondaryFormatter`, `secondaryBaseSize`, `secondaryOffsetY`
174
+ - `offsets`로 특정 시도 라벨 위치 미세 조정
175
+
176
+ ### 3. 줌 제한과 드릴다운 깊이 제한
177
+
178
+ ```tsx
179
+ <KoreaAdministrativeMap
180
+ zoomOptions={{
181
+ minZoom: 1,
182
+ maxZoom: 13,
183
+ step: 0.8,
184
+ }}
185
+ drilldown={{
186
+ maxDepth: "sido",
187
+ }}
188
+ />
189
+ ```
190
+
191
+ `maxDepth: "sido"`면 시군구까지 내려가지 않고 시도 선택까지만 허용합니다.
192
+
193
+ ### 4. 지역별 색상화
194
+
195
+ 숫자 데이터를 지도 차트처럼 시각화하려면 `choropleth`를 사용합니다.
196
+
197
+ ```tsx
198
+ <KoreaAdministrativeMap
199
+ choropleth={{
200
+ enabled: true,
201
+ level: "current",
202
+ sidoValues: {
203
+ "11": 180,
204
+ "26": 110,
205
+ "41": 260,
206
+ },
207
+ sggValues: {
208
+ "41111": 48,
209
+ "41113": 67,
210
+ },
211
+ palette: ["#e0f2fe", "#7dd3fc", "#0284c7", "#0f4c81"],
212
+ showLegend: true,
213
+ legendTitle: "지표",
214
+ legendPosition: "top-right",
215
+ preserveSelectionFill: true,
216
+ formatValue: (value) => `${value.toLocaleString()}점`,
217
+ }}
218
+ />
219
+ ```
220
+
221
+ 지원 항목:
222
+
223
+ - `level: "sido" | "sgg" | "current"`
224
+ - `domain`으로 범위 고정
225
+ - `palette`
226
+ - `nullFill`
227
+ - `showLegend`
228
+ - `legendTitle`
229
+ - `legendDecimals`
230
+ - `legendPosition`
231
+ - `preserveSelectionFill`
232
+ - `formatValue`
233
+
234
+ ### 5. 정적 지역 색상 맵
235
+
236
+ 숫자 차트가 아니라 지역별로 임의 색을 직접 입히려면 `regionFills`를 사용합니다.
237
+
238
+ ```tsx
239
+ <KoreaAdministrativeMap
240
+ regionFills={{
241
+ enabled: true,
242
+ preserveSelectionFill: true,
243
+ sido: {
244
+ "11": "#dbeafe",
245
+ "26": "#fee2e2",
246
+ "41": "#dcfce7",
247
+ },
248
+ sgg: {
249
+ "41111": "#0ea5e9",
250
+ "41113": "#f97316",
251
+ },
252
+ }}
253
+ />
254
+ ```
255
+
256
+ `regionFills`와 `choropleth`를 동시에 줄 수도 있습니다. 이 경우 명시한 색상 맵이 먼저 적용되고, 나머지 영역은 choropleth가 채웁니다.
257
+
258
+ ### 6. Tooltip, legend, overlay
259
+
260
+ ```tsx
261
+ <KoreaAdministrativeMap
262
+ tooltip={{
263
+ enabled: true,
264
+ followCursor: false,
265
+ anchor: "bottom-left",
266
+ render: ({ level, summary, value }) => (
267
+ <div>
268
+ <strong>{summary.name}</strong>
269
+ <div>{level}</div>
270
+ <div>{value ?? "-"}</div>
271
+ </div>
272
+ ),
273
+ }}
274
+ renderOverlay={({ currentDepth, reset, stepBack }) => (
275
+ <div>
276
+ <div>{currentDepth}</div>
277
+ <button onClick={stepBack}>뒤로</button>
278
+ <button onClick={reset}>초기화</button>
279
+ </div>
280
+ )}
281
+ />
282
+ ```
283
+
284
+ `renderOverlay`가 받는 API:
285
+
286
+ - `selection`, `viewport`, `currentDepth`
287
+ - `selectedSido`, `selectedSgg`, `selectedSggList`
288
+ - `hoveredRegion`, `legendItems`
289
+ - `reset`, `stepBack`
290
+ - `zoomIn`, `zoomOut`
291
+ - `selectSido`, `selectSgg`, `setSelection`
292
+
293
+ ### 7. 완전 커스텀 렌더와 스타일 훅
294
+
295
+ 기본 라벨이나 지역 fill 규칙만으로 부족하면 직접 렌더링할 수 있습니다.
296
+
297
+ ```tsx
298
+ <KoreaAdministrativeMap
299
+ getSidoStyle={({ value, isSelected }) => ({
300
+ default: {
301
+ fill: isSelected ? "#2563eb" : value ? "#dbeafe" : "#e5e7eb",
302
+ },
303
+ })}
304
+ renderSggLabel={({ summary, value }) => (
305
+ <text textAnchor="middle" fontSize={11} fontWeight={700}>
306
+ {summary.name} {value ?? ""}
307
+ </text>
308
+ )}
309
+ />
310
+ ```
311
+
312
+ 사용 가능한 확장 포인트:
313
+
314
+ - `getSidoStyle`
315
+ - `getSggStyle`
316
+ - `renderSidoLabel`
317
+ - `renderSggLabel`
318
+ - `renderOverlay`
319
+ - `theme`
320
+ - `labels`
321
+
322
+ ### 8. 애니메이션과 컨트롤
323
+
324
+ ```tsx
325
+ <KoreaAdministrativeMap
326
+ showControls={false}
327
+ animations={{
328
+ enabled: true,
329
+ durationMs: 820,
330
+ }}
331
+ />
332
+ ```
333
+
334
+ ## 주요 props 요약
335
+
336
+ | prop | 설명 |
337
+ | --- | --- |
338
+ | `metadata` | `regions.json`에서 읽은 지역 메타데이터 |
339
+ | `loaders` | 경계 로더. 보통 `createBundledBoundaryLoaders()` 사용 |
340
+ | `selection`, `defaultSelection` | 제어형/비제어형 선택 상태 |
341
+ | `theme` | 지도 색상 및 overlay 테마 |
342
+ | `labels` | `loading`, `zoomIn`, `zoomOut`, `back` 텍스트 |
343
+ | `strokes` | 선 굵기와 경계선 색 |
344
+ | `labelOptions` | 라벨 폰트, 크기, halo, 포맷 |
345
+ | `zoomOptions` | 최소/최대 줌과 버튼 step |
346
+ | `drilldown` | 선택 depth 제한 |
347
+ | `choropleth` | 숫자 기반 지도 차트 |
348
+ | `regionFills` | 정적 지역별 색상 맵 |
349
+ | `tooltip` | hover tooltip 렌더와 위치 |
350
+ | `showControls` | 내장 확대/축소/뒤로 UI 표시 여부 |
351
+ | `animations` | 포커스 이동 애니메이션 설정 |
352
+ | `onSelectionChange` | 선택 변경 콜백 |
353
+ | `onHoverRegionChange` | hover 변경 콜백 |
354
+ | `renderOverlay` | 지도 위 임의 UI 렌더 |
355
+
356
+ ## 자산 헬퍼
357
+
358
+ - `createBundledBoundaryLoaders()`
359
+ - `loadBundledRegionsMetadata()`
360
+ - `createAssetBoundaryLoaders(basePath = "/boundaries")`
361
+ - `loadRegionsMetadata(basePath = "/boundaries")`
362
+ - `fetchBoundaryCollection(url)`
363
+ - `buildChoroplethLegendItems(...)`
364
+ - `resolveChoroplethDomain(...)`
365
+ - `getChoroplethColor(...)`
366
+
367
+ ## 예제 앱 실행
368
+
369
+ 저장소를 clone한 뒤 예제를 실행하면 패키지와 데모를 함께 검증할 수 있습니다.
370
+
371
+ ```bash
372
+ cd examples/vite-demo
373
+ pnpm install
374
+ pnpm dev
375
+ ```
376
+
377
+ 데모에서 바로 시험할 수 있는 항목:
378
+
379
+ - 시도/시군구 선 굵기
380
+ - 라벨 폰트, 폰트 굵기, 크기
381
+ - 라벨 halo on/off와 halo 두께
382
+ - 라벨 포맷터
383
+ - 시군구 라벨 최소 줌
384
+ - 줌 최소/최대값과 step
385
+ - 드릴다운 최대 depth
386
+ - 애니메이션 on/off와 duration
387
+ - choropleth, 정적 지역 색상, 혼합 모드
388
+ - legend 위치
389
+ - tooltip follow cursor, 고정 anchor
390
+
391
+ ## 경계 데이터 재생성
392
+
393
+ 전처리 문서는 `docs/boundary-preprocessing.md`에 있습니다.