@mint-ui/map 1.2.0-test.34 → 1.2.0-test.35
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/shared/context.d.ts +71 -2
- package/dist/components/mint-map/core/advanced/shared/context.js +74 -1
- package/dist/components/mint-map/core/advanced/shared/helpers.d.ts +28 -0
- package/dist/components/mint-map/core/advanced/shared/helpers.js +52 -0
- package/dist/components/mint-map/core/advanced/shared/hooks.d.ts +144 -0
- package/dist/components/mint-map/core/advanced/shared/hooks.js +283 -0
- package/dist/components/mint-map/core/advanced/shared/index.d.ts +3 -0
- package/dist/components/mint-map/core/advanced/shared/performance.d.ts +105 -24
- package/dist/components/mint-map/core/advanced/shared/performance.js +105 -24
- package/dist/components/mint-map/core/advanced/shared/utils.d.ts +128 -14
- package/dist/components/mint-map/core/advanced/shared/utils.js +128 -14
- package/dist/components/mint-map/core/advanced/shared/viewport.d.ts +72 -0
- package/dist/components/mint-map/core/advanced/shared/viewport.js +81 -0
- package/dist/components/mint-map/core/advanced/woongCanvasMarker/WoongCanvasMarker.js +142 -209
- package/dist/components/mint-map/core/advanced/woongCanvasPolygon/WoongCanvasPolygon.js +121 -206
- package/dist/components/mint-map/core/advanced/woongCanvasPolygon/renderer.d.ts +64 -5
- package/dist/components/mint-map/core/advanced/woongCanvasPolygon/renderer.js +81 -20
- package/dist/index.es.js +1062 -497
- package/dist/index.js +11 -0
- package/dist/index.umd.js +1068 -495
- package/package.json +1 -1
|
@@ -3,47 +3,161 @@ import { MintMapController } from "../../MintMapController";
|
|
|
3
3
|
import { KonvaCanvasData } from "./types";
|
|
4
4
|
/**
|
|
5
5
|
* 폴리곤 offset 계산
|
|
6
|
+
*
|
|
7
|
+
* GeoJSON MultiPolygon 형식의 위경도 좌표를 화면 픽셀 좌표로 변환합니다.
|
|
8
|
+
*
|
|
9
|
+
* @param polygonData 폴리곤 데이터 (paths 필드 필수)
|
|
10
|
+
* @param controller MintMapController 인스턴스
|
|
11
|
+
* @returns 변환된 화면 좌표 배열 (4차원 배열) 또는 null (변환 실패 시)
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* - 반환 형식: [MultiPolygon][Polygon][Point][x/y]
|
|
15
|
+
* - 성능: O(n), n은 폴리곤의 총 좌표 수
|
|
16
|
+
* - GeoJSON MultiPolygon 형식 지원
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const offsets = computePolygonOffsets(polygonData, controller);
|
|
21
|
+
* if (!offsets) return; // 변환 실패
|
|
22
|
+
*
|
|
23
|
+
* // offsets 구조: [MultiPolygon][Polygon][Point][x/y]
|
|
24
|
+
* for (const multiPolygon of offsets) {
|
|
25
|
+
* for (const polygon of multiPolygon) {
|
|
26
|
+
* // polygon은 [Point][x/y] 배열
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
6
30
|
*/
|
|
7
31
|
export declare const computePolygonOffsets: (polygonData: KonvaCanvasData<any>, controller: MintMapController) => number[][][][] | null;
|
|
8
32
|
/**
|
|
9
33
|
* 마커 offset 계산
|
|
34
|
+
*
|
|
35
|
+
* 마커의 위경도 좌표를 화면 픽셀 좌표로 변환합니다.
|
|
36
|
+
*
|
|
37
|
+
* @param markerData 마커 데이터 (position 필드 필수)
|
|
38
|
+
* @param controller MintMapController 인스턴스
|
|
39
|
+
* @returns 변환된 화면 좌표 (Offset) 또는 null (변환 실패 시)
|
|
40
|
+
*
|
|
41
|
+
* @remarks
|
|
42
|
+
* - 반환된 좌표는 마커의 중심점 (x, y)
|
|
43
|
+
* - 성능: O(1) - 단일 좌표 변환
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const offset = computeMarkerOffset(markerData, controller);
|
|
48
|
+
* if (!offset) return; // 변환 실패
|
|
49
|
+
* // offset.x, offset.y는 화면 픽셀 좌표
|
|
50
|
+
* ```
|
|
10
51
|
*/
|
|
11
52
|
export declare const computeMarkerOffset: (markerData: KonvaCanvasData<any>, controller: MintMapController) => Offset | null;
|
|
12
53
|
/**
|
|
13
54
|
* Point-in-Polygon 알고리즘
|
|
55
|
+
*
|
|
56
|
+
* Ray Casting 알고리즘을 사용하여 점이 폴리곤 내부에 있는지 확인합니다.
|
|
57
|
+
*
|
|
58
|
+
* @param point 확인할 점의 좌표
|
|
59
|
+
* @param polygon 폴리곤 좌표 배열 (각 요소는 [x, y] 형식)
|
|
60
|
+
* @returns 점이 폴리곤 내부에 있으면 true, 아니면 false
|
|
61
|
+
*
|
|
62
|
+
* @remarks
|
|
63
|
+
* - **알고리즘**: Ray Casting (Ray Crossing)
|
|
64
|
+
* - **성능**: O(n), n은 폴리곤의 좌표 수
|
|
65
|
+
* - **경계 처리**: 경계선 위의 점은 내부로 간주
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const point = { x: 100, y: 200 };
|
|
70
|
+
* const polygon = [[0, 0], [100, 0], [100, 100], [0, 100]];
|
|
71
|
+
* const isInside = isPointInPolygon(point, polygon);
|
|
72
|
+
* ```
|
|
14
73
|
*/
|
|
15
74
|
export declare const isPointInPolygon: (point: Offset, polygon: number[][]) => boolean;
|
|
16
75
|
/**
|
|
17
76
|
* 폴리곤 히트 테스트 (도넛 폴리곤 지원)
|
|
18
77
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
78
|
+
* 점이 폴리곤 내부에 있는지 확인합니다. 도넛 폴리곤(구멍이 있는 폴리곤)을 지원합니다.
|
|
79
|
+
*
|
|
80
|
+
* @param clickedOffset 클릭/마우스 위치 좌표
|
|
81
|
+
* @param polygonData 폴리곤 데이터
|
|
82
|
+
* @param getPolygonOffsets 폴리곤 좌표 변환 함수
|
|
83
|
+
* @returns 점이 폴리곤 내부에 있으면 true, 아니면 false
|
|
22
84
|
*
|
|
23
|
-
*
|
|
85
|
+
* @remarks
|
|
86
|
+
* - **도넛 폴리곤 처리** (isDonutPolygon === true):
|
|
87
|
+
* 1. 외부 폴리곤(첫 번째): 내부에 있어야 함
|
|
88
|
+
* 2. 내부 구멍들(나머지): 내부에 있으면 안 됨 (evenodd 규칙)
|
|
89
|
+
* - **일반 폴리곤 처리**: Point-in-Polygon 알고리즘 사용
|
|
90
|
+
* - **성능**: O(n), n은 폴리곤의 총 좌표 수
|
|
91
|
+
*
|
|
92
|
+
* **중요**: 도넛 폴리곤과 내부 폴리곤은 별개의 polygonData로 처리됩니다.
|
|
24
93
|
* - 도넛 폴리곤 A: isDonutPolygon=true
|
|
25
94
|
* - 내부 폴리곤 B: isDonutPolygon=false (별도 데이터)
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* const isHit = isPointInPolygonData(
|
|
99
|
+
* clickedOffset,
|
|
100
|
+
* polygonData,
|
|
101
|
+
* getOrComputePolygonOffsets
|
|
102
|
+
* );
|
|
103
|
+
* ```
|
|
26
104
|
*/
|
|
27
105
|
export declare const isPointInPolygonData: (clickedOffset: Offset, polygonData: KonvaCanvasData<any>, getPolygonOffsets: (data: KonvaCanvasData<any>) => number[][][][] | null) => boolean;
|
|
28
106
|
/**
|
|
29
107
|
* 마커 히트 테스트 (클릭/hover 영역 체크)
|
|
30
108
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
109
|
+
* 점이 마커의 클릭/호버 영역 내부에 있는지 확인합니다.
|
|
110
|
+
* 마커의 꼬리(tail)는 Hit Test 영역에서 제외됩니다.
|
|
111
|
+
*
|
|
112
|
+
* @param clickedOffset 클릭/마우스 위치 좌표
|
|
113
|
+
* @param markerData 마커 데이터
|
|
114
|
+
* @param getMarkerOffset 마커 좌표 변환 함수
|
|
115
|
+
* @returns 점이 마커 영역 내부에 있으면 true, 아니면 false
|
|
116
|
+
*
|
|
117
|
+
* @remarks
|
|
118
|
+
* - **꼬리 제외**: 꼬리(tail)는 Hit Test 영역에서 제외됩니다
|
|
119
|
+
* - markerOffset.y는 마커 최하단(꼬리 끝) 좌표
|
|
120
|
+
* - boxHeight는 마커 본체만 포함 (꼬리 제외)
|
|
121
|
+
* - tailHeight만큼 위로 올려서 본체만 Hit Test 영역으로 사용
|
|
122
|
+
* - **성능**: O(1) - 단순 사각형 영역 체크
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```typescript
|
|
126
|
+
* const isHit = isPointInMarkerData(
|
|
127
|
+
* clickedOffset,
|
|
128
|
+
* markerData,
|
|
129
|
+
* getOrComputeMarkerOffset
|
|
130
|
+
* );
|
|
131
|
+
* ```
|
|
35
132
|
*/
|
|
36
133
|
export declare const isPointInMarkerData: (clickedOffset: Offset, markerData: KonvaCanvasData<any>, getMarkerOffset: (data: KonvaCanvasData<any>) => Offset | null) => boolean;
|
|
37
134
|
export declare const hexToRgba: (hexColor: string, alpha?: number) => string;
|
|
38
135
|
/**
|
|
39
136
|
* 텍스트 박스의 너비를 계산합니다.
|
|
40
137
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* @param
|
|
45
|
-
* @param
|
|
46
|
-
* @
|
|
138
|
+
* Canvas 2D Context의 measureText()를 사용하여 텍스트의 실제 너비를 계산하고,
|
|
139
|
+
* 패딩과 최소 너비를 고려하여 최종 너비를 반환합니다.
|
|
140
|
+
*
|
|
141
|
+
* @param params 파라미터 객체
|
|
142
|
+
* @param params.text 측정할 텍스트
|
|
143
|
+
* @param params.fontConfig 폰트 설정 (예: 'bold 16px Arial')
|
|
144
|
+
* @param params.padding 텍스트 박스에 적용할 패딩 값 (px)
|
|
145
|
+
* @param params.minWidth 최소 너비 (px)
|
|
146
|
+
* @returns 계산된 텍스트 박스의 너비 (px)
|
|
147
|
+
*
|
|
148
|
+
* @remarks
|
|
149
|
+
* - 성능: O(1) - 단일 텍스트 측정
|
|
150
|
+
* - 임시 Canvas를 사용하여 정확한 너비 측정
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```typescript
|
|
154
|
+
* const width = calculateTextBoxWidth({
|
|
155
|
+
* text: "Hello World",
|
|
156
|
+
* fontConfig: 'bold 16px Arial',
|
|
157
|
+
* padding: 20,
|
|
158
|
+
* minWidth: 60
|
|
159
|
+
* });
|
|
160
|
+
* ```
|
|
47
161
|
*/
|
|
48
162
|
export declare const calculateTextBoxWidth: ({ text, fontConfig, padding, minWidth, }: {
|
|
49
163
|
text: string;
|
|
@@ -8,6 +8,30 @@ require('../../../types/MapEventTypes.js');
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* 폴리곤 offset 계산
|
|
11
|
+
*
|
|
12
|
+
* GeoJSON MultiPolygon 형식의 위경도 좌표를 화면 픽셀 좌표로 변환합니다.
|
|
13
|
+
*
|
|
14
|
+
* @param polygonData 폴리곤 데이터 (paths 필드 필수)
|
|
15
|
+
* @param controller MintMapController 인스턴스
|
|
16
|
+
* @returns 변환된 화면 좌표 배열 (4차원 배열) 또는 null (변환 실패 시)
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* - 반환 형식: [MultiPolygon][Polygon][Point][x/y]
|
|
20
|
+
* - 성능: O(n), n은 폴리곤의 총 좌표 수
|
|
21
|
+
* - GeoJSON MultiPolygon 형식 지원
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const offsets = computePolygonOffsets(polygonData, controller);
|
|
26
|
+
* if (!offsets) return; // 변환 실패
|
|
27
|
+
*
|
|
28
|
+
* // offsets 구조: [MultiPolygon][Polygon][Point][x/y]
|
|
29
|
+
* for (const multiPolygon of offsets) {
|
|
30
|
+
* for (const polygon of multiPolygon) {
|
|
31
|
+
* // polygon은 [Point][x/y] 배열
|
|
32
|
+
* }
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
11
35
|
*/
|
|
12
36
|
|
|
13
37
|
var computePolygonOffsets = function (polygonData, controller) {
|
|
@@ -44,6 +68,23 @@ var computePolygonOffsets = function (polygonData, controller) {
|
|
|
44
68
|
};
|
|
45
69
|
/**
|
|
46
70
|
* 마커 offset 계산
|
|
71
|
+
*
|
|
72
|
+
* 마커의 위경도 좌표를 화면 픽셀 좌표로 변환합니다.
|
|
73
|
+
*
|
|
74
|
+
* @param markerData 마커 데이터 (position 필드 필수)
|
|
75
|
+
* @param controller MintMapController 인스턴스
|
|
76
|
+
* @returns 변환된 화면 좌표 (Offset) 또는 null (변환 실패 시)
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
* - 반환된 좌표는 마커의 중심점 (x, y)
|
|
80
|
+
* - 성능: O(1) - 단일 좌표 변환
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const offset = computeMarkerOffset(markerData, controller);
|
|
85
|
+
* if (!offset) return; // 변환 실패
|
|
86
|
+
* // offset.x, offset.y는 화면 픽셀 좌표
|
|
87
|
+
* ```
|
|
47
88
|
*/
|
|
48
89
|
|
|
49
90
|
var computeMarkerOffset = function (markerData, controller) {
|
|
@@ -55,6 +96,24 @@ var computeMarkerOffset = function (markerData, controller) {
|
|
|
55
96
|
};
|
|
56
97
|
/**
|
|
57
98
|
* Point-in-Polygon 알고리즘
|
|
99
|
+
*
|
|
100
|
+
* Ray Casting 알고리즘을 사용하여 점이 폴리곤 내부에 있는지 확인합니다.
|
|
101
|
+
*
|
|
102
|
+
* @param point 확인할 점의 좌표
|
|
103
|
+
* @param polygon 폴리곤 좌표 배열 (각 요소는 [x, y] 형식)
|
|
104
|
+
* @returns 점이 폴리곤 내부에 있으면 true, 아니면 false
|
|
105
|
+
*
|
|
106
|
+
* @remarks
|
|
107
|
+
* - **알고리즘**: Ray Casting (Ray Crossing)
|
|
108
|
+
* - **성능**: O(n), n은 폴리곤의 좌표 수
|
|
109
|
+
* - **경계 처리**: 경계선 위의 점은 내부로 간주
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* const point = { x: 100, y: 200 };
|
|
114
|
+
* const polygon = [[0, 0], [100, 0], [100, 100], [0, 100]];
|
|
115
|
+
* const isInside = isPointInPolygon(point, polygon);
|
|
116
|
+
* ```
|
|
58
117
|
*/
|
|
59
118
|
|
|
60
119
|
var isPointInPolygon = function (point, polygon) {
|
|
@@ -74,13 +133,32 @@ var isPointInPolygon = function (point, polygon) {
|
|
|
74
133
|
/**
|
|
75
134
|
* 폴리곤 히트 테스트 (도넛 폴리곤 지원)
|
|
76
135
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
136
|
+
* 점이 폴리곤 내부에 있는지 확인합니다. 도넛 폴리곤(구멍이 있는 폴리곤)을 지원합니다.
|
|
137
|
+
*
|
|
138
|
+
* @param clickedOffset 클릭/마우스 위치 좌표
|
|
139
|
+
* @param polygonData 폴리곤 데이터
|
|
140
|
+
* @param getPolygonOffsets 폴리곤 좌표 변환 함수
|
|
141
|
+
* @returns 점이 폴리곤 내부에 있으면 true, 아니면 false
|
|
80
142
|
*
|
|
81
|
-
*
|
|
143
|
+
* @remarks
|
|
144
|
+
* - **도넛 폴리곤 처리** (isDonutPolygon === true):
|
|
145
|
+
* 1. 외부 폴리곤(첫 번째): 내부에 있어야 함
|
|
146
|
+
* 2. 내부 구멍들(나머지): 내부에 있으면 안 됨 (evenodd 규칙)
|
|
147
|
+
* - **일반 폴리곤 처리**: Point-in-Polygon 알고리즘 사용
|
|
148
|
+
* - **성능**: O(n), n은 폴리곤의 총 좌표 수
|
|
149
|
+
*
|
|
150
|
+
* **중요**: 도넛 폴리곤과 내부 폴리곤은 별개의 polygonData로 처리됩니다.
|
|
82
151
|
* - 도넛 폴리곤 A: isDonutPolygon=true
|
|
83
152
|
* - 내부 폴리곤 B: isDonutPolygon=false (별도 데이터)
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const isHit = isPointInPolygonData(
|
|
157
|
+
* clickedOffset,
|
|
158
|
+
* polygonData,
|
|
159
|
+
* getOrComputePolygonOffsets
|
|
160
|
+
* );
|
|
161
|
+
* ```
|
|
84
162
|
*/
|
|
85
163
|
|
|
86
164
|
var isPointInPolygonData = function (clickedOffset, polygonData, getPolygonOffsets) {
|
|
@@ -145,10 +223,29 @@ var isPointInPolygonData = function (clickedOffset, polygonData, getPolygonOffse
|
|
|
145
223
|
/**
|
|
146
224
|
* 마커 히트 테스트 (클릭/hover 영역 체크)
|
|
147
225
|
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
226
|
+
* 점이 마커의 클릭/호버 영역 내부에 있는지 확인합니다.
|
|
227
|
+
* 마커의 꼬리(tail)는 Hit Test 영역에서 제외됩니다.
|
|
228
|
+
*
|
|
229
|
+
* @param clickedOffset 클릭/마우스 위치 좌표
|
|
230
|
+
* @param markerData 마커 데이터
|
|
231
|
+
* @param getMarkerOffset 마커 좌표 변환 함수
|
|
232
|
+
* @returns 점이 마커 영역 내부에 있으면 true, 아니면 false
|
|
233
|
+
*
|
|
234
|
+
* @remarks
|
|
235
|
+
* - **꼬리 제외**: 꼬리(tail)는 Hit Test 영역에서 제외됩니다
|
|
236
|
+
* - markerOffset.y는 마커 최하단(꼬리 끝) 좌표
|
|
237
|
+
* - boxHeight는 마커 본체만 포함 (꼬리 제외)
|
|
238
|
+
* - tailHeight만큼 위로 올려서 본체만 Hit Test 영역으로 사용
|
|
239
|
+
* - **성능**: O(1) - 단순 사각형 영역 체크
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* const isHit = isPointInMarkerData(
|
|
244
|
+
* clickedOffset,
|
|
245
|
+
* markerData,
|
|
246
|
+
* getOrComputeMarkerOffset
|
|
247
|
+
* );
|
|
248
|
+
* ```
|
|
152
249
|
*/
|
|
153
250
|
|
|
154
251
|
var isPointInMarkerData = function (clickedOffset, markerData, getMarkerOffset) {
|
|
@@ -185,12 +282,29 @@ var tempCtx = tempCanvas.getContext('2d');
|
|
|
185
282
|
/**
|
|
186
283
|
* 텍스트 박스의 너비를 계산합니다.
|
|
187
284
|
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* @param
|
|
192
|
-
* @param
|
|
193
|
-
* @
|
|
285
|
+
* Canvas 2D Context의 measureText()를 사용하여 텍스트의 실제 너비를 계산하고,
|
|
286
|
+
* 패딩과 최소 너비를 고려하여 최종 너비를 반환합니다.
|
|
287
|
+
*
|
|
288
|
+
* @param params 파라미터 객체
|
|
289
|
+
* @param params.text 측정할 텍스트
|
|
290
|
+
* @param params.fontConfig 폰트 설정 (예: 'bold 16px Arial')
|
|
291
|
+
* @param params.padding 텍스트 박스에 적용할 패딩 값 (px)
|
|
292
|
+
* @param params.minWidth 최소 너비 (px)
|
|
293
|
+
* @returns 계산된 텍스트 박스의 너비 (px)
|
|
294
|
+
*
|
|
295
|
+
* @remarks
|
|
296
|
+
* - 성능: O(1) - 단일 텍스트 측정
|
|
297
|
+
* - 임시 Canvas를 사용하여 정확한 너비 측정
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```typescript
|
|
301
|
+
* const width = calculateTextBoxWidth({
|
|
302
|
+
* text: "Hello World",
|
|
303
|
+
* fontConfig: 'bold 16px Arial',
|
|
304
|
+
* padding: 20,
|
|
305
|
+
* minWidth: 60
|
|
306
|
+
* });
|
|
307
|
+
* ```
|
|
194
308
|
*/
|
|
195
309
|
|
|
196
310
|
var calculateTextBoxWidth = function (_a) {
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { MutableRefObject } from "react";
|
|
2
|
+
import { KonvaCanvasData } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* 뷰포트 영역 (화면에 보이는 영역)
|
|
5
|
+
*/
|
|
6
|
+
export interface ViewportBounds {
|
|
7
|
+
minX: number;
|
|
8
|
+
maxX: number;
|
|
9
|
+
minY: number;
|
|
10
|
+
maxY: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 바운딩 박스 (마커/폴리곤의 최소/최대 좌표)
|
|
14
|
+
*/
|
|
15
|
+
export interface BoundingBox {
|
|
16
|
+
minX: number;
|
|
17
|
+
minY: number;
|
|
18
|
+
maxX: number;
|
|
19
|
+
maxY: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 현재 뷰포트 영역 계산
|
|
23
|
+
*
|
|
24
|
+
* Konva Stage의 크기와 컬링 마진을 기반으로 뷰포트 경계를 계산합니다.
|
|
25
|
+
*
|
|
26
|
+
* @param stage Konva Stage 인스턴스 (width, height 메서드 제공)
|
|
27
|
+
* @param cullingMargin 컬링 여유 공간 (px)
|
|
28
|
+
* @param viewportRef 뷰포트 경계를 저장할 ref
|
|
29
|
+
*
|
|
30
|
+
* @remarks
|
|
31
|
+
* - 화면 밖 cullingMargin만큼의 영역까지 포함하여 계산
|
|
32
|
+
* - 스크롤 시 부드러운 전환을 위해 여유 공간 포함
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* updateViewport(stageRef.current, cullingMargin, viewportRef);
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare const updateViewport: (stage: {
|
|
40
|
+
width: () => number;
|
|
41
|
+
height: () => number;
|
|
42
|
+
} | null, cullingMargin: number, viewportRef: MutableRefObject<ViewportBounds | null>) => void;
|
|
43
|
+
/**
|
|
44
|
+
* 아이템이 현재 뷰포트 안에 있는지 확인 (바운딩 박스 캐싱)
|
|
45
|
+
*
|
|
46
|
+
* 뷰포트 컬링을 위한 함수입니다. 바운딩 박스와 뷰포트 경계의 교차를 확인합니다.
|
|
47
|
+
* 바운딩 박스는 캐시되어 성능을 최적화합니다.
|
|
48
|
+
*
|
|
49
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
50
|
+
* @param item 확인할 아이템
|
|
51
|
+
* @param enableViewportCulling 뷰포트 컬링 활성화 여부
|
|
52
|
+
* @param viewportRef 뷰포트 경계 ref
|
|
53
|
+
* @param boundingBoxCacheRef 바운딩 박스 캐시 ref
|
|
54
|
+
* @param computeBoundingBox 바운딩 박스 계산 함수
|
|
55
|
+
* @returns 뷰포트 안에 있으면 true, 아니면 false
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* - 성능: O(1) (캐시 히트 시) 또는 O(바운딩 박스 계산 비용) (캐시 미스 시)
|
|
59
|
+
* - 바운딩 박스는 자동으로 캐시되어 재사용됨
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* const isVisible = isInViewport(
|
|
64
|
+
* item,
|
|
65
|
+
* enableViewportCulling,
|
|
66
|
+
* viewportRef,
|
|
67
|
+
* boundingBoxCacheRef,
|
|
68
|
+
* computeBoundingBox
|
|
69
|
+
* );
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export declare const isInViewport: <T>(item: KonvaCanvasData<T>, enableViewportCulling: boolean, viewportRef: MutableRefObject<ViewportBounds | null>, boundingBoxCacheRef: MutableRefObject<Map<string, BoundingBox>>, computeBoundingBox: (item: KonvaCanvasData<T>) => BoundingBox | null) => boolean;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 현재 뷰포트 영역 계산
|
|
7
|
+
*
|
|
8
|
+
* Konva Stage의 크기와 컬링 마진을 기반으로 뷰포트 경계를 계산합니다.
|
|
9
|
+
*
|
|
10
|
+
* @param stage Konva Stage 인스턴스 (width, height 메서드 제공)
|
|
11
|
+
* @param cullingMargin 컬링 여유 공간 (px)
|
|
12
|
+
* @param viewportRef 뷰포트 경계를 저장할 ref
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* - 화면 밖 cullingMargin만큼의 영역까지 포함하여 계산
|
|
16
|
+
* - 스크롤 시 부드러운 전환을 위해 여유 공간 포함
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* updateViewport(stageRef.current, cullingMargin, viewportRef);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
var updateViewport = function (stage, cullingMargin, viewportRef) {
|
|
24
|
+
if (!stage) return;
|
|
25
|
+
viewportRef.current = {
|
|
26
|
+
minX: -cullingMargin,
|
|
27
|
+
maxX: stage.width() + cullingMargin,
|
|
28
|
+
minY: -cullingMargin,
|
|
29
|
+
maxY: stage.height() + cullingMargin
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* 아이템이 현재 뷰포트 안에 있는지 확인 (바운딩 박스 캐싱)
|
|
34
|
+
*
|
|
35
|
+
* 뷰포트 컬링을 위한 함수입니다. 바운딩 박스와 뷰포트 경계의 교차를 확인합니다.
|
|
36
|
+
* 바운딩 박스는 캐시되어 성능을 최적화합니다.
|
|
37
|
+
*
|
|
38
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
39
|
+
* @param item 확인할 아이템
|
|
40
|
+
* @param enableViewportCulling 뷰포트 컬링 활성화 여부
|
|
41
|
+
* @param viewportRef 뷰포트 경계 ref
|
|
42
|
+
* @param boundingBoxCacheRef 바운딩 박스 캐시 ref
|
|
43
|
+
* @param computeBoundingBox 바운딩 박스 계산 함수
|
|
44
|
+
* @returns 뷰포트 안에 있으면 true, 아니면 false
|
|
45
|
+
*
|
|
46
|
+
* @remarks
|
|
47
|
+
* - 성능: O(1) (캐시 히트 시) 또는 O(바운딩 박스 계산 비용) (캐시 미스 시)
|
|
48
|
+
* - 바운딩 박스는 자동으로 캐시되어 재사용됨
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const isVisible = isInViewport(
|
|
53
|
+
* item,
|
|
54
|
+
* enableViewportCulling,
|
|
55
|
+
* viewportRef,
|
|
56
|
+
* boundingBoxCacheRef,
|
|
57
|
+
* computeBoundingBox
|
|
58
|
+
* );
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
var isInViewport = function (item, enableViewportCulling, viewportRef, boundingBoxCacheRef, computeBoundingBox) {
|
|
63
|
+
if (!enableViewportCulling || !viewportRef.current) return true;
|
|
64
|
+
var viewport = viewportRef.current; // 캐시된 바운딩 박스 확인
|
|
65
|
+
|
|
66
|
+
var bbox = boundingBoxCacheRef.current.get(item.id);
|
|
67
|
+
|
|
68
|
+
if (!bbox) {
|
|
69
|
+
// 바운딩 박스 계산 (공통 함수 사용)
|
|
70
|
+
var computed = computeBoundingBox(item);
|
|
71
|
+
if (!computed) return false;
|
|
72
|
+
bbox = computed;
|
|
73
|
+
boundingBoxCacheRef.current.set(item.id, bbox);
|
|
74
|
+
} // 바운딩 박스와 viewport 교차 체크
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
return !(bbox.maxX < viewport.minX || bbox.minX > viewport.maxX || bbox.maxY < viewport.minY || bbox.minY > viewport.maxY);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
exports.isInViewport = isInViewport;
|
|
81
|
+
exports.updateViewport = updateViewport;
|