@mint-ui/map 1.2.0-test.3 → 1.2.0-test.31

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.
@@ -1,2 +1,3 @@
1
- export * from "./WoongKonvaMarker";
1
+ export { default as WoongCanvasLayer } from "./WoongCanvasLayer";
2
+ export * from "./WoongCanvasLayer";
2
3
  export * from "./shared";
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import { Offset } from "../../../../types";
3
- import { KonvaCanvasMarkerData } from "./types";
3
+ import { KonvaCanvasData } from "./types";
4
4
  /**
5
5
  * 다중 WoongKonvaMarker 인스턴스를 관리하기 위한 Context
6
6
  *
@@ -12,13 +12,14 @@ import { KonvaCanvasMarkerData } from "./types";
12
12
  export interface ComponentInstance<T> {
13
13
  zIndex: number;
14
14
  hitTest: (offset: Offset) => boolean;
15
- onClick?: (payload: KonvaCanvasMarkerData<T>, selectedIds: Set<string>) => void;
16
- onMouseOver?: (payload: KonvaCanvasMarkerData<T>) => void;
17
- onMouseOut?: (payload: KonvaCanvasMarkerData<T>) => void;
18
- findData: (offset: Offset) => KonvaCanvasMarkerData<T> | null;
19
- setHovered: (data: KonvaCanvasMarkerData<T> | null) => void;
20
- handleLocalClick: (data: KonvaCanvasMarkerData<T>) => void;
15
+ onClick?: (payload: KonvaCanvasData<T>, selectedIds: Set<string>) => void;
16
+ onMouseOver?: (payload: KonvaCanvasData<T>) => void;
17
+ onMouseOut?: (payload: KonvaCanvasData<T>) => void;
18
+ findData: (offset: Offset) => KonvaCanvasData<T> | null;
19
+ setHovered: (data: KonvaCanvasData<T> | null) => void;
20
+ handleLocalClick: (data: KonvaCanvasData<T>) => void;
21
21
  getSelectedIds: () => Set<string>;
22
+ isInteractionDisabled: () => boolean;
22
23
  }
23
24
  interface KonvaMarkerContextValue {
24
25
  registerComponent: <T>(instance: ComponentInstance<T>) => void;
@@ -55,7 +55,9 @@ var KonvaMarkerProvider = function (_a) {
55
55
  var clickedOffset = controller.positionToOffset(event.param.position); // zIndex 순서대로 순회 (높은 것부터)
56
56
 
57
57
  for (var _i = 0, _b = componentsRef.current; _i < _b.length; _i++) {
58
- var component = _b[_i];
58
+ var component = _b[_i]; // 🚫 상호작용이 비활성화된 컴포넌트는 스킵
59
+
60
+ if (component.isInteractionDisabled()) continue;
59
61
  var data = component.findData(clickedOffset);
60
62
 
61
63
  if (data) {
@@ -83,7 +85,9 @@ var KonvaMarkerProvider = function (_a) {
83
85
  var newHoveredData = null;
84
86
 
85
87
  for (var _i = 0, _b = componentsRef.current; _i < _b.length; _i++) {
86
- var component = _b[_i];
88
+ var component = _b[_i]; // 🚫 상호작용이 비활성화된 컴포넌트는 스킵
89
+
90
+ if (component.isInteractionDisabled()) continue;
87
91
  var data = component.findData(mouseOffset);
88
92
 
89
93
  if (data) {
@@ -0,0 +1,61 @@
1
+ /**
2
+ * 폴리곤 렌더링 유틸리티
3
+ *
4
+ * 이 파일은 폴리곤 렌더링을 위한 헬퍼 함수와 팩토리 함수를 제공합니다.
5
+ */
6
+ import { CustomRenderBase, CustomRenderEvent, KonvaCanvasData } from "./types";
7
+ /**
8
+ * 폴리곤 그리기 헬퍼 함수 (도넛 폴리곤 지원)
9
+ */
10
+ export declare const drawPolygon: ({ ctx, polygonOffsets, isDonutPolygon, fillColor, strokeColor, lineWidth }: {
11
+ ctx: CanvasRenderingContext2D;
12
+ polygonOffsets: number[][][][];
13
+ isDonutPolygon: boolean;
14
+ fillColor: string;
15
+ strokeColor: string;
16
+ lineWidth: number;
17
+ }) => void;
18
+ /**
19
+ * 폴리곤 Base 렌더링 함수
20
+ *
21
+ * @param baseFillColor 기본 폴리곤 채우기 색상
22
+ * @param baseStrokeColor 기본 폴리곤 테두리 색상
23
+ * @param baseLineWidth 기본 폴리곤 테두리 두께
24
+ * @returns Base Layer 렌더링 함수
25
+ *
26
+ * @example
27
+ * const renderBase = renderPolygonBase(
28
+ * 'rgba(255, 100, 100, 0.5)',
29
+ * 'rgba(200, 50, 50, 0.8)',
30
+ * 2
31
+ * );
32
+ */
33
+ export declare const renderPolygonBase: <T = any>(baseFillColor: string, baseStrokeColor: string, baseLineWidth: number) => CustomRenderBase<KonvaCanvasData<T>>;
34
+ /**
35
+ * 폴리곤 Event 렌더링 함수
36
+ *
37
+ * @param baseFillColor 기본 폴리곤 채우기 색상 (필수, fallback용)
38
+ * @param baseStrokeColor 기본 폴리곤 테두리 색상 (필수, fallback용)
39
+ * @param baseLineWidth 기본 폴리곤 테두리 두께 (필수, fallback용)
40
+ * @param selectedFillColor 선택된 폴리곤 채우기 색상 (선택, 기본값: baseFillColor)
41
+ * @param selectedStrokeColor 선택된 폴리곤 테두리 색상 (선택, 기본값: baseStrokeColor)
42
+ * @param selectedLineWidth 선택된 폴리곤 테두리 두께 (선택, 기본값: baseLineWidth)
43
+ * @param activeFillColor 마지막 선택된 폴리곤 채우기 색상 (선택, 기본값: selectedFillColor)
44
+ * @param activeStrokeColor 마지막 선택된 폴리곤 테두리 색상 (선택, 기본값: selectedStrokeColor)
45
+ * @param activeLineWidth 마지막 선택된 폴리곤 테두리 두께 (선택, 기본값: selectedLineWidth)
46
+ * @param hoveredFillColor Hover 시 폴리곤 채우기 색상 (선택, 기본값: selectedFillColor)
47
+ * @param hoveredStrokeColor Hover 시 폴리곤 테두리 색상 (선택, 기본값: selectedStrokeColor)
48
+ * @param hoveredLineWidth Hover 시 폴리곤 테두리 두께 (선택, 기본값: selectedLineWidth)
49
+ * @returns Event Layer 렌더링 함수
50
+ *
51
+ * @example
52
+ * const renderEvent = renderPolygonEvent(
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
59
+ * );
60
+ */
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>>;
@@ -0,0 +1,234 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ /**
6
+ * 폴리곤 렌더링 유틸리티
7
+ *
8
+ * 이 파일은 폴리곤 렌더링을 위한 헬퍼 함수와 팩토리 함수를 제공합니다.
9
+ */
10
+
11
+ /**
12
+ * 폴리곤 그리기 헬퍼 함수 (도넛 폴리곤 지원)
13
+ */
14
+ var drawPolygon = function (_a) {
15
+ var ctx = _a.ctx,
16
+ polygonOffsets = _a.polygonOffsets,
17
+ isDonutPolygon = _a.isDonutPolygon,
18
+ fillColor = _a.fillColor,
19
+ strokeColor = _a.strokeColor,
20
+ lineWidth = _a.lineWidth;
21
+
22
+ for (var _i = 0, polygonOffsets_1 = polygonOffsets; _i < polygonOffsets_1.length; _i++) {
23
+ var multiPolygon = polygonOffsets_1[_i];
24
+
25
+ if (isDonutPolygon) {
26
+ ctx.beginPath(); // 1. 외부 폴리곤 그리기
27
+
28
+ if (multiPolygon[0] && multiPolygon[0].length > 0) {
29
+ ctx.moveTo(multiPolygon[0][0][0], multiPolygon[0][0][1]);
30
+
31
+ for (var i = 1; i < multiPolygon[0].length; i++) {
32
+ ctx.lineTo(multiPolygon[0][i][0], multiPolygon[0][i][1]);
33
+ }
34
+
35
+ ctx.closePath();
36
+ } // 2. 내부 폴리곤 (구멍들) 그리기 - 같은 path에 추가
37
+
38
+
39
+ for (var j = 1; j < multiPolygon.length; j++) {
40
+ var innerPolygon = multiPolygon[j];
41
+ if (innerPolygon.length === 0) continue;
42
+ ctx.moveTo(innerPolygon[0][0], innerPolygon[0][1]);
43
+
44
+ for (var i = 1; i < innerPolygon.length; i++) {
45
+ ctx.lineTo(innerPolygon[i][0], innerPolygon[i][1]);
46
+ }
47
+
48
+ ctx.closePath();
49
+ } // 3. evenodd fill rule로 구멍 뚫기
50
+
51
+
52
+ ctx.fillStyle = fillColor;
53
+ ctx.fill('evenodd'); // 4. 외곽선 그리기
54
+
55
+ ctx.strokeStyle = strokeColor;
56
+ ctx.lineWidth = lineWidth;
57
+ ctx.stroke();
58
+ } else {
59
+ // 일반 폴리곤
60
+ for (var _b = 0, multiPolygon_1 = multiPolygon; _b < multiPolygon_1.length; _b++) {
61
+ var polygonGroup = multiPolygon_1[_b];
62
+ if (!polygonGroup.length) continue;
63
+ ctx.beginPath();
64
+ var firstPoint = polygonGroup[0];
65
+ ctx.moveTo(firstPoint[0], firstPoint[1]);
66
+
67
+ for (var i = 1; i < polygonGroup.length; i++) {
68
+ var point = polygonGroup[i];
69
+ ctx.lineTo(point[0], point[1]);
70
+ }
71
+
72
+ ctx.closePath();
73
+ ctx.fillStyle = fillColor;
74
+ ctx.strokeStyle = strokeColor;
75
+ ctx.lineWidth = lineWidth;
76
+ ctx.fill();
77
+ ctx.stroke();
78
+ }
79
+ }
80
+ }
81
+ };
82
+ /**
83
+ * 폴리곤 Base 렌더링 함수
84
+ *
85
+ * @param baseFillColor 기본 폴리곤 채우기 색상
86
+ * @param baseStrokeColor 기본 폴리곤 테두리 색상
87
+ * @param baseLineWidth 기본 폴리곤 테두리 두께
88
+ * @returns Base Layer 렌더링 함수
89
+ *
90
+ * @example
91
+ * const renderBase = renderPolygonBase(
92
+ * 'rgba(255, 100, 100, 0.5)',
93
+ * 'rgba(200, 50, 50, 0.8)',
94
+ * 2
95
+ * );
96
+ */
97
+
98
+ var renderPolygonBase = function (baseFillColor, baseStrokeColor, baseLineWidth) {
99
+ return function (_a) {
100
+ var ctx = _a.ctx,
101
+ items = _a.items,
102
+ selectedIds = _a.selectedIds,
103
+ utils = _a.utils;
104
+
105
+ for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
106
+ var item = items_1[_i]; // 선택된 항목은 Event Layer에서 그림
107
+
108
+ if (selectedIds.has(item.id)) continue;
109
+ if (!item.paths) continue;
110
+ var polygonOffsets = utils.getOrComputePolygonOffsets(item);
111
+ if (!polygonOffsets) continue;
112
+ drawPolygon({
113
+ ctx: ctx,
114
+ polygonOffsets: polygonOffsets,
115
+ isDonutPolygon: item.isDonutPolygon || false,
116
+ fillColor: baseFillColor,
117
+ strokeColor: baseStrokeColor,
118
+ lineWidth: baseLineWidth
119
+ });
120
+ }
121
+ };
122
+ };
123
+ /**
124
+ * 폴리곤 Event 렌더링 함수
125
+ *
126
+ * @param baseFillColor 기본 폴리곤 채우기 색상 (필수, fallback용)
127
+ * @param baseStrokeColor 기본 폴리곤 테두리 색상 (필수, fallback용)
128
+ * @param baseLineWidth 기본 폴리곤 테두리 두께 (필수, fallback용)
129
+ * @param selectedFillColor 선택된 폴리곤 채우기 색상 (선택, 기본값: baseFillColor)
130
+ * @param selectedStrokeColor 선택된 폴리곤 테두리 색상 (선택, 기본값: baseStrokeColor)
131
+ * @param selectedLineWidth 선택된 폴리곤 테두리 두께 (선택, 기본값: baseLineWidth)
132
+ * @param activeFillColor 마지막 선택된 폴리곤 채우기 색상 (선택, 기본값: selectedFillColor)
133
+ * @param activeStrokeColor 마지막 선택된 폴리곤 테두리 색상 (선택, 기본값: selectedStrokeColor)
134
+ * @param activeLineWidth 마지막 선택된 폴리곤 테두리 두께 (선택, 기본값: selectedLineWidth)
135
+ * @param hoveredFillColor Hover 시 폴리곤 채우기 색상 (선택, 기본값: selectedFillColor)
136
+ * @param hoveredStrokeColor Hover 시 폴리곤 테두리 색상 (선택, 기본값: selectedStrokeColor)
137
+ * @param hoveredLineWidth Hover 시 폴리곤 테두리 두께 (선택, 기본값: selectedLineWidth)
138
+ * @returns Event Layer 렌더링 함수
139
+ *
140
+ * @example
141
+ * const renderEvent = renderPolygonEvent(
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
148
+ * );
149
+ */
150
+
151
+ var renderPolygonEvent = function (baseFillColor, baseStrokeColor, baseLineWidth, selectedFillColor, selectedStrokeColor, selectedLineWidth, activeFillColor, activeStrokeColor, activeLineWidth, hoveredFillColor, hoveredStrokeColor, hoveredLineWidth) {
152
+ // 기본값 설정 (base 기준)
153
+ var _selectedFillColor = selectedFillColor || baseFillColor;
154
+
155
+ var _selectedStrokeColor = selectedStrokeColor || baseStrokeColor;
156
+
157
+ var _selectedLineWidth = selectedLineWidth || baseLineWidth;
158
+
159
+ var _activeFillColor = activeFillColor || _selectedFillColor;
160
+
161
+ var _activeStrokeColor = activeStrokeColor || _selectedStrokeColor;
162
+
163
+ var _activeLineWidth = activeLineWidth || _selectedLineWidth;
164
+
165
+ var _hoveredFillColor = hoveredFillColor || _selectedFillColor;
166
+
167
+ var _hoveredStrokeColor = hoveredStrokeColor || _selectedStrokeColor;
168
+
169
+ var _hoveredLineWidth = hoveredLineWidth || _selectedLineWidth;
170
+
171
+ return function (_a) {
172
+ var ctx = _a.ctx,
173
+ hoveredItem = _a.hoveredItem,
174
+ utils = _a.utils,
175
+ selectedItems = _a.selectedItems,
176
+ selectedItem = _a.selectedItem; // 1. 선택된 항목들 그리기 (마지막 선택 항목과 호버된 항목 제외)
177
+
178
+ if (selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.length) {
179
+ for (var _i = 0, selectedItems_1 = selectedItems; _i < selectedItems_1.length; _i++) {
180
+ var item = selectedItems_1[_i]; // 마지막 선택 항목과 호버된 항목은 나중에 따로 그림
181
+
182
+ if (item.id === (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.id) || (hoveredItem === null || hoveredItem === void 0 ? void 0 : hoveredItem.id) === item.id) continue;
183
+ if (!item.paths) continue;
184
+ var polygonOffsets = utils.getOrComputePolygonOffsets(item);
185
+ if (!polygonOffsets) continue;
186
+ drawPolygon({
187
+ ctx: ctx,
188
+ polygonOffsets: polygonOffsets,
189
+ isDonutPolygon: item.isDonutPolygon || false,
190
+ fillColor: _selectedFillColor,
191
+ strokeColor: _selectedStrokeColor,
192
+ lineWidth: _selectedLineWidth
193
+ });
194
+ }
195
+ } // 2. 마지막 선택된 항목 그리기 (호버되지 않은 경우)
196
+
197
+
198
+ if ((selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.paths) && (hoveredItem === null || hoveredItem === void 0 ? void 0 : hoveredItem.id) !== selectedItem.id) {
199
+ var polygonOffsets = utils.getOrComputePolygonOffsets(selectedItem);
200
+
201
+ if (polygonOffsets) {
202
+ drawPolygon({
203
+ ctx: ctx,
204
+ polygonOffsets: polygonOffsets,
205
+ isDonutPolygon: selectedItem.isDonutPolygon || false,
206
+ fillColor: _activeFillColor,
207
+ strokeColor: _activeStrokeColor,
208
+ lineWidth: _activeLineWidth
209
+ });
210
+ }
211
+ } // 3. 호버된 항목 그리기 (가장 위에 표시)
212
+
213
+
214
+ if (hoveredItem === null || hoveredItem === void 0 ? void 0 : hoveredItem.paths) {
215
+ var polygonOffsets = utils.getOrComputePolygonOffsets(hoveredItem);
216
+ if (!polygonOffsets) return;
217
+ var isSelected = selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.some(function (item) {
218
+ return item.id === hoveredItem.id;
219
+ });
220
+ drawPolygon({
221
+ ctx: ctx,
222
+ polygonOffsets: polygonOffsets,
223
+ isDonutPolygon: hoveredItem.isDonutPolygon || false,
224
+ fillColor: isSelected ? _activeFillColor : _hoveredFillColor,
225
+ strokeColor: isSelected ? _activeStrokeColor : _hoveredStrokeColor,
226
+ lineWidth: isSelected ? _activeLineWidth : _hoveredLineWidth
227
+ });
228
+ }
229
+ };
230
+ };
231
+
232
+ exports.drawPolygon = drawPolygon;
233
+ exports.renderPolygonBase = renderPolygonBase;
234
+ exports.renderPolygonEvent = renderPolygonEvent;
@@ -22,11 +22,12 @@ export interface Paths {
22
22
  * Konva 캔버스 마커/폴리곤의 기본 필수 속성
23
23
  * (렌더링에 필요한 최소 정보)
24
24
  */
25
- export interface KonvaCanvasMarkerOption {
25
+ export interface KonvaCanvasOption {
26
26
  id: string;
27
27
  position: Position;
28
28
  boxWidth?: number;
29
29
  boxHeight?: number;
30
+ tailHeight?: number;
30
31
  paths?: Paths;
31
32
  isDonutPolygon?: boolean;
32
33
  }
@@ -35,16 +36,110 @@ export interface KonvaCanvasMarkerOption {
35
36
  * @template T 서버에서 받은 원본 데이터 타입 (예: Marker, Polygon)
36
37
  * @example
37
38
  * // API에서 받은 Marker 타입을 그대로 유지하면서 캔버스 렌더링 정보 추가
38
- * type MarkerWithCanvas = KonvaCanvasMarkerData<Marker>
39
+ * type MarkerWithCanvas = KonvaCanvasData<Marker>
39
40
  * // { raId, lat, lng, buildingName, totalArea } + { id, position, boxWidth, ... }
40
41
  */
41
- export declare type KonvaCanvasMarkerData<T = {}> = T & KonvaCanvasMarkerOption;
42
+ export declare type KonvaCanvasData<T = {}> = T & KonvaCanvasOption;
42
43
  /**
43
- * 렌더링 유틸리티 함수들
44
+ * 🛠️ 렌더링 유틸리티 함수들
45
+ *
46
+ * WoongCanvasLayer가 제공하는 헬퍼 함수 모음입니다.
47
+ * 커스텀 렌더링 함수 내에서 좌표 변환 시 사용하세요.
48
+ *
49
+ * ## 주요 기능
50
+ * - **자동 캐싱**: 좌표 변환 결과를 LRU 캐시에 저장 (성능 최적화)
51
+ * - **지도 좌표 → 화면 좌표**: 위경도를 픽셀 좌표로 자동 변환
52
+ * - **null 안전성**: 변환 실패 시 null 반환 (안전한 예외 처리)
53
+ *
54
+ * @template T 마커/폴리곤 데이터의 추가 속성 타입
55
+ *
56
+ * @example
57
+ * // 마커 렌더링 예시
58
+ * const renderBase = ({ ctx, items, utils }) => {
59
+ * for (const item of items) {
60
+ * const offset = utils.getOrComputeMarkerOffset(item);
61
+ * if (!offset) continue; // 변환 실패 시 스킵
62
+ *
63
+ * ctx.fillRect(offset.x, offset.y, 50, 50);
64
+ * }
65
+ * };
66
+ *
67
+ * @example
68
+ * // 폴리곤 렌더링 예시
69
+ * const renderBase = ({ ctx, items, utils }) => {
70
+ * for (const item of items) {
71
+ * const offsets = utils.getOrComputePolygonOffsets(item);
72
+ * if (!offsets) continue;
73
+ *
74
+ * for (const multiPolygon of offsets) {
75
+ * for (const polygon of multiPolygon) {
76
+ * ctx.beginPath();
77
+ * ctx.moveTo(polygon[0][0], polygon[0][1]);
78
+ * for (let i = 1; i < polygon.length; i++) {
79
+ * ctx.lineTo(polygon[i][0], polygon[i][1]);
80
+ * }
81
+ * ctx.closePath();
82
+ * ctx.fill();
83
+ * }
84
+ * }
85
+ * }
86
+ * };
44
87
  */
45
88
  export interface RenderUtils<T> {
46
- getOrComputePolygonOffsets: (polygonData: KonvaCanvasMarkerData<T>) => number[][][][] | null;
47
- getOrComputeMarkerOffset: (markerData: KonvaCanvasMarkerData<T>) => Offset | null;
89
+ /**
90
+ * 폴리곤의 위경도 좌표를 화면 픽셀 좌표로 변환합니다.
91
+ *
92
+ * - **자동 캐싱**: 동일한 폴리곤은 캐시에서 즉시 반환 (성능 최적화)
93
+ * - **MultiPolygon 지원**: GeoJSON MultiPolygon 형식 지원
94
+ * - **Donut Polygon 지원**: 구멍이 있는 폴리곤 지원
95
+ *
96
+ * @param polygonData 폴리곤 데이터 (paths 필드 필수)
97
+ * @returns 변환된 픽셀 좌표 배열 (4차원 배열) 또는 null (변환 실패 시)
98
+ *
99
+ * @example
100
+ * const offsets = utils.getOrComputePolygonOffsets(polygonItem);
101
+ * if (!offsets) return; // 변환 실패
102
+ *
103
+ * // offsets 구조: [MultiPolygon][Polygon][Point][x/y]
104
+ * for (const multiPolygon of offsets) {
105
+ * for (const polygon of multiPolygon) {
106
+ * ctx.beginPath();
107
+ * ctx.moveTo(polygon[0][0], polygon[0][1]);
108
+ * for (let i = 1; i < polygon.length; i++) {
109
+ * ctx.lineTo(polygon[i][0], polygon[i][1]);
110
+ * }
111
+ * ctx.closePath();
112
+ * ctx.fill();
113
+ * }
114
+ * }
115
+ */
116
+ getOrComputePolygonOffsets: (polygonData: KonvaCanvasData<T>) => number[][][][] | null;
117
+ /**
118
+ * 마커의 위경도 좌표를 화면 픽셀 좌표로 변환합니다.
119
+ *
120
+ * - **자동 캐싱**: 동일한 마커는 캐시에서 즉시 반환 (성능 최적화)
121
+ * - **중심점 기준**: 반환된 좌표는 마커의 중심점 (x, y)
122
+ *
123
+ * @param markerData 마커 데이터 (position 필드 필수)
124
+ * @returns 변환된 픽셀 좌표 { x, y } 또는 null (변환 실패 시)
125
+ *
126
+ * @example
127
+ * const offset = utils.getOrComputeMarkerOffset(markerItem);
128
+ * if (!offset) return; // 변환 실패
129
+ *
130
+ * // offset.x, offset.y는 화면 픽셀 좌표
131
+ * const boxWidth = markerItem.boxWidth || 60;
132
+ * const boxHeight = markerItem.boxHeight || 75;
133
+ *
134
+ * // 중앙 정렬, 하단 기준으로 그리기
135
+ * ctx.fillRect(
136
+ * offset.x - boxWidth / 2,
137
+ * offset.y - boxHeight,
138
+ * boxWidth,
139
+ * boxHeight
140
+ * );
141
+ */
142
+ getOrComputeMarkerOffset: (markerData: KonvaCanvasData<T>) => Offset | null;
48
143
  }
49
144
  /**
50
145
  * 커스텀 렌더링 함수 파라미터 - Base Layer
@@ -53,9 +148,11 @@ export interface RenderBaseParams<T> {
53
148
  /** Canvas 2D 렌더링 컨텍스트 (순수 Canvas API) */
54
149
  ctx: CanvasRenderingContext2D;
55
150
  /** 렌더링할 마커 데이터 배열 */
56
- items: KonvaCanvasMarkerData<T>[];
151
+ items: KonvaCanvasData<T>[];
57
152
  /** 현재 선택된 마커 ID Set */
58
153
  selectedIds: Set<string>;
154
+ /** 현재 hover된 마커 데이터 (선택) */
155
+ hoveredItem?: KonvaCanvasData<T> | null;
59
156
  /** 렌더링 유틸리티 함수들 */
60
157
  utils: RenderUtils<T>;
61
158
  }
@@ -83,7 +180,7 @@ export interface RenderAnimationParams<T> {
83
180
  /** 현재 선택된 마커 ID Set */
84
181
  selectedIds: Set<string>;
85
182
  /** 전체 마커 데이터 배열 */
86
- items: KonvaCanvasMarkerData<T>[];
183
+ items: KonvaCanvasData<T>[];
87
184
  /** 렌더링 유틸리티 함수들 */
88
185
  utils: RenderUtils<T>;
89
186
  }
@@ -106,13 +203,13 @@ export interface RenderEventParams<T> {
106
203
  /** Canvas 2D 렌더링 컨텍스트 (순수 Canvas API) */
107
204
  ctx: CanvasRenderingContext2D;
108
205
  /** 현재 hover된 마커 데이터 */
109
- hoveredItem: KonvaCanvasMarkerData<T> | null;
206
+ hoveredItem: KonvaCanvasData<T> | null;
110
207
  /** 렌더링 유틸리티 함수들 */
111
208
  utils: RenderUtils<T>;
112
209
  /** 현재 선택된 마커 데이터 배열 (선택 강조용) */
113
- selectedItems?: KonvaCanvasMarkerData<T>[];
114
- /** 마지막으로 클릭된 마커 데이터 */
115
- lastClickedItem: KonvaCanvasMarkerData<T> | null;
210
+ selectedItems?: KonvaCanvasData<T>[];
211
+ /** 외부에서 전달된 단일 선택 아이템 (특별한 효과용) */
212
+ selectedItem?: KonvaCanvasData<T> | null;
116
213
  }
117
214
  /**
118
215
  * 커스텀 렌더링 함수 타입 - Event Layer
@@ -1,23 +1,53 @@
1
1
  import { Offset } from "../../../../types";
2
2
  import { MintMapController } from "../../../MintMapController";
3
- import { KonvaCanvasMarkerData } from "./types";
3
+ import { KonvaCanvasData } from "./types";
4
4
  /**
5
5
  * 폴리곤 offset 계산
6
6
  */
7
- export declare const computePolygonOffsets: (polygonData: KonvaCanvasMarkerData<any>, controller: MintMapController) => number[][][][] | null;
7
+ export declare const computePolygonOffsets: (polygonData: KonvaCanvasData<any>, controller: MintMapController) => number[][][][] | null;
8
8
  /**
9
9
  * 마커 offset 계산
10
10
  */
11
- export declare const computeMarkerOffset: (markerData: KonvaCanvasMarkerData<any>, controller: MintMapController) => Offset | null;
11
+ export declare const computeMarkerOffset: (markerData: KonvaCanvasData<any>, controller: MintMapController) => Offset | null;
12
12
  /**
13
13
  * Point-in-Polygon 알고리즘
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
- export declare const isPointInPolygonData: (clickedOffset: Offset, polygonData: KonvaCanvasMarkerData<any>, getPolygonOffsets: (data: KonvaCanvasMarkerData<any>) => number[][][][] | null) => boolean;
27
+ export declare const isPointInPolygonData: (clickedOffset: Offset, polygonData: KonvaCanvasData<any>, getPolygonOffsets: (data: KonvaCanvasData<any>) => number[][][][] | null) => boolean;
20
28
  /**
21
- * 마커 히트 테스트
29
+ * 마커 히트 테스트 (클릭/hover 영역 체크)
30
+ *
31
+ * 🎯 중요: 꼬리(tail)는 Hit Test 영역에서 제외됩니다!
32
+ * - markerOffset.y는 마커 최하단(꼬리 끝) 좌표
33
+ * - boxHeight는 마커 본체만 포함 (꼬리 제외)
34
+ * - tailHeight만큼 위로 올려서 본체만 Hit Test 영역으로 사용
22
35
  */
23
- export declare const isPointInMarkerData: (clickedOffset: Offset, markerData: KonvaCanvasMarkerData<any>, getMarkerOffset: (data: KonvaCanvasMarkerData<any>) => Offset | null) => boolean;
36
+ export declare const isPointInMarkerData: (clickedOffset: Offset, markerData: KonvaCanvasData<any>, getMarkerOffset: (data: KonvaCanvasData<any>) => Offset | null) => boolean;
37
+ export declare const hexToRgba: (hexColor: string, alpha?: number) => string;
38
+ /**
39
+ * 텍스트 박스의 너비를 계산합니다.
40
+ *
41
+ * @param {Object} params - 파라미터 객체
42
+ * @param {string} params.text - 측정할 텍스트
43
+ * @param {string} params.fontConfig - 폰트 설정 (예: 'bold 16px Arial')
44
+ * @param {number} params.padding - 텍스트 박스에 적용할 패딩 값
45
+ * @param {number} params.minWidth - 최소 너비
46
+ * @returns {number} 계산된 텍스트 박스의 너비
47
+ */
48
+ export declare const calculateTextBoxWidth: ({ text, fontConfig, padding, minWidth, }: {
49
+ text: string;
50
+ fontConfig: string;
51
+ padding: number;
52
+ minWidth: number;
53
+ }) => number;