@mint-ui/map 1.2.0-test.18 → 1.2.0-test.19
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/advanced/woongCanvas/WoongCanvasLayer.js +23 -17
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/types.d.ts +1 -0
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.d.ts +6 -1
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.js +10 -3
- package/dist/index.es.js +33 -20
- package/dist/index.umd.js +33 -20
- package/package.json +1 -1
|
@@ -71,7 +71,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
71
71
|
|
|
72
72
|
/** data prop을 ref로 추적 (stale closure 방지, useEffect에서 동기화) */
|
|
73
73
|
|
|
74
|
-
var
|
|
74
|
+
var dataRef = React.useRef(data); // --------------------------------------------------------------------------
|
|
75
75
|
// State Refs - 선택 및 Hover 상태 관리
|
|
76
76
|
// --------------------------------------------------------------------------
|
|
77
77
|
|
|
@@ -222,6 +222,10 @@ var WoongCanvasLayer = function (props) {
|
|
|
222
222
|
/**
|
|
223
223
|
* 아이템의 바운딩 박스 계산 (폴리곤/마커 공통)
|
|
224
224
|
*
|
|
225
|
+
* 🎯 마커의 경우:
|
|
226
|
+
* - boxHeight: 본체만 (Hit Test 영역)
|
|
227
|
+
* - tailHeight: 꼬리 높이 (Viewport Culling용, 화면에 보이는 전체 영역)
|
|
228
|
+
*
|
|
225
229
|
* @param item 마커 또는 폴리곤 데이터
|
|
226
230
|
* @returns 바운딩 박스 또는 null
|
|
227
231
|
*/
|
|
@@ -262,14 +266,16 @@ var WoongCanvasLayer = function (props) {
|
|
|
262
266
|
maxY: maxY
|
|
263
267
|
};
|
|
264
268
|
} else {
|
|
265
|
-
// 마커: 중심점 기준 박스 크기 계산
|
|
269
|
+
// 마커: 중심점 기준 박스 크기 계산 (꼬리 포함)
|
|
266
270
|
var offset = getOrComputeMarkerOffset(item);
|
|
267
271
|
if (!offset) return null;
|
|
268
272
|
var boxWidth = item.boxWidth || 50;
|
|
269
273
|
var boxHeight = item.boxHeight || 28;
|
|
274
|
+
var tailHeight = item.tailHeight || 0; // 🎯 tailHeight 사용 (Viewport Culling용)
|
|
275
|
+
|
|
270
276
|
return {
|
|
271
277
|
minX: offset.x - boxWidth / 2,
|
|
272
|
-
minY: offset.y - boxHeight -
|
|
278
|
+
minY: offset.y - boxHeight - tailHeight,
|
|
273
279
|
maxX: offset.x + boxWidth / 2,
|
|
274
280
|
maxY: offset.y
|
|
275
281
|
};
|
|
@@ -286,10 +292,10 @@ var WoongCanvasLayer = function (props) {
|
|
|
286
292
|
var buildSpatialIndex = function () {
|
|
287
293
|
var spatial = spatialIndexRef.current;
|
|
288
294
|
spatial.clear();
|
|
289
|
-
var
|
|
295
|
+
var currentData = dataRef.current;
|
|
290
296
|
|
|
291
|
-
for (var _i = 0,
|
|
292
|
-
var item =
|
|
297
|
+
for (var _i = 0, currentData_1 = currentData; _i < currentData_1.length; _i++) {
|
|
298
|
+
var item = currentData_1[_i]; // 바운딩 박스 계산 (공통 함수 사용)
|
|
293
299
|
|
|
294
300
|
var bbox = computeBoundingBox(item);
|
|
295
301
|
|
|
@@ -353,13 +359,13 @@ var WoongCanvasLayer = function (props) {
|
|
|
353
359
|
var ctx = context;
|
|
354
360
|
var hovered = hoveredItemRef.current; // 클로저로 최신 ref 값 참조
|
|
355
361
|
|
|
356
|
-
var
|
|
362
|
+
var visibleItems = enableViewportCulling ? dataRef.current.filter(function (item) {
|
|
357
363
|
return isInViewport(item);
|
|
358
|
-
}) :
|
|
364
|
+
}) : dataRef.current; // topOnHover가 true이고 renderEvent가 없으면 Base Layer에서 hover 처리
|
|
359
365
|
|
|
360
366
|
if (topOnHover && !renderEvent && hovered) {
|
|
361
367
|
// hover된 항목 제외하고 렌더링
|
|
362
|
-
|
|
368
|
+
visibleItems = visibleItems.filter(function (item) {
|
|
363
369
|
return item.id !== hovered.id;
|
|
364
370
|
});
|
|
365
371
|
} // 일반 항목 렌더링
|
|
@@ -367,7 +373,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
367
373
|
|
|
368
374
|
renderBase({
|
|
369
375
|
ctx: ctx,
|
|
370
|
-
items:
|
|
376
|
+
items: visibleItems,
|
|
371
377
|
selectedIds: selectedIdsRef.current,
|
|
372
378
|
utils: renderUtils
|
|
373
379
|
}); // hover된 항목을 최상단에 렌더링 (renderEvent가 없을 때만)
|
|
@@ -411,7 +417,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
411
417
|
renderAnimation({
|
|
412
418
|
layer: layer,
|
|
413
419
|
selectedIds: selectedIdsRef.current,
|
|
414
|
-
items:
|
|
420
|
+
items: dataRef.current,
|
|
415
421
|
utils: renderUtils
|
|
416
422
|
});
|
|
417
423
|
};
|
|
@@ -1000,9 +1006,9 @@ var WoongCanvasLayer = function (props) {
|
|
|
1000
1006
|
// --------------------------------------------------------------------------
|
|
1001
1007
|
|
|
1002
1008
|
React.useEffect(function () {
|
|
1003
|
-
if (!stageRef.current) return; //
|
|
1009
|
+
if (!stageRef.current) return; // dataRef 동기화
|
|
1004
1010
|
|
|
1005
|
-
|
|
1011
|
+
dataRef.current = data; // 데이터 변경 시 즉시 transform 제거 및 캐시 정리 (겹침 방지)
|
|
1006
1012
|
|
|
1007
1013
|
if (containerRef.current) {
|
|
1008
1014
|
containerRef.current.style.transform = '';
|
|
@@ -1030,13 +1036,13 @@ var WoongCanvasLayer = function (props) {
|
|
|
1030
1036
|
* - O(전체 데이터 수 + 선택된 개수) - 매우 효율적
|
|
1031
1037
|
*/
|
|
1032
1038
|
|
|
1033
|
-
var
|
|
1039
|
+
var dataMap = new Map(data.map(function (m) {
|
|
1034
1040
|
return [m.id, m];
|
|
1035
1041
|
}));
|
|
1036
1042
|
var newSelectedItemsMap = new Map();
|
|
1037
1043
|
selectedIdsRef.current.forEach(function (id) {
|
|
1038
|
-
// 현재
|
|
1039
|
-
var currentItem =
|
|
1044
|
+
// 현재 data에 있으면 최신 데이터 사용
|
|
1045
|
+
var currentItem = dataMap.get(id);
|
|
1040
1046
|
|
|
1041
1047
|
if (currentItem) {
|
|
1042
1048
|
newSelectedItemsMap.set(id, currentItem);
|
|
@@ -1048,7 +1054,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
1048
1054
|
newSelectedItemsMap.set(id, prevItem);
|
|
1049
1055
|
}
|
|
1050
1056
|
}
|
|
1051
|
-
}); // selectedIdsRef는 그대로 유지 (화면 밖
|
|
1057
|
+
}); // selectedIdsRef는 그대로 유지 (화면 밖 항목도 선택 상태 유지)
|
|
1052
1058
|
|
|
1053
1059
|
selectedItemsMapRef.current = newSelectedItemsMap; // 즉시 렌더링
|
|
1054
1060
|
|
|
@@ -26,7 +26,12 @@ export declare const isPointInPolygon: (point: Offset, polygon: number[][]) => b
|
|
|
26
26
|
*/
|
|
27
27
|
export declare const isPointInPolygonData: (clickedOffset: Offset, polygonData: KonvaCanvasData<any>, getPolygonOffsets: (data: KonvaCanvasData<any>) => number[][][][] | null) => boolean;
|
|
28
28
|
/**
|
|
29
|
-
* 마커 히트 테스트
|
|
29
|
+
* 마커 히트 테스트 (클릭/hover 영역 체크)
|
|
30
|
+
*
|
|
31
|
+
* 🎯 중요: 꼬리(tail)는 Hit Test 영역에서 제외됩니다!
|
|
32
|
+
* - markerOffset.y는 마커 최하단(꼬리 끝) 좌표
|
|
33
|
+
* - boxHeight는 마커 본체만 포함 (꼬리 제외)
|
|
34
|
+
* - tailHeight만큼 위로 올려서 본체만 Hit Test 영역으로 사용
|
|
30
35
|
*/
|
|
31
36
|
export declare const isPointInMarkerData: (clickedOffset: Offset, markerData: KonvaCanvasData<any>, getMarkerOffset: (data: KonvaCanvasData<any>) => Offset | null) => boolean;
|
|
32
37
|
export declare const hexToRgba: (hexColor: string, alpha?: number) => string;
|
|
@@ -143,7 +143,12 @@ var isPointInPolygonData = function (clickedOffset, polygonData, getPolygonOffse
|
|
|
143
143
|
return false;
|
|
144
144
|
};
|
|
145
145
|
/**
|
|
146
|
-
* 마커 히트 테스트
|
|
146
|
+
* 마커 히트 테스트 (클릭/hover 영역 체크)
|
|
147
|
+
*
|
|
148
|
+
* 🎯 중요: 꼬리(tail)는 Hit Test 영역에서 제외됩니다!
|
|
149
|
+
* - markerOffset.y는 마커 최하단(꼬리 끝) 좌표
|
|
150
|
+
* - boxHeight는 마커 본체만 포함 (꼬리 제외)
|
|
151
|
+
* - tailHeight만큼 위로 올려서 본체만 Hit Test 영역으로 사용
|
|
147
152
|
*/
|
|
148
153
|
|
|
149
154
|
var isPointInMarkerData = function (clickedOffset, markerData, getMarkerOffset) {
|
|
@@ -151,9 +156,11 @@ var isPointInMarkerData = function (clickedOffset, markerData, getMarkerOffset)
|
|
|
151
156
|
if (!markerOffset) return false;
|
|
152
157
|
var boxWidth = markerData.boxWidth || 50;
|
|
153
158
|
var boxHeight = markerData.boxHeight || 28;
|
|
154
|
-
var tailHeight =
|
|
159
|
+
var tailHeight = markerData.tailHeight || 0; // 🎯 tailHeight 사용!
|
|
160
|
+
|
|
155
161
|
var x = markerOffset.x - boxWidth / 2;
|
|
156
|
-
var y = markerOffset.y - boxHeight - tailHeight;
|
|
162
|
+
var y = markerOffset.y - boxHeight - tailHeight; // 🔥 꼬리만큼 위로!
|
|
163
|
+
|
|
157
164
|
return clickedOffset.x >= x && clickedOffset.x <= x + boxWidth && clickedOffset.y >= y && clickedOffset.y <= y + boxHeight;
|
|
158
165
|
};
|
|
159
166
|
var hexToRgba = function (hexColor, alpha) {
|
package/dist/index.es.js
CHANGED
|
@@ -931,7 +931,12 @@ var isPointInPolygonData = function (clickedOffset, polygonData, getPolygonOffse
|
|
|
931
931
|
return false;
|
|
932
932
|
};
|
|
933
933
|
/**
|
|
934
|
-
* 마커 히트 테스트
|
|
934
|
+
* 마커 히트 테스트 (클릭/hover 영역 체크)
|
|
935
|
+
*
|
|
936
|
+
* 🎯 중요: 꼬리(tail)는 Hit Test 영역에서 제외됩니다!
|
|
937
|
+
* - markerOffset.y는 마커 최하단(꼬리 끝) 좌표
|
|
938
|
+
* - boxHeight는 마커 본체만 포함 (꼬리 제외)
|
|
939
|
+
* - tailHeight만큼 위로 올려서 본체만 Hit Test 영역으로 사용
|
|
935
940
|
*/
|
|
936
941
|
|
|
937
942
|
var isPointInMarkerData = function (clickedOffset, markerData, getMarkerOffset) {
|
|
@@ -939,9 +944,11 @@ var isPointInMarkerData = function (clickedOffset, markerData, getMarkerOffset)
|
|
|
939
944
|
if (!markerOffset) return false;
|
|
940
945
|
var boxWidth = markerData.boxWidth || 50;
|
|
941
946
|
var boxHeight = markerData.boxHeight || 28;
|
|
942
|
-
var tailHeight =
|
|
947
|
+
var tailHeight = markerData.tailHeight || 0; // 🎯 tailHeight 사용!
|
|
948
|
+
|
|
943
949
|
var x = markerOffset.x - boxWidth / 2;
|
|
944
|
-
var y = markerOffset.y - boxHeight - tailHeight;
|
|
950
|
+
var y = markerOffset.y - boxHeight - tailHeight; // 🔥 꼬리만큼 위로!
|
|
951
|
+
|
|
945
952
|
return clickedOffset.x >= x && clickedOffset.x <= x + boxWidth && clickedOffset.y >= y && clickedOffset.y <= y + boxHeight;
|
|
946
953
|
};
|
|
947
954
|
var hexToRgba = function (hexColor, alpha) {
|
|
@@ -5691,7 +5698,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
5691
5698
|
|
|
5692
5699
|
/** data prop을 ref로 추적 (stale closure 방지, useEffect에서 동기화) */
|
|
5693
5700
|
|
|
5694
|
-
var
|
|
5701
|
+
var dataRef = useRef(data); // --------------------------------------------------------------------------
|
|
5695
5702
|
// State Refs - 선택 및 Hover 상태 관리
|
|
5696
5703
|
// --------------------------------------------------------------------------
|
|
5697
5704
|
|
|
@@ -5842,6 +5849,10 @@ var WoongCanvasLayer = function (props) {
|
|
|
5842
5849
|
/**
|
|
5843
5850
|
* 아이템의 바운딩 박스 계산 (폴리곤/마커 공통)
|
|
5844
5851
|
*
|
|
5852
|
+
* 🎯 마커의 경우:
|
|
5853
|
+
* - boxHeight: 본체만 (Hit Test 영역)
|
|
5854
|
+
* - tailHeight: 꼬리 높이 (Viewport Culling용, 화면에 보이는 전체 영역)
|
|
5855
|
+
*
|
|
5845
5856
|
* @param item 마커 또는 폴리곤 데이터
|
|
5846
5857
|
* @returns 바운딩 박스 또는 null
|
|
5847
5858
|
*/
|
|
@@ -5882,14 +5893,16 @@ var WoongCanvasLayer = function (props) {
|
|
|
5882
5893
|
maxY: maxY
|
|
5883
5894
|
};
|
|
5884
5895
|
} else {
|
|
5885
|
-
// 마커: 중심점 기준 박스 크기 계산
|
|
5896
|
+
// 마커: 중심점 기준 박스 크기 계산 (꼬리 포함)
|
|
5886
5897
|
var offset = getOrComputeMarkerOffset(item);
|
|
5887
5898
|
if (!offset) return null;
|
|
5888
5899
|
var boxWidth = item.boxWidth || 50;
|
|
5889
5900
|
var boxHeight = item.boxHeight || 28;
|
|
5901
|
+
var tailHeight = item.tailHeight || 0; // 🎯 tailHeight 사용 (Viewport Culling용)
|
|
5902
|
+
|
|
5890
5903
|
return {
|
|
5891
5904
|
minX: offset.x - boxWidth / 2,
|
|
5892
|
-
minY: offset.y - boxHeight -
|
|
5905
|
+
minY: offset.y - boxHeight - tailHeight,
|
|
5893
5906
|
maxX: offset.x + boxWidth / 2,
|
|
5894
5907
|
maxY: offset.y
|
|
5895
5908
|
};
|
|
@@ -5906,10 +5919,10 @@ var WoongCanvasLayer = function (props) {
|
|
|
5906
5919
|
var buildSpatialIndex = function () {
|
|
5907
5920
|
var spatial = spatialIndexRef.current;
|
|
5908
5921
|
spatial.clear();
|
|
5909
|
-
var
|
|
5922
|
+
var currentData = dataRef.current;
|
|
5910
5923
|
|
|
5911
|
-
for (var _i = 0,
|
|
5912
|
-
var item =
|
|
5924
|
+
for (var _i = 0, currentData_1 = currentData; _i < currentData_1.length; _i++) {
|
|
5925
|
+
var item = currentData_1[_i]; // 바운딩 박스 계산 (공통 함수 사용)
|
|
5913
5926
|
|
|
5914
5927
|
var bbox = computeBoundingBox(item);
|
|
5915
5928
|
|
|
@@ -5973,13 +5986,13 @@ var WoongCanvasLayer = function (props) {
|
|
|
5973
5986
|
var ctx = context;
|
|
5974
5987
|
var hovered = hoveredItemRef.current; // 클로저로 최신 ref 값 참조
|
|
5975
5988
|
|
|
5976
|
-
var
|
|
5989
|
+
var visibleItems = enableViewportCulling ? dataRef.current.filter(function (item) {
|
|
5977
5990
|
return isInViewport(item);
|
|
5978
|
-
}) :
|
|
5991
|
+
}) : dataRef.current; // topOnHover가 true이고 renderEvent가 없으면 Base Layer에서 hover 처리
|
|
5979
5992
|
|
|
5980
5993
|
if (topOnHover && !renderEvent && hovered) {
|
|
5981
5994
|
// hover된 항목 제외하고 렌더링
|
|
5982
|
-
|
|
5995
|
+
visibleItems = visibleItems.filter(function (item) {
|
|
5983
5996
|
return item.id !== hovered.id;
|
|
5984
5997
|
});
|
|
5985
5998
|
} // 일반 항목 렌더링
|
|
@@ -5987,7 +6000,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
5987
6000
|
|
|
5988
6001
|
renderBase({
|
|
5989
6002
|
ctx: ctx,
|
|
5990
|
-
items:
|
|
6003
|
+
items: visibleItems,
|
|
5991
6004
|
selectedIds: selectedIdsRef.current,
|
|
5992
6005
|
utils: renderUtils
|
|
5993
6006
|
}); // hover된 항목을 최상단에 렌더링 (renderEvent가 없을 때만)
|
|
@@ -6031,7 +6044,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
6031
6044
|
renderAnimation({
|
|
6032
6045
|
layer: layer,
|
|
6033
6046
|
selectedIds: selectedIdsRef.current,
|
|
6034
|
-
items:
|
|
6047
|
+
items: dataRef.current,
|
|
6035
6048
|
utils: renderUtils
|
|
6036
6049
|
});
|
|
6037
6050
|
};
|
|
@@ -6620,9 +6633,9 @@ var WoongCanvasLayer = function (props) {
|
|
|
6620
6633
|
// --------------------------------------------------------------------------
|
|
6621
6634
|
|
|
6622
6635
|
useEffect(function () {
|
|
6623
|
-
if (!stageRef.current) return; //
|
|
6636
|
+
if (!stageRef.current) return; // dataRef 동기화
|
|
6624
6637
|
|
|
6625
|
-
|
|
6638
|
+
dataRef.current = data; // 데이터 변경 시 즉시 transform 제거 및 캐시 정리 (겹침 방지)
|
|
6626
6639
|
|
|
6627
6640
|
if (containerRef.current) {
|
|
6628
6641
|
containerRef.current.style.transform = '';
|
|
@@ -6650,13 +6663,13 @@ var WoongCanvasLayer = function (props) {
|
|
|
6650
6663
|
* - O(전체 데이터 수 + 선택된 개수) - 매우 효율적
|
|
6651
6664
|
*/
|
|
6652
6665
|
|
|
6653
|
-
var
|
|
6666
|
+
var dataMap = new Map(data.map(function (m) {
|
|
6654
6667
|
return [m.id, m];
|
|
6655
6668
|
}));
|
|
6656
6669
|
var newSelectedItemsMap = new Map();
|
|
6657
6670
|
selectedIdsRef.current.forEach(function (id) {
|
|
6658
|
-
// 현재
|
|
6659
|
-
var currentItem =
|
|
6671
|
+
// 현재 data에 있으면 최신 데이터 사용
|
|
6672
|
+
var currentItem = dataMap.get(id);
|
|
6660
6673
|
|
|
6661
6674
|
if (currentItem) {
|
|
6662
6675
|
newSelectedItemsMap.set(id, currentItem);
|
|
@@ -6668,7 +6681,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
6668
6681
|
newSelectedItemsMap.set(id, prevItem);
|
|
6669
6682
|
}
|
|
6670
6683
|
}
|
|
6671
|
-
}); // selectedIdsRef는 그대로 유지 (화면 밖
|
|
6684
|
+
}); // selectedIdsRef는 그대로 유지 (화면 밖 항목도 선택 상태 유지)
|
|
6672
6685
|
|
|
6673
6686
|
selectedItemsMapRef.current = newSelectedItemsMap; // 즉시 렌더링
|
|
6674
6687
|
|
package/dist/index.umd.js
CHANGED
|
@@ -935,7 +935,12 @@
|
|
|
935
935
|
return false;
|
|
936
936
|
};
|
|
937
937
|
/**
|
|
938
|
-
* 마커 히트 테스트
|
|
938
|
+
* 마커 히트 테스트 (클릭/hover 영역 체크)
|
|
939
|
+
*
|
|
940
|
+
* 🎯 중요: 꼬리(tail)는 Hit Test 영역에서 제외됩니다!
|
|
941
|
+
* - markerOffset.y는 마커 최하단(꼬리 끝) 좌표
|
|
942
|
+
* - boxHeight는 마커 본체만 포함 (꼬리 제외)
|
|
943
|
+
* - tailHeight만큼 위로 올려서 본체만 Hit Test 영역으로 사용
|
|
939
944
|
*/
|
|
940
945
|
|
|
941
946
|
var isPointInMarkerData = function (clickedOffset, markerData, getMarkerOffset) {
|
|
@@ -943,9 +948,11 @@
|
|
|
943
948
|
if (!markerOffset) return false;
|
|
944
949
|
var boxWidth = markerData.boxWidth || 50;
|
|
945
950
|
var boxHeight = markerData.boxHeight || 28;
|
|
946
|
-
var tailHeight =
|
|
951
|
+
var tailHeight = markerData.tailHeight || 0; // 🎯 tailHeight 사용!
|
|
952
|
+
|
|
947
953
|
var x = markerOffset.x - boxWidth / 2;
|
|
948
|
-
var y = markerOffset.y - boxHeight - tailHeight;
|
|
954
|
+
var y = markerOffset.y - boxHeight - tailHeight; // 🔥 꼬리만큼 위로!
|
|
955
|
+
|
|
949
956
|
return clickedOffset.x >= x && clickedOffset.x <= x + boxWidth && clickedOffset.y >= y && clickedOffset.y <= y + boxHeight;
|
|
950
957
|
};
|
|
951
958
|
var hexToRgba = function (hexColor, alpha) {
|
|
@@ -5695,7 +5702,7 @@
|
|
|
5695
5702
|
|
|
5696
5703
|
/** data prop을 ref로 추적 (stale closure 방지, useEffect에서 동기화) */
|
|
5697
5704
|
|
|
5698
|
-
var
|
|
5705
|
+
var dataRef = React.useRef(data); // --------------------------------------------------------------------------
|
|
5699
5706
|
// State Refs - 선택 및 Hover 상태 관리
|
|
5700
5707
|
// --------------------------------------------------------------------------
|
|
5701
5708
|
|
|
@@ -5846,6 +5853,10 @@
|
|
|
5846
5853
|
/**
|
|
5847
5854
|
* 아이템의 바운딩 박스 계산 (폴리곤/마커 공통)
|
|
5848
5855
|
*
|
|
5856
|
+
* 🎯 마커의 경우:
|
|
5857
|
+
* - boxHeight: 본체만 (Hit Test 영역)
|
|
5858
|
+
* - tailHeight: 꼬리 높이 (Viewport Culling용, 화면에 보이는 전체 영역)
|
|
5859
|
+
*
|
|
5849
5860
|
* @param item 마커 또는 폴리곤 데이터
|
|
5850
5861
|
* @returns 바운딩 박스 또는 null
|
|
5851
5862
|
*/
|
|
@@ -5886,14 +5897,16 @@
|
|
|
5886
5897
|
maxY: maxY
|
|
5887
5898
|
};
|
|
5888
5899
|
} else {
|
|
5889
|
-
// 마커: 중심점 기준 박스 크기 계산
|
|
5900
|
+
// 마커: 중심점 기준 박스 크기 계산 (꼬리 포함)
|
|
5890
5901
|
var offset = getOrComputeMarkerOffset(item);
|
|
5891
5902
|
if (!offset) return null;
|
|
5892
5903
|
var boxWidth = item.boxWidth || 50;
|
|
5893
5904
|
var boxHeight = item.boxHeight || 28;
|
|
5905
|
+
var tailHeight = item.tailHeight || 0; // 🎯 tailHeight 사용 (Viewport Culling용)
|
|
5906
|
+
|
|
5894
5907
|
return {
|
|
5895
5908
|
minX: offset.x - boxWidth / 2,
|
|
5896
|
-
minY: offset.y - boxHeight -
|
|
5909
|
+
minY: offset.y - boxHeight - tailHeight,
|
|
5897
5910
|
maxX: offset.x + boxWidth / 2,
|
|
5898
5911
|
maxY: offset.y
|
|
5899
5912
|
};
|
|
@@ -5910,10 +5923,10 @@
|
|
|
5910
5923
|
var buildSpatialIndex = function () {
|
|
5911
5924
|
var spatial = spatialIndexRef.current;
|
|
5912
5925
|
spatial.clear();
|
|
5913
|
-
var
|
|
5926
|
+
var currentData = dataRef.current;
|
|
5914
5927
|
|
|
5915
|
-
for (var _i = 0,
|
|
5916
|
-
var item =
|
|
5928
|
+
for (var _i = 0, currentData_1 = currentData; _i < currentData_1.length; _i++) {
|
|
5929
|
+
var item = currentData_1[_i]; // 바운딩 박스 계산 (공통 함수 사용)
|
|
5917
5930
|
|
|
5918
5931
|
var bbox = computeBoundingBox(item);
|
|
5919
5932
|
|
|
@@ -5977,13 +5990,13 @@
|
|
|
5977
5990
|
var ctx = context;
|
|
5978
5991
|
var hovered = hoveredItemRef.current; // 클로저로 최신 ref 값 참조
|
|
5979
5992
|
|
|
5980
|
-
var
|
|
5993
|
+
var visibleItems = enableViewportCulling ? dataRef.current.filter(function (item) {
|
|
5981
5994
|
return isInViewport(item);
|
|
5982
|
-
}) :
|
|
5995
|
+
}) : dataRef.current; // topOnHover가 true이고 renderEvent가 없으면 Base Layer에서 hover 처리
|
|
5983
5996
|
|
|
5984
5997
|
if (topOnHover && !renderEvent && hovered) {
|
|
5985
5998
|
// hover된 항목 제외하고 렌더링
|
|
5986
|
-
|
|
5999
|
+
visibleItems = visibleItems.filter(function (item) {
|
|
5987
6000
|
return item.id !== hovered.id;
|
|
5988
6001
|
});
|
|
5989
6002
|
} // 일반 항목 렌더링
|
|
@@ -5991,7 +6004,7 @@
|
|
|
5991
6004
|
|
|
5992
6005
|
renderBase({
|
|
5993
6006
|
ctx: ctx,
|
|
5994
|
-
items:
|
|
6007
|
+
items: visibleItems,
|
|
5995
6008
|
selectedIds: selectedIdsRef.current,
|
|
5996
6009
|
utils: renderUtils
|
|
5997
6010
|
}); // hover된 항목을 최상단에 렌더링 (renderEvent가 없을 때만)
|
|
@@ -6035,7 +6048,7 @@
|
|
|
6035
6048
|
renderAnimation({
|
|
6036
6049
|
layer: layer,
|
|
6037
6050
|
selectedIds: selectedIdsRef.current,
|
|
6038
|
-
items:
|
|
6051
|
+
items: dataRef.current,
|
|
6039
6052
|
utils: renderUtils
|
|
6040
6053
|
});
|
|
6041
6054
|
};
|
|
@@ -6624,9 +6637,9 @@
|
|
|
6624
6637
|
// --------------------------------------------------------------------------
|
|
6625
6638
|
|
|
6626
6639
|
React.useEffect(function () {
|
|
6627
|
-
if (!stageRef.current) return; //
|
|
6640
|
+
if (!stageRef.current) return; // dataRef 동기화
|
|
6628
6641
|
|
|
6629
|
-
|
|
6642
|
+
dataRef.current = data; // 데이터 변경 시 즉시 transform 제거 및 캐시 정리 (겹침 방지)
|
|
6630
6643
|
|
|
6631
6644
|
if (containerRef.current) {
|
|
6632
6645
|
containerRef.current.style.transform = '';
|
|
@@ -6654,13 +6667,13 @@
|
|
|
6654
6667
|
* - O(전체 데이터 수 + 선택된 개수) - 매우 효율적
|
|
6655
6668
|
*/
|
|
6656
6669
|
|
|
6657
|
-
var
|
|
6670
|
+
var dataMap = new Map(data.map(function (m) {
|
|
6658
6671
|
return [m.id, m];
|
|
6659
6672
|
}));
|
|
6660
6673
|
var newSelectedItemsMap = new Map();
|
|
6661
6674
|
selectedIdsRef.current.forEach(function (id) {
|
|
6662
|
-
// 현재
|
|
6663
|
-
var currentItem =
|
|
6675
|
+
// 현재 data에 있으면 최신 데이터 사용
|
|
6676
|
+
var currentItem = dataMap.get(id);
|
|
6664
6677
|
|
|
6665
6678
|
if (currentItem) {
|
|
6666
6679
|
newSelectedItemsMap.set(id, currentItem);
|
|
@@ -6672,7 +6685,7 @@
|
|
|
6672
6685
|
newSelectedItemsMap.set(id, prevItem);
|
|
6673
6686
|
}
|
|
6674
6687
|
}
|
|
6675
|
-
}); // selectedIdsRef는 그대로 유지 (화면 밖
|
|
6688
|
+
}); // selectedIdsRef는 그대로 유지 (화면 밖 항목도 선택 상태 유지)
|
|
6676
6689
|
|
|
6677
6690
|
selectedItemsMapRef.current = newSelectedItemsMap; // 즉시 렌더링
|
|
6678
6691
|
|