@mint-ui/map 1.2.0-test.15 → 1.2.0-test.17
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.d.ts +12 -17
- package/dist/components/mint-map/core/advanced/woongCanvas/WoongCanvasLayer.js +78 -241
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/renderer.d.ts +14 -12
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/renderer.js +29 -21
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/types.d.ts +16 -72
- package/dist/components/mint-map/google/GoogleMintMapController.js +1 -1
- package/dist/components/mint-map/kakao/KakaoMintMapController.js +1 -1
- package/dist/components/mint-map/naver/NaverMintMapController.js +1 -1
- package/dist/index.es.js +107 -262
- package/dist/index.umd.js +107 -262
- package/package.json +1 -1
|
@@ -35,17 +35,15 @@ interface WoongCanvasLayerBaseProps<T> extends Pick<MarkerOptions, 'zIndex' | 'a
|
|
|
35
35
|
/**
|
|
36
36
|
* MARKER 타입 Props - 커스텀 렌더링 필수
|
|
37
37
|
*/
|
|
38
|
-
interface WoongCanvasLayerPropsForMarker<T
|
|
38
|
+
interface WoongCanvasLayerPropsForMarker<T> extends WoongCanvasLayerBaseProps<T> {
|
|
39
39
|
/** 데이터 타입 */
|
|
40
40
|
dataType: CanvasDataType.MARKER;
|
|
41
41
|
/** Base Layer 렌더링 함수 (필수) */
|
|
42
|
-
renderBase: CustomRenderBase<T
|
|
42
|
+
renderBase: CustomRenderBase<T>;
|
|
43
43
|
/** Animation Layer 렌더링 함수 (선택, 애니메이션용) */
|
|
44
|
-
renderAnimation?: CustomRenderAnimation<T
|
|
44
|
+
renderAnimation?: CustomRenderAnimation<T>;
|
|
45
45
|
/** Event Layer 렌더링 함수 (선택) */
|
|
46
|
-
renderEvent?: CustomRenderEvent<T
|
|
47
|
-
/** 렌더링 설정 (색상, 표시 여부, 모양 등) */
|
|
48
|
-
renderConfig?: C;
|
|
46
|
+
renderEvent?: CustomRenderEvent<T>;
|
|
49
47
|
}
|
|
50
48
|
/**
|
|
51
49
|
* POLYGON 타입 Props - 스타일 속성으로 내부 처리
|
|
@@ -59,12 +57,12 @@ interface WoongCanvasLayerPropsForPolygon<T> extends WoongCanvasLayerBaseProps<T
|
|
|
59
57
|
baseStrokeColor: string;
|
|
60
58
|
/** 기본 폴리곤 테두리 두께 (필수) */
|
|
61
59
|
baseLineWidth: number;
|
|
62
|
-
/** 선택된 폴리곤 채우기 색상 (
|
|
63
|
-
selectedFillColor
|
|
64
|
-
/** 선택된 폴리곤 테두리 색상 (
|
|
65
|
-
selectedStrokeColor
|
|
66
|
-
/** 선택된 폴리곤 테두리 두께 (
|
|
67
|
-
selectedLineWidth
|
|
60
|
+
/** 선택된 폴리곤 채우기 색상 (선택) */
|
|
61
|
+
selectedFillColor?: string;
|
|
62
|
+
/** 선택된 폴리곤 테두리 색상 (선택) */
|
|
63
|
+
selectedStrokeColor?: string;
|
|
64
|
+
/** 선택된 폴리곤 테두리 두께 (선택) */
|
|
65
|
+
selectedLineWidth?: number;
|
|
68
66
|
/** 마지막 선택된 폴리곤 채우기 색상 (선택, 기본값: selectedFillColor) */
|
|
69
67
|
activeFillColor?: string;
|
|
70
68
|
/** 마지막 선택된 폴리곤 테두리 색상 (선택, 기본값: selectedStrokeColor) */
|
|
@@ -80,11 +78,9 @@ interface WoongCanvasLayerPropsForPolygon<T> extends WoongCanvasLayerBaseProps<T
|
|
|
80
78
|
}
|
|
81
79
|
/**
|
|
82
80
|
* 최종 Props 타입 - Discriminated Union
|
|
83
|
-
*
|
|
84
|
-
* @template T 데이터 타입
|
|
85
|
-
* @template C 렌더링 설정 타입 (MARKER 모드에서만 사용)
|
|
86
81
|
*/
|
|
87
|
-
export declare type WoongCanvasLayerProps<T
|
|
82
|
+
export declare type WoongCanvasLayerProps<T> = WoongCanvasLayerPropsForMarker<T> | WoongCanvasLayerPropsForPolygon<T>;
|
|
83
|
+
declare const WoongCanvasLayer: <T>(props: WoongCanvasLayerProps<T>) => React.ReactPortal;
|
|
88
84
|
/**
|
|
89
85
|
* 🚀 WoongCanvasLayer - Konva 기반 초고성능 마커/폴리곤 렌더링 컴포넌트
|
|
90
86
|
*
|
|
@@ -163,5 +159,4 @@ export declare type WoongCanvasLayerProps<T, C = any> = WoongCanvasLayerPropsFor
|
|
|
163
159
|
*
|
|
164
160
|
* @see {@link https://github.com/your-repo/docs/WoongCanvasLayer.md} 전체 문서
|
|
165
161
|
*/
|
|
166
|
-
declare const WoongCanvasLayer: <T, C = any>(props: WoongCanvasLayerProps<T, C>) => React.ReactPortal;
|
|
167
162
|
export default WoongCanvasLayer;
|
|
@@ -24,7 +24,7 @@ var Konva__default = /*#__PURE__*/_interopDefaultLegacy(Konva);
|
|
|
24
24
|
// 메인 컴포넌트
|
|
25
25
|
// ============================================================================
|
|
26
26
|
|
|
27
|
-
var
|
|
27
|
+
var WoongCanvasLayer = function (props) {
|
|
28
28
|
var data = props.data,
|
|
29
29
|
dataType = props.dataType,
|
|
30
30
|
onClick = props.onClick,
|
|
@@ -78,9 +78,6 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
78
78
|
/** 상호작용 비활성화 상태 (Ref로 관리하여 클로저 문제 해결) */
|
|
79
79
|
|
|
80
80
|
var disableInteractionRef = React.useRef(disableInteraction);
|
|
81
|
-
/** 렌더링 설정 (Ref로 관리하여 클로저 문제 해결) */
|
|
82
|
-
|
|
83
|
-
var renderConfigRef = React.useRef(dataType === types.CanvasDataType.MARKER ? props.renderConfig : undefined);
|
|
84
81
|
/** 현재 Hover 중인 항목 */
|
|
85
82
|
|
|
86
83
|
var hoveredItemRef = React.useRef(null);
|
|
@@ -169,55 +166,11 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
169
166
|
var bbox = boundingBoxCacheRef.current.get(item.id);
|
|
170
167
|
|
|
171
168
|
if (!bbox) {
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
var minX = Infinity,
|
|
178
|
-
minY = Infinity,
|
|
179
|
-
maxX = -Infinity,
|
|
180
|
-
maxY = -Infinity;
|
|
181
|
-
|
|
182
|
-
for (var _i = 0, offsets_1 = offsets; _i < offsets_1.length; _i++) {
|
|
183
|
-
var multiPolygon = offsets_1[_i];
|
|
184
|
-
|
|
185
|
-
for (var _a = 0, multiPolygon_1 = multiPolygon; _a < multiPolygon_1.length; _a++) {
|
|
186
|
-
var polygonGroup = multiPolygon_1[_a];
|
|
187
|
-
|
|
188
|
-
for (var _b = 0, polygonGroup_1 = polygonGroup; _b < polygonGroup_1.length; _b++) {
|
|
189
|
-
var _c = polygonGroup_1[_b],
|
|
190
|
-
x = _c[0],
|
|
191
|
-
y = _c[1];
|
|
192
|
-
if (x < minX) minX = x;
|
|
193
|
-
if (y < minY) minY = y;
|
|
194
|
-
if (x > maxX) maxX = x;
|
|
195
|
-
if (y > maxY) maxY = y;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
bbox = {
|
|
201
|
-
minX: minX,
|
|
202
|
-
minY: minY,
|
|
203
|
-
maxX: maxX,
|
|
204
|
-
maxY: maxY
|
|
205
|
-
};
|
|
206
|
-
boundingBoxCacheRef.current.set(item.id, bbox);
|
|
207
|
-
} // 마커인 경우
|
|
208
|
-
else {
|
|
209
|
-
var offset = getOrComputeMarkerOffset(item);
|
|
210
|
-
if (!offset) return false;
|
|
211
|
-
var boxWidth = item.boxWidth || 50;
|
|
212
|
-
var boxHeight = item.boxHeight || 28;
|
|
213
|
-
bbox = {
|
|
214
|
-
minX: offset.x - boxWidth / 2,
|
|
215
|
-
minY: offset.y - boxHeight - 6,
|
|
216
|
-
maxX: offset.x + boxWidth / 2,
|
|
217
|
-
maxY: offset.y
|
|
218
|
-
};
|
|
219
|
-
boundingBoxCacheRef.current.set(item.id, bbox);
|
|
220
|
-
}
|
|
169
|
+
// 바운딩 박스 계산 (공통 함수 사용)
|
|
170
|
+
var computed = computeBoundingBox(item);
|
|
171
|
+
if (!computed) return false;
|
|
172
|
+
bbox = computed;
|
|
173
|
+
boundingBoxCacheRef.current.set(item.id, bbox);
|
|
221
174
|
} // 바운딩 박스와 viewport 교차 체크
|
|
222
175
|
|
|
223
176
|
|
|
@@ -263,6 +216,65 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
263
216
|
|
|
264
217
|
return result;
|
|
265
218
|
}; // --------------------------------------------------------------------------
|
|
219
|
+
// 유틸리티 함수: 바운딩 박스 계산
|
|
220
|
+
// --------------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* 아이템의 바운딩 박스 계산 (폴리곤/마커 공통)
|
|
224
|
+
*
|
|
225
|
+
* @param item 마커 또는 폴리곤 데이터
|
|
226
|
+
* @returns 바운딩 박스 또는 null
|
|
227
|
+
*/
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
var computeBoundingBox = function (item) {
|
|
231
|
+
if (dataType === types.CanvasDataType.POLYGON) {
|
|
232
|
+
// 폴리곤: 모든 좌표의 최소/최대값 계산
|
|
233
|
+
var offsets = getOrComputePolygonOffsets(item);
|
|
234
|
+
if (!offsets) return null;
|
|
235
|
+
var minX = Infinity,
|
|
236
|
+
minY = Infinity,
|
|
237
|
+
maxX = -Infinity,
|
|
238
|
+
maxY = -Infinity;
|
|
239
|
+
|
|
240
|
+
for (var _i = 0, offsets_1 = offsets; _i < offsets_1.length; _i++) {
|
|
241
|
+
var multiPolygon = offsets_1[_i];
|
|
242
|
+
|
|
243
|
+
for (var _a = 0, multiPolygon_1 = multiPolygon; _a < multiPolygon_1.length; _a++) {
|
|
244
|
+
var polygonGroup = multiPolygon_1[_a];
|
|
245
|
+
|
|
246
|
+
for (var _b = 0, polygonGroup_1 = polygonGroup; _b < polygonGroup_1.length; _b++) {
|
|
247
|
+
var _c = polygonGroup_1[_b],
|
|
248
|
+
x = _c[0],
|
|
249
|
+
y = _c[1];
|
|
250
|
+
if (x < minX) minX = x;
|
|
251
|
+
if (y < minY) minY = y;
|
|
252
|
+
if (x > maxX) maxX = x;
|
|
253
|
+
if (y > maxY) maxY = y;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
minX: minX,
|
|
260
|
+
minY: minY,
|
|
261
|
+
maxX: maxX,
|
|
262
|
+
maxY: maxY
|
|
263
|
+
};
|
|
264
|
+
} else {
|
|
265
|
+
// 마커: 중심점 기준 박스 크기 계산
|
|
266
|
+
var offset = getOrComputeMarkerOffset(item);
|
|
267
|
+
if (!offset) return null;
|
|
268
|
+
var boxWidth = item.boxWidth || 50;
|
|
269
|
+
var boxHeight = item.boxHeight || 28;
|
|
270
|
+
return {
|
|
271
|
+
minX: offset.x - boxWidth / 2,
|
|
272
|
+
minY: offset.y - boxHeight - 6,
|
|
273
|
+
maxX: offset.x + boxWidth / 2,
|
|
274
|
+
maxY: offset.y
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
}; // --------------------------------------------------------------------------
|
|
266
278
|
// 유틸리티 함수: 공간 인덱싱
|
|
267
279
|
// --------------------------------------------------------------------------
|
|
268
280
|
|
|
@@ -277,52 +289,12 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
277
289
|
var currentMarkers = markersRef.current;
|
|
278
290
|
|
|
279
291
|
for (var _i = 0, currentMarkers_1 = currentMarkers; _i < currentMarkers_1.length; _i++) {
|
|
280
|
-
var item = currentMarkers_1[_i];
|
|
292
|
+
var item = currentMarkers_1[_i]; // 바운딩 박스 계산 (공통 함수 사용)
|
|
281
293
|
|
|
282
|
-
|
|
283
|
-
// 폴리곤: 바운딩 박스 계산 (최적화: 직접 비교)
|
|
284
|
-
var offsets = getOrComputePolygonOffsets(item);
|
|
285
|
-
|
|
286
|
-
if (offsets) {
|
|
287
|
-
var minX = Infinity,
|
|
288
|
-
minY = Infinity,
|
|
289
|
-
maxX = -Infinity,
|
|
290
|
-
maxY = -Infinity;
|
|
291
|
-
|
|
292
|
-
for (var _a = 0, offsets_2 = offsets; _a < offsets_2.length; _a++) {
|
|
293
|
-
var multiPolygon = offsets_2[_a];
|
|
294
|
-
|
|
295
|
-
for (var _b = 0, multiPolygon_2 = multiPolygon; _b < multiPolygon_2.length; _b++) {
|
|
296
|
-
var polygonGroup = multiPolygon_2[_b];
|
|
297
|
-
|
|
298
|
-
for (var _c = 0, polygonGroup_2 = polygonGroup; _c < polygonGroup_2.length; _c++) {
|
|
299
|
-
var _d = polygonGroup_2[_c],
|
|
300
|
-
x = _d[0],
|
|
301
|
-
y = _d[1];
|
|
302
|
-
if (x < minX) minX = x;
|
|
303
|
-
if (y < minY) minY = y;
|
|
304
|
-
if (x > maxX) maxX = x;
|
|
305
|
-
if (y > maxY) maxY = y;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
294
|
+
var bbox = computeBoundingBox(item);
|
|
309
295
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
} else {
|
|
313
|
-
// 마커: 점 기반 바운딩 박스
|
|
314
|
-
var offset = getOrComputeMarkerOffset(item);
|
|
315
|
-
|
|
316
|
-
if (offset) {
|
|
317
|
-
var boxWidth = item.boxWidth || 50;
|
|
318
|
-
var boxHeight = item.boxHeight || 28;
|
|
319
|
-
var tailHeight = 6;
|
|
320
|
-
var minX = offset.x - boxWidth / 2;
|
|
321
|
-
var minY = offset.y - boxHeight - tailHeight;
|
|
322
|
-
var maxX = offset.x + boxWidth / 2;
|
|
323
|
-
var maxY = offset.y;
|
|
324
|
-
spatial.insert(item, minX, minY, maxX, maxY);
|
|
325
|
-
}
|
|
296
|
+
if (bbox) {
|
|
297
|
+
spatial.insert(item, bbox.minX, bbox.minY, bbox.maxX, bbox.maxY);
|
|
326
298
|
}
|
|
327
299
|
}
|
|
328
300
|
}; // --------------------------------------------------------------------------
|
|
@@ -351,7 +323,7 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
351
323
|
var renderAnimation = dataType === types.CanvasDataType.MARKER ? props.renderAnimation : undefined;
|
|
352
324
|
var renderEvent = dataType === types.CanvasDataType.MARKER ? props.renderEvent : function () {
|
|
353
325
|
var polygonProps = props;
|
|
354
|
-
return renderer.renderPolygonEvent(polygonProps.selectedFillColor, polygonProps.selectedStrokeColor, polygonProps.selectedLineWidth, polygonProps.activeFillColor, polygonProps.activeStrokeColor, polygonProps.activeLineWidth, polygonProps.hoveredFillColor, polygonProps.hoveredStrokeColor, polygonProps.hoveredLineWidth);
|
|
326
|
+
return renderer.renderPolygonEvent(polygonProps.baseFillColor, polygonProps.baseStrokeColor, polygonProps.baseLineWidth, polygonProps.selectedFillColor, polygonProps.selectedStrokeColor, polygonProps.selectedLineWidth, polygonProps.activeFillColor, polygonProps.activeStrokeColor, polygonProps.activeLineWidth, polygonProps.hoveredFillColor, polygonProps.hoveredStrokeColor, polygonProps.hoveredLineWidth);
|
|
355
327
|
}();
|
|
356
328
|
/**
|
|
357
329
|
* Base 레이어 렌더링 (뷰포트 컬링 적용, 선택된 마커 제외)
|
|
@@ -383,8 +355,7 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
383
355
|
ctx: ctx,
|
|
384
356
|
items: visibleMarkers,
|
|
385
357
|
selectedIds: selectedIdsRef.current,
|
|
386
|
-
utils: renderUtils
|
|
387
|
-
config: renderConfigRef.current
|
|
358
|
+
utils: renderUtils
|
|
388
359
|
});
|
|
389
360
|
},
|
|
390
361
|
perfectDrawEnabled: false,
|
|
@@ -414,8 +385,7 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
414
385
|
layer: layer,
|
|
415
386
|
selectedIds: selectedIdsRef.current,
|
|
416
387
|
items: markersRef.current,
|
|
417
|
-
utils: renderUtils
|
|
418
|
-
config: renderConfigRef.current
|
|
388
|
+
utils: renderUtils
|
|
419
389
|
});
|
|
420
390
|
};
|
|
421
391
|
/**
|
|
@@ -431,13 +401,6 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
431
401
|
var doRenderEvent = function () {
|
|
432
402
|
var layer = eventLayerRef.current;
|
|
433
403
|
if (!layer) return;
|
|
434
|
-
|
|
435
|
-
if (!onClick && !onMouseOver && !onMouseOut) {
|
|
436
|
-
layer.destroyChildren();
|
|
437
|
-
layer.batchDraw();
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
404
|
if (!renderEvent) return; // 🔥 Shape 재사용: 이미 존재하면 재사용, 없으면 생성
|
|
442
405
|
|
|
443
406
|
var shape = layer.findOne('.event-render-shape');
|
|
@@ -456,8 +419,7 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
456
419
|
hoveredItem: hoveredItemRef.current,
|
|
457
420
|
utils: renderUtils,
|
|
458
421
|
selectedItems: selectedItems,
|
|
459
|
-
selectedItem: selectedItemRef.current
|
|
460
|
-
config: renderConfigRef.current
|
|
422
|
+
selectedItem: selectedItemRef.current
|
|
461
423
|
});
|
|
462
424
|
},
|
|
463
425
|
perfectDrawEnabled: false,
|
|
@@ -637,7 +599,6 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
637
599
|
|
|
638
600
|
|
|
639
601
|
var setHovered = function (data) {
|
|
640
|
-
if (!onMouseOver && !onMouseOut) return;
|
|
641
602
|
hoveredItemRef.current = data;
|
|
642
603
|
|
|
643
604
|
if (draggingRef.current) {
|
|
@@ -662,8 +623,7 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
662
623
|
|
|
663
624
|
|
|
664
625
|
var handleLocalClick = function (data) {
|
|
665
|
-
|
|
666
|
-
|
|
626
|
+
// 1. 선택 상태 업데이트
|
|
667
627
|
if (enableMultiSelect) {
|
|
668
628
|
// 다중 선택: Set과 Map 동시 업데이트
|
|
669
629
|
var newSelected = new Set(selectedIdsRef.current);
|
|
@@ -715,7 +675,6 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
715
675
|
|
|
716
676
|
if (disableInteractionRef.current) return; // 🚫 상호작용 비활성화 시 즉시 반환
|
|
717
677
|
|
|
718
|
-
if (!onClick) return;
|
|
719
678
|
if (context$1 || !((_a = event === null || event === void 0 ? void 0 : event.param) === null || _a === void 0 ? void 0 : _a.position)) return;
|
|
720
679
|
|
|
721
680
|
try {
|
|
@@ -724,7 +683,10 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
724
683
|
|
|
725
684
|
if (data_1) {
|
|
726
685
|
handleLocalClick(data_1);
|
|
727
|
-
|
|
686
|
+
|
|
687
|
+
if (onClick) {
|
|
688
|
+
onClick(data_1, selectedIdsRef.current);
|
|
689
|
+
}
|
|
728
690
|
}
|
|
729
691
|
} catch (error) {
|
|
730
692
|
console.error('[WoongKonvaMarker] handleClick error:', error);
|
|
@@ -740,7 +702,6 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
740
702
|
|
|
741
703
|
if (disableInteractionRef.current) return; // 🚫 상호작용 비활성화 시 즉시 반환
|
|
742
704
|
|
|
743
|
-
if (!onMouseOver && !onMouseOut) return;
|
|
744
705
|
if (context$1 || !((_a = event === null || event === void 0 ? void 0 : event.param) === null || _a === void 0 ? void 0 : _a.position)) return;
|
|
745
706
|
|
|
746
707
|
try {
|
|
@@ -783,7 +744,6 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
783
744
|
var handleMouseLeave = function () {
|
|
784
745
|
if (disableInteractionRef.current) return; // 🚫 상호작용 비활성화 시 즉시 반환
|
|
785
746
|
|
|
786
|
-
if (!onMouseOver && !onMouseOut) return;
|
|
787
747
|
var prevHovered = hoveredItemRef.current;
|
|
788
748
|
|
|
789
749
|
if (prevHovered) {
|
|
@@ -969,18 +929,6 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
969
929
|
React.useEffect(function () {
|
|
970
930
|
disableInteractionRef.current = disableInteraction;
|
|
971
931
|
}, [disableInteraction]); // --------------------------------------------------------------------------
|
|
972
|
-
// Lifecycle: renderConfig 동기화
|
|
973
|
-
// --------------------------------------------------------------------------
|
|
974
|
-
|
|
975
|
-
React.useEffect(function () {
|
|
976
|
-
if (dataType === types.CanvasDataType.MARKER) {
|
|
977
|
-
renderConfigRef.current = props.renderConfig; // config 변경 시 렌더링 업데이트
|
|
978
|
-
|
|
979
|
-
doRenderBase();
|
|
980
|
-
doRenderAnimation();
|
|
981
|
-
doRenderEvent();
|
|
982
|
-
}
|
|
983
|
-
}, [dataType === types.CanvasDataType.MARKER ? props.renderConfig : undefined]); // --------------------------------------------------------------------------
|
|
984
932
|
// Lifecycle: 외부 selectedItems 동기화
|
|
985
933
|
// --------------------------------------------------------------------------
|
|
986
934
|
|
|
@@ -1080,117 +1028,6 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
1080
1028
|
}
|
|
1081
1029
|
}), divElement);
|
|
1082
1030
|
};
|
|
1083
|
-
/**
|
|
1084
|
-
* 🚀 WoongCanvasLayer - Konva 기반 초고성능 마커/폴리곤 렌더링 컴포넌트
|
|
1085
|
-
*
|
|
1086
|
-
* ## 📌 주요 특징
|
|
1087
|
-
* - **30,000개 이상의 폴리곤/마커를 60fps로 렌더링**
|
|
1088
|
-
* - **Multi-Layer 아키텍처**: Base/Animation/Event 레이어 분리
|
|
1089
|
-
* - **Spatial Hash Grid**: O(1) 수준의 빠른 Hit Test
|
|
1090
|
-
* - **LRU 캐시**: 좌표 변환 결과 캐싱으로 성능 최적화
|
|
1091
|
-
* - **Viewport Culling**: 화면에 보이는 영역만 렌더링
|
|
1092
|
-
* - **Discriminated Union Props**: 타입 안전한 MARKER/POLYGON 모드
|
|
1093
|
-
*
|
|
1094
|
-
* ## 🎯 사용 방법
|
|
1095
|
-
*
|
|
1096
|
-
* ### 1️⃣ POLYGON 모드 (자동 렌더링)
|
|
1097
|
-
* ```tsx
|
|
1098
|
-
* <WoongCanvasLayer
|
|
1099
|
-
* dataType={CanvasDataType.POLYGON}
|
|
1100
|
-
* data={polygons}
|
|
1101
|
-
* baseFillColor="rgba(255, 100, 100, 0.5)"
|
|
1102
|
-
* baseStrokeColor="rgba(200, 50, 50, 0.8)"
|
|
1103
|
-
* baseLineWidth={2}
|
|
1104
|
-
* selectedFillColor="rgba(255, 193, 7, 0.7)"
|
|
1105
|
-
* selectedStrokeColor="rgba(255, 152, 0, 1)"
|
|
1106
|
-
* selectedLineWidth={4}
|
|
1107
|
-
* hoveredFillColor="rgba(100, 150, 255, 0.8)" // optional
|
|
1108
|
-
* hoveredStrokeColor="rgba(0, 100, 200, 1)" // optional
|
|
1109
|
-
* hoveredLineWidth={3} // optional
|
|
1110
|
-
* enableMultiSelect={true}
|
|
1111
|
-
* onClick={handleClick}
|
|
1112
|
-
* />
|
|
1113
|
-
* ```
|
|
1114
|
-
*
|
|
1115
|
-
* ### 2️⃣ MARKER 모드 (커스텀 렌더링)
|
|
1116
|
-
* ```tsx
|
|
1117
|
-
* <WoongCanvasLayer
|
|
1118
|
-
* dataType={CanvasDataType.MARKER}
|
|
1119
|
-
* data={markers}
|
|
1120
|
-
* renderBase={renderMarkerBase} // required
|
|
1121
|
-
* renderAnimation={renderMarkerAnimation} // optional
|
|
1122
|
-
* renderEvent={renderMarkerEvent} // optional
|
|
1123
|
-
* topOnHover={true}
|
|
1124
|
-
* onClick={handleClick}
|
|
1125
|
-
* />
|
|
1126
|
-
* ```
|
|
1127
|
-
*
|
|
1128
|
-
* ## 📊 데이터 형식
|
|
1129
|
-
* ```typescript
|
|
1130
|
-
* const data: KonvaCanvasData<T>[] = [
|
|
1131
|
-
* {
|
|
1132
|
-
* id: 'unique-id',
|
|
1133
|
-
* position: new Position(lat, lng),
|
|
1134
|
-
* // POLYGON: paths 필수
|
|
1135
|
-
* paths: [[[lat, lng], [lat, lng], ...]],
|
|
1136
|
-
* // MARKER: boxWidth/boxHeight 권장 (Hit Test 정확도)
|
|
1137
|
-
* boxWidth: 60,
|
|
1138
|
-
* boxHeight: 75,
|
|
1139
|
-
* // 커스텀 데이터
|
|
1140
|
-
* ...customData
|
|
1141
|
-
* }
|
|
1142
|
-
* ];
|
|
1143
|
-
* ```
|
|
1144
|
-
*
|
|
1145
|
-
* ## ⚡ 성능 최적화 팁
|
|
1146
|
-
* 1. **동적 boxWidth 계산**: `measureText()`로 실제 너비 계산 후 전달
|
|
1147
|
-
* 2. **enableViewportCulling**: 대량 데이터 시 필수 (기본 true)
|
|
1148
|
-
* 3. **selectedItems 외부 관리**: 상태를 외부에서 관리하여 리렌더링 최소화
|
|
1149
|
-
* 4. **React.memo 최적화**: 컴포넌트가 자동으로 불필요한 리렌더링 방지
|
|
1150
|
-
*
|
|
1151
|
-
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
1152
|
-
*
|
|
1153
|
-
* @example
|
|
1154
|
-
* // 동적 boxWidth 계산 예시
|
|
1155
|
-
* const tempCtx = document.createElement('canvas').getContext('2d');
|
|
1156
|
-
* tempCtx.font = 'bold 15px Arial';
|
|
1157
|
-
* const boxWidth = Math.max(60, tempCtx.measureText(text).width + 20);
|
|
1158
|
-
*
|
|
1159
|
-
* @see {@link https://github.com/your-repo/docs/WoongCanvasLayer.md} 전체 문서
|
|
1160
|
-
*/
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
var WoongCanvasLayer = React__default["default"].memo(WoongCanvasLayerComponent, function (prevProps, nextProps) {
|
|
1164
|
-
// 1. data 비교
|
|
1165
|
-
var prevData = prevProps.data;
|
|
1166
|
-
var nextData = nextProps.data; // 참조가 같으면 스킵
|
|
1167
|
-
|
|
1168
|
-
if (prevData !== nextData) {
|
|
1169
|
-
// 길이가 다르면 변경됨
|
|
1170
|
-
if (prevData.length !== nextData.length) return false; // 각 데이터의 ID 비교
|
|
1171
|
-
|
|
1172
|
-
for (var i = 0; i < prevData.length; i++) {
|
|
1173
|
-
if (prevData[i].id !== nextData[i].id) {
|
|
1174
|
-
return false; // 변경됨 → 리렌더링
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
} // 2. selectedItems 비교 (참조만 비교)
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
if (prevProps.selectedItems !== nextProps.selectedItems) {
|
|
1181
|
-
return false; // 변경됨 → 리렌더링
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
if (prevProps.selectedItem !== nextProps.selectedItem) {
|
|
1185
|
-
return false; // 변경됨 → 리렌더링
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
if (prevProps.disableInteraction !== nextProps.disableInteraction) {
|
|
1189
|
-
return false; // 변경됨 → 리렌더링
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
return true; // 같음 → 리렌더링 스킵
|
|
1193
|
-
});
|
|
1194
1031
|
|
|
1195
1032
|
Object.defineProperty(exports, 'CanvasDataType', {
|
|
1196
1033
|
enumerable: true,
|
|
@@ -30,13 +30,16 @@ export declare const drawPolygon: ({ ctx, polygonOffsets, isDonutPolygon, fillCo
|
|
|
30
30
|
* 2
|
|
31
31
|
* );
|
|
32
32
|
*/
|
|
33
|
-
export declare const renderPolygonBase: <T = any>(baseFillColor: string, baseStrokeColor: string, baseLineWidth: number) => CustomRenderBase<KonvaCanvasData<T
|
|
33
|
+
export declare const renderPolygonBase: <T = any>(baseFillColor: string, baseStrokeColor: string, baseLineWidth: number) => CustomRenderBase<KonvaCanvasData<T>>;
|
|
34
34
|
/**
|
|
35
35
|
* 폴리곤 Event 렌더링 함수
|
|
36
36
|
*
|
|
37
|
-
* @param
|
|
38
|
-
* @param
|
|
39
|
-
* @param
|
|
37
|
+
* @param baseFillColor 기본 폴리곤 채우기 색상 (필수, fallback용)
|
|
38
|
+
* @param baseStrokeColor 기본 폴리곤 테두리 색상 (필수, fallback용)
|
|
39
|
+
* @param baseLineWidth 기본 폴리곤 테두리 두께 (필수, fallback용)
|
|
40
|
+
* @param selectedFillColor 선택된 폴리곤 채우기 색상 (선택, 기본값: baseFillColor)
|
|
41
|
+
* @param selectedStrokeColor 선택된 폴리곤 테두리 색상 (선택, 기본값: baseStrokeColor)
|
|
42
|
+
* @param selectedLineWidth 선택된 폴리곤 테두리 두께 (선택, 기본값: baseLineWidth)
|
|
40
43
|
* @param activeFillColor 마지막 선택된 폴리곤 채우기 색상 (선택, 기본값: selectedFillColor)
|
|
41
44
|
* @param activeStrokeColor 마지막 선택된 폴리곤 테두리 색상 (선택, 기본값: selectedStrokeColor)
|
|
42
45
|
* @param activeLineWidth 마지막 선택된 폴리곤 테두리 두께 (선택, 기본값: selectedLineWidth)
|
|
@@ -47,13 +50,12 @@ export declare const renderPolygonBase: <T = any>(baseFillColor: string, baseStr
|
|
|
47
50
|
*
|
|
48
51
|
* @example
|
|
49
52
|
* const renderEvent = renderPolygonEvent(
|
|
50
|
-
* 'rgba(255,
|
|
51
|
-
* 'rgba(
|
|
52
|
-
*
|
|
53
|
-
* 'rgba(255,
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* 'rgba(100, 150, 255, 0.8)'
|
|
53
|
+
* 'rgba(255, 100, 100, 0.5)', // baseFillColor
|
|
54
|
+
* 'rgba(200, 50, 50, 0.8)', // baseStrokeColor
|
|
55
|
+
* 2, // baseLineWidth
|
|
56
|
+
* 'rgba(255, 193, 7, 0.7)', // selectedFillColor
|
|
57
|
+
* 'rgba(255, 152, 0, 1)', // selectedStrokeColor
|
|
58
|
+
* 4 // selectedLineWidth
|
|
57
59
|
* );
|
|
58
60
|
*/
|
|
59
|
-
export declare const renderPolygonEvent: <T = any>(
|
|
61
|
+
export declare const renderPolygonEvent: <T = any>(baseFillColor: string, baseStrokeColor: string, baseLineWidth: number, selectedFillColor?: string, selectedStrokeColor?: string, selectedLineWidth?: number, activeFillColor?: string, activeStrokeColor?: string, activeLineWidth?: number, hoveredFillColor?: string, hoveredStrokeColor?: string, hoveredLineWidth?: number) => CustomRenderEvent<KonvaCanvasData<T>>;
|
|
@@ -123,9 +123,12 @@ var renderPolygonBase = function (baseFillColor, baseStrokeColor, baseLineWidth)
|
|
|
123
123
|
/**
|
|
124
124
|
* 폴리곤 Event 렌더링 함수
|
|
125
125
|
*
|
|
126
|
-
* @param
|
|
127
|
-
* @param
|
|
128
|
-
* @param
|
|
126
|
+
* @param baseFillColor 기본 폴리곤 채우기 색상 (필수, fallback용)
|
|
127
|
+
* @param baseStrokeColor 기본 폴리곤 테두리 색상 (필수, fallback용)
|
|
128
|
+
* @param baseLineWidth 기본 폴리곤 테두리 두께 (필수, fallback용)
|
|
129
|
+
* @param selectedFillColor 선택된 폴리곤 채우기 색상 (선택, 기본값: baseFillColor)
|
|
130
|
+
* @param selectedStrokeColor 선택된 폴리곤 테두리 색상 (선택, 기본값: baseStrokeColor)
|
|
131
|
+
* @param selectedLineWidth 선택된 폴리곤 테두리 두께 (선택, 기본값: baseLineWidth)
|
|
129
132
|
* @param activeFillColor 마지막 선택된 폴리곤 채우기 색상 (선택, 기본값: selectedFillColor)
|
|
130
133
|
* @param activeStrokeColor 마지막 선택된 폴리곤 테두리 색상 (선택, 기본값: selectedStrokeColor)
|
|
131
134
|
* @param activeLineWidth 마지막 선택된 폴리곤 테두리 두께 (선택, 기본값: selectedLineWidth)
|
|
@@ -136,29 +139,34 @@ var renderPolygonBase = function (baseFillColor, baseStrokeColor, baseLineWidth)
|
|
|
136
139
|
*
|
|
137
140
|
* @example
|
|
138
141
|
* const renderEvent = renderPolygonEvent(
|
|
139
|
-
* 'rgba(255,
|
|
140
|
-
* 'rgba(
|
|
141
|
-
*
|
|
142
|
-
* 'rgba(255,
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
* 'rgba(100, 150, 255, 0.8)'
|
|
142
|
+
* 'rgba(255, 100, 100, 0.5)', // baseFillColor
|
|
143
|
+
* 'rgba(200, 50, 50, 0.8)', // baseStrokeColor
|
|
144
|
+
* 2, // baseLineWidth
|
|
145
|
+
* 'rgba(255, 193, 7, 0.7)', // selectedFillColor
|
|
146
|
+
* 'rgba(255, 152, 0, 1)', // selectedStrokeColor
|
|
147
|
+
* 4 // selectedLineWidth
|
|
146
148
|
* );
|
|
147
149
|
*/
|
|
148
150
|
|
|
149
|
-
var renderPolygonEvent = function (selectedFillColor, selectedStrokeColor, selectedLineWidth, activeFillColor, activeStrokeColor, activeLineWidth, hoveredFillColor, hoveredStrokeColor, hoveredLineWidth) {
|
|
150
|
-
// 기본값 설정 (
|
|
151
|
-
var
|
|
151
|
+
var renderPolygonEvent = function (baseFillColor, baseStrokeColor, baseLineWidth, selectedFillColor, selectedStrokeColor, selectedLineWidth, activeFillColor, activeStrokeColor, activeLineWidth, hoveredFillColor, hoveredStrokeColor, hoveredLineWidth) {
|
|
152
|
+
// 기본값 설정 (base 기준)
|
|
153
|
+
var _selectedFillColor = selectedFillColor || baseFillColor;
|
|
152
154
|
|
|
153
|
-
var
|
|
155
|
+
var _selectedStrokeColor = selectedStrokeColor || baseStrokeColor;
|
|
154
156
|
|
|
155
|
-
var
|
|
157
|
+
var _selectedLineWidth = selectedLineWidth || baseLineWidth;
|
|
156
158
|
|
|
157
|
-
var
|
|
159
|
+
var _activeFillColor = activeFillColor || _selectedFillColor;
|
|
158
160
|
|
|
159
|
-
var
|
|
161
|
+
var _activeStrokeColor = activeStrokeColor || _selectedStrokeColor;
|
|
160
162
|
|
|
161
|
-
var
|
|
163
|
+
var _activeLineWidth = activeLineWidth || _selectedLineWidth;
|
|
164
|
+
|
|
165
|
+
var _hoveredFillColor = hoveredFillColor || _selectedFillColor;
|
|
166
|
+
|
|
167
|
+
var _hoveredStrokeColor = hoveredStrokeColor || _selectedStrokeColor;
|
|
168
|
+
|
|
169
|
+
var _hoveredLineWidth = hoveredLineWidth || _selectedLineWidth;
|
|
162
170
|
|
|
163
171
|
return function (_a) {
|
|
164
172
|
var ctx = _a.ctx,
|
|
@@ -179,9 +187,9 @@ var renderPolygonEvent = function (selectedFillColor, selectedStrokeColor, selec
|
|
|
179
187
|
ctx: ctx,
|
|
180
188
|
polygonOffsets: polygonOffsets,
|
|
181
189
|
isDonutPolygon: item.isDonutPolygon || false,
|
|
182
|
-
fillColor:
|
|
183
|
-
strokeColor:
|
|
184
|
-
lineWidth:
|
|
190
|
+
fillColor: _selectedFillColor,
|
|
191
|
+
strokeColor: _selectedStrokeColor,
|
|
192
|
+
lineWidth: _selectedLineWidth
|
|
185
193
|
});
|
|
186
194
|
}
|
|
187
195
|
} // 2. 마지막 선택된 항목 그리기 (호버되지 않은 경우)
|