@mint-ui/map 1.2.0-test.11 → 1.2.0-test.12
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/components/mint-map/core/MintMapCore.js +1 -2
- package/dist/components/mint-map/core/advanced/woongCanvas/WoongCanvasLayer.d.ts +76 -7
- package/dist/components/mint-map/core/advanced/woongCanvas/WoongCanvasLayer.js +99 -53
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/types.d.ts +95 -1
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.d.ts +16 -0
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.js +24 -0
- package/dist/components/mint-map/google/GoogleMintMapController.js +1 -0
- package/dist/components/mint-map/kakao/KakaoMintMapController.js +1 -0
- package/dist/components/mint-map/naver/NaverMintMapController.js +1 -0
- package/dist/index.es.js +123 -54
- package/dist/index.js +1 -0
- package/dist/index.umd.js +123 -53
- package/package.json +1 -1
- package/dist/components/mint-map/core/advanced/woongCanvas/ClusterMarker.d.ts +0 -11
|
@@ -9,8 +9,7 @@ var MapTypes = require('../types/MapTypes.js');
|
|
|
9
9
|
var MintMapProvider = require('./provider/MintMapProvider.js');
|
|
10
10
|
var MintMapCore_module = require('./MintMapCore.module.scss.js');
|
|
11
11
|
require('./advanced/woongCanvas/shared/types.js');
|
|
12
|
-
require('
|
|
13
|
-
require('../types/MapEventTypes.js');
|
|
12
|
+
require('./advanced/woongCanvas/shared/utils.js');
|
|
14
13
|
var context = require('./advanced/woongCanvas/shared/context.js');
|
|
15
14
|
require('./advanced/woongCanvas/shared/performance.js');
|
|
16
15
|
|
|
@@ -7,8 +7,8 @@ export type { KonvaCanvasMarkerOption, Paths, KonvaCanvasMarkerData, CustomRende
|
|
|
7
7
|
* 공통 Props (MARKER와 POLYGON 모두 사용)
|
|
8
8
|
*/
|
|
9
9
|
interface WoongCanvasLayerBaseProps<T> extends Pick<MarkerOptions, 'zIndex' | 'anchor' | 'visible'> {
|
|
10
|
-
/** 렌더링할
|
|
11
|
-
|
|
10
|
+
/** 렌더링할 데이터 배열 (마커 또는 폴리곤) */
|
|
11
|
+
data: KonvaCanvasMarkerData<T>[];
|
|
12
12
|
/** 마커 클릭 시 호출되는 콜백 (선택) */
|
|
13
13
|
onClick?: (payload: KonvaCanvasMarkerData<T>, selectedIds: Set<string>) => void;
|
|
14
14
|
/** 마커에 마우스 오버 시 호출되는 콜백 (선택) */
|
|
@@ -81,13 +81,82 @@ interface WoongCanvasLayerPropsForPolygon<T> extends WoongCanvasLayerBaseProps<T
|
|
|
81
81
|
*/
|
|
82
82
|
export declare type WoongCanvasLayerProps<T> = WoongCanvasLayerPropsForMarker<T> | WoongCanvasLayerPropsForPolygon<T>;
|
|
83
83
|
/**
|
|
84
|
-
*
|
|
84
|
+
* 🚀 WoongCanvasLayer - Konva 기반 초고성능 마커/폴리곤 렌더링 컴포넌트
|
|
85
85
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
86
|
+
* ## 📌 주요 특징
|
|
87
|
+
* - **30,000개 이상의 폴리곤/마커를 60fps로 렌더링**
|
|
88
|
+
* - **Multi-Layer 아키텍처**: Base/Animation/Event 레이어 분리
|
|
89
|
+
* - **Spatial Hash Grid**: O(1) 수준의 빠른 Hit Test
|
|
90
|
+
* - **LRU 캐시**: 좌표 변환 결과 캐싱으로 성능 최적화
|
|
91
|
+
* - **Viewport Culling**: 화면에 보이는 영역만 렌더링
|
|
92
|
+
* - **Discriminated Union Props**: 타입 안전한 MARKER/POLYGON 모드
|
|
89
93
|
*
|
|
90
|
-
*
|
|
94
|
+
* ## 🎯 사용 방법
|
|
95
|
+
*
|
|
96
|
+
* ### 1️⃣ POLYGON 모드 (자동 렌더링)
|
|
97
|
+
* ```tsx
|
|
98
|
+
* <WoongCanvasLayer
|
|
99
|
+
* dataType={CanvasDataType.POLYGON}
|
|
100
|
+
* data={polygons}
|
|
101
|
+
* baseFillColor="rgba(255, 100, 100, 0.5)"
|
|
102
|
+
* baseStrokeColor="rgba(200, 50, 50, 0.8)"
|
|
103
|
+
* baseLineWidth={2}
|
|
104
|
+
* selectedFillColor="rgba(255, 193, 7, 0.7)"
|
|
105
|
+
* selectedStrokeColor="rgba(255, 152, 0, 1)"
|
|
106
|
+
* selectedLineWidth={4}
|
|
107
|
+
* hoveredFillColor="rgba(100, 150, 255, 0.8)" // optional
|
|
108
|
+
* hoveredStrokeColor="rgba(0, 100, 200, 1)" // optional
|
|
109
|
+
* hoveredLineWidth={3} // optional
|
|
110
|
+
* enableMultiSelect={true}
|
|
111
|
+
* onClick={handleClick}
|
|
112
|
+
* />
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* ### 2️⃣ MARKER 모드 (커스텀 렌더링)
|
|
116
|
+
* ```tsx
|
|
117
|
+
* <WoongCanvasLayer
|
|
118
|
+
* dataType={CanvasDataType.MARKER}
|
|
119
|
+
* data={markers}
|
|
120
|
+
* renderBase={renderMarkerBase} // required
|
|
121
|
+
* renderAnimation={renderMarkerAnimation} // optional
|
|
122
|
+
* renderEvent={renderMarkerEvent} // optional
|
|
123
|
+
* topOnHover={true}
|
|
124
|
+
* onClick={handleClick}
|
|
125
|
+
* />
|
|
126
|
+
* ```
|
|
127
|
+
*
|
|
128
|
+
* ## 📊 데이터 형식
|
|
129
|
+
* ```typescript
|
|
130
|
+
* const data: KonvaCanvasMarkerData<T>[] = [
|
|
131
|
+
* {
|
|
132
|
+
* id: 'unique-id',
|
|
133
|
+
* position: new Position(lat, lng),
|
|
134
|
+
* // POLYGON: paths 필수
|
|
135
|
+
* paths: [[[lat, lng], [lat, lng], ...]],
|
|
136
|
+
* // MARKER: boxWidth/boxHeight 권장 (Hit Test 정확도)
|
|
137
|
+
* boxWidth: 60,
|
|
138
|
+
* boxHeight: 75,
|
|
139
|
+
* // 커스텀 데이터
|
|
140
|
+
* ...customData
|
|
141
|
+
* }
|
|
142
|
+
* ];
|
|
143
|
+
* ```
|
|
144
|
+
*
|
|
145
|
+
* ## ⚡ 성능 최적화 팁
|
|
146
|
+
* 1. **동적 boxWidth 계산**: `measureText()`로 실제 너비 계산 후 전달
|
|
147
|
+
* 2. **enableViewportCulling**: 대량 데이터 시 필수 (기본 true)
|
|
148
|
+
* 3. **selectedItems 외부 관리**: 상태를 외부에서 관리하여 리렌더링 최소화
|
|
149
|
+
* 4. **React.memo 최적화**: 컴포넌트가 자동으로 불필요한 리렌더링 방지
|
|
150
|
+
*
|
|
151
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* // 동적 boxWidth 계산 예시
|
|
155
|
+
* const tempCtx = document.createElement('canvas').getContext('2d');
|
|
156
|
+
* tempCtx.font = 'bold 15px Arial';
|
|
157
|
+
* const boxWidth = Math.max(60, tempCtx.measureText(text).width + 20);
|
|
158
|
+
*
|
|
159
|
+
* @see {@link https://github.com/your-repo/docs/WoongCanvasLayer.md} 전체 문서
|
|
91
160
|
*/
|
|
92
161
|
declare const WoongCanvasLayer: <T>(props: WoongCanvasLayerProps<T>) => React.ReactPortal;
|
|
93
162
|
export default WoongCanvasLayer;
|
|
@@ -24,20 +24,8 @@ var Konva__default = /*#__PURE__*/_interopDefaultLegacy(Konva);
|
|
|
24
24
|
// 메인 컴포넌트
|
|
25
25
|
// ============================================================================
|
|
26
26
|
|
|
27
|
-
/**
|
|
28
|
-
* Konva 기반 고성능 마커/폴리곤 렌더링 컴포넌트
|
|
29
|
-
*
|
|
30
|
-
* 특징:
|
|
31
|
-
* - Base/Event 레이어 분리로 성능 최적화
|
|
32
|
-
* - LRU 캐시로 좌표 변환 결과 캐싱
|
|
33
|
-
* - Spatial Hash Grid로 빠른 Hit Test
|
|
34
|
-
* - Viewport Culling으로 보이는 영역만 렌더링
|
|
35
|
-
*
|
|
36
|
-
* @template T 마커 데이터의 추가 속성 타입
|
|
37
|
-
*/
|
|
38
|
-
|
|
39
27
|
var WoongCanvasLayerComponent = function (props) {
|
|
40
|
-
var
|
|
28
|
+
var data = props.data,
|
|
41
29
|
dataType = props.dataType,
|
|
42
30
|
onClick = props.onClick,
|
|
43
31
|
onMouseOver = props.onMouseOver,
|
|
@@ -56,7 +44,7 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
56
44
|
externalSelectedItem = props.selectedItem,
|
|
57
45
|
_f = props.disableInteraction,
|
|
58
46
|
disableInteraction = _f === void 0 ? false : _f,
|
|
59
|
-
options = tslib.__rest(props, ["
|
|
47
|
+
options = tslib.__rest(props, ["data", "dataType", "onClick", "onMouseOver", "onMouseOut", "enableMultiSelect", "topOnHover", "enableViewportCulling", "cullingMargin", "maxCacheSize", "selectedItems", "selectedItem", "disableInteraction"]); // --------------------------------------------------------------------------
|
|
60
48
|
// Hooks & Context
|
|
61
49
|
// --------------------------------------------------------------------------
|
|
62
50
|
|
|
@@ -81,9 +69,9 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
81
69
|
// Data Refs - 선택 및 Hover 상태 관리
|
|
82
70
|
// --------------------------------------------------------------------------
|
|
83
71
|
|
|
84
|
-
/**
|
|
72
|
+
/** data prop을 ref로 추적 (stale closure 방지, useEffect에서 동기화) */
|
|
85
73
|
|
|
86
|
-
var markersRef = React.useRef(
|
|
74
|
+
var markersRef = React.useRef(data); // --------------------------------------------------------------------------
|
|
87
75
|
// State Refs - 선택 및 Hover 상태 관리
|
|
88
76
|
// --------------------------------------------------------------------------
|
|
89
77
|
|
|
@@ -255,6 +243,7 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
255
243
|
};
|
|
256
244
|
/**
|
|
257
245
|
* 마커 좌표 변환 결과를 캐시하고 반환
|
|
246
|
+
*
|
|
258
247
|
* @param markerData 마커 데이터
|
|
259
248
|
* @returns 변환된 좌표 또는 null
|
|
260
249
|
*/
|
|
@@ -725,11 +714,11 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
725
714
|
|
|
726
715
|
try {
|
|
727
716
|
var clickedOffset = controller.positionToOffset(event.param.position);
|
|
728
|
-
var
|
|
717
|
+
var data_1 = findData(clickedOffset);
|
|
729
718
|
|
|
730
|
-
if (
|
|
731
|
-
handleLocalClick(
|
|
732
|
-
onClick(
|
|
719
|
+
if (data_1) {
|
|
720
|
+
handleLocalClick(data_1);
|
|
721
|
+
onClick(data_1, selectedIdsRef.current);
|
|
733
722
|
}
|
|
734
723
|
} catch (error) {
|
|
735
724
|
console.error('[WoongKonvaMarker] handleClick error:', error);
|
|
@@ -1006,13 +995,13 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
1006
995
|
|
|
1007
996
|
doRenderEvent();
|
|
1008
997
|
}, [externalSelectedItem]); // --------------------------------------------------------------------------
|
|
1009
|
-
// Lifecycle:
|
|
998
|
+
// Lifecycle: 데이터 변경 시 렌더링
|
|
1010
999
|
// --------------------------------------------------------------------------
|
|
1011
1000
|
|
|
1012
1001
|
React.useEffect(function () {
|
|
1013
1002
|
if (!stageRef.current) return; // markersRef 동기화
|
|
1014
1003
|
|
|
1015
|
-
markersRef.current =
|
|
1004
|
+
markersRef.current = data; // 데이터 변경 시 즉시 transform 제거 및 캐시 정리 (겹침 방지)
|
|
1016
1005
|
|
|
1017
1006
|
if (containerRef.current) {
|
|
1018
1007
|
containerRef.current.style.transform = '';
|
|
@@ -1029,18 +1018,18 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
1029
1018
|
/**
|
|
1030
1019
|
* 선택 상태 동기화 (최적화 버전)
|
|
1031
1020
|
*
|
|
1032
|
-
*
|
|
1021
|
+
* data가 변경되면 selectedItemsMapRef도 업데이트 필요
|
|
1033
1022
|
* (참조가 바뀌므로 기존 Map의 데이터는 stale 상태)
|
|
1034
1023
|
*
|
|
1035
|
-
* 🔥 중요: 화면 밖
|
|
1036
|
-
* - 현재
|
|
1024
|
+
* 🔥 중요: 화면 밖 데이터도 선택 상태 유지!
|
|
1025
|
+
* - 현재 data에 있으면 최신 데이터로 업데이트
|
|
1037
1026
|
* - 없으면 기존 selectedItemsMapRef의 데이터 유지
|
|
1038
1027
|
*
|
|
1039
|
-
* 최적화:
|
|
1040
|
-
* - O(전체
|
|
1028
|
+
* 최적화: data를 Map으로 먼저 변환하여 find() 순회 제거
|
|
1029
|
+
* - O(전체 데이터 수 + 선택된 개수) - 매우 효율적
|
|
1041
1030
|
*/
|
|
1042
1031
|
|
|
1043
|
-
var markersMap = new Map(
|
|
1032
|
+
var markersMap = new Map(data.map(function (m) {
|
|
1044
1033
|
return [m.id, m];
|
|
1045
1034
|
}));
|
|
1046
1035
|
var newSelectedItemsMap = new Map();
|
|
@@ -1063,7 +1052,7 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
1063
1052
|
selectedItemsMapRef.current = newSelectedItemsMap; // 즉시 렌더링
|
|
1064
1053
|
|
|
1065
1054
|
renderAllImmediate();
|
|
1066
|
-
}, [
|
|
1055
|
+
}, [data]);
|
|
1067
1056
|
return reactDom.createPortal(React__default["default"].createElement("div", {
|
|
1068
1057
|
ref: containerRef,
|
|
1069
1058
|
style: {
|
|
@@ -1074,27 +1063,96 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
1074
1063
|
}), divElement);
|
|
1075
1064
|
};
|
|
1076
1065
|
/**
|
|
1077
|
-
*
|
|
1066
|
+
* 🚀 WoongCanvasLayer - Konva 기반 초고성능 마커/폴리곤 렌더링 컴포넌트
|
|
1067
|
+
*
|
|
1068
|
+
* ## 📌 주요 특징
|
|
1069
|
+
* - **30,000개 이상의 폴리곤/마커를 60fps로 렌더링**
|
|
1070
|
+
* - **Multi-Layer 아키텍처**: Base/Animation/Event 레이어 분리
|
|
1071
|
+
* - **Spatial Hash Grid**: O(1) 수준의 빠른 Hit Test
|
|
1072
|
+
* - **LRU 캐시**: 좌표 변환 결과 캐싱으로 성능 최적화
|
|
1073
|
+
* - **Viewport Culling**: 화면에 보이는 영역만 렌더링
|
|
1074
|
+
* - **Discriminated Union Props**: 타입 안전한 MARKER/POLYGON 모드
|
|
1075
|
+
*
|
|
1076
|
+
* ## 🎯 사용 방법
|
|
1077
|
+
*
|
|
1078
|
+
* ### 1️⃣ POLYGON 모드 (자동 렌더링)
|
|
1079
|
+
* ```tsx
|
|
1080
|
+
* <WoongCanvasLayer
|
|
1081
|
+
* dataType={CanvasDataType.POLYGON}
|
|
1082
|
+
* data={polygons}
|
|
1083
|
+
* baseFillColor="rgba(255, 100, 100, 0.5)"
|
|
1084
|
+
* baseStrokeColor="rgba(200, 50, 50, 0.8)"
|
|
1085
|
+
* baseLineWidth={2}
|
|
1086
|
+
* selectedFillColor="rgba(255, 193, 7, 0.7)"
|
|
1087
|
+
* selectedStrokeColor="rgba(255, 152, 0, 1)"
|
|
1088
|
+
* selectedLineWidth={4}
|
|
1089
|
+
* hoveredFillColor="rgba(100, 150, 255, 0.8)" // optional
|
|
1090
|
+
* hoveredStrokeColor="rgba(0, 100, 200, 1)" // optional
|
|
1091
|
+
* hoveredLineWidth={3} // optional
|
|
1092
|
+
* enableMultiSelect={true}
|
|
1093
|
+
* onClick={handleClick}
|
|
1094
|
+
* />
|
|
1095
|
+
* ```
|
|
1096
|
+
*
|
|
1097
|
+
* ### 2️⃣ MARKER 모드 (커스텀 렌더링)
|
|
1098
|
+
* ```tsx
|
|
1099
|
+
* <WoongCanvasLayer
|
|
1100
|
+
* dataType={CanvasDataType.MARKER}
|
|
1101
|
+
* data={markers}
|
|
1102
|
+
* renderBase={renderMarkerBase} // required
|
|
1103
|
+
* renderAnimation={renderMarkerAnimation} // optional
|
|
1104
|
+
* renderEvent={renderMarkerEvent} // optional
|
|
1105
|
+
* topOnHover={true}
|
|
1106
|
+
* onClick={handleClick}
|
|
1107
|
+
* />
|
|
1108
|
+
* ```
|
|
1109
|
+
*
|
|
1110
|
+
* ## 📊 데이터 형식
|
|
1111
|
+
* ```typescript
|
|
1112
|
+
* const data: KonvaCanvasMarkerData<T>[] = [
|
|
1113
|
+
* {
|
|
1114
|
+
* id: 'unique-id',
|
|
1115
|
+
* position: new Position(lat, lng),
|
|
1116
|
+
* // POLYGON: paths 필수
|
|
1117
|
+
* paths: [[[lat, lng], [lat, lng], ...]],
|
|
1118
|
+
* // MARKER: boxWidth/boxHeight 권장 (Hit Test 정확도)
|
|
1119
|
+
* boxWidth: 60,
|
|
1120
|
+
* boxHeight: 75,
|
|
1121
|
+
* // 커스텀 데이터
|
|
1122
|
+
* ...customData
|
|
1123
|
+
* }
|
|
1124
|
+
* ];
|
|
1125
|
+
* ```
|
|
1078
1126
|
*
|
|
1079
|
-
*
|
|
1080
|
-
* 1.
|
|
1081
|
-
* 2.
|
|
1127
|
+
* ## ⚡ 성능 최적화 팁
|
|
1128
|
+
* 1. **동적 boxWidth 계산**: `measureText()`로 실제 너비 계산 후 전달
|
|
1129
|
+
* 2. **enableViewportCulling**: 대량 데이터 시 필수 (기본 true)
|
|
1130
|
+
* 3. **selectedItems 외부 관리**: 상태를 외부에서 관리하여 리렌더링 최소화
|
|
1131
|
+
* 4. **React.memo 최적화**: 컴포넌트가 자동으로 불필요한 리렌더링 방지
|
|
1082
1132
|
*
|
|
1083
|
-
*
|
|
1133
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
1134
|
+
*
|
|
1135
|
+
* @example
|
|
1136
|
+
* // 동적 boxWidth 계산 예시
|
|
1137
|
+
* const tempCtx = document.createElement('canvas').getContext('2d');
|
|
1138
|
+
* tempCtx.font = 'bold 15px Arial';
|
|
1139
|
+
* const boxWidth = Math.max(60, tempCtx.measureText(text).width + 20);
|
|
1140
|
+
*
|
|
1141
|
+
* @see {@link https://github.com/your-repo/docs/WoongCanvasLayer.md} 전체 문서
|
|
1084
1142
|
*/
|
|
1085
1143
|
|
|
1086
1144
|
|
|
1087
1145
|
var WoongCanvasLayer = React__default["default"].memo(WoongCanvasLayerComponent, function (prevProps, nextProps) {
|
|
1088
|
-
// 1.
|
|
1089
|
-
var
|
|
1090
|
-
var
|
|
1146
|
+
// 1. data 비교
|
|
1147
|
+
var prevData = prevProps.data;
|
|
1148
|
+
var nextData = nextProps.data; // 참조가 같으면 스킵
|
|
1091
1149
|
|
|
1092
|
-
if (
|
|
1150
|
+
if (prevData !== nextData) {
|
|
1093
1151
|
// 길이가 다르면 변경됨
|
|
1094
|
-
if (
|
|
1152
|
+
if (prevData.length !== nextData.length) return false; // 각 데이터의 ID 비교
|
|
1095
1153
|
|
|
1096
|
-
for (var i = 0; i <
|
|
1097
|
-
if (
|
|
1154
|
+
for (var i = 0; i < prevData.length; i++) {
|
|
1155
|
+
if (prevData[i].id !== nextData[i].id) {
|
|
1098
1156
|
return false; // 변경됨 → 리렌더링
|
|
1099
1157
|
}
|
|
1100
1158
|
}
|
|
@@ -1109,18 +1167,6 @@ var WoongCanvasLayer = React__default["default"].memo(WoongCanvasLayerComponent,
|
|
|
1109
1167
|
return false; // 변경됨 → 리렌더링
|
|
1110
1168
|
}
|
|
1111
1169
|
|
|
1112
|
-
if (prevProps.onClick !== nextProps.onClick) {
|
|
1113
|
-
return false; // 변경됨 → 리렌더링
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
if (prevProps.onMouseOver !== nextProps.onMouseOver) {
|
|
1117
|
-
return false; // 변경됨 → 리렌더링
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
if (prevProps.onMouseOut !== nextProps.onMouseOut) {
|
|
1121
|
-
return false; // 변경됨 → 리렌더링
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
1170
|
if (prevProps.disableInteraction !== nextProps.disableInteraction) {
|
|
1125
1171
|
return false; // 변경됨 → 리렌더링
|
|
1126
1172
|
}
|
|
@@ -40,10 +40,104 @@ export interface KonvaCanvasMarkerOption {
|
|
|
40
40
|
*/
|
|
41
41
|
export declare type KonvaCanvasMarkerData<T = {}> = T & KonvaCanvasMarkerOption;
|
|
42
42
|
/**
|
|
43
|
-
* 렌더링 유틸리티 함수들
|
|
43
|
+
* 🛠️ 렌더링 유틸리티 함수들
|
|
44
|
+
*
|
|
45
|
+
* WoongCanvasLayer가 제공하는 헬퍼 함수 모음입니다.
|
|
46
|
+
* 커스텀 렌더링 함수 내에서 좌표 변환 시 사용하세요.
|
|
47
|
+
*
|
|
48
|
+
* ## 주요 기능
|
|
49
|
+
* - **자동 캐싱**: 좌표 변환 결과를 LRU 캐시에 저장 (성능 최적화)
|
|
50
|
+
* - **지도 좌표 → 화면 좌표**: 위경도를 픽셀 좌표로 자동 변환
|
|
51
|
+
* - **null 안전성**: 변환 실패 시 null 반환 (안전한 예외 처리)
|
|
52
|
+
*
|
|
53
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* // 마커 렌더링 예시
|
|
57
|
+
* const renderBase = ({ ctx, items, utils }) => {
|
|
58
|
+
* for (const item of items) {
|
|
59
|
+
* const offset = utils.getOrComputeMarkerOffset(item);
|
|
60
|
+
* if (!offset) continue; // 변환 실패 시 스킵
|
|
61
|
+
*
|
|
62
|
+
* ctx.fillRect(offset.x, offset.y, 50, 50);
|
|
63
|
+
* }
|
|
64
|
+
* };
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* // 폴리곤 렌더링 예시
|
|
68
|
+
* const renderBase = ({ ctx, items, utils }) => {
|
|
69
|
+
* for (const item of items) {
|
|
70
|
+
* const offsets = utils.getOrComputePolygonOffsets(item);
|
|
71
|
+
* if (!offsets) continue;
|
|
72
|
+
*
|
|
73
|
+
* for (const multiPolygon of offsets) {
|
|
74
|
+
* for (const polygon of multiPolygon) {
|
|
75
|
+
* ctx.beginPath();
|
|
76
|
+
* ctx.moveTo(polygon[0][0], polygon[0][1]);
|
|
77
|
+
* for (let i = 1; i < polygon.length; i++) {
|
|
78
|
+
* ctx.lineTo(polygon[i][0], polygon[i][1]);
|
|
79
|
+
* }
|
|
80
|
+
* ctx.closePath();
|
|
81
|
+
* ctx.fill();
|
|
82
|
+
* }
|
|
83
|
+
* }
|
|
84
|
+
* }
|
|
85
|
+
* };
|
|
44
86
|
*/
|
|
45
87
|
export interface RenderUtils<T> {
|
|
88
|
+
/**
|
|
89
|
+
* 폴리곤의 위경도 좌표를 화면 픽셀 좌표로 변환합니다.
|
|
90
|
+
*
|
|
91
|
+
* - **자동 캐싱**: 동일한 폴리곤은 캐시에서 즉시 반환 (성능 최적화)
|
|
92
|
+
* - **MultiPolygon 지원**: GeoJSON MultiPolygon 형식 지원
|
|
93
|
+
* - **Donut Polygon 지원**: 구멍이 있는 폴리곤 지원
|
|
94
|
+
*
|
|
95
|
+
* @param polygonData 폴리곤 데이터 (paths 필드 필수)
|
|
96
|
+
* @returns 변환된 픽셀 좌표 배열 (4차원 배열) 또는 null (변환 실패 시)
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* const offsets = utils.getOrComputePolygonOffsets(polygonItem);
|
|
100
|
+
* if (!offsets) return; // 변환 실패
|
|
101
|
+
*
|
|
102
|
+
* // offsets 구조: [MultiPolygon][Polygon][Point][x/y]
|
|
103
|
+
* for (const multiPolygon of offsets) {
|
|
104
|
+
* for (const polygon of multiPolygon) {
|
|
105
|
+
* ctx.beginPath();
|
|
106
|
+
* ctx.moveTo(polygon[0][0], polygon[0][1]);
|
|
107
|
+
* for (let i = 1; i < polygon.length; i++) {
|
|
108
|
+
* ctx.lineTo(polygon[i][0], polygon[i][1]);
|
|
109
|
+
* }
|
|
110
|
+
* ctx.closePath();
|
|
111
|
+
* ctx.fill();
|
|
112
|
+
* }
|
|
113
|
+
* }
|
|
114
|
+
*/
|
|
46
115
|
getOrComputePolygonOffsets: (polygonData: KonvaCanvasMarkerData<T>) => number[][][][] | null;
|
|
116
|
+
/**
|
|
117
|
+
* 마커의 위경도 좌표를 화면 픽셀 좌표로 변환합니다.
|
|
118
|
+
*
|
|
119
|
+
* - **자동 캐싱**: 동일한 마커는 캐시에서 즉시 반환 (성능 최적화)
|
|
120
|
+
* - **중심점 기준**: 반환된 좌표는 마커의 중심점 (x, y)
|
|
121
|
+
*
|
|
122
|
+
* @param markerData 마커 데이터 (position 필드 필수)
|
|
123
|
+
* @returns 변환된 픽셀 좌표 { x, y } 또는 null (변환 실패 시)
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* const offset = utils.getOrComputeMarkerOffset(markerItem);
|
|
127
|
+
* if (!offset) return; // 변환 실패
|
|
128
|
+
*
|
|
129
|
+
* // offset.x, offset.y는 화면 픽셀 좌표
|
|
130
|
+
* const boxWidth = markerItem.boxWidth || 60;
|
|
131
|
+
* const boxHeight = markerItem.boxHeight || 75;
|
|
132
|
+
*
|
|
133
|
+
* // 중앙 정렬, 하단 기준으로 그리기
|
|
134
|
+
* ctx.fillRect(
|
|
135
|
+
* offset.x - boxWidth / 2,
|
|
136
|
+
* offset.y - boxHeight,
|
|
137
|
+
* boxWidth,
|
|
138
|
+
* boxHeight
|
|
139
|
+
* );
|
|
140
|
+
*/
|
|
47
141
|
getOrComputeMarkerOffset: (markerData: KonvaCanvasMarkerData<T>) => Offset | null;
|
|
48
142
|
}
|
|
49
143
|
/**
|
|
@@ -30,3 +30,19 @@ export declare const isPointInPolygonData: (clickedOffset: Offset, polygonData:
|
|
|
30
30
|
*/
|
|
31
31
|
export declare const isPointInMarkerData: (clickedOffset: Offset, markerData: KonvaCanvasMarkerData<any>, getMarkerOffset: (data: KonvaCanvasMarkerData<any>) => Offset | null) => boolean;
|
|
32
32
|
export declare const hexToRgba: (hexColor: string, alpha?: number) => string;
|
|
33
|
+
/**
|
|
34
|
+
* 텍스트 박스의 너비를 계산합니다.
|
|
35
|
+
*
|
|
36
|
+
* @param {Object} params - 파라미터 객체
|
|
37
|
+
* @param {string} params.text - 측정할 텍스트
|
|
38
|
+
* @param {string} params.fontConfig - 폰트 설정 (예: 'bold 16px Arial')
|
|
39
|
+
* @param {number} params.padding - 텍스트 박스에 적용할 패딩 값
|
|
40
|
+
* @param {number} params.minWidth - 최소 너비
|
|
41
|
+
* @returns {number} 계산된 텍스트 박스의 너비
|
|
42
|
+
*/
|
|
43
|
+
export declare const calculateTextBoxWidth: ({ text, fontConfig, padding, minWidth, }: {
|
|
44
|
+
text: string;
|
|
45
|
+
fontConfig: string;
|
|
46
|
+
padding: number;
|
|
47
|
+
minWidth: number;
|
|
48
|
+
}) => number;
|
|
@@ -173,7 +173,31 @@ var hexToRgba = function (hexColor, alpha) {
|
|
|
173
173
|
|
|
174
174
|
throw new Error('Invalid hex color format');
|
|
175
175
|
};
|
|
176
|
+
var tempCanvas = document.createElement('canvas');
|
|
177
|
+
var tempCtx = tempCanvas.getContext('2d');
|
|
178
|
+
/**
|
|
179
|
+
* 텍스트 박스의 너비를 계산합니다.
|
|
180
|
+
*
|
|
181
|
+
* @param {Object} params - 파라미터 객체
|
|
182
|
+
* @param {string} params.text - 측정할 텍스트
|
|
183
|
+
* @param {string} params.fontConfig - 폰트 설정 (예: 'bold 16px Arial')
|
|
184
|
+
* @param {number} params.padding - 텍스트 박스에 적용할 패딩 값
|
|
185
|
+
* @param {number} params.minWidth - 최소 너비
|
|
186
|
+
* @returns {number} 계산된 텍스트 박스의 너비
|
|
187
|
+
*/
|
|
188
|
+
|
|
189
|
+
var calculateTextBoxWidth = function (_a) {
|
|
190
|
+
var text = _a.text,
|
|
191
|
+
fontConfig = _a.fontConfig,
|
|
192
|
+
padding = _a.padding,
|
|
193
|
+
minWidth = _a.minWidth;
|
|
194
|
+
if (!tempCtx) return 0;
|
|
195
|
+
tempCtx.font = fontConfig;
|
|
196
|
+
var textWidth = tempCtx.measureText(text).width;
|
|
197
|
+
return Math.max(minWidth, textWidth + padding);
|
|
198
|
+
};
|
|
176
199
|
|
|
200
|
+
exports.calculateTextBoxWidth = calculateTextBoxWidth;
|
|
177
201
|
exports.computeMarkerOffset = computeMarkerOffset;
|
|
178
202
|
exports.computePolygonOffsets = computePolygonOffsets;
|
|
179
203
|
exports.hexToRgba = hexToRgba;
|
|
@@ -22,6 +22,7 @@ require('../core/advanced/canvas/CanvasMarkerClaude.js');
|
|
|
22
22
|
require('../core/advanced/MapLoadingComponents.js');
|
|
23
23
|
require('../core/advanced/woongCanvas/WoongCanvasLayer.js');
|
|
24
24
|
require('../core/advanced/woongCanvas/shared/types.js');
|
|
25
|
+
require('../core/advanced/woongCanvas/shared/utils.js');
|
|
25
26
|
require('../core/advanced/woongCanvas/shared/context.js');
|
|
26
27
|
require('../core/advanced/woongCanvas/shared/performance.js');
|
|
27
28
|
require('../core/wrapper/MapControlWrapper.js');
|
|
@@ -23,6 +23,7 @@ require('../core/advanced/canvas/CanvasMarkerClaude.js');
|
|
|
23
23
|
require('../core/advanced/MapLoadingComponents.js');
|
|
24
24
|
require('../core/advanced/woongCanvas/WoongCanvasLayer.js');
|
|
25
25
|
require('../core/advanced/woongCanvas/shared/types.js');
|
|
26
|
+
require('../core/advanced/woongCanvas/shared/utils.js');
|
|
26
27
|
require('../core/advanced/woongCanvas/shared/context.js');
|
|
27
28
|
require('../core/advanced/woongCanvas/shared/performance.js');
|
|
28
29
|
require('../core/wrapper/MapControlWrapper.js');
|
|
@@ -22,6 +22,7 @@ require('../core/advanced/canvas/CanvasMarkerClaude.js');
|
|
|
22
22
|
require('../core/advanced/MapLoadingComponents.js');
|
|
23
23
|
require('../core/advanced/woongCanvas/WoongCanvasLayer.js');
|
|
24
24
|
require('../core/advanced/woongCanvas/shared/types.js');
|
|
25
|
+
require('../core/advanced/woongCanvas/shared/utils.js');
|
|
25
26
|
require('../core/advanced/woongCanvas/shared/context.js');
|
|
26
27
|
require('../core/advanced/woongCanvas/shared/performance.js');
|
|
27
28
|
require('../core/wrapper/MapControlWrapper.js');
|
package/dist/index.es.js
CHANGED
|
@@ -961,6 +961,29 @@ var hexToRgba = function (hexColor, alpha) {
|
|
|
961
961
|
|
|
962
962
|
throw new Error('Invalid hex color format');
|
|
963
963
|
};
|
|
964
|
+
var tempCanvas = document.createElement('canvas');
|
|
965
|
+
var tempCtx = tempCanvas.getContext('2d');
|
|
966
|
+
/**
|
|
967
|
+
* 텍스트 박스의 너비를 계산합니다.
|
|
968
|
+
*
|
|
969
|
+
* @param {Object} params - 파라미터 객체
|
|
970
|
+
* @param {string} params.text - 측정할 텍스트
|
|
971
|
+
* @param {string} params.fontConfig - 폰트 설정 (예: 'bold 16px Arial')
|
|
972
|
+
* @param {number} params.padding - 텍스트 박스에 적용할 패딩 값
|
|
973
|
+
* @param {number} params.minWidth - 최소 너비
|
|
974
|
+
* @returns {number} 계산된 텍스트 박스의 너비
|
|
975
|
+
*/
|
|
976
|
+
|
|
977
|
+
var calculateTextBoxWidth = function (_a) {
|
|
978
|
+
var text = _a.text,
|
|
979
|
+
fontConfig = _a.fontConfig,
|
|
980
|
+
padding = _a.padding,
|
|
981
|
+
minWidth = _a.minWidth;
|
|
982
|
+
if (!tempCtx) return 0;
|
|
983
|
+
tempCtx.font = fontConfig;
|
|
984
|
+
var textWidth = tempCtx.measureText(text).width;
|
|
985
|
+
return Math.max(minWidth, textWidth + padding);
|
|
986
|
+
};
|
|
964
987
|
|
|
965
988
|
var KonvaMarkerContext = createContext(null);
|
|
966
989
|
var KonvaMarkerProvider = function (_a) {
|
|
@@ -5613,20 +5636,8 @@ var renderPolygonEvent = function (selectedFillColor, selectedStrokeColor, selec
|
|
|
5613
5636
|
// 메인 컴포넌트
|
|
5614
5637
|
// ============================================================================
|
|
5615
5638
|
|
|
5616
|
-
/**
|
|
5617
|
-
* Konva 기반 고성능 마커/폴리곤 렌더링 컴포넌트
|
|
5618
|
-
*
|
|
5619
|
-
* 특징:
|
|
5620
|
-
* - Base/Event 레이어 분리로 성능 최적화
|
|
5621
|
-
* - LRU 캐시로 좌표 변환 결과 캐싱
|
|
5622
|
-
* - Spatial Hash Grid로 빠른 Hit Test
|
|
5623
|
-
* - Viewport Culling으로 보이는 영역만 렌더링
|
|
5624
|
-
*
|
|
5625
|
-
* @template T 마커 데이터의 추가 속성 타입
|
|
5626
|
-
*/
|
|
5627
|
-
|
|
5628
5639
|
var WoongCanvasLayerComponent = function (props) {
|
|
5629
|
-
var
|
|
5640
|
+
var data = props.data,
|
|
5630
5641
|
dataType = props.dataType,
|
|
5631
5642
|
onClick = props.onClick,
|
|
5632
5643
|
onMouseOver = props.onMouseOver,
|
|
@@ -5645,7 +5656,7 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
5645
5656
|
externalSelectedItem = props.selectedItem,
|
|
5646
5657
|
_f = props.disableInteraction,
|
|
5647
5658
|
disableInteraction = _f === void 0 ? false : _f,
|
|
5648
|
-
options = __rest(props, ["
|
|
5659
|
+
options = __rest(props, ["data", "dataType", "onClick", "onMouseOver", "onMouseOut", "enableMultiSelect", "topOnHover", "enableViewportCulling", "cullingMargin", "maxCacheSize", "selectedItems", "selectedItem", "disableInteraction"]); // --------------------------------------------------------------------------
|
|
5649
5660
|
// Hooks & Context
|
|
5650
5661
|
// --------------------------------------------------------------------------
|
|
5651
5662
|
|
|
@@ -5670,9 +5681,9 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
5670
5681
|
// Data Refs - 선택 및 Hover 상태 관리
|
|
5671
5682
|
// --------------------------------------------------------------------------
|
|
5672
5683
|
|
|
5673
|
-
/**
|
|
5684
|
+
/** data prop을 ref로 추적 (stale closure 방지, useEffect에서 동기화) */
|
|
5674
5685
|
|
|
5675
|
-
var markersRef = useRef(
|
|
5686
|
+
var markersRef = useRef(data); // --------------------------------------------------------------------------
|
|
5676
5687
|
// State Refs - 선택 및 Hover 상태 관리
|
|
5677
5688
|
// --------------------------------------------------------------------------
|
|
5678
5689
|
|
|
@@ -5844,6 +5855,7 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
5844
5855
|
};
|
|
5845
5856
|
/**
|
|
5846
5857
|
* 마커 좌표 변환 결과를 캐시하고 반환
|
|
5858
|
+
*
|
|
5847
5859
|
* @param markerData 마커 데이터
|
|
5848
5860
|
* @returns 변환된 좌표 또는 null
|
|
5849
5861
|
*/
|
|
@@ -6314,11 +6326,11 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
6314
6326
|
|
|
6315
6327
|
try {
|
|
6316
6328
|
var clickedOffset = controller.positionToOffset(event.param.position);
|
|
6317
|
-
var
|
|
6329
|
+
var data_1 = findData(clickedOffset);
|
|
6318
6330
|
|
|
6319
|
-
if (
|
|
6320
|
-
handleLocalClick(
|
|
6321
|
-
onClick(
|
|
6331
|
+
if (data_1) {
|
|
6332
|
+
handleLocalClick(data_1);
|
|
6333
|
+
onClick(data_1, selectedIdsRef.current);
|
|
6322
6334
|
}
|
|
6323
6335
|
} catch (error) {
|
|
6324
6336
|
console.error('[WoongKonvaMarker] handleClick error:', error);
|
|
@@ -6595,13 +6607,13 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
6595
6607
|
|
|
6596
6608
|
doRenderEvent();
|
|
6597
6609
|
}, [externalSelectedItem]); // --------------------------------------------------------------------------
|
|
6598
|
-
// Lifecycle:
|
|
6610
|
+
// Lifecycle: 데이터 변경 시 렌더링
|
|
6599
6611
|
// --------------------------------------------------------------------------
|
|
6600
6612
|
|
|
6601
6613
|
useEffect(function () {
|
|
6602
6614
|
if (!stageRef.current) return; // markersRef 동기화
|
|
6603
6615
|
|
|
6604
|
-
markersRef.current =
|
|
6616
|
+
markersRef.current = data; // 데이터 변경 시 즉시 transform 제거 및 캐시 정리 (겹침 방지)
|
|
6605
6617
|
|
|
6606
6618
|
if (containerRef.current) {
|
|
6607
6619
|
containerRef.current.style.transform = '';
|
|
@@ -6618,18 +6630,18 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
6618
6630
|
/**
|
|
6619
6631
|
* 선택 상태 동기화 (최적화 버전)
|
|
6620
6632
|
*
|
|
6621
|
-
*
|
|
6633
|
+
* data가 변경되면 selectedItemsMapRef도 업데이트 필요
|
|
6622
6634
|
* (참조가 바뀌므로 기존 Map의 데이터는 stale 상태)
|
|
6623
6635
|
*
|
|
6624
|
-
* 🔥 중요: 화면 밖
|
|
6625
|
-
* - 현재
|
|
6636
|
+
* 🔥 중요: 화면 밖 데이터도 선택 상태 유지!
|
|
6637
|
+
* - 현재 data에 있으면 최신 데이터로 업데이트
|
|
6626
6638
|
* - 없으면 기존 selectedItemsMapRef의 데이터 유지
|
|
6627
6639
|
*
|
|
6628
|
-
* 최적화:
|
|
6629
|
-
* - O(전체
|
|
6640
|
+
* 최적화: data를 Map으로 먼저 변환하여 find() 순회 제거
|
|
6641
|
+
* - O(전체 데이터 수 + 선택된 개수) - 매우 효율적
|
|
6630
6642
|
*/
|
|
6631
6643
|
|
|
6632
|
-
var markersMap = new Map(
|
|
6644
|
+
var markersMap = new Map(data.map(function (m) {
|
|
6633
6645
|
return [m.id, m];
|
|
6634
6646
|
}));
|
|
6635
6647
|
var newSelectedItemsMap = new Map();
|
|
@@ -6652,7 +6664,7 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
6652
6664
|
selectedItemsMapRef.current = newSelectedItemsMap; // 즉시 렌더링
|
|
6653
6665
|
|
|
6654
6666
|
renderAllImmediate();
|
|
6655
|
-
}, [
|
|
6667
|
+
}, [data]);
|
|
6656
6668
|
return createPortal(React.createElement("div", {
|
|
6657
6669
|
ref: containerRef,
|
|
6658
6670
|
style: {
|
|
@@ -6663,27 +6675,96 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
6663
6675
|
}), divElement);
|
|
6664
6676
|
};
|
|
6665
6677
|
/**
|
|
6666
|
-
*
|
|
6678
|
+
* 🚀 WoongCanvasLayer - Konva 기반 초고성능 마커/폴리곤 렌더링 컴포넌트
|
|
6679
|
+
*
|
|
6680
|
+
* ## 📌 주요 특징
|
|
6681
|
+
* - **30,000개 이상의 폴리곤/마커를 60fps로 렌더링**
|
|
6682
|
+
* - **Multi-Layer 아키텍처**: Base/Animation/Event 레이어 분리
|
|
6683
|
+
* - **Spatial Hash Grid**: O(1) 수준의 빠른 Hit Test
|
|
6684
|
+
* - **LRU 캐시**: 좌표 변환 결과 캐싱으로 성능 최적화
|
|
6685
|
+
* - **Viewport Culling**: 화면에 보이는 영역만 렌더링
|
|
6686
|
+
* - **Discriminated Union Props**: 타입 안전한 MARKER/POLYGON 모드
|
|
6687
|
+
*
|
|
6688
|
+
* ## 🎯 사용 방법
|
|
6689
|
+
*
|
|
6690
|
+
* ### 1️⃣ POLYGON 모드 (자동 렌더링)
|
|
6691
|
+
* ```tsx
|
|
6692
|
+
* <WoongCanvasLayer
|
|
6693
|
+
* dataType={CanvasDataType.POLYGON}
|
|
6694
|
+
* data={polygons}
|
|
6695
|
+
* baseFillColor="rgba(255, 100, 100, 0.5)"
|
|
6696
|
+
* baseStrokeColor="rgba(200, 50, 50, 0.8)"
|
|
6697
|
+
* baseLineWidth={2}
|
|
6698
|
+
* selectedFillColor="rgba(255, 193, 7, 0.7)"
|
|
6699
|
+
* selectedStrokeColor="rgba(255, 152, 0, 1)"
|
|
6700
|
+
* selectedLineWidth={4}
|
|
6701
|
+
* hoveredFillColor="rgba(100, 150, 255, 0.8)" // optional
|
|
6702
|
+
* hoveredStrokeColor="rgba(0, 100, 200, 1)" // optional
|
|
6703
|
+
* hoveredLineWidth={3} // optional
|
|
6704
|
+
* enableMultiSelect={true}
|
|
6705
|
+
* onClick={handleClick}
|
|
6706
|
+
* />
|
|
6707
|
+
* ```
|
|
6667
6708
|
*
|
|
6668
|
-
*
|
|
6669
|
-
*
|
|
6670
|
-
*
|
|
6709
|
+
* ### 2️⃣ MARKER 모드 (커스텀 렌더링)
|
|
6710
|
+
* ```tsx
|
|
6711
|
+
* <WoongCanvasLayer
|
|
6712
|
+
* dataType={CanvasDataType.MARKER}
|
|
6713
|
+
* data={markers}
|
|
6714
|
+
* renderBase={renderMarkerBase} // required
|
|
6715
|
+
* renderAnimation={renderMarkerAnimation} // optional
|
|
6716
|
+
* renderEvent={renderMarkerEvent} // optional
|
|
6717
|
+
* topOnHover={true}
|
|
6718
|
+
* onClick={handleClick}
|
|
6719
|
+
* />
|
|
6720
|
+
* ```
|
|
6671
6721
|
*
|
|
6672
|
-
*
|
|
6722
|
+
* ## 📊 데이터 형식
|
|
6723
|
+
* ```typescript
|
|
6724
|
+
* const data: KonvaCanvasMarkerData<T>[] = [
|
|
6725
|
+
* {
|
|
6726
|
+
* id: 'unique-id',
|
|
6727
|
+
* position: new Position(lat, lng),
|
|
6728
|
+
* // POLYGON: paths 필수
|
|
6729
|
+
* paths: [[[lat, lng], [lat, lng], ...]],
|
|
6730
|
+
* // MARKER: boxWidth/boxHeight 권장 (Hit Test 정확도)
|
|
6731
|
+
* boxWidth: 60,
|
|
6732
|
+
* boxHeight: 75,
|
|
6733
|
+
* // 커스텀 데이터
|
|
6734
|
+
* ...customData
|
|
6735
|
+
* }
|
|
6736
|
+
* ];
|
|
6737
|
+
* ```
|
|
6738
|
+
*
|
|
6739
|
+
* ## ⚡ 성능 최적화 팁
|
|
6740
|
+
* 1. **동적 boxWidth 계산**: `measureText()`로 실제 너비 계산 후 전달
|
|
6741
|
+
* 2. **enableViewportCulling**: 대량 데이터 시 필수 (기본 true)
|
|
6742
|
+
* 3. **selectedItems 외부 관리**: 상태를 외부에서 관리하여 리렌더링 최소화
|
|
6743
|
+
* 4. **React.memo 최적화**: 컴포넌트가 자동으로 불필요한 리렌더링 방지
|
|
6744
|
+
*
|
|
6745
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
6746
|
+
*
|
|
6747
|
+
* @example
|
|
6748
|
+
* // 동적 boxWidth 계산 예시
|
|
6749
|
+
* const tempCtx = document.createElement('canvas').getContext('2d');
|
|
6750
|
+
* tempCtx.font = 'bold 15px Arial';
|
|
6751
|
+
* const boxWidth = Math.max(60, tempCtx.measureText(text).width + 20);
|
|
6752
|
+
*
|
|
6753
|
+
* @see {@link https://github.com/your-repo/docs/WoongCanvasLayer.md} 전체 문서
|
|
6673
6754
|
*/
|
|
6674
6755
|
|
|
6675
6756
|
|
|
6676
6757
|
var WoongCanvasLayer = React.memo(WoongCanvasLayerComponent, function (prevProps, nextProps) {
|
|
6677
|
-
// 1.
|
|
6678
|
-
var
|
|
6679
|
-
var
|
|
6758
|
+
// 1. data 비교
|
|
6759
|
+
var prevData = prevProps.data;
|
|
6760
|
+
var nextData = nextProps.data; // 참조가 같으면 스킵
|
|
6680
6761
|
|
|
6681
|
-
if (
|
|
6762
|
+
if (prevData !== nextData) {
|
|
6682
6763
|
// 길이가 다르면 변경됨
|
|
6683
|
-
if (
|
|
6764
|
+
if (prevData.length !== nextData.length) return false; // 각 데이터의 ID 비교
|
|
6684
6765
|
|
|
6685
|
-
for (var i = 0; i <
|
|
6686
|
-
if (
|
|
6766
|
+
for (var i = 0; i < prevData.length; i++) {
|
|
6767
|
+
if (prevData[i].id !== nextData[i].id) {
|
|
6687
6768
|
return false; // 변경됨 → 리렌더링
|
|
6688
6769
|
}
|
|
6689
6770
|
}
|
|
@@ -6698,18 +6779,6 @@ var WoongCanvasLayer = React.memo(WoongCanvasLayerComponent, function (prevProps
|
|
|
6698
6779
|
return false; // 변경됨 → 리렌더링
|
|
6699
6780
|
}
|
|
6700
6781
|
|
|
6701
|
-
if (prevProps.onClick !== nextProps.onClick) {
|
|
6702
|
-
return false; // 변경됨 → 리렌더링
|
|
6703
|
-
}
|
|
6704
|
-
|
|
6705
|
-
if (prevProps.onMouseOver !== nextProps.onMouseOver) {
|
|
6706
|
-
return false; // 변경됨 → 리렌더링
|
|
6707
|
-
}
|
|
6708
|
-
|
|
6709
|
-
if (prevProps.onMouseOut !== nextProps.onMouseOut) {
|
|
6710
|
-
return false; // 변경됨 → 리렌더링
|
|
6711
|
-
}
|
|
6712
|
-
|
|
6713
6782
|
if (prevProps.disableInteraction !== nextProps.disableInteraction) {
|
|
6714
6783
|
return false; // 변경됨 → 리렌더링
|
|
6715
6784
|
}
|
|
@@ -9548,4 +9617,4 @@ function MintMap(_a) {
|
|
|
9548
9617
|
}), loading));
|
|
9549
9618
|
}
|
|
9550
9619
|
|
|
9551
|
-
export { AnimationPlayer, Bounds, CanvasDataType, CanvasMarker, CanvasMarkerClaude, CanvasMarkerHanquf, CircleMarker, DEFAULT_CULLING_MARGIN, DEFAULT_MAX_CACHE_SIZE, Drawable, GeoCalulator, GoogleMintMapController, KonvaMarkerProvider, LRUCache, MapBuildingProjection, MapCanvasMarkerWrapper, MapCanvasWrapper, MapControlWrapper, MapEvent, MapLoadingWithImage, MapMarkerWrapper, MapPolygonWrapper, MapPolylineWrapper, MapUIEvent, Marker, MintMap, MintMapCanvasRenderer, MintMapController, MintMapCore, MintMapProvider, NaverMintMapController, Offset, PointLoading, Polygon, PolygonCalculator, PolygonMarker, Polyline, Position, SPATIAL_GRID_CELL_SIZE, SVGCircle, SVGPolygon, SVGRect, Spacing, SpatialHashGrid, Status, WoongCanvasLayer, computeMarkerOffset, computePolygonOffsets, getClusterInfo, getMapOfType, hexToRgba, isPointInMarkerData, isPointInPolygon, isPointInPolygonData, log, useKonvaMarkerContext, useMarkerMoving, useMintMapController, waiting };
|
|
9620
|
+
export { AnimationPlayer, Bounds, CanvasDataType, CanvasMarker, CanvasMarkerClaude, CanvasMarkerHanquf, CircleMarker, DEFAULT_CULLING_MARGIN, DEFAULT_MAX_CACHE_SIZE, Drawable, GeoCalulator, GoogleMintMapController, KonvaMarkerProvider, LRUCache, MapBuildingProjection, MapCanvasMarkerWrapper, MapCanvasWrapper, MapControlWrapper, MapEvent, MapLoadingWithImage, MapMarkerWrapper, MapPolygonWrapper, MapPolylineWrapper, MapUIEvent, Marker, MintMap, MintMapCanvasRenderer, MintMapController, MintMapCore, MintMapProvider, NaverMintMapController, Offset, PointLoading, Polygon, PolygonCalculator, PolygonMarker, Polyline, Position, SPATIAL_GRID_CELL_SIZE, SVGCircle, SVGPolygon, SVGRect, Spacing, SpatialHashGrid, Status, WoongCanvasLayer, calculateTextBoxWidth, computeMarkerOffset, computePolygonOffsets, getClusterInfo, getMapOfType, hexToRgba, isPointInMarkerData, isPointInPolygon, isPointInPolygonData, log, useKonvaMarkerContext, useMarkerMoving, useMintMapController, waiting };
|
package/dist/index.js
CHANGED
|
@@ -65,6 +65,7 @@ Object.defineProperty(exports, 'CanvasDataType', {
|
|
|
65
65
|
enumerable: true,
|
|
66
66
|
get: function () { return types.CanvasDataType; }
|
|
67
67
|
});
|
|
68
|
+
exports.calculateTextBoxWidth = utils.calculateTextBoxWidth;
|
|
68
69
|
exports.computeMarkerOffset = utils.computeMarkerOffset;
|
|
69
70
|
exports.computePolygonOffsets = utils.computePolygonOffsets;
|
|
70
71
|
exports.hexToRgba = utils.hexToRgba;
|
package/dist/index.umd.js
CHANGED
|
@@ -965,6 +965,29 @@
|
|
|
965
965
|
|
|
966
966
|
throw new Error('Invalid hex color format');
|
|
967
967
|
};
|
|
968
|
+
var tempCanvas = document.createElement('canvas');
|
|
969
|
+
var tempCtx = tempCanvas.getContext('2d');
|
|
970
|
+
/**
|
|
971
|
+
* 텍스트 박스의 너비를 계산합니다.
|
|
972
|
+
*
|
|
973
|
+
* @param {Object} params - 파라미터 객체
|
|
974
|
+
* @param {string} params.text - 측정할 텍스트
|
|
975
|
+
* @param {string} params.fontConfig - 폰트 설정 (예: 'bold 16px Arial')
|
|
976
|
+
* @param {number} params.padding - 텍스트 박스에 적용할 패딩 값
|
|
977
|
+
* @param {number} params.minWidth - 최소 너비
|
|
978
|
+
* @returns {number} 계산된 텍스트 박스의 너비
|
|
979
|
+
*/
|
|
980
|
+
|
|
981
|
+
var calculateTextBoxWidth = function (_a) {
|
|
982
|
+
var text = _a.text,
|
|
983
|
+
fontConfig = _a.fontConfig,
|
|
984
|
+
padding = _a.padding,
|
|
985
|
+
minWidth = _a.minWidth;
|
|
986
|
+
if (!tempCtx) return 0;
|
|
987
|
+
tempCtx.font = fontConfig;
|
|
988
|
+
var textWidth = tempCtx.measureText(text).width;
|
|
989
|
+
return Math.max(minWidth, textWidth + padding);
|
|
990
|
+
};
|
|
968
991
|
|
|
969
992
|
var KonvaMarkerContext = React.createContext(null);
|
|
970
993
|
var KonvaMarkerProvider = function (_a) {
|
|
@@ -5617,20 +5640,8 @@
|
|
|
5617
5640
|
// 메인 컴포넌트
|
|
5618
5641
|
// ============================================================================
|
|
5619
5642
|
|
|
5620
|
-
/**
|
|
5621
|
-
* Konva 기반 고성능 마커/폴리곤 렌더링 컴포넌트
|
|
5622
|
-
*
|
|
5623
|
-
* 특징:
|
|
5624
|
-
* - Base/Event 레이어 분리로 성능 최적화
|
|
5625
|
-
* - LRU 캐시로 좌표 변환 결과 캐싱
|
|
5626
|
-
* - Spatial Hash Grid로 빠른 Hit Test
|
|
5627
|
-
* - Viewport Culling으로 보이는 영역만 렌더링
|
|
5628
|
-
*
|
|
5629
|
-
* @template T 마커 데이터의 추가 속성 타입
|
|
5630
|
-
*/
|
|
5631
|
-
|
|
5632
5643
|
var WoongCanvasLayerComponent = function (props) {
|
|
5633
|
-
var
|
|
5644
|
+
var data = props.data,
|
|
5634
5645
|
dataType = props.dataType,
|
|
5635
5646
|
onClick = props.onClick,
|
|
5636
5647
|
onMouseOver = props.onMouseOver,
|
|
@@ -5649,7 +5660,7 @@
|
|
|
5649
5660
|
externalSelectedItem = props.selectedItem,
|
|
5650
5661
|
_f = props.disableInteraction,
|
|
5651
5662
|
disableInteraction = _f === void 0 ? false : _f,
|
|
5652
|
-
options = tslib.__rest(props, ["
|
|
5663
|
+
options = tslib.__rest(props, ["data", "dataType", "onClick", "onMouseOver", "onMouseOut", "enableMultiSelect", "topOnHover", "enableViewportCulling", "cullingMargin", "maxCacheSize", "selectedItems", "selectedItem", "disableInteraction"]); // --------------------------------------------------------------------------
|
|
5653
5664
|
// Hooks & Context
|
|
5654
5665
|
// --------------------------------------------------------------------------
|
|
5655
5666
|
|
|
@@ -5674,9 +5685,9 @@
|
|
|
5674
5685
|
// Data Refs - 선택 및 Hover 상태 관리
|
|
5675
5686
|
// --------------------------------------------------------------------------
|
|
5676
5687
|
|
|
5677
|
-
/**
|
|
5688
|
+
/** data prop을 ref로 추적 (stale closure 방지, useEffect에서 동기화) */
|
|
5678
5689
|
|
|
5679
|
-
var markersRef = React.useRef(
|
|
5690
|
+
var markersRef = React.useRef(data); // --------------------------------------------------------------------------
|
|
5680
5691
|
// State Refs - 선택 및 Hover 상태 관리
|
|
5681
5692
|
// --------------------------------------------------------------------------
|
|
5682
5693
|
|
|
@@ -5848,6 +5859,7 @@
|
|
|
5848
5859
|
};
|
|
5849
5860
|
/**
|
|
5850
5861
|
* 마커 좌표 변환 결과를 캐시하고 반환
|
|
5862
|
+
*
|
|
5851
5863
|
* @param markerData 마커 데이터
|
|
5852
5864
|
* @returns 변환된 좌표 또는 null
|
|
5853
5865
|
*/
|
|
@@ -6318,11 +6330,11 @@
|
|
|
6318
6330
|
|
|
6319
6331
|
try {
|
|
6320
6332
|
var clickedOffset = controller.positionToOffset(event.param.position);
|
|
6321
|
-
var
|
|
6333
|
+
var data_1 = findData(clickedOffset);
|
|
6322
6334
|
|
|
6323
|
-
if (
|
|
6324
|
-
handleLocalClick(
|
|
6325
|
-
onClick(
|
|
6335
|
+
if (data_1) {
|
|
6336
|
+
handleLocalClick(data_1);
|
|
6337
|
+
onClick(data_1, selectedIdsRef.current);
|
|
6326
6338
|
}
|
|
6327
6339
|
} catch (error) {
|
|
6328
6340
|
console.error('[WoongKonvaMarker] handleClick error:', error);
|
|
@@ -6599,13 +6611,13 @@
|
|
|
6599
6611
|
|
|
6600
6612
|
doRenderEvent();
|
|
6601
6613
|
}, [externalSelectedItem]); // --------------------------------------------------------------------------
|
|
6602
|
-
// Lifecycle:
|
|
6614
|
+
// Lifecycle: 데이터 변경 시 렌더링
|
|
6603
6615
|
// --------------------------------------------------------------------------
|
|
6604
6616
|
|
|
6605
6617
|
React.useEffect(function () {
|
|
6606
6618
|
if (!stageRef.current) return; // markersRef 동기화
|
|
6607
6619
|
|
|
6608
|
-
markersRef.current =
|
|
6620
|
+
markersRef.current = data; // 데이터 변경 시 즉시 transform 제거 및 캐시 정리 (겹침 방지)
|
|
6609
6621
|
|
|
6610
6622
|
if (containerRef.current) {
|
|
6611
6623
|
containerRef.current.style.transform = '';
|
|
@@ -6622,18 +6634,18 @@
|
|
|
6622
6634
|
/**
|
|
6623
6635
|
* 선택 상태 동기화 (최적화 버전)
|
|
6624
6636
|
*
|
|
6625
|
-
*
|
|
6637
|
+
* data가 변경되면 selectedItemsMapRef도 업데이트 필요
|
|
6626
6638
|
* (참조가 바뀌므로 기존 Map의 데이터는 stale 상태)
|
|
6627
6639
|
*
|
|
6628
|
-
* 🔥 중요: 화면 밖
|
|
6629
|
-
* - 현재
|
|
6640
|
+
* 🔥 중요: 화면 밖 데이터도 선택 상태 유지!
|
|
6641
|
+
* - 현재 data에 있으면 최신 데이터로 업데이트
|
|
6630
6642
|
* - 없으면 기존 selectedItemsMapRef의 데이터 유지
|
|
6631
6643
|
*
|
|
6632
|
-
* 최적화:
|
|
6633
|
-
* - O(전체
|
|
6644
|
+
* 최적화: data를 Map으로 먼저 변환하여 find() 순회 제거
|
|
6645
|
+
* - O(전체 데이터 수 + 선택된 개수) - 매우 효율적
|
|
6634
6646
|
*/
|
|
6635
6647
|
|
|
6636
|
-
var markersMap = new Map(
|
|
6648
|
+
var markersMap = new Map(data.map(function (m) {
|
|
6637
6649
|
return [m.id, m];
|
|
6638
6650
|
}));
|
|
6639
6651
|
var newSelectedItemsMap = new Map();
|
|
@@ -6656,7 +6668,7 @@
|
|
|
6656
6668
|
selectedItemsMapRef.current = newSelectedItemsMap; // 즉시 렌더링
|
|
6657
6669
|
|
|
6658
6670
|
renderAllImmediate();
|
|
6659
|
-
}, [
|
|
6671
|
+
}, [data]);
|
|
6660
6672
|
return reactDom.createPortal(React__default["default"].createElement("div", {
|
|
6661
6673
|
ref: containerRef,
|
|
6662
6674
|
style: {
|
|
@@ -6667,27 +6679,96 @@
|
|
|
6667
6679
|
}), divElement);
|
|
6668
6680
|
};
|
|
6669
6681
|
/**
|
|
6670
|
-
*
|
|
6682
|
+
* 🚀 WoongCanvasLayer - Konva 기반 초고성능 마커/폴리곤 렌더링 컴포넌트
|
|
6683
|
+
*
|
|
6684
|
+
* ## 📌 주요 특징
|
|
6685
|
+
* - **30,000개 이상의 폴리곤/마커를 60fps로 렌더링**
|
|
6686
|
+
* - **Multi-Layer 아키텍처**: Base/Animation/Event 레이어 분리
|
|
6687
|
+
* - **Spatial Hash Grid**: O(1) 수준의 빠른 Hit Test
|
|
6688
|
+
* - **LRU 캐시**: 좌표 변환 결과 캐싱으로 성능 최적화
|
|
6689
|
+
* - **Viewport Culling**: 화면에 보이는 영역만 렌더링
|
|
6690
|
+
* - **Discriminated Union Props**: 타입 안전한 MARKER/POLYGON 모드
|
|
6691
|
+
*
|
|
6692
|
+
* ## 🎯 사용 방법
|
|
6693
|
+
*
|
|
6694
|
+
* ### 1️⃣ POLYGON 모드 (자동 렌더링)
|
|
6695
|
+
* ```tsx
|
|
6696
|
+
* <WoongCanvasLayer
|
|
6697
|
+
* dataType={CanvasDataType.POLYGON}
|
|
6698
|
+
* data={polygons}
|
|
6699
|
+
* baseFillColor="rgba(255, 100, 100, 0.5)"
|
|
6700
|
+
* baseStrokeColor="rgba(200, 50, 50, 0.8)"
|
|
6701
|
+
* baseLineWidth={2}
|
|
6702
|
+
* selectedFillColor="rgba(255, 193, 7, 0.7)"
|
|
6703
|
+
* selectedStrokeColor="rgba(255, 152, 0, 1)"
|
|
6704
|
+
* selectedLineWidth={4}
|
|
6705
|
+
* hoveredFillColor="rgba(100, 150, 255, 0.8)" // optional
|
|
6706
|
+
* hoveredStrokeColor="rgba(0, 100, 200, 1)" // optional
|
|
6707
|
+
* hoveredLineWidth={3} // optional
|
|
6708
|
+
* enableMultiSelect={true}
|
|
6709
|
+
* onClick={handleClick}
|
|
6710
|
+
* />
|
|
6711
|
+
* ```
|
|
6671
6712
|
*
|
|
6672
|
-
*
|
|
6673
|
-
*
|
|
6674
|
-
*
|
|
6713
|
+
* ### 2️⃣ MARKER 모드 (커스텀 렌더링)
|
|
6714
|
+
* ```tsx
|
|
6715
|
+
* <WoongCanvasLayer
|
|
6716
|
+
* dataType={CanvasDataType.MARKER}
|
|
6717
|
+
* data={markers}
|
|
6718
|
+
* renderBase={renderMarkerBase} // required
|
|
6719
|
+
* renderAnimation={renderMarkerAnimation} // optional
|
|
6720
|
+
* renderEvent={renderMarkerEvent} // optional
|
|
6721
|
+
* topOnHover={true}
|
|
6722
|
+
* onClick={handleClick}
|
|
6723
|
+
* />
|
|
6724
|
+
* ```
|
|
6675
6725
|
*
|
|
6676
|
-
*
|
|
6726
|
+
* ## 📊 데이터 형식
|
|
6727
|
+
* ```typescript
|
|
6728
|
+
* const data: KonvaCanvasMarkerData<T>[] = [
|
|
6729
|
+
* {
|
|
6730
|
+
* id: 'unique-id',
|
|
6731
|
+
* position: new Position(lat, lng),
|
|
6732
|
+
* // POLYGON: paths 필수
|
|
6733
|
+
* paths: [[[lat, lng], [lat, lng], ...]],
|
|
6734
|
+
* // MARKER: boxWidth/boxHeight 권장 (Hit Test 정확도)
|
|
6735
|
+
* boxWidth: 60,
|
|
6736
|
+
* boxHeight: 75,
|
|
6737
|
+
* // 커스텀 데이터
|
|
6738
|
+
* ...customData
|
|
6739
|
+
* }
|
|
6740
|
+
* ];
|
|
6741
|
+
* ```
|
|
6742
|
+
*
|
|
6743
|
+
* ## ⚡ 성능 최적화 팁
|
|
6744
|
+
* 1. **동적 boxWidth 계산**: `measureText()`로 실제 너비 계산 후 전달
|
|
6745
|
+
* 2. **enableViewportCulling**: 대량 데이터 시 필수 (기본 true)
|
|
6746
|
+
* 3. **selectedItems 외부 관리**: 상태를 외부에서 관리하여 리렌더링 최소화
|
|
6747
|
+
* 4. **React.memo 최적화**: 컴포넌트가 자동으로 불필요한 리렌더링 방지
|
|
6748
|
+
*
|
|
6749
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
6750
|
+
*
|
|
6751
|
+
* @example
|
|
6752
|
+
* // 동적 boxWidth 계산 예시
|
|
6753
|
+
* const tempCtx = document.createElement('canvas').getContext('2d');
|
|
6754
|
+
* tempCtx.font = 'bold 15px Arial';
|
|
6755
|
+
* const boxWidth = Math.max(60, tempCtx.measureText(text).width + 20);
|
|
6756
|
+
*
|
|
6757
|
+
* @see {@link https://github.com/your-repo/docs/WoongCanvasLayer.md} 전체 문서
|
|
6677
6758
|
*/
|
|
6678
6759
|
|
|
6679
6760
|
|
|
6680
6761
|
var WoongCanvasLayer = React__default["default"].memo(WoongCanvasLayerComponent, function (prevProps, nextProps) {
|
|
6681
|
-
// 1.
|
|
6682
|
-
var
|
|
6683
|
-
var
|
|
6762
|
+
// 1. data 비교
|
|
6763
|
+
var prevData = prevProps.data;
|
|
6764
|
+
var nextData = nextProps.data; // 참조가 같으면 스킵
|
|
6684
6765
|
|
|
6685
|
-
if (
|
|
6766
|
+
if (prevData !== nextData) {
|
|
6686
6767
|
// 길이가 다르면 변경됨
|
|
6687
|
-
if (
|
|
6768
|
+
if (prevData.length !== nextData.length) return false; // 각 데이터의 ID 비교
|
|
6688
6769
|
|
|
6689
|
-
for (var i = 0; i <
|
|
6690
|
-
if (
|
|
6770
|
+
for (var i = 0; i < prevData.length; i++) {
|
|
6771
|
+
if (prevData[i].id !== nextData[i].id) {
|
|
6691
6772
|
return false; // 변경됨 → 리렌더링
|
|
6692
6773
|
}
|
|
6693
6774
|
}
|
|
@@ -6702,18 +6783,6 @@
|
|
|
6702
6783
|
return false; // 변경됨 → 리렌더링
|
|
6703
6784
|
}
|
|
6704
6785
|
|
|
6705
|
-
if (prevProps.onClick !== nextProps.onClick) {
|
|
6706
|
-
return false; // 변경됨 → 리렌더링
|
|
6707
|
-
}
|
|
6708
|
-
|
|
6709
|
-
if (prevProps.onMouseOver !== nextProps.onMouseOver) {
|
|
6710
|
-
return false; // 변경됨 → 리렌더링
|
|
6711
|
-
}
|
|
6712
|
-
|
|
6713
|
-
if (prevProps.onMouseOut !== nextProps.onMouseOut) {
|
|
6714
|
-
return false; // 변경됨 → 리렌더링
|
|
6715
|
-
}
|
|
6716
|
-
|
|
6717
6786
|
if (prevProps.disableInteraction !== nextProps.disableInteraction) {
|
|
6718
6787
|
return false; // 변경됨 → 리렌더링
|
|
6719
6788
|
}
|
|
@@ -9597,6 +9666,7 @@
|
|
|
9597
9666
|
exports.SpatialHashGrid = SpatialHashGrid;
|
|
9598
9667
|
exports.Status = Status;
|
|
9599
9668
|
exports.WoongCanvasLayer = WoongCanvasLayer;
|
|
9669
|
+
exports.calculateTextBoxWidth = calculateTextBoxWidth;
|
|
9600
9670
|
exports.computeMarkerOffset = computeMarkerOffset;
|
|
9601
9671
|
exports.computePolygonOffsets = computePolygonOffsets;
|
|
9602
9672
|
exports.getClusterInfo = getClusterInfo;
|
package/package.json
CHANGED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
interface Cluster {
|
|
3
|
-
buildingCnt: number;
|
|
4
|
-
lat: number;
|
|
5
|
-
lng: number;
|
|
6
|
-
}
|
|
7
|
-
export interface ClusterMarkerProps {
|
|
8
|
-
cluster: Cluster;
|
|
9
|
-
}
|
|
10
|
-
declare const ClusterMarker: ({ cluster }: ClusterMarkerProps) => JSX.Element;
|
|
11
|
-
export default ClusterMarker;
|