@mint-ui/map 1.2.0-test.4 → 1.2.0-test.6
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/WoongKonvaMarker.d.ts +3 -1
- package/dist/components/mint-map/core/advanced/woongCanvas/WoongKonvaMarker.js +16 -7
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/types.d.ts +2 -2
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.d.ts +9 -1
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.js +55 -6
- package/dist/index.es.js +71 -13
- package/dist/index.umd.js +71 -13
- package/package.json +1 -1
|
@@ -36,6 +36,8 @@ export interface WoongKonvaMarkerProps<T> extends Pick<MarkerOptions, 'zIndex' |
|
|
|
36
36
|
maxCacheSize?: number;
|
|
37
37
|
/** 외부에서 제어하는 선택된 항목 배열 (선택) */
|
|
38
38
|
selectedItems?: KonvaCanvasMarkerData<T>[];
|
|
39
|
+
/** 외부에서 전달된 단일 선택 아이템 (특별한 효과용) */
|
|
40
|
+
selectedItem?: KonvaCanvasMarkerData<T> | null;
|
|
39
41
|
}
|
|
40
42
|
/**
|
|
41
43
|
* 🔥 React.memo 최적화: 마커 배열과 selectedItems 변경 체크
|
|
@@ -46,5 +48,5 @@ export interface WoongKonvaMarkerProps<T> extends Pick<MarkerOptions, 'zIndex' |
|
|
|
46
48
|
*
|
|
47
49
|
* 주의: JSON.stringify() 사용 금지! (매우 느림)
|
|
48
50
|
*/
|
|
49
|
-
declare const WoongKonvaMarker: <T>({ markers, dataType, onClick, onMouseOver, onMouseOut, renderBase, renderAnimation, renderEvent, enableMultiSelect, topOnHover, enableViewportCulling, cullingMargin, maxCacheSize, selectedItems: externalSelectedItems, ...options }: WoongKonvaMarkerProps<T>) => React.ReactPortal;
|
|
51
|
+
declare const WoongKonvaMarker: <T>({ markers, dataType, onClick, onMouseOver, onMouseOut, renderBase, renderAnimation, renderEvent, enableMultiSelect, topOnHover, enableViewportCulling, cullingMargin, maxCacheSize, selectedItems: externalSelectedItems, selectedItem: externalSelectedItem, ...options }: WoongKonvaMarkerProps<T>) => React.ReactPortal;
|
|
50
52
|
export default WoongKonvaMarker;
|
|
@@ -55,7 +55,8 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
55
55
|
_f = _a.maxCacheSize,
|
|
56
56
|
maxCacheSize = _f === void 0 ? performance.DEFAULT_MAX_CACHE_SIZE : _f,
|
|
57
57
|
externalSelectedItems = _a.selectedItems,
|
|
58
|
-
|
|
58
|
+
externalSelectedItem = _a.selectedItem,
|
|
59
|
+
options = tslib.__rest(_a, ["markers", "dataType", "onClick", "onMouseOver", "onMouseOut", "renderBase", "renderAnimation", "renderEvent", "enableMultiSelect", "topOnHover", "enableViewportCulling", "cullingMargin", "maxCacheSize", "selectedItems", "selectedItem"]); // --------------------------------------------------------------------------
|
|
59
60
|
// Hooks & Context
|
|
60
61
|
// --------------------------------------------------------------------------
|
|
61
62
|
|
|
@@ -89,9 +90,9 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
89
90
|
/** 현재 Hover 중인 항목 */
|
|
90
91
|
|
|
91
92
|
var hoveredItemRef = React.useRef(null);
|
|
92
|
-
/**
|
|
93
|
+
/** 외부에서 전달된 선택 항목 (Ref로 관리하여 클로저 문제 해결) */
|
|
93
94
|
|
|
94
|
-
var
|
|
95
|
+
var selectedItemRef = React.useRef(externalSelectedItem);
|
|
95
96
|
/**
|
|
96
97
|
* 선택된 항목의 ID Set
|
|
97
98
|
*
|
|
@@ -439,7 +440,7 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
439
440
|
hoveredItem: hoveredItemRef.current,
|
|
440
441
|
utils: renderUtils,
|
|
441
442
|
selectedItems: selectedItems,
|
|
442
|
-
|
|
443
|
+
selectedItem: selectedItemRef.current
|
|
443
444
|
});
|
|
444
445
|
},
|
|
445
446
|
perfectDrawEnabled: false,
|
|
@@ -643,9 +644,7 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
643
644
|
|
|
644
645
|
|
|
645
646
|
var handleLocalClick = function (data) {
|
|
646
|
-
//
|
|
647
|
-
lastClickedItemRef.current = data; // 1. 선택 상태 업데이트
|
|
648
|
-
|
|
647
|
+
// 1. 선택 상태 업데이트
|
|
649
648
|
if (enableMultiSelect) {
|
|
650
649
|
// 다중 선택: Set과 Map 동시 업데이트
|
|
651
650
|
var newSelected = new Set(selectedIdsRef.current);
|
|
@@ -953,6 +952,16 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
953
952
|
doRenderEvent();
|
|
954
953
|
}, [externalSelectedItems]); // 배열 자체를 dependency로 사용
|
|
955
954
|
// --------------------------------------------------------------------------
|
|
955
|
+
// Lifecycle: 외부 selectedItem 변경 시 Event Layer 리렌더링
|
|
956
|
+
// --------------------------------------------------------------------------
|
|
957
|
+
|
|
958
|
+
React.useEffect(function () {
|
|
959
|
+
if (!stageRef.current) return; // Ref 동기화
|
|
960
|
+
|
|
961
|
+
selectedItemRef.current = externalSelectedItem; // selectedItem이 변경되면 Event Layer만 다시 그림
|
|
962
|
+
|
|
963
|
+
doRenderEvent();
|
|
964
|
+
}, [externalSelectedItem]); // --------------------------------------------------------------------------
|
|
956
965
|
// Lifecycle: 마커 데이터 변경 시 렌더링
|
|
957
966
|
// --------------------------------------------------------------------------
|
|
958
967
|
|
|
@@ -111,8 +111,8 @@ export interface RenderEventParams<T> {
|
|
|
111
111
|
utils: RenderUtils<T>;
|
|
112
112
|
/** 현재 선택된 마커 데이터 배열 (선택 강조용) */
|
|
113
113
|
selectedItems?: KonvaCanvasMarkerData<T>[];
|
|
114
|
-
/**
|
|
115
|
-
|
|
114
|
+
/** 외부에서 전달된 단일 선택 아이템 (특별한 효과용) */
|
|
115
|
+
selectedItem?: KonvaCanvasMarkerData<T> | null;
|
|
116
116
|
}
|
|
117
117
|
/**
|
|
118
118
|
* 커스텀 렌더링 함수 타입 - Event Layer
|
|
@@ -14,7 +14,15 @@ export declare const computeMarkerOffset: (markerData: KonvaCanvasMarkerData<any
|
|
|
14
14
|
*/
|
|
15
15
|
export declare const isPointInPolygon: (point: Offset, polygon: number[][]) => boolean;
|
|
16
16
|
/**
|
|
17
|
-
* 폴리곤 히트 테스트
|
|
17
|
+
* 폴리곤 히트 테스트 (도넛 폴리곤 지원)
|
|
18
|
+
*
|
|
19
|
+
* 로직:
|
|
20
|
+
* 1. 외부 폴리곤(첫 번째): 내부에 있어야 함
|
|
21
|
+
* 2. 내부 구멍들(나머지): 내부에 있으면 안 됨 (evenodd 규칙)
|
|
22
|
+
*
|
|
23
|
+
* 중요: 도넛 폴리곤과 내부 폴리곤은 별개의 polygonData로 처리됨
|
|
24
|
+
* - 도넛 폴리곤 A: isDonutPolygon=true
|
|
25
|
+
* - 내부 폴리곤 B: isDonutPolygon=false (별도 데이터)
|
|
18
26
|
*/
|
|
19
27
|
export declare const isPointInPolygonData: (clickedOffset: Offset, polygonData: KonvaCanvasMarkerData<any>, getPolygonOffsets: (data: KonvaCanvasMarkerData<any>) => number[][][][] | null) => boolean;
|
|
20
28
|
/**
|
|
@@ -72,18 +72,67 @@ var isPointInPolygon = function (point, polygon) {
|
|
|
72
72
|
return inside;
|
|
73
73
|
};
|
|
74
74
|
/**
|
|
75
|
-
* 폴리곤 히트 테스트
|
|
75
|
+
* 폴리곤 히트 테스트 (도넛 폴리곤 지원)
|
|
76
|
+
*
|
|
77
|
+
* 로직:
|
|
78
|
+
* 1. 외부 폴리곤(첫 번째): 내부에 있어야 함
|
|
79
|
+
* 2. 내부 구멍들(나머지): 내부에 있으면 안 됨 (evenodd 규칙)
|
|
80
|
+
*
|
|
81
|
+
* 중요: 도넛 폴리곤과 내부 폴리곤은 별개의 polygonData로 처리됨
|
|
82
|
+
* - 도넛 폴리곤 A: isDonutPolygon=true
|
|
83
|
+
* - 내부 폴리곤 B: isDonutPolygon=false (별도 데이터)
|
|
76
84
|
*/
|
|
77
85
|
|
|
78
86
|
var isPointInPolygonData = function (clickedOffset, polygonData, getPolygonOffsets) {
|
|
79
87
|
var polygonOffsets = getPolygonOffsets(polygonData);
|
|
80
|
-
if (!polygonOffsets) return false;
|
|
88
|
+
if (!polygonOffsets) return false; // 🍩 도넛 폴리곤 처리 (isDonutPolygon === true)
|
|
81
89
|
|
|
82
|
-
|
|
83
|
-
var
|
|
90
|
+
if (polygonData.isDonutPolygon) {
|
|
91
|
+
for (var _i = 0, polygonOffsets_1 = polygonOffsets; _i < polygonOffsets_1.length; _i++) {
|
|
92
|
+
var multiPolygon = polygonOffsets_1[_i];
|
|
93
|
+
if (multiPolygon.length === 0) continue; // 외부 폴리곤만 있는 경우 (구멍 없음) - 일반 폴리곤처럼 처리
|
|
84
94
|
|
|
85
|
-
|
|
86
|
-
|
|
95
|
+
if (multiPolygon.length === 1) {
|
|
96
|
+
if (isPointInPolygon(clickedOffset, multiPolygon[0])) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
continue;
|
|
101
|
+
} // 1. 외부 폴리곤(첫 번째)에 포함되는지 확인
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
var outerPolygon = multiPolygon[0];
|
|
105
|
+
|
|
106
|
+
if (!isPointInPolygon(clickedOffset, outerPolygon)) {
|
|
107
|
+
continue; // 외부 폴리곤 밖이면 다음 multiPolygon 확인
|
|
108
|
+
} // 2. 내부 구멍들(나머지)에 포함되는지 확인
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
for (var i = 1; i < multiPolygon.length; i++) {
|
|
112
|
+
var hole = multiPolygon[i];
|
|
113
|
+
|
|
114
|
+
if (isPointInPolygon(clickedOffset, hole)) {
|
|
115
|
+
// ❌ 구멍 안에 있음 → 이 도넛 폴리곤은 히트 안 됨
|
|
116
|
+
// 다른 multiPolygon 체크하지 않고 바로 false 반환
|
|
117
|
+
// (도넛 폴리곤의 구멍 안은 무조건 클릭 불가)
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
} // ✅ 외부 폴리곤 안 + 구멍 밖 = 히트!
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return false;
|
|
127
|
+
} // 일반 폴리곤 처리 (isDonutPolygon === false 또는 undefined)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
for (var _a = 0, polygonOffsets_2 = polygonOffsets; _a < polygonOffsets_2.length; _a++) {
|
|
131
|
+
var multiPolygon = polygonOffsets_2[_a];
|
|
132
|
+
|
|
133
|
+
for (var _b = 0, multiPolygon_2 = multiPolygon; _b < multiPolygon_2.length; _b++) {
|
|
134
|
+
var polygonGroup = multiPolygon_2[_b];
|
|
135
|
+
if (polygonGroup.length === 0) continue;
|
|
87
136
|
|
|
88
137
|
if (isPointInPolygon(clickedOffset, polygonGroup)) {
|
|
89
138
|
return true;
|
package/dist/index.es.js
CHANGED
|
@@ -860,18 +860,67 @@ var isPointInPolygon = function (point, polygon) {
|
|
|
860
860
|
return inside;
|
|
861
861
|
};
|
|
862
862
|
/**
|
|
863
|
-
* 폴리곤 히트 테스트
|
|
863
|
+
* 폴리곤 히트 테스트 (도넛 폴리곤 지원)
|
|
864
|
+
*
|
|
865
|
+
* 로직:
|
|
866
|
+
* 1. 외부 폴리곤(첫 번째): 내부에 있어야 함
|
|
867
|
+
* 2. 내부 구멍들(나머지): 내부에 있으면 안 됨 (evenodd 규칙)
|
|
868
|
+
*
|
|
869
|
+
* 중요: 도넛 폴리곤과 내부 폴리곤은 별개의 polygonData로 처리됨
|
|
870
|
+
* - 도넛 폴리곤 A: isDonutPolygon=true
|
|
871
|
+
* - 내부 폴리곤 B: isDonutPolygon=false (별도 데이터)
|
|
864
872
|
*/
|
|
865
873
|
|
|
866
874
|
var isPointInPolygonData = function (clickedOffset, polygonData, getPolygonOffsets) {
|
|
867
875
|
var polygonOffsets = getPolygonOffsets(polygonData);
|
|
868
|
-
if (!polygonOffsets) return false;
|
|
876
|
+
if (!polygonOffsets) return false; // 🍩 도넛 폴리곤 처리 (isDonutPolygon === true)
|
|
877
|
+
|
|
878
|
+
if (polygonData.isDonutPolygon) {
|
|
879
|
+
for (var _i = 0, polygonOffsets_1 = polygonOffsets; _i < polygonOffsets_1.length; _i++) {
|
|
880
|
+
var multiPolygon = polygonOffsets_1[_i];
|
|
881
|
+
if (multiPolygon.length === 0) continue; // 외부 폴리곤만 있는 경우 (구멍 없음) - 일반 폴리곤처럼 처리
|
|
882
|
+
|
|
883
|
+
if (multiPolygon.length === 1) {
|
|
884
|
+
if (isPointInPolygon(clickedOffset, multiPolygon[0])) {
|
|
885
|
+
return true;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
continue;
|
|
889
|
+
} // 1. 외부 폴리곤(첫 번째)에 포함되는지 확인
|
|
890
|
+
|
|
869
891
|
|
|
870
|
-
|
|
871
|
-
var multiPolygon = polygonOffsets_1[_i];
|
|
892
|
+
var outerPolygon = multiPolygon[0];
|
|
872
893
|
|
|
873
|
-
|
|
874
|
-
|
|
894
|
+
if (!isPointInPolygon(clickedOffset, outerPolygon)) {
|
|
895
|
+
continue; // 외부 폴리곤 밖이면 다음 multiPolygon 확인
|
|
896
|
+
} // 2. 내부 구멍들(나머지)에 포함되는지 확인
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
for (var i = 1; i < multiPolygon.length; i++) {
|
|
900
|
+
var hole = multiPolygon[i];
|
|
901
|
+
|
|
902
|
+
if (isPointInPolygon(clickedOffset, hole)) {
|
|
903
|
+
// ❌ 구멍 안에 있음 → 이 도넛 폴리곤은 히트 안 됨
|
|
904
|
+
// 다른 multiPolygon 체크하지 않고 바로 false 반환
|
|
905
|
+
// (도넛 폴리곤의 구멍 안은 무조건 클릭 불가)
|
|
906
|
+
return false;
|
|
907
|
+
}
|
|
908
|
+
} // ✅ 외부 폴리곤 안 + 구멍 밖 = 히트!
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
return true;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
return false;
|
|
915
|
+
} // 일반 폴리곤 처리 (isDonutPolygon === false 또는 undefined)
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
for (var _a = 0, polygonOffsets_2 = polygonOffsets; _a < polygonOffsets_2.length; _a++) {
|
|
919
|
+
var multiPolygon = polygonOffsets_2[_a];
|
|
920
|
+
|
|
921
|
+
for (var _b = 0, multiPolygon_2 = multiPolygon; _b < multiPolygon_2.length; _b++) {
|
|
922
|
+
var polygonGroup = multiPolygon_2[_b];
|
|
923
|
+
if (polygonGroup.length === 0) continue;
|
|
875
924
|
|
|
876
925
|
if (isPointInPolygon(clickedOffset, polygonGroup)) {
|
|
877
926
|
return true;
|
|
@@ -5356,7 +5405,8 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
5356
5405
|
_f = _a.maxCacheSize,
|
|
5357
5406
|
maxCacheSize = _f === void 0 ? DEFAULT_MAX_CACHE_SIZE : _f,
|
|
5358
5407
|
externalSelectedItems = _a.selectedItems,
|
|
5359
|
-
|
|
5408
|
+
externalSelectedItem = _a.selectedItem,
|
|
5409
|
+
options = __rest(_a, ["markers", "dataType", "onClick", "onMouseOver", "onMouseOut", "renderBase", "renderAnimation", "renderEvent", "enableMultiSelect", "topOnHover", "enableViewportCulling", "cullingMargin", "maxCacheSize", "selectedItems", "selectedItem"]); // --------------------------------------------------------------------------
|
|
5360
5410
|
// Hooks & Context
|
|
5361
5411
|
// --------------------------------------------------------------------------
|
|
5362
5412
|
|
|
@@ -5390,9 +5440,9 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
5390
5440
|
/** 현재 Hover 중인 항목 */
|
|
5391
5441
|
|
|
5392
5442
|
var hoveredItemRef = useRef(null);
|
|
5393
|
-
/**
|
|
5443
|
+
/** 외부에서 전달된 선택 항목 (Ref로 관리하여 클로저 문제 해결) */
|
|
5394
5444
|
|
|
5395
|
-
var
|
|
5445
|
+
var selectedItemRef = useRef(externalSelectedItem);
|
|
5396
5446
|
/**
|
|
5397
5447
|
* 선택된 항목의 ID Set
|
|
5398
5448
|
*
|
|
@@ -5740,7 +5790,7 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
5740
5790
|
hoveredItem: hoveredItemRef.current,
|
|
5741
5791
|
utils: renderUtils,
|
|
5742
5792
|
selectedItems: selectedItems,
|
|
5743
|
-
|
|
5793
|
+
selectedItem: selectedItemRef.current
|
|
5744
5794
|
});
|
|
5745
5795
|
},
|
|
5746
5796
|
perfectDrawEnabled: false,
|
|
@@ -5944,9 +5994,7 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
5944
5994
|
|
|
5945
5995
|
|
|
5946
5996
|
var handleLocalClick = function (data) {
|
|
5947
|
-
//
|
|
5948
|
-
lastClickedItemRef.current = data; // 1. 선택 상태 업데이트
|
|
5949
|
-
|
|
5997
|
+
// 1. 선택 상태 업데이트
|
|
5950
5998
|
if (enableMultiSelect) {
|
|
5951
5999
|
// 다중 선택: Set과 Map 동시 업데이트
|
|
5952
6000
|
var newSelected = new Set(selectedIdsRef.current);
|
|
@@ -6254,6 +6302,16 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
6254
6302
|
doRenderEvent();
|
|
6255
6303
|
}, [externalSelectedItems]); // 배열 자체를 dependency로 사용
|
|
6256
6304
|
// --------------------------------------------------------------------------
|
|
6305
|
+
// Lifecycle: 외부 selectedItem 변경 시 Event Layer 리렌더링
|
|
6306
|
+
// --------------------------------------------------------------------------
|
|
6307
|
+
|
|
6308
|
+
useEffect(function () {
|
|
6309
|
+
if (!stageRef.current) return; // Ref 동기화
|
|
6310
|
+
|
|
6311
|
+
selectedItemRef.current = externalSelectedItem; // selectedItem이 변경되면 Event Layer만 다시 그림
|
|
6312
|
+
|
|
6313
|
+
doRenderEvent();
|
|
6314
|
+
}, [externalSelectedItem]); // --------------------------------------------------------------------------
|
|
6257
6315
|
// Lifecycle: 마커 데이터 변경 시 렌더링
|
|
6258
6316
|
// --------------------------------------------------------------------------
|
|
6259
6317
|
|
package/dist/index.umd.js
CHANGED
|
@@ -864,18 +864,67 @@
|
|
|
864
864
|
return inside;
|
|
865
865
|
};
|
|
866
866
|
/**
|
|
867
|
-
* 폴리곤 히트 테스트
|
|
867
|
+
* 폴리곤 히트 테스트 (도넛 폴리곤 지원)
|
|
868
|
+
*
|
|
869
|
+
* 로직:
|
|
870
|
+
* 1. 외부 폴리곤(첫 번째): 내부에 있어야 함
|
|
871
|
+
* 2. 내부 구멍들(나머지): 내부에 있으면 안 됨 (evenodd 규칙)
|
|
872
|
+
*
|
|
873
|
+
* 중요: 도넛 폴리곤과 내부 폴리곤은 별개의 polygonData로 처리됨
|
|
874
|
+
* - 도넛 폴리곤 A: isDonutPolygon=true
|
|
875
|
+
* - 내부 폴리곤 B: isDonutPolygon=false (별도 데이터)
|
|
868
876
|
*/
|
|
869
877
|
|
|
870
878
|
var isPointInPolygonData = function (clickedOffset, polygonData, getPolygonOffsets) {
|
|
871
879
|
var polygonOffsets = getPolygonOffsets(polygonData);
|
|
872
|
-
if (!polygonOffsets) return false;
|
|
880
|
+
if (!polygonOffsets) return false; // 🍩 도넛 폴리곤 처리 (isDonutPolygon === true)
|
|
881
|
+
|
|
882
|
+
if (polygonData.isDonutPolygon) {
|
|
883
|
+
for (var _i = 0, polygonOffsets_1 = polygonOffsets; _i < polygonOffsets_1.length; _i++) {
|
|
884
|
+
var multiPolygon = polygonOffsets_1[_i];
|
|
885
|
+
if (multiPolygon.length === 0) continue; // 외부 폴리곤만 있는 경우 (구멍 없음) - 일반 폴리곤처럼 처리
|
|
886
|
+
|
|
887
|
+
if (multiPolygon.length === 1) {
|
|
888
|
+
if (isPointInPolygon(clickedOffset, multiPolygon[0])) {
|
|
889
|
+
return true;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
continue;
|
|
893
|
+
} // 1. 외부 폴리곤(첫 번째)에 포함되는지 확인
|
|
894
|
+
|
|
873
895
|
|
|
874
|
-
|
|
875
|
-
var multiPolygon = polygonOffsets_1[_i];
|
|
896
|
+
var outerPolygon = multiPolygon[0];
|
|
876
897
|
|
|
877
|
-
|
|
878
|
-
|
|
898
|
+
if (!isPointInPolygon(clickedOffset, outerPolygon)) {
|
|
899
|
+
continue; // 외부 폴리곤 밖이면 다음 multiPolygon 확인
|
|
900
|
+
} // 2. 내부 구멍들(나머지)에 포함되는지 확인
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
for (var i = 1; i < multiPolygon.length; i++) {
|
|
904
|
+
var hole = multiPolygon[i];
|
|
905
|
+
|
|
906
|
+
if (isPointInPolygon(clickedOffset, hole)) {
|
|
907
|
+
// ❌ 구멍 안에 있음 → 이 도넛 폴리곤은 히트 안 됨
|
|
908
|
+
// 다른 multiPolygon 체크하지 않고 바로 false 반환
|
|
909
|
+
// (도넛 폴리곤의 구멍 안은 무조건 클릭 불가)
|
|
910
|
+
return false;
|
|
911
|
+
}
|
|
912
|
+
} // ✅ 외부 폴리곤 안 + 구멍 밖 = 히트!
|
|
913
|
+
|
|
914
|
+
|
|
915
|
+
return true;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
return false;
|
|
919
|
+
} // 일반 폴리곤 처리 (isDonutPolygon === false 또는 undefined)
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
for (var _a = 0, polygonOffsets_2 = polygonOffsets; _a < polygonOffsets_2.length; _a++) {
|
|
923
|
+
var multiPolygon = polygonOffsets_2[_a];
|
|
924
|
+
|
|
925
|
+
for (var _b = 0, multiPolygon_2 = multiPolygon; _b < multiPolygon_2.length; _b++) {
|
|
926
|
+
var polygonGroup = multiPolygon_2[_b];
|
|
927
|
+
if (polygonGroup.length === 0) continue;
|
|
879
928
|
|
|
880
929
|
if (isPointInPolygon(clickedOffset, polygonGroup)) {
|
|
881
930
|
return true;
|
|
@@ -5360,7 +5409,8 @@
|
|
|
5360
5409
|
_f = _a.maxCacheSize,
|
|
5361
5410
|
maxCacheSize = _f === void 0 ? DEFAULT_MAX_CACHE_SIZE : _f,
|
|
5362
5411
|
externalSelectedItems = _a.selectedItems,
|
|
5363
|
-
|
|
5412
|
+
externalSelectedItem = _a.selectedItem,
|
|
5413
|
+
options = tslib.__rest(_a, ["markers", "dataType", "onClick", "onMouseOver", "onMouseOut", "renderBase", "renderAnimation", "renderEvent", "enableMultiSelect", "topOnHover", "enableViewportCulling", "cullingMargin", "maxCacheSize", "selectedItems", "selectedItem"]); // --------------------------------------------------------------------------
|
|
5364
5414
|
// Hooks & Context
|
|
5365
5415
|
// --------------------------------------------------------------------------
|
|
5366
5416
|
|
|
@@ -5394,9 +5444,9 @@
|
|
|
5394
5444
|
/** 현재 Hover 중인 항목 */
|
|
5395
5445
|
|
|
5396
5446
|
var hoveredItemRef = React.useRef(null);
|
|
5397
|
-
/**
|
|
5447
|
+
/** 외부에서 전달된 선택 항목 (Ref로 관리하여 클로저 문제 해결) */
|
|
5398
5448
|
|
|
5399
|
-
var
|
|
5449
|
+
var selectedItemRef = React.useRef(externalSelectedItem);
|
|
5400
5450
|
/**
|
|
5401
5451
|
* 선택된 항목의 ID Set
|
|
5402
5452
|
*
|
|
@@ -5744,7 +5794,7 @@
|
|
|
5744
5794
|
hoveredItem: hoveredItemRef.current,
|
|
5745
5795
|
utils: renderUtils,
|
|
5746
5796
|
selectedItems: selectedItems,
|
|
5747
|
-
|
|
5797
|
+
selectedItem: selectedItemRef.current
|
|
5748
5798
|
});
|
|
5749
5799
|
},
|
|
5750
5800
|
perfectDrawEnabled: false,
|
|
@@ -5948,9 +5998,7 @@
|
|
|
5948
5998
|
|
|
5949
5999
|
|
|
5950
6000
|
var handleLocalClick = function (data) {
|
|
5951
|
-
//
|
|
5952
|
-
lastClickedItemRef.current = data; // 1. 선택 상태 업데이트
|
|
5953
|
-
|
|
6001
|
+
// 1. 선택 상태 업데이트
|
|
5954
6002
|
if (enableMultiSelect) {
|
|
5955
6003
|
// 다중 선택: Set과 Map 동시 업데이트
|
|
5956
6004
|
var newSelected = new Set(selectedIdsRef.current);
|
|
@@ -6258,6 +6306,16 @@
|
|
|
6258
6306
|
doRenderEvent();
|
|
6259
6307
|
}, [externalSelectedItems]); // 배열 자체를 dependency로 사용
|
|
6260
6308
|
// --------------------------------------------------------------------------
|
|
6309
|
+
// Lifecycle: 외부 selectedItem 변경 시 Event Layer 리렌더링
|
|
6310
|
+
// --------------------------------------------------------------------------
|
|
6311
|
+
|
|
6312
|
+
React.useEffect(function () {
|
|
6313
|
+
if (!stageRef.current) return; // Ref 동기화
|
|
6314
|
+
|
|
6315
|
+
selectedItemRef.current = externalSelectedItem; // selectedItem이 변경되면 Event Layer만 다시 그림
|
|
6316
|
+
|
|
6317
|
+
doRenderEvent();
|
|
6318
|
+
}, [externalSelectedItem]); // --------------------------------------------------------------------------
|
|
6261
6319
|
// Lifecycle: 마커 데이터 변경 시 렌더링
|
|
6262
6320
|
// --------------------------------------------------------------------------
|
|
6263
6321
|
|