@mint-ui/map 1.2.0-test.20 → 1.2.0-test.21
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 +55 -36
- package/dist/components/mint-map/core/advanced/woongCanvas/index.d.ts +10 -0
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/context.d.ts +73 -5
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/context.js +81 -14
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/index.d.ts +11 -0
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/performance.d.ts +62 -13
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/performance.js +62 -13
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/renderer.d.ts +78 -24
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/renderer.js +77 -23
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.d.ts +142 -20
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.js +146 -23
- package/dist/index.es.js +638 -326
- package/dist/index.js +4 -0
- package/dist/index.umd.js +640 -325
- package/package.json +1 -1
|
@@ -59,20 +59,20 @@ var WoongCanvasLayer = function (props) {
|
|
|
59
59
|
var divElement = divRef.current;
|
|
60
60
|
var containerRef = React.useRef(null);
|
|
61
61
|
var markerRef = React.useRef(); // --------------------------------------------------------------------------
|
|
62
|
-
// Konva Refs
|
|
62
|
+
// Konva Refs - Multi-Layer 아키텍처
|
|
63
63
|
// --------------------------------------------------------------------------
|
|
64
64
|
|
|
65
65
|
var stageRef = React.useRef(null);
|
|
66
66
|
var baseLayerRef = React.useRef(null);
|
|
67
67
|
var animationLayerRef = React.useRef(null);
|
|
68
68
|
var eventLayerRef = React.useRef(null); // --------------------------------------------------------------------------
|
|
69
|
-
// Data Refs -
|
|
69
|
+
// Data Refs - 데이터 동기화 및 상태 관리
|
|
70
70
|
// --------------------------------------------------------------------------
|
|
71
71
|
|
|
72
72
|
/** data prop을 ref로 추적 (stale closure 방지, useEffect에서 동기화) */
|
|
73
73
|
|
|
74
74
|
var dataRef = React.useRef(data); // --------------------------------------------------------------------------
|
|
75
|
-
// State Refs - 선택 및 Hover 상태 관리
|
|
75
|
+
// State Refs - 선택 및 Hover 상태 관리 (성능 최적화)
|
|
76
76
|
// --------------------------------------------------------------------------
|
|
77
77
|
|
|
78
78
|
/** 상호작용 비활성화 상태 (Ref로 관리하여 클로저 문제 해결) */
|
|
@@ -113,7 +113,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
113
113
|
*/
|
|
114
114
|
|
|
115
115
|
var selectedItemsMapRef = React.useRef(new Map()); // --------------------------------------------------------------------------
|
|
116
|
-
// Drag Refs
|
|
116
|
+
// Drag Refs - 지도 드래그 상태 관리
|
|
117
117
|
// --------------------------------------------------------------------------
|
|
118
118
|
|
|
119
119
|
var draggingRef = React.useRef(false);
|
|
@@ -122,7 +122,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
122
122
|
x: 0,
|
|
123
123
|
y: 0
|
|
124
124
|
}); // --------------------------------------------------------------------------
|
|
125
|
-
// Performance Refs (캐싱 &
|
|
125
|
+
// Performance Refs - 성능 최적화 (캐싱 & 인덱싱)
|
|
126
126
|
// --------------------------------------------------------------------------
|
|
127
127
|
|
|
128
128
|
/** 좌표 변환 결과 LRU 캐시 */
|
|
@@ -137,7 +137,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
137
137
|
/** 뷰포트 경계 캐시 (Viewport Culling) */
|
|
138
138
|
|
|
139
139
|
var viewportRef = React.useRef(null); // --------------------------------------------------------------------------
|
|
140
|
-
// 유틸리티 함수: 뷰포트 관리
|
|
140
|
+
// 유틸리티 함수: 뷰포트 관리 (Viewport Culling)
|
|
141
141
|
// --------------------------------------------------------------------------
|
|
142
142
|
|
|
143
143
|
/**
|
|
@@ -216,7 +216,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
216
216
|
|
|
217
217
|
return result;
|
|
218
218
|
}; // --------------------------------------------------------------------------
|
|
219
|
-
// 유틸리티 함수: 바운딩 박스 계산
|
|
219
|
+
// 유틸리티 함수: 바운딩 박스 계산 (Viewport Culling 최적화)
|
|
220
220
|
// --------------------------------------------------------------------------
|
|
221
221
|
|
|
222
222
|
/**
|
|
@@ -330,11 +330,14 @@ var WoongCanvasLayer = function (props) {
|
|
|
330
330
|
var renderEvent = dataType === types.CanvasDataType.MARKER ? props.renderEvent : function () {
|
|
331
331
|
var polygonProps = props;
|
|
332
332
|
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);
|
|
333
|
-
}();
|
|
333
|
+
}(); // --------------------------------------------------------------------------
|
|
334
|
+
// 렌더링 함수: Base Layer (기본 상태 렌더링)
|
|
335
|
+
// --------------------------------------------------------------------------
|
|
336
|
+
|
|
334
337
|
/**
|
|
335
338
|
* Base 레이어 렌더링 (뷰포트 컬링 적용, 선택된 마커 제외)
|
|
336
339
|
*
|
|
337
|
-
* 🔥 최적화:
|
|
340
|
+
* 🔥 성능 최적화:
|
|
338
341
|
* 1. Shape 재사용으로 객체 생성/파괴 오버헤드 제거
|
|
339
342
|
* 2. sceneFunc 한 번만 설정 (함수 재생성 제거)
|
|
340
343
|
* 3. 클로저로 최신 데이터 참조
|
|
@@ -400,11 +403,14 @@ var WoongCanvasLayer = function (props) {
|
|
|
400
403
|
|
|
401
404
|
|
|
402
405
|
layer.batchDraw();
|
|
403
|
-
};
|
|
406
|
+
}; // --------------------------------------------------------------------------
|
|
407
|
+
// 렌더링 함수: Animation Layer (선택된 항목 애니메이션)
|
|
408
|
+
// --------------------------------------------------------------------------
|
|
409
|
+
|
|
404
410
|
/**
|
|
405
411
|
* Animation 레이어 렌더링 (선택된 마커 애니메이션)
|
|
406
412
|
*
|
|
407
|
-
* 🔥 최적화: sceneFunc 내부에서 최신 items 참조
|
|
413
|
+
* 🔥 성능 최적화: sceneFunc 내부에서 최신 items 참조
|
|
408
414
|
* - 선택 변경 시에만 재생성
|
|
409
415
|
* - 지도 이동 시에는 기존 Animation 계속 실행
|
|
410
416
|
*/
|
|
@@ -420,11 +426,14 @@ var WoongCanvasLayer = function (props) {
|
|
|
420
426
|
items: dataRef.current,
|
|
421
427
|
utils: renderUtils
|
|
422
428
|
});
|
|
423
|
-
};
|
|
429
|
+
}; // --------------------------------------------------------------------------
|
|
430
|
+
// 렌더링 함수: Event Layer (상호작용 상태 렌더링)
|
|
431
|
+
// --------------------------------------------------------------------------
|
|
432
|
+
|
|
424
433
|
/**
|
|
425
434
|
* Event 레이어 렌더링 (hover + 선택 상태 표시)
|
|
426
435
|
*
|
|
427
|
-
* 🔥 최적화:
|
|
436
|
+
* 🔥 성능 최적화:
|
|
428
437
|
* 1. Shape 재사용으로 객체 생성/파괴 오버헤드 제거
|
|
429
438
|
* 2. sceneFunc 한 번만 설정 (함수 재생성 제거)
|
|
430
439
|
* 3. 클로저로 최신 데이터 참조
|
|
@@ -450,10 +459,11 @@ var WoongCanvasLayer = function (props) {
|
|
|
450
459
|
shape = new Konva__default["default"].Shape({
|
|
451
460
|
name: 'event-render-shape',
|
|
452
461
|
sceneFunc: function (context, shape) {
|
|
453
|
-
var ctx = context; // 클로저로 최신 ref 값 참조
|
|
462
|
+
var ctx = context; // 클로저로 최신 ref 값 참조 (안전한 처리)
|
|
454
463
|
|
|
455
464
|
var selectedItems = Array.from(selectedItemsMapRef.current.values());
|
|
456
|
-
var hovered = hoveredItemRef.current;
|
|
465
|
+
var hovered = hoveredItemRef.current;
|
|
466
|
+
var selectedItem = selectedItemRef.current; // topOnHover가 true이면 hover된 항목을 최상단에 렌더링
|
|
457
467
|
|
|
458
468
|
if (topOnHover && hovered) {
|
|
459
469
|
// 1. 먼저 일반 항목들 렌더링 (hover된 항목 제외)
|
|
@@ -462,9 +472,9 @@ var WoongCanvasLayer = function (props) {
|
|
|
462
472
|
hoveredItem: null,
|
|
463
473
|
utils: renderUtils,
|
|
464
474
|
selectedItems: selectedItems.filter(function (item) {
|
|
465
|
-
return item.id !== hovered.id;
|
|
475
|
+
return item && item.id !== hovered.id;
|
|
466
476
|
}),
|
|
467
|
-
selectedItem:
|
|
477
|
+
selectedItem: selectedItem
|
|
468
478
|
}); // 2. hover된 항목을 최상단에 렌더링
|
|
469
479
|
|
|
470
480
|
var isHoveredInViewport = enableViewportCulling ? isInViewport(hovered) : true;
|
|
@@ -475,7 +485,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
475
485
|
hoveredItem: hovered,
|
|
476
486
|
utils: renderUtils,
|
|
477
487
|
selectedItems: selectedItems,
|
|
478
|
-
selectedItem:
|
|
488
|
+
selectedItem: selectedItem
|
|
479
489
|
});
|
|
480
490
|
}
|
|
481
491
|
} else {
|
|
@@ -485,7 +495,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
485
495
|
hoveredItem: hovered,
|
|
486
496
|
utils: renderUtils,
|
|
487
497
|
selectedItems: selectedItems,
|
|
488
|
-
selectedItem:
|
|
498
|
+
selectedItem: selectedItem
|
|
489
499
|
});
|
|
490
500
|
}
|
|
491
501
|
},
|
|
@@ -598,7 +608,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
598
608
|
containerRef.current.style.transform = "translate(".concat(accumTranslateRef.current.x, "px, ").concat(accumTranslateRef.current.y, "px)");
|
|
599
609
|
}
|
|
600
610
|
}; // --------------------------------------------------------------------------
|
|
601
|
-
// Hit Test & 상태 관리
|
|
611
|
+
// Hit Test & 상태 관리 (이벤트 처리)
|
|
602
612
|
// --------------------------------------------------------------------------
|
|
603
613
|
|
|
604
614
|
/**
|
|
@@ -768,7 +778,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
768
778
|
}
|
|
769
779
|
};
|
|
770
780
|
/**
|
|
771
|
-
* 마우스 이동 이벤트 처리 (hover 감지)
|
|
781
|
+
* 마우스 이동 이벤트 처리 (hover 감지 및 상태 업데이트)
|
|
772
782
|
*/
|
|
773
783
|
|
|
774
784
|
|
|
@@ -812,7 +822,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
812
822
|
controller.setMapCursor('grab');
|
|
813
823
|
};
|
|
814
824
|
/**
|
|
815
|
-
* 마우스가 canvas를 벗어날 때 hover
|
|
825
|
+
* 마우스가 canvas를 벗어날 때 hover 상태 정리
|
|
816
826
|
*/
|
|
817
827
|
|
|
818
828
|
|
|
@@ -872,7 +882,7 @@ var WoongCanvasLayer = function (props) {
|
|
|
872
882
|
}
|
|
873
883
|
}
|
|
874
884
|
}, [options]); // --------------------------------------------------------------------------
|
|
875
|
-
// Lifecycle: Konva 초기화 및 이벤트 리스너 등록
|
|
885
|
+
// Lifecycle: Konva 초기화 및 이벤트 리스너 등록 (컴포넌트 마운트)
|
|
876
886
|
// --------------------------------------------------------------------------
|
|
877
887
|
|
|
878
888
|
React.useEffect(function () {
|
|
@@ -998,26 +1008,32 @@ var WoongCanvasLayer = function (props) {
|
|
|
998
1008
|
};
|
|
999
1009
|
}, []); // 초기화는 한 번만
|
|
1000
1010
|
// --------------------------------------------------------------------------
|
|
1001
|
-
// Lifecycle: disableInteraction 동기화
|
|
1011
|
+
// Lifecycle: disableInteraction 동기화 (상호작용 상태 관리)
|
|
1002
1012
|
// --------------------------------------------------------------------------
|
|
1003
1013
|
|
|
1004
1014
|
React.useEffect(function () {
|
|
1005
1015
|
disableInteractionRef.current = disableInteraction;
|
|
1006
1016
|
}, [disableInteraction]); // --------------------------------------------------------------------------
|
|
1007
|
-
// Lifecycle: 외부 selectedItems 동기화
|
|
1017
|
+
// Lifecycle: 외부 selectedItems 동기화 (선택 상태 관리)
|
|
1008
1018
|
// --------------------------------------------------------------------------
|
|
1009
1019
|
|
|
1010
1020
|
React.useEffect(function () {
|
|
1011
1021
|
if (!stageRef.current) return; // externalSelectedItems가 undefined면 외부 제어 안 함
|
|
1012
1022
|
|
|
1013
|
-
if (externalSelectedItems === undefined) return; // 외부에서 전달된 selectedItems로 동기화
|
|
1023
|
+
if (externalSelectedItems === undefined) return; // 외부에서 전달된 selectedItems로 동기화 (안전한 처리)
|
|
1014
1024
|
|
|
1015
1025
|
var newSelectedIds = new Set();
|
|
1016
|
-
var newSelectedItemsMap = new Map();
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1026
|
+
var newSelectedItemsMap = new Map(); // selectedItems가 배열인지 확인하고 안전하게 처리
|
|
1027
|
+
|
|
1028
|
+
if (Array.isArray(externalSelectedItems)) {
|
|
1029
|
+
externalSelectedItems.forEach(function (item) {
|
|
1030
|
+
if (item && item.id) {
|
|
1031
|
+
newSelectedIds.add(item.id);
|
|
1032
|
+
newSelectedItemsMap.set(item.id, item);
|
|
1033
|
+
}
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1021
1037
|
selectedIdsRef.current = newSelectedIds;
|
|
1022
1038
|
selectedItemsMapRef.current = newSelectedItemsMap; // 렌더링
|
|
1023
1039
|
|
|
@@ -1026,17 +1042,17 @@ var WoongCanvasLayer = function (props) {
|
|
|
1026
1042
|
doRenderEvent();
|
|
1027
1043
|
}, [externalSelectedItems]); // 배열 자체를 dependency로 사용
|
|
1028
1044
|
// --------------------------------------------------------------------------
|
|
1029
|
-
// Lifecycle: 외부 selectedItem 변경 시 Event Layer 리렌더링
|
|
1045
|
+
// Lifecycle: 외부 selectedItem 변경 시 Event Layer 리렌더링 (단일 선택 관리)
|
|
1030
1046
|
// --------------------------------------------------------------------------
|
|
1031
1047
|
|
|
1032
1048
|
React.useEffect(function () {
|
|
1033
|
-
if (!stageRef.current) return; // Ref 동기화
|
|
1049
|
+
if (!stageRef.current) return; // Ref 동기화 (안전한 처리)
|
|
1034
1050
|
|
|
1035
|
-
selectedItemRef.current = externalSelectedItem; // selectedItem이 변경되면 Event Layer만 다시 그림
|
|
1051
|
+
selectedItemRef.current = externalSelectedItem || null; // selectedItem이 변경되면 Event Layer만 다시 그림
|
|
1036
1052
|
|
|
1037
1053
|
doRenderEvent();
|
|
1038
1054
|
}, [externalSelectedItem]); // --------------------------------------------------------------------------
|
|
1039
|
-
// Lifecycle: 데이터 변경 시 렌더링
|
|
1055
|
+
// Lifecycle: 데이터 변경 시 렌더링 (데이터 동기화 및 최적화)
|
|
1040
1056
|
// --------------------------------------------------------------------------
|
|
1041
1057
|
|
|
1042
1058
|
React.useEffect(function () {
|
|
@@ -1093,7 +1109,10 @@ var WoongCanvasLayer = function (props) {
|
|
|
1093
1109
|
selectedItemsMapRef.current = newSelectedItemsMap; // 즉시 렌더링
|
|
1094
1110
|
|
|
1095
1111
|
renderAllImmediate();
|
|
1096
|
-
}, [data]);
|
|
1112
|
+
}, [data]); // --------------------------------------------------------------------------
|
|
1113
|
+
// Render - React Portal을 통한 DOM 렌더링
|
|
1114
|
+
// --------------------------------------------------------------------------
|
|
1115
|
+
|
|
1097
1116
|
return reactDom.createPortal(React__default["default"].createElement("div", {
|
|
1098
1117
|
ref: containerRef,
|
|
1099
1118
|
style: {
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview WoongCanvasLayer 모듈의 메인 엔트리 포인트
|
|
3
|
+
*
|
|
4
|
+
* 이 파일은 WoongCanvasLayer 컴포넌트와 관련된 모든 타입, 유틸리티,
|
|
5
|
+
* 성능 최적화 클래스들을 외부로 노출합니다.
|
|
6
|
+
*
|
|
7
|
+
* @version 2.2.1
|
|
8
|
+
* @since 2.0.0
|
|
9
|
+
* @author 박건웅
|
|
10
|
+
*/
|
|
1
11
|
export { default as WoongCanvasLayer } from "./WoongCanvasLayer";
|
|
2
12
|
export * from "./WoongCanvasLayer";
|
|
3
13
|
export * from "./shared";
|
|
@@ -2,31 +2,99 @@ import React from "react";
|
|
|
2
2
|
import { Offset } from "../../../../types";
|
|
3
3
|
import { KonvaCanvasData } from "./types";
|
|
4
4
|
/**
|
|
5
|
-
* 다중
|
|
5
|
+
* @fileoverview 다중 WoongCanvasLayer 인스턴스를 관리하기 위한 React Context
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* 이 Context는 여러 개의 WoongCanvasLayer가 동시에 사용될 때 이벤트 우선순위를
|
|
8
|
+
* 관리하고 전역 클릭/호버 이벤트를 조정합니다.
|
|
9
|
+
*
|
|
10
|
+
* ## 주요 기능
|
|
11
|
+
* - **zIndex 기반 이벤트 우선순위**: 높은 zIndex를 가진 레이어가 먼저 이벤트 처리
|
|
12
|
+
* - **전역 이벤트 관리**: 지도 전체의 클릭/호버 이벤트를 중앙에서 관리
|
|
13
|
+
* - **다중 레이어 상호작용**: 여러 레이어 간의 이벤트 충돌 방지
|
|
14
|
+
* - **상호작용 비활성화 지원**: disableInteraction prop 지원
|
|
15
|
+
*
|
|
16
|
+
* ## 사용 방법
|
|
17
|
+
* ```tsx
|
|
18
|
+
* <KonvaMarkerProvider>
|
|
19
|
+
* <WoongCanvasLayer zIndex={1} ... />
|
|
20
|
+
* <WoongCanvasLayer zIndex={2} ... />
|
|
21
|
+
* </KonvaMarkerProvider>
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @version 2.2.1
|
|
25
|
+
* @since 2.0.0
|
|
26
|
+
* @author 박건웅
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* WoongCanvasLayer 컴포넌트 인스턴스 인터페이스
|
|
30
|
+
*
|
|
31
|
+
* Context에서 관리하는 각 WoongCanvasLayer 인스턴스가 구현해야 하는 메서드들입니다.
|
|
32
|
+
*
|
|
33
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
11
34
|
*/
|
|
12
35
|
export interface ComponentInstance<T> {
|
|
36
|
+
/** 레이어 순서 (높을수록 우선순위 높음) */
|
|
13
37
|
zIndex: number;
|
|
38
|
+
/** 특정 좌표에서 히트 테스트 수행 */
|
|
14
39
|
hitTest: (offset: Offset) => boolean;
|
|
40
|
+
/** 클릭 이벤트 핸들러 */
|
|
15
41
|
onClick?: (payload: KonvaCanvasData<T>, selectedIds: Set<string>) => void;
|
|
42
|
+
/** 마우스 오버 이벤트 핸들러 */
|
|
16
43
|
onMouseOver?: (payload: KonvaCanvasData<T>) => void;
|
|
44
|
+
/** 마우스 아웃 이벤트 핸들러 */
|
|
17
45
|
onMouseOut?: (payload: KonvaCanvasData<T>) => void;
|
|
46
|
+
/** 특정 좌표에서 데이터 찾기 */
|
|
18
47
|
findData: (offset: Offset) => KonvaCanvasData<T> | null;
|
|
48
|
+
/** 호버 상태 설정 */
|
|
19
49
|
setHovered: (data: KonvaCanvasData<T> | null) => void;
|
|
50
|
+
/** 로컬 클릭 처리 */
|
|
20
51
|
handleLocalClick: (data: KonvaCanvasData<T>) => void;
|
|
52
|
+
/** 선택된 항목 ID 목록 반환 */
|
|
21
53
|
getSelectedIds: () => Set<string>;
|
|
54
|
+
/** 상호작용 비활성화 여부 체크 */
|
|
22
55
|
isInteractionDisabled: () => boolean;
|
|
23
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* KonvaMarkerContext의 값 타입
|
|
59
|
+
*/
|
|
24
60
|
interface KonvaMarkerContextValue {
|
|
61
|
+
/** 컴포넌트 인스턴스 등록 */
|
|
25
62
|
registerComponent: <T>(instance: ComponentInstance<T>) => void;
|
|
63
|
+
/** 컴포넌트 인스턴스 등록 해제 */
|
|
26
64
|
unregisterComponent: <T>(instance: ComponentInstance<T>) => void;
|
|
27
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* 다중 WoongCanvasLayer 관리를 위한 Context Provider
|
|
68
|
+
*
|
|
69
|
+
* 여러 개의 WoongCanvasLayer가 동시에 사용될 때 이벤트 우선순위를 관리하고
|
|
70
|
+
* 전역 클릭/호버 이벤트를 조정합니다.
|
|
71
|
+
*
|
|
72
|
+
* @param children - Provider로 감쌀 React 컴포넌트들
|
|
73
|
+
* @returns Context Provider 컴포넌트
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```tsx
|
|
77
|
+
* <KonvaMarkerProvider>
|
|
78
|
+
* <WoongCanvasLayer zIndex={1} data={markers1} ... />
|
|
79
|
+
* <WoongCanvasLayer zIndex={2} data={markers2} ... />
|
|
80
|
+
* </KonvaMarkerProvider>
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
28
83
|
export declare const KonvaMarkerProvider: React.FC<{
|
|
29
84
|
children: React.ReactNode;
|
|
30
85
|
}>;
|
|
86
|
+
/**
|
|
87
|
+
* KonvaMarkerContext를 사용하기 위한 Hook
|
|
88
|
+
*
|
|
89
|
+
* @returns Context 값 또는 null (Provider 외부에서 사용 시)
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```tsx
|
|
93
|
+
* const context = useKonvaMarkerContext();
|
|
94
|
+
* if (context) {
|
|
95
|
+
* context.registerComponent(instance);
|
|
96
|
+
* }
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
31
99
|
export declare const useKonvaMarkerContext: () => KonvaMarkerContextValue | null;
|
|
32
100
|
export {};
|
|
@@ -9,18 +9,50 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
|
9
9
|
|
|
10
10
|
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
11
11
|
|
|
12
|
+
/** 다중 레이어 관리를 위한 React Context */
|
|
13
|
+
|
|
12
14
|
var KonvaMarkerContext = React.createContext(null);
|
|
15
|
+
/**
|
|
16
|
+
* 다중 WoongCanvasLayer 관리를 위한 Context Provider
|
|
17
|
+
*
|
|
18
|
+
* 여러 개의 WoongCanvasLayer가 동시에 사용될 때 이벤트 우선순위를 관리하고
|
|
19
|
+
* 전역 클릭/호버 이벤트를 조정합니다.
|
|
20
|
+
*
|
|
21
|
+
* @param children - Provider로 감쌀 React 컴포넌트들
|
|
22
|
+
* @returns Context Provider 컴포넌트
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <KonvaMarkerProvider>
|
|
27
|
+
* <WoongCanvasLayer zIndex={1} data={markers1} ... />
|
|
28
|
+
* <WoongCanvasLayer zIndex={2} data={markers2} ... />
|
|
29
|
+
* </KonvaMarkerProvider>
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
|
|
13
33
|
var KonvaMarkerProvider = function (_a) {
|
|
14
34
|
var children = _a.children;
|
|
15
|
-
var controller = MintMapProvider.useMintMapController(); // Refs
|
|
35
|
+
var controller = MintMapProvider.useMintMapController(); // === Refs ===
|
|
36
|
+
|
|
37
|
+
/** 등록된 모든 컴포넌트 인스턴스들 (zIndex 내림차순 정렬) */
|
|
16
38
|
|
|
17
39
|
var componentsRef = React.useRef([]);
|
|
40
|
+
/** 현재 호버된 컴포넌트 인스턴스 */
|
|
41
|
+
|
|
18
42
|
var currentHoveredRef = React.useRef(null);
|
|
43
|
+
/** 현재 호버된 데이터 */
|
|
44
|
+
|
|
19
45
|
var currentHoveredDataRef = React.useRef(null);
|
|
20
|
-
|
|
46
|
+
/** 드래그/줌 중 여부 (마우스 이동 이벤트 무시용) */
|
|
47
|
+
|
|
48
|
+
var draggingRef = React.useRef(false); // === 컴포넌트 관리 함수들 ===
|
|
49
|
+
|
|
21
50
|
/**
|
|
22
|
-
* 컴포넌트 등록
|
|
23
|
-
*
|
|
51
|
+
* 컴포넌트 인스턴스 등록
|
|
52
|
+
*
|
|
53
|
+
* zIndex 내림차순으로 정렬하여 높은 우선순위의 컴포넌트가 먼저 이벤트를 처리하도록 합니다.
|
|
54
|
+
*
|
|
55
|
+
* @param instance - 등록할 컴포넌트 인스턴스
|
|
24
56
|
*/
|
|
25
57
|
|
|
26
58
|
var registerComponent = React.useCallback(function (instance) {
|
|
@@ -30,7 +62,12 @@ var KonvaMarkerProvider = function (_a) {
|
|
|
30
62
|
});
|
|
31
63
|
}, []);
|
|
32
64
|
/**
|
|
33
|
-
* 컴포넌트 등록 해제
|
|
65
|
+
* 컴포넌트 인스턴스 등록 해제
|
|
66
|
+
*
|
|
67
|
+
* 컴포넌트가 언마운트될 때 호출되어 Context에서 제거합니다.
|
|
68
|
+
* 현재 호버 중인 컴포넌트라면 호버 상태도 초기화합니다.
|
|
69
|
+
*
|
|
70
|
+
* @param instance - 등록 해제할 컴포넌트 인스턴스
|
|
34
71
|
*/
|
|
35
72
|
|
|
36
73
|
var unregisterComponent = React.useCallback(function (instance) {
|
|
@@ -43,9 +80,15 @@ var KonvaMarkerProvider = function (_a) {
|
|
|
43
80
|
componentsRef.current = componentsRef.current.filter(function (c) {
|
|
44
81
|
return c !== instance;
|
|
45
82
|
});
|
|
46
|
-
}, []);
|
|
83
|
+
}, []); // === 전역 이벤트 핸들러들 ===
|
|
84
|
+
|
|
47
85
|
/**
|
|
48
|
-
* 전역 클릭 핸들러
|
|
86
|
+
* 전역 클릭 이벤트 핸들러
|
|
87
|
+
*
|
|
88
|
+
* zIndex 우선순위에 따라 등록된 컴포넌트들을 순회하며 클릭된 데이터를 찾습니다.
|
|
89
|
+
* 첫 번째로 히트된 컴포넌트의 이벤트만 처리합니다.
|
|
90
|
+
*
|
|
91
|
+
* @param event - 지도 클릭 이벤트 파라미터
|
|
49
92
|
*/
|
|
50
93
|
|
|
51
94
|
var handleGlobalClick = React.useCallback(function (event) {
|
|
@@ -55,7 +98,7 @@ var KonvaMarkerProvider = function (_a) {
|
|
|
55
98
|
var clickedOffset = controller.positionToOffset(event.param.position); // zIndex 순서대로 순회 (높은 것부터)
|
|
56
99
|
|
|
57
100
|
for (var _i = 0, _b = componentsRef.current; _i < _b.length; _i++) {
|
|
58
|
-
var component = _b[_i]; //
|
|
101
|
+
var component = _b[_i]; // 상호작용이 비활성화된 컴포넌트는 스킵
|
|
59
102
|
|
|
60
103
|
if (component.isInteractionDisabled()) continue;
|
|
61
104
|
var data = component.findData(clickedOffset);
|
|
@@ -72,7 +115,12 @@ var KonvaMarkerProvider = function (_a) {
|
|
|
72
115
|
}
|
|
73
116
|
}, [controller]);
|
|
74
117
|
/**
|
|
75
|
-
* 전역 마우스 이동 핸들러
|
|
118
|
+
* 전역 마우스 이동 이벤트 핸들러
|
|
119
|
+
*
|
|
120
|
+
* zIndex 우선순위에 따라 호버된 데이터를 찾고, 호버 상태가 변경되면
|
|
121
|
+
* 이전 호버를 해제하고 새로운 호버를 설정합니다.
|
|
122
|
+
*
|
|
123
|
+
* @param event - 지도 마우스 이동 이벤트 파라미터
|
|
76
124
|
*/
|
|
77
125
|
|
|
78
126
|
var handleGlobalMouseMove = React.useCallback(function (event) {
|
|
@@ -85,7 +133,7 @@ var KonvaMarkerProvider = function (_a) {
|
|
|
85
133
|
var newHoveredData = null;
|
|
86
134
|
|
|
87
135
|
for (var _i = 0, _b = componentsRef.current; _i < _b.length; _i++) {
|
|
88
|
-
var component = _b[_i]; //
|
|
136
|
+
var component = _b[_i]; // 상호작용이 비활성화된 컴포넌트는 스킵
|
|
89
137
|
|
|
90
138
|
if (component.isInteractionDisabled()) continue;
|
|
91
139
|
var data = component.findData(mouseOffset);
|
|
@@ -122,19 +170,24 @@ var KonvaMarkerProvider = function (_a) {
|
|
|
122
170
|
}
|
|
123
171
|
}, [controller]);
|
|
124
172
|
/**
|
|
125
|
-
* 줌/드래그 시작
|
|
173
|
+
* 줌/드래그 시작 이벤트 핸들러
|
|
174
|
+
*
|
|
175
|
+
* 지도가 줌이나 드래그를 시작할 때 마우스 이동 이벤트를 무시하도록 설정합니다.
|
|
176
|
+
* 이는 성능 최적화와 불필요한 호버 이벤트 방지를 위한 것입니다.
|
|
126
177
|
*/
|
|
127
178
|
|
|
128
179
|
var handleZoomStart = React.useCallback(function () {
|
|
129
180
|
draggingRef.current = true;
|
|
130
181
|
}, []);
|
|
131
182
|
/**
|
|
132
|
-
* 지도 idle
|
|
183
|
+
* 지도 idle 이벤트 핸들러
|
|
184
|
+
*
|
|
185
|
+
* 지도가 idle 상태가 되면 마우스 이동 이벤트를 다시 활성화합니다.
|
|
133
186
|
*/
|
|
134
187
|
|
|
135
188
|
var handleIdle = React.useCallback(function () {
|
|
136
189
|
draggingRef.current = false;
|
|
137
|
-
}, []); // 이벤트 리스너 등록
|
|
190
|
+
}, []); // === 이벤트 리스너 등록 ===
|
|
138
191
|
|
|
139
192
|
React.useEffect(function () {
|
|
140
193
|
controller.addEventListener('CLICK', handleGlobalClick);
|
|
@@ -147,7 +200,7 @@ var KonvaMarkerProvider = function (_a) {
|
|
|
147
200
|
controller.removeEventListener('ZOOMSTART', handleZoomStart);
|
|
148
201
|
controller.removeEventListener('IDLE', handleIdle);
|
|
149
202
|
};
|
|
150
|
-
}, [controller, handleGlobalClick, handleGlobalMouseMove, handleZoomStart, handleIdle]); // Context value 메모이제이션
|
|
203
|
+
}, [controller, handleGlobalClick, handleGlobalMouseMove, handleZoomStart, handleIdle]); // === Context value 메모이제이션 ===
|
|
151
204
|
|
|
152
205
|
var contextValue = React.useMemo(function () {
|
|
153
206
|
return {
|
|
@@ -159,6 +212,20 @@ var KonvaMarkerProvider = function (_a) {
|
|
|
159
212
|
value: contextValue
|
|
160
213
|
}, children);
|
|
161
214
|
};
|
|
215
|
+
/**
|
|
216
|
+
* KonvaMarkerContext를 사용하기 위한 Hook
|
|
217
|
+
*
|
|
218
|
+
* @returns Context 값 또는 null (Provider 외부에서 사용 시)
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```tsx
|
|
222
|
+
* const context = useKonvaMarkerContext();
|
|
223
|
+
* if (context) {
|
|
224
|
+
* context.registerComponent(instance);
|
|
225
|
+
* }
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
|
|
162
229
|
var useKonvaMarkerContext = function () {
|
|
163
230
|
var context = React.useContext(KonvaMarkerContext);
|
|
164
231
|
return context;
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview WoongCanvasLayer의 공유 유틸리티 모듈
|
|
3
|
+
*
|
|
4
|
+
* 이 파일은 WoongCanvasLayer에서 사용하는 모든 공통 타입, 유틸리티 함수,
|
|
5
|
+
* 성능 최적화 클래스, Context Provider를 외부로 노출합니다.
|
|
6
|
+
*
|
|
7
|
+
* @version 2.2.1
|
|
8
|
+
* @since 2.0.0
|
|
9
|
+
* @author 박건웅
|
|
10
|
+
*/
|
|
1
11
|
export * from './types';
|
|
2
12
|
export * from './utils';
|
|
3
13
|
export * from './context';
|
|
4
14
|
export * from './performance';
|
|
15
|
+
export * from './renderer';
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview WoongCanvasLayer 성능 최적화를 위한 상수 및 클래스
|
|
3
|
+
*
|
|
4
|
+
* 이 파일은 30,000개 이상의 마커/폴리곤을 60fps로 렌더링하기 위한
|
|
5
|
+
* 성능 최적화 상수와 최적화된 자료구조들을 제공합니다.
|
|
6
|
+
*
|
|
7
|
+
* ## 주요 구성 요소
|
|
8
|
+
* - **성능 최적화 상수**: 그리드 셀 크기, 캐시 크기, 컬링 여유 공간
|
|
9
|
+
* - **LRUCache**: 좌표 변환 결과 캐싱을 위한 LRU 캐시 구현
|
|
10
|
+
* - **SpatialHashGrid**: O(1) 수준의 빠른 Hit Test를 위한 공간 해시 그리드
|
|
11
|
+
*
|
|
12
|
+
* @version 2.2.1
|
|
13
|
+
* @since 2.0.0
|
|
14
|
+
* @author 박건웅
|
|
15
|
+
*/
|
|
1
16
|
/**
|
|
2
17
|
* 공간 인덱스 그리드 셀 크기 (px)
|
|
3
18
|
*
|
|
@@ -40,12 +55,29 @@ export declare const DEFAULT_CULLING_MARGIN = 100;
|
|
|
40
55
|
export declare const DEFAULT_MAX_CACHE_SIZE = 30000;
|
|
41
56
|
/**
|
|
42
57
|
* LRU (Least Recently Used) Cache
|
|
43
|
-
* 메모리 제한을 위한 캐시 구현 (최적화 버전)
|
|
44
58
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
59
|
+
* 메모리 제한을 위한 캐시 구현으로, 좌표 변환 결과를 캐싱하여
|
|
60
|
+
* 성능을 최적화합니다. WoongCanvasLayer의 특성에 맞게 최적화되었습니다.
|
|
61
|
+
*
|
|
62
|
+
* ## 주요 특징
|
|
63
|
+
* - **빠른 조회**: O(1) 해시 조회로 성능 최적화
|
|
64
|
+
* - **메모리 제한**: 최대 크기 초과 시 자동 eviction
|
|
65
|
+
* - **FIFO 방식**: 삽입 순서 기반 eviction (접근 빈도 추적 없음)
|
|
66
|
+
*
|
|
67
|
+
* ## 개선 사항
|
|
68
|
+
* 1. **get() 성능 향상**: 접근 빈도 추적 없이 단순 조회만 수행
|
|
69
|
+
* 2. **set() 버그 수정**: 기존 키 업데이트 시 maxSize 체크 로직 개선
|
|
70
|
+
* 3. **메모리 효율**: 단순 FIFO 캐시로 동작하여 오버헤드 최소화
|
|
71
|
+
*
|
|
72
|
+
* @template K 캐시 키 타입
|
|
73
|
+
* @template V 캐시 값 타입
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const cache = new LRUCache<string, Offset>(1000);
|
|
78
|
+
* cache.set('marker-1', { x: 100, y: 200 });
|
|
79
|
+
* const offset = cache.get('marker-1'); // { x: 100, y: 200 }
|
|
80
|
+
* ```
|
|
49
81
|
*/
|
|
50
82
|
export declare class LRUCache<K, V> {
|
|
51
83
|
private cache;
|
|
@@ -81,16 +113,33 @@ export declare class LRUCache<K, V> {
|
|
|
81
113
|
}
|
|
82
114
|
/**
|
|
83
115
|
* Spatial Hash Grid (공간 해시 그리드)
|
|
84
|
-
* 공간 인덱싱을 위한 그리드 기반 자료구조 (개선 버전)
|
|
85
116
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
117
|
+
* 공간 인덱싱을 위한 그리드 기반 자료구조로, 2D 공간을 격자로 나누어
|
|
118
|
+
* 특정 영역에 있는 객체들을 빠르게 찾을 수 있게 해줍니다.
|
|
119
|
+
*
|
|
120
|
+
* ## 주요 특징
|
|
121
|
+
* - **O(1) 조회**: 클릭 위치 주변의 객체들만 체크하여 성능 최적화
|
|
122
|
+
* - **메모리 효율**: 격자 기반으로 필요한 영역만 인덱싱
|
|
123
|
+
* - **중복 방지**: 같은 항목을 여러 번 삽입해도 안전
|
|
124
|
+
*
|
|
125
|
+
* ## 성능 비교
|
|
126
|
+
* - **일반 검색**: 30,000개 항목 전체 체크 → O(n)
|
|
127
|
+
* - **Spatial Hash**: 클릭 위치 주변 ~10개만 체크 → O(1) + O(10)
|
|
128
|
+
* - **성능 향상**: 약 3,000배 빠름! 🚀
|
|
129
|
+
*
|
|
130
|
+
* ## 개선 사항
|
|
131
|
+
* 1. **중복 삽입 방지**: 같은 항목을 여러 번 insert 해도 안전
|
|
132
|
+
* 2. **메모리 누수 방지**: 기존 항목 자동 제거
|
|
133
|
+
* 3. **성능 최적화**: 불필요한 배열 생성 최소화
|
|
134
|
+
*
|
|
135
|
+
* @template T 그리드에 저장할 객체 타입
|
|
90
136
|
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* const grid = new SpatialHashGrid<Marker>(50);
|
|
140
|
+
* grid.insert(marker, { x: 100, y: 200, width: 30, height: 40 });
|
|
141
|
+
* const nearby = grid.query(105, 205, 10); // (105, 205) 주변 10px 반경
|
|
142
|
+
* ```
|
|
94
143
|
*/
|
|
95
144
|
export declare class SpatialHashGrid<T> {
|
|
96
145
|
private cellSize;
|