@mint-ui/map 1.2.0-test.8 → 1.2.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/.eslintrc.js +11 -4
- package/.vscode/settings.json +32 -9
- package/dist/components/mint-map/core/MintMapController.d.ts +1 -0
- package/dist/components/mint-map/core/MintMapCore.js +5 -6
- package/dist/components/mint-map/core/advanced/CanvasMarkerLayer/CanvasMarkerLayer.d.ts +12 -0
- package/dist/components/mint-map/core/advanced/CanvasMarkerLayer/CanvasMarkerLayer.js +962 -0
- package/dist/components/mint-map/core/advanced/CanvasMarkerLayer/index.d.ts +4 -0
- package/dist/components/mint-map/core/advanced/CanvasMarkerLayer/types.d.ts +280 -0
- package/dist/components/mint-map/core/advanced/CanvasPolygonLayer/CanvasPolygonLayer.d.ts +17 -0
- package/dist/components/mint-map/core/advanced/CanvasPolygonLayer/CanvasPolygonLayer.js +624 -0
- package/dist/components/mint-map/core/advanced/CanvasPolygonLayer/index.d.ts +4 -0
- package/dist/components/mint-map/core/advanced/CanvasPolygonLayer/renderer.d.ts +303 -0
- package/dist/components/mint-map/core/advanced/CanvasPolygonLayer/renderer.js +1091 -0
- package/dist/components/mint-map/core/advanced/CanvasPolygonLayer/types.d.ts +284 -0
- package/dist/components/mint-map/core/advanced/canvas/CanvasMarker.d.ts +7 -0
- package/dist/components/mint-map/core/advanced/canvas/CanvasMarkerClaude.js +7 -7
- package/dist/components/mint-map/core/advanced/canvas/index.d.ts +0 -1
- package/dist/components/mint-map/core/advanced/index.d.ts +4 -2
- package/dist/components/mint-map/core/advanced/shared/context.d.ts +44 -0
- package/dist/components/mint-map/core/advanced/shared/context.js +230 -0
- package/dist/components/mint-map/core/advanced/shared/helpers.d.ts +20 -0
- package/dist/components/mint-map/core/advanced/shared/helpers.js +41 -0
- package/dist/components/mint-map/core/advanced/shared/hooks.d.ts +74 -0
- package/dist/components/mint-map/core/advanced/shared/hooks.js +196 -0
- package/dist/components/mint-map/core/advanced/{woongCanvas/shared → shared}/index.d.ts +5 -2
- package/dist/components/mint-map/core/advanced/shared/performance.d.ts +82 -0
- package/dist/components/mint-map/core/advanced/shared/performance.js +288 -0
- package/dist/components/mint-map/core/advanced/shared/types.d.ts +150 -0
- package/dist/components/mint-map/core/advanced/shared/types.js +31 -0
- package/dist/components/mint-map/core/advanced/shared/utils.d.ts +173 -0
- package/dist/components/mint-map/core/advanced/shared/utils.js +382 -0
- package/dist/components/mint-map/core/advanced/shared/viewport.d.ts +42 -0
- package/dist/components/mint-map/core/advanced/shared/viewport.js +52 -0
- package/dist/components/mint-map/core/wrapper/MapMarkerWrapper.js +22 -1
- package/dist/components/mint-map/google/GoogleMintMapController.d.ts +1 -0
- package/dist/components/mint-map/google/GoogleMintMapController.js +13 -8
- package/dist/components/mint-map/kakao/KakaoMintMapController.d.ts +1 -0
- package/dist/components/mint-map/kakao/KakaoMintMapController.js +13 -8
- package/dist/components/mint-map/naver/NaverMintMapController.d.ts +3 -0
- package/dist/components/mint-map/naver/NaverMintMapController.js +46 -11
- package/dist/index.es.js +5605 -4056
- package/dist/index.js +47 -27
- package/dist/index.umd.js +5621 -4059
- package/package.json +1 -1
- package/CLAUDE.md +0 -100
- package/dist/components/mint-map/core/advanced/canvas/CanvasMarkerHanquf.d.ts +0 -22
- package/dist/components/mint-map/core/advanced/canvas/CanvasMarkerHanquf.js +0 -413
- package/dist/components/mint-map/core/advanced/woongCanvas/ClusterMarker.d.ts +0 -11
- package/dist/components/mint-map/core/advanced/woongCanvas/WoongKonvaMarker.d.ts +0 -53
- package/dist/components/mint-map/core/advanced/woongCanvas/WoongKonvaMarker.js +0 -1123
- package/dist/components/mint-map/core/advanced/woongCanvas/index.d.ts +0 -3
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/context.d.ts +0 -31
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/context.js +0 -164
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/performance.d.ts +0 -161
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/performance.js +0 -343
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/types.d.ts +0 -131
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/types.js +0 -14
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.d.ts +0 -31
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.js +0 -164
- package/dist/components/mint-map/core/util/geohash.js +0 -125
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 이벤트 유효성 검증 및 좌표 변환
|
|
7
|
+
*
|
|
8
|
+
* @param event 이벤트 파라미터
|
|
9
|
+
* @param context CanvasContext 인스턴스
|
|
10
|
+
* @param controller MintMapController 인스턴스
|
|
11
|
+
* @returns 유효한 화면 좌표 또는 null
|
|
12
|
+
*/
|
|
13
|
+
var validateEvent = function (event, // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
+
context, controller) {
|
|
15
|
+
var _a;
|
|
16
|
+
|
|
17
|
+
if (context) return null;
|
|
18
|
+
if (!((_a = event === null || event === void 0 ? void 0 : event.param) === null || _a === void 0 ? void 0 : _a.position)) return null;
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
return controller.positionToOffset(event.param.position);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error('[CanvasLayer] validateEvent error:', error);
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Map의 values를 배열로 변환
|
|
29
|
+
*
|
|
30
|
+
* @template T Map 값의 타입
|
|
31
|
+
* @param map 변환할 Map
|
|
32
|
+
* @returns Map의 값 배열
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
var mapValuesToArray = function (map) {
|
|
36
|
+
if (map.size === 0) return [];
|
|
37
|
+
return Array.from(map.values());
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
exports.mapValuesToArray = mapValuesToArray;
|
|
41
|
+
exports.validateEvent = validateEvent;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { MutableRefObject } from 'react';
|
|
2
|
+
import type { SpatialHashGrid } from './performance';
|
|
3
|
+
import type { CanvasData } from './types';
|
|
4
|
+
import type { BoundingBox } from './viewport';
|
|
5
|
+
import type { Marker, MarkerOptions } from '../../../types';
|
|
6
|
+
import type { MintMapController } from '../../MintMapController';
|
|
7
|
+
/**
|
|
8
|
+
* 공통 이벤트 핸들러 의존성 인터페이스
|
|
9
|
+
*
|
|
10
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* 지도 이벤트 핸들러 생성 시 필요한 모든 의존성을 포함합니다.
|
|
14
|
+
*/
|
|
15
|
+
export interface EventHandlerDeps<T> {
|
|
16
|
+
boundingBoxCacheRef: MutableRefObject<Map<string, BoundingBox>>;
|
|
17
|
+
accumTranslateRef: MutableRefObject<{
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
}>;
|
|
21
|
+
containerRef: MutableRefObject<HTMLDivElement | null>;
|
|
22
|
+
controller: MintMapController;
|
|
23
|
+
markerRef: MutableRefObject<Marker | undefined>;
|
|
24
|
+
clearCache: () => void;
|
|
25
|
+
options: Pick<MarkerOptions, 'anchor' | 'visible' | 'zIndex'>;
|
|
26
|
+
prevCenterOffsetRef: MutableRefObject<{
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
} | null>;
|
|
30
|
+
renderAllImmediate: () => void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 지도 이벤트 핸들러 생성 함수
|
|
34
|
+
*
|
|
35
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
36
|
+
* @param deps 이벤트 핸들러 생성에 필요한 의존성
|
|
37
|
+
* @returns 지도 이벤트 핸들러 객체
|
|
38
|
+
*/
|
|
39
|
+
export declare const createMapEventHandlers: <T>(deps: EventHandlerDeps<T>) => {
|
|
40
|
+
handleCenterChanged: () => void;
|
|
41
|
+
handleDragEnd: () => void;
|
|
42
|
+
handleDragStart: () => void;
|
|
43
|
+
handleIdle: () => void;
|
|
44
|
+
handleZoomEnd: () => void;
|
|
45
|
+
handleZoomStart: () => void;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* 공간 인덱스 빌드 (빠른 Hit Test를 위한 자료구조)
|
|
49
|
+
*
|
|
50
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
51
|
+
* @param data 공간 인덱스에 삽입할 데이터 배열
|
|
52
|
+
* @param spatialIndex Spatial Hash Grid 인스턴스
|
|
53
|
+
* @param computeBoundingBox 바운딩 박스 계산 함수
|
|
54
|
+
*/
|
|
55
|
+
export declare const buildSpatialIndex: <T>(data: CanvasData<T>[], spatialIndex: SpatialHashGrid<CanvasData<T>>, computeBoundingBox: (item: CanvasData<T>) => BoundingBox | null) => void;
|
|
56
|
+
/**
|
|
57
|
+
* 선택 상태 동기화 (화면 밖 데이터도 선택 상태 유지)
|
|
58
|
+
*
|
|
59
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
60
|
+
* @param data 최신 데이터 배열
|
|
61
|
+
* @param selectedIds 선택된 항목 ID Set
|
|
62
|
+
* @param selectedItemsMap 현재 선택된 항목 Map
|
|
63
|
+
* @returns 업데이트된 선택된 항목 Map
|
|
64
|
+
*/
|
|
65
|
+
export declare const syncSelectedItems: <T>(data: CanvasData<T>[], selectedIds: Set<string>, selectedItemsMap: Map<string, CanvasData<T>>) => Map<string, CanvasData<T>>;
|
|
66
|
+
/**
|
|
67
|
+
* 외부 selectedItems를 내부 상태로 동기화
|
|
68
|
+
*
|
|
69
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
70
|
+
* @param externalSelectedItems 외부에서 전달된 선택된 항목 배열
|
|
71
|
+
* @param selectedIdsRef 선택된 ID Set ref
|
|
72
|
+
* @param selectedItemsMapRef 선택된 항목 Map ref
|
|
73
|
+
*/
|
|
74
|
+
export declare const syncExternalSelectedItems: <T>(externalSelectedItems: CanvasData<T>[] | undefined, selectedIdsRef: MutableRefObject<Set<string>>, selectedItemsMapRef: MutableRefObject<Map<string, CanvasData<T>>>) => void;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var tslib = require('tslib');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 지도 이벤트 핸들러 생성 함수
|
|
9
|
+
*
|
|
10
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
11
|
+
* @param deps 이벤트 핸들러 생성에 필요한 의존성
|
|
12
|
+
* @returns 지도 이벤트 핸들러 객체
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/* eslint-disable no-restricted-syntax */
|
|
16
|
+
|
|
17
|
+
var createMapEventHandlers = function (deps) {
|
|
18
|
+
var accumTranslateRef = deps.accumTranslateRef,
|
|
19
|
+
boundingBoxCacheRef = deps.boundingBoxCacheRef,
|
|
20
|
+
clearCache = deps.clearCache,
|
|
21
|
+
containerRef = deps.containerRef,
|
|
22
|
+
controller = deps.controller,
|
|
23
|
+
markerRef = deps.markerRef,
|
|
24
|
+
options = deps.options,
|
|
25
|
+
prevCenterOffsetRef = deps.prevCenterOffsetRef,
|
|
26
|
+
renderAllImmediate = deps.renderAllImmediate; // 지도 이동/줌 완료 시 처리 (캐시 초기화 및 렌더링)
|
|
27
|
+
|
|
28
|
+
var handleIdle = function () {
|
|
29
|
+
prevCenterOffsetRef.current = null;
|
|
30
|
+
accumTranslateRef.current = {
|
|
31
|
+
x: 0,
|
|
32
|
+
y: 0
|
|
33
|
+
}; // 캐시 정리 (지도 이동/줌으로 좌표 변환 결과가 바뀜)
|
|
34
|
+
|
|
35
|
+
clearCache();
|
|
36
|
+
boundingBoxCacheRef.current.clear(); // 마커 위치 업데이트
|
|
37
|
+
|
|
38
|
+
var bounds = controller.getCurrBounds();
|
|
39
|
+
|
|
40
|
+
var markerOptions = tslib.__assign(tslib.__assign({}, options), {
|
|
41
|
+
position: bounds.nw
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (markerRef.current) {
|
|
45
|
+
controller.updateMarker(markerRef.current, markerOptions);
|
|
46
|
+
} // transform 제거 전에 새 데이터로 즉시 렌더링 (transform 제거 시 잠깐 빈 화면이 보이는 것 방지)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if (containerRef.current) {
|
|
50
|
+
containerRef.current.style.transform = '';
|
|
51
|
+
containerRef.current.style.visibility = '';
|
|
52
|
+
} // 새 위치에서 렌더링 (캐시는 이미 초기화됨)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
renderAllImmediate();
|
|
56
|
+
}; // 줌 시작 시 처리 (일시적으로 숨김)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
var handleZoomStart = function () {
|
|
60
|
+
if (!containerRef.current) return;
|
|
61
|
+
containerRef.current.style.visibility = 'hidden';
|
|
62
|
+
}; // 줌 종료 시 처리 (다시 표시)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
var handleZoomEnd = function () {
|
|
66
|
+
if (!containerRef.current) return;
|
|
67
|
+
containerRef.current.style.visibility = '';
|
|
68
|
+
}; // 지도 중심 변경 시 처리 (transform으로 이동 추적, 캐시 유지)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
var handleCenterChanged = function () {
|
|
72
|
+
var center = controller.getCurrBounds().getCenter();
|
|
73
|
+
var curr = controller.positionToOffset(center);
|
|
74
|
+
var prev = prevCenterOffsetRef.current; // 첫 번째 호출 시 이전 위치 저장만 하고 종료
|
|
75
|
+
|
|
76
|
+
if (!prev) {
|
|
77
|
+
prevCenterOffsetRef.current = {
|
|
78
|
+
x: curr.x,
|
|
79
|
+
y: curr.y
|
|
80
|
+
};
|
|
81
|
+
return;
|
|
82
|
+
} // 이전 위치와 현재 위치의 차이 계산 (이동 거리)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
var dx = prev.x - curr.x;
|
|
86
|
+
var dy = prev.y - curr.y; // 누적 이동 거리 저장 (transform으로 화면만 이동, 캐시는 유지하여 성능 최적화)
|
|
87
|
+
|
|
88
|
+
accumTranslateRef.current = {
|
|
89
|
+
x: accumTranslateRef.current.x + dx,
|
|
90
|
+
y: accumTranslateRef.current.y + dy
|
|
91
|
+
};
|
|
92
|
+
prevCenterOffsetRef.current = {
|
|
93
|
+
x: curr.x,
|
|
94
|
+
y: curr.y
|
|
95
|
+
}; // CSS transform으로 컨테이너 이동 (캐시된 좌표는 그대로 유지)
|
|
96
|
+
|
|
97
|
+
if (containerRef.current) {
|
|
98
|
+
containerRef.current.style.transform = "translate(".concat(accumTranslateRef.current.x, "px, ").concat(accumTranslateRef.current.y, "px)");
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
var handleDragStart = function () {// 커서는 각 컴포넌트에서 처리
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
var handleDragEnd = function () {// 커서는 각 컴포넌트에서 처리
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
handleCenterChanged: handleCenterChanged,
|
|
110
|
+
handleDragEnd: handleDragEnd,
|
|
111
|
+
handleDragStart: handleDragStart,
|
|
112
|
+
handleIdle: handleIdle,
|
|
113
|
+
handleZoomEnd: handleZoomEnd,
|
|
114
|
+
handleZoomStart: handleZoomStart
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* 공간 인덱스 빌드 (빠른 Hit Test를 위한 자료구조)
|
|
119
|
+
*
|
|
120
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
121
|
+
* @param data 공간 인덱스에 삽입할 데이터 배열
|
|
122
|
+
* @param spatialIndex Spatial Hash Grid 인스턴스
|
|
123
|
+
* @param computeBoundingBox 바운딩 박스 계산 함수
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
var buildSpatialIndex = function (data, spatialIndex, computeBoundingBox) {
|
|
127
|
+
spatialIndex.clear();
|
|
128
|
+
|
|
129
|
+
for (var _i = 0, data_1 = data; _i < data_1.length; _i++) {
|
|
130
|
+
var item = data_1[_i];
|
|
131
|
+
var bbox = computeBoundingBox(item);
|
|
132
|
+
|
|
133
|
+
if (bbox) {
|
|
134
|
+
spatialIndex.insert(item, bbox.minX, bbox.minY, bbox.maxX, bbox.maxY);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* 선택 상태 동기화 (화면 밖 데이터도 선택 상태 유지)
|
|
140
|
+
*
|
|
141
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
142
|
+
* @param data 최신 데이터 배열
|
|
143
|
+
* @param selectedIds 선택된 항목 ID Set
|
|
144
|
+
* @param selectedItemsMap 현재 선택된 항목 Map
|
|
145
|
+
* @returns 업데이트된 선택된 항목 Map
|
|
146
|
+
*/
|
|
147
|
+
|
|
148
|
+
var syncSelectedItems = function (data, selectedIds, selectedItemsMap) {
|
|
149
|
+
var dataMap = new Map(data.map(function (m) {
|
|
150
|
+
return [m.id, m];
|
|
151
|
+
}));
|
|
152
|
+
var newSelectedItemsMap = new Map();
|
|
153
|
+
selectedIds.forEach(function (id) {
|
|
154
|
+
// 현재 data에 있으면 최신 데이터 사용
|
|
155
|
+
var currentItem = dataMap.get(id);
|
|
156
|
+
|
|
157
|
+
if (currentItem) {
|
|
158
|
+
newSelectedItemsMap.set(id, currentItem);
|
|
159
|
+
} else {
|
|
160
|
+
// 화면 밖이면 기존 데이터 유지
|
|
161
|
+
var prevItem = selectedItemsMap.get(id);
|
|
162
|
+
|
|
163
|
+
if (prevItem) {
|
|
164
|
+
newSelectedItemsMap.set(id, prevItem);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
return newSelectedItemsMap;
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* 외부 selectedItems를 내부 상태로 동기화
|
|
172
|
+
*
|
|
173
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
174
|
+
* @param externalSelectedItems 외부에서 전달된 선택된 항목 배열
|
|
175
|
+
* @param selectedIdsRef 선택된 ID Set ref
|
|
176
|
+
* @param selectedItemsMapRef 선택된 항목 Map ref
|
|
177
|
+
*/
|
|
178
|
+
|
|
179
|
+
var syncExternalSelectedItems = function (externalSelectedItems, selectedIdsRef, selectedItemsMapRef) {
|
|
180
|
+
if (externalSelectedItems === undefined) return;
|
|
181
|
+
var newSelectedIds = new Set();
|
|
182
|
+
var newSelectedItemsMap = new Map();
|
|
183
|
+
externalSelectedItems.forEach(function (item) {
|
|
184
|
+
newSelectedIds.add(item.id);
|
|
185
|
+
newSelectedItemsMap.set(item.id, item);
|
|
186
|
+
}); // eslint-disable-next-line no-param-reassign
|
|
187
|
+
|
|
188
|
+
selectedIdsRef.current = newSelectedIds; // eslint-disable-next-line no-param-reassign
|
|
189
|
+
|
|
190
|
+
selectedItemsMapRef.current = newSelectedItemsMap;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
exports.buildSpatialIndex = buildSpatialIndex;
|
|
194
|
+
exports.createMapEventHandlers = createMapEventHandlers;
|
|
195
|
+
exports.syncExternalSelectedItems = syncExternalSelectedItems;
|
|
196
|
+
exports.syncSelectedItems = syncSelectedItems;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 공간 인덱스 그리드 셀 크기 (픽셀 단위)
|
|
3
|
+
*
|
|
4
|
+
* @default 200
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* 셀 크기는 평균 마커 크기의 1.5~2배가 적절합니다.
|
|
8
|
+
* - 마커가 50px 이하: 50px 권장
|
|
9
|
+
* - 마커가 60-80px: 100px 권장
|
|
10
|
+
* - 마커가 100px 이상: 150-200px 권장 (현재 설정)
|
|
11
|
+
*
|
|
12
|
+
* 셀 크기가 너무 작으면:
|
|
13
|
+
* - 한 마커가 여러 셀에 등록되어 메모리 사용량 증가
|
|
14
|
+
* - 인덱스 빌드 비용 증가
|
|
15
|
+
*
|
|
16
|
+
* 셀 크기가 너무 크면:
|
|
17
|
+
* - 한 셀에 많은 마커가 들어가서 Hit Test 시 후보 항목이 많아짐
|
|
18
|
+
* - Hit Test 성능 저하
|
|
19
|
+
*/
|
|
20
|
+
export declare const SPATIAL_GRID_CELL_SIZE = 200;
|
|
21
|
+
/**
|
|
22
|
+
* 뷰포트 컬링 여유 공간 (픽셀 단위)
|
|
23
|
+
*
|
|
24
|
+
* @default 100
|
|
25
|
+
*/
|
|
26
|
+
export declare const DEFAULT_CULLING_MARGIN = 100;
|
|
27
|
+
/**
|
|
28
|
+
* Queue 캐시 최대 항목 수
|
|
29
|
+
*
|
|
30
|
+
* @default 30000
|
|
31
|
+
*/
|
|
32
|
+
export declare const DEFAULT_MAX_CACHE_SIZE = 30000;
|
|
33
|
+
/**
|
|
34
|
+
* Queue Cache (FIFO - First In First Out)
|
|
35
|
+
*
|
|
36
|
+
* 좌표 변환 결과를 캐싱하기 위한 캐시 구현
|
|
37
|
+
* FIFO 방식으로 가장 먼저 저장된 항목부터 제거합니다.
|
|
38
|
+
*
|
|
39
|
+
* @template K 캐시 키 타입
|
|
40
|
+
* @template V 캐시 값 타입
|
|
41
|
+
*/
|
|
42
|
+
export declare class QueueCache<K, V> {
|
|
43
|
+
private cache;
|
|
44
|
+
private maxSize;
|
|
45
|
+
constructor(maxSize?: number);
|
|
46
|
+
get(key: K): V | undefined;
|
|
47
|
+
set(key: K, value: V): void;
|
|
48
|
+
clear(): void;
|
|
49
|
+
size(): number;
|
|
50
|
+
has(key: K): boolean;
|
|
51
|
+
getAllKeys(): K[];
|
|
52
|
+
getAllEntries(): Array<[K, V]>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Spatial Hash Grid (공간 해시 그리드)
|
|
56
|
+
*
|
|
57
|
+
* 빠른 Hit Test를 위한 그리드 기반 공간 인덱싱 자료구조
|
|
58
|
+
*
|
|
59
|
+
* @template T 인덱싱할 항목 타입
|
|
60
|
+
*/
|
|
61
|
+
export declare class SpatialHashGrid<T> {
|
|
62
|
+
private cellSize;
|
|
63
|
+
private grid;
|
|
64
|
+
private itemToCells;
|
|
65
|
+
constructor(cellSize?: number);
|
|
66
|
+
private getCellKey;
|
|
67
|
+
private getCellsForBounds;
|
|
68
|
+
insert(item: T, minX: number, minY: number, maxX: number, maxY: number): void;
|
|
69
|
+
remove(item: T): void;
|
|
70
|
+
update(item: T, minX: number, minY: number, maxX: number, maxY: number): void;
|
|
71
|
+
queryPoint(x: number, y: number): T[];
|
|
72
|
+
queryBounds(minX: number, minY: number, maxX: number, maxY: number): T[];
|
|
73
|
+
has(item: T): boolean;
|
|
74
|
+
clear(): void;
|
|
75
|
+
stats(): {
|
|
76
|
+
avgItemsPerCell: number;
|
|
77
|
+
totalCells: number;
|
|
78
|
+
totalItems: number;
|
|
79
|
+
};
|
|
80
|
+
getAllCells(): Map<string, T[]>;
|
|
81
|
+
getCellItems(cellKey: string): T[];
|
|
82
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
/* eslint-disable max-classes-per-file */
|
|
6
|
+
|
|
7
|
+
/* eslint-disable no-restricted-syntax */
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 공간 인덱스 그리드 셀 크기 (픽셀 단위)
|
|
11
|
+
*
|
|
12
|
+
* @default 200
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* 셀 크기는 평균 마커 크기의 1.5~2배가 적절합니다.
|
|
16
|
+
* - 마커가 50px 이하: 50px 권장
|
|
17
|
+
* - 마커가 60-80px: 100px 권장
|
|
18
|
+
* - 마커가 100px 이상: 150-200px 권장 (현재 설정)
|
|
19
|
+
*
|
|
20
|
+
* 셀 크기가 너무 작으면:
|
|
21
|
+
* - 한 마커가 여러 셀에 등록되어 메모리 사용량 증가
|
|
22
|
+
* - 인덱스 빌드 비용 증가
|
|
23
|
+
*
|
|
24
|
+
* 셀 크기가 너무 크면:
|
|
25
|
+
* - 한 셀에 많은 마커가 들어가서 Hit Test 시 후보 항목이 많아짐
|
|
26
|
+
* - Hit Test 성능 저하
|
|
27
|
+
*/
|
|
28
|
+
var SPATIAL_GRID_CELL_SIZE = 200;
|
|
29
|
+
/**
|
|
30
|
+
* 뷰포트 컬링 여유 공간 (픽셀 단위)
|
|
31
|
+
*
|
|
32
|
+
* @default 100
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
var DEFAULT_CULLING_MARGIN = 100;
|
|
36
|
+
/**
|
|
37
|
+
* Queue 캐시 최대 항목 수
|
|
38
|
+
*
|
|
39
|
+
* @default 30000
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
var DEFAULT_MAX_CACHE_SIZE = 30000;
|
|
43
|
+
/**
|
|
44
|
+
* Queue Cache (FIFO - First In First Out)
|
|
45
|
+
*
|
|
46
|
+
* 좌표 변환 결과를 캐싱하기 위한 캐시 구현
|
|
47
|
+
* FIFO 방식으로 가장 먼저 저장된 항목부터 제거합니다.
|
|
48
|
+
*
|
|
49
|
+
* @template K 캐시 키 타입
|
|
50
|
+
* @template V 캐시 값 타입
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
var QueueCache =
|
|
54
|
+
/** @class */
|
|
55
|
+
function () {
|
|
56
|
+
function QueueCache(maxSize) {
|
|
57
|
+
if (maxSize === void 0) {
|
|
58
|
+
maxSize = 10000;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.cache = new Map();
|
|
62
|
+
this.maxSize = maxSize;
|
|
63
|
+
} // 캐시에서 값 조회
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
QueueCache.prototype.get = function (key) {
|
|
67
|
+
return this.cache.get(key);
|
|
68
|
+
}; // 캐시에 값 저장 (FIFO eviction)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
QueueCache.prototype.set = function (key, value) {
|
|
72
|
+
var exists = this.cache.has(key);
|
|
73
|
+
|
|
74
|
+
if (exists) {
|
|
75
|
+
this.cache.set(key, value);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (this.cache.size >= this.maxSize) {
|
|
80
|
+
var firstKey = this.cache.keys().next().value;
|
|
81
|
+
|
|
82
|
+
if (firstKey !== undefined) {
|
|
83
|
+
this.cache.delete(firstKey);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
this.cache.set(key, value);
|
|
88
|
+
}; // 캐시 초기화
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
QueueCache.prototype.clear = function () {
|
|
92
|
+
this.cache.clear();
|
|
93
|
+
}; // 캐시 크기 반환
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
QueueCache.prototype.size = function () {
|
|
97
|
+
return this.cache.size;
|
|
98
|
+
}; // 키 존재 여부 확인
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
QueueCache.prototype.has = function (key) {
|
|
102
|
+
return this.cache.has(key);
|
|
103
|
+
}; // 모든 캐시 키 반환 (디버깅/모니터링용)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
QueueCache.prototype.getAllKeys = function () {
|
|
107
|
+
return Array.from(this.cache.keys());
|
|
108
|
+
}; // 모든 캐시 항목 반환 (디버깅/모니터링용)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
QueueCache.prototype.getAllEntries = function () {
|
|
112
|
+
return Array.from(this.cache.entries());
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
return QueueCache;
|
|
116
|
+
}();
|
|
117
|
+
/**
|
|
118
|
+
* Spatial Hash Grid (공간 해시 그리드)
|
|
119
|
+
*
|
|
120
|
+
* 빠른 Hit Test를 위한 그리드 기반 공간 인덱싱 자료구조
|
|
121
|
+
*
|
|
122
|
+
* @template T 인덱싱할 항목 타입
|
|
123
|
+
*/
|
|
124
|
+
|
|
125
|
+
var SpatialHashGrid =
|
|
126
|
+
/** @class */
|
|
127
|
+
function () {
|
|
128
|
+
function SpatialHashGrid(cellSize) {
|
|
129
|
+
if (cellSize === void 0) {
|
|
130
|
+
cellSize = SPATIAL_GRID_CELL_SIZE;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
this.cellSize = cellSize;
|
|
134
|
+
this.grid = new Map();
|
|
135
|
+
this.itemToCells = new Map();
|
|
136
|
+
} // 셀 키 생성 (x, y 좌표 → 그리드 셀 ID)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
SpatialHashGrid.prototype.getCellKey = function (x, y) {
|
|
140
|
+
// 좌표를 셀 크기로 나눈 몫으로 셀 인덱스 계산
|
|
141
|
+
var cellX = Math.floor(x / this.cellSize);
|
|
142
|
+
var cellY = Math.floor(y / this.cellSize);
|
|
143
|
+
return "".concat(cellX, ",").concat(cellY);
|
|
144
|
+
}; // 바운딩 박스가 걸치는 모든 셀 키 배열 반환
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
SpatialHashGrid.prototype.getCellsForBounds = function (minX, minY, maxX, maxY) {
|
|
148
|
+
var cells = []; // 바운딩 박스가 걸치는 셀 범위 계산
|
|
149
|
+
|
|
150
|
+
var startCellX = Math.floor(minX / this.cellSize);
|
|
151
|
+
var startCellY = Math.floor(minY / this.cellSize);
|
|
152
|
+
var endCellX = Math.floor(maxX / this.cellSize);
|
|
153
|
+
var endCellY = Math.floor(maxY / this.cellSize); // 바운딩 박스가 걸치는 모든 셀을 배열에 추가
|
|
154
|
+
|
|
155
|
+
for (var x = startCellX; x <= endCellX; x++) {
|
|
156
|
+
for (var y = startCellY; y <= endCellY; y++) {
|
|
157
|
+
cells.push("".concat(x, ",").concat(y));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return cells;
|
|
162
|
+
}; // 항목 추가 (바운딩 박스 기반, 중복 삽입 방지)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
SpatialHashGrid.prototype.insert = function (item, minX, minY, maxX, maxY) {
|
|
166
|
+
// 기존 항목 제거 (중복 삽입 방지: 같은 항목을 여러 번 insert 해도 안전)
|
|
167
|
+
this.remove(item); // 바운딩 박스가 걸치는 모든 셀에 항목 등록
|
|
168
|
+
|
|
169
|
+
var cells = this.getCellsForBounds(minX, minY, maxX, maxY);
|
|
170
|
+
this.itemToCells.set(item, cells); // 항목과 셀의 매핑 저장 (제거 시 필요)
|
|
171
|
+
|
|
172
|
+
for (var _i = 0, cells_1 = cells; _i < cells_1.length; _i++) {
|
|
173
|
+
var cell = cells_1[_i];
|
|
174
|
+
|
|
175
|
+
if (!this.grid.has(cell)) {
|
|
176
|
+
this.grid.set(cell, []);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
this.grid.get(cell).push(item);
|
|
180
|
+
}
|
|
181
|
+
}; // 항목 제거 (모든 셀에서 참조 제거)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
SpatialHashGrid.prototype.remove = function (item) {
|
|
185
|
+
var prevCells = this.itemToCells.get(item);
|
|
186
|
+
if (!prevCells) return; // 항목이 등록된 모든 셀에서 참조 제거 (메모리 누수 방지)
|
|
187
|
+
|
|
188
|
+
for (var _i = 0, prevCells_1 = prevCells; _i < prevCells_1.length; _i++) {
|
|
189
|
+
var cell = prevCells_1[_i];
|
|
190
|
+
var cellItems = this.grid.get(cell);
|
|
191
|
+
|
|
192
|
+
if (cellItems) {
|
|
193
|
+
var index = cellItems.indexOf(item);
|
|
194
|
+
|
|
195
|
+
if (index !== -1) {
|
|
196
|
+
cellItems.splice(index, 1);
|
|
197
|
+
} // 빈 셀 정리 (메모리 효율: 사용하지 않는 셀 제거)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
if (cellItems.length === 0) {
|
|
201
|
+
this.grid.delete(cell);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
} // 항목과 셀의 매핑 제거
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
this.itemToCells.delete(item);
|
|
208
|
+
}; // 항목 위치 업데이트 (remove + insert)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
SpatialHashGrid.prototype.update = function (item, minX, minY, maxX, maxY) {
|
|
212
|
+
this.insert(item, minX, minY, maxX, maxY);
|
|
213
|
+
}; // 점 주변의 항목 조회 (Hit Test용)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
SpatialHashGrid.prototype.queryPoint = function (x, y) {
|
|
217
|
+
// 클릭 위치가 속한 셀의 모든 항목 조회 (O(1) 수준의 빠른 조회)
|
|
218
|
+
var cellKey = this.getCellKey(x, y);
|
|
219
|
+
var items = this.grid.get(cellKey); // 빈 배열 재사용 (메모리 할당 최소화)
|
|
220
|
+
|
|
221
|
+
return items || [];
|
|
222
|
+
}; // 영역 내 항목 조회 (Viewport Culling용)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
SpatialHashGrid.prototype.queryBounds = function (minX, minY, maxX, maxY) {
|
|
226
|
+
// 영역이 걸치는 모든 셀 찾기
|
|
227
|
+
var cells = this.getCellsForBounds(minX, minY, maxX, maxY);
|
|
228
|
+
var results = new Set(); // 중복 제거를 위해 Set 사용
|
|
229
|
+
// 각 셀의 모든 항목을 결과에 추가
|
|
230
|
+
|
|
231
|
+
for (var _i = 0, cells_2 = cells; _i < cells_2.length; _i++) {
|
|
232
|
+
var cell = cells_2[_i];
|
|
233
|
+
var items = this.grid.get(cell);
|
|
234
|
+
|
|
235
|
+
if (items) {
|
|
236
|
+
for (var _a = 0, items_1 = items; _a < items_1.length; _a++) {
|
|
237
|
+
var item = items_1[_a];
|
|
238
|
+
results.add(item); // Set이므로 중복 자동 제거
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return Array.from(results);
|
|
244
|
+
}; // 항목 존재 여부 확인
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
SpatialHashGrid.prototype.has = function (item) {
|
|
248
|
+
return this.itemToCells.has(item);
|
|
249
|
+
}; // 전체 초기화
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
SpatialHashGrid.prototype.clear = function () {
|
|
253
|
+
this.grid.clear();
|
|
254
|
+
this.itemToCells.clear();
|
|
255
|
+
}; // 통계 정보 반환
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
SpatialHashGrid.prototype.stats = function () {
|
|
259
|
+
var totalCellItems = 0;
|
|
260
|
+
this.grid.forEach(function (items) {
|
|
261
|
+
totalCellItems += items.length;
|
|
262
|
+
});
|
|
263
|
+
return {
|
|
264
|
+
// 고유 항목 수 (정확)
|
|
265
|
+
avgItemsPerCell: this.grid.size > 0 ? totalCellItems / this.grid.size : 0,
|
|
266
|
+
totalCells: this.grid.size,
|
|
267
|
+
totalItems: this.itemToCells.size
|
|
268
|
+
};
|
|
269
|
+
}; // 모든 그리드 셀 데이터 반환 (디버깅/모니터링용)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
SpatialHashGrid.prototype.getAllCells = function () {
|
|
273
|
+
return new Map(this.grid);
|
|
274
|
+
}; // 특정 셀의 항목 조회
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
SpatialHashGrid.prototype.getCellItems = function (cellKey) {
|
|
278
|
+
return this.grid.get(cellKey) || [];
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
return SpatialHashGrid;
|
|
282
|
+
}();
|
|
283
|
+
|
|
284
|
+
exports.DEFAULT_CULLING_MARGIN = DEFAULT_CULLING_MARGIN;
|
|
285
|
+
exports.DEFAULT_MAX_CACHE_SIZE = DEFAULT_MAX_CACHE_SIZE;
|
|
286
|
+
exports.QueueCache = QueueCache;
|
|
287
|
+
exports.SPATIAL_GRID_CELL_SIZE = SPATIAL_GRID_CELL_SIZE;
|
|
288
|
+
exports.SpatialHashGrid = SpatialHashGrid;
|