@mint-ui/map 1.2.0-test.16 → 1.2.0-test.18
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 +7 -7
- package/dist/components/mint-map/core/advanced/woongCanvas/WoongCanvasLayer.js +117 -226
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/renderer.d.ts +13 -11
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/renderer.js +29 -21
- 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 +146 -247
- package/dist/index.umd.js +146 -247
- package/package.json +1 -1
|
@@ -57,12 +57,12 @@ interface WoongCanvasLayerPropsForPolygon<T> extends WoongCanvasLayerBaseProps<T
|
|
|
57
57
|
baseStrokeColor: string;
|
|
58
58
|
/** 기본 폴리곤 테두리 두께 (필수) */
|
|
59
59
|
baseLineWidth: number;
|
|
60
|
-
/** 선택된 폴리곤 채우기 색상 (
|
|
61
|
-
selectedFillColor
|
|
62
|
-
/** 선택된 폴리곤 테두리 색상 (
|
|
63
|
-
selectedStrokeColor
|
|
64
|
-
/** 선택된 폴리곤 테두리 두께 (
|
|
65
|
-
selectedLineWidth
|
|
60
|
+
/** 선택된 폴리곤 채우기 색상 (선택) */
|
|
61
|
+
selectedFillColor?: string;
|
|
62
|
+
/** 선택된 폴리곤 테두리 색상 (선택) */
|
|
63
|
+
selectedStrokeColor?: string;
|
|
64
|
+
/** 선택된 폴리곤 테두리 두께 (선택) */
|
|
65
|
+
selectedLineWidth?: number;
|
|
66
66
|
/** 마지막 선택된 폴리곤 채우기 색상 (선택, 기본값: selectedFillColor) */
|
|
67
67
|
activeFillColor?: string;
|
|
68
68
|
/** 마지막 선택된 폴리곤 테두리 색상 (선택, 기본값: selectedStrokeColor) */
|
|
@@ -80,6 +80,7 @@ interface WoongCanvasLayerPropsForPolygon<T> extends WoongCanvasLayerBaseProps<T
|
|
|
80
80
|
* 최종 Props 타입 - Discriminated Union
|
|
81
81
|
*/
|
|
82
82
|
export declare type WoongCanvasLayerProps<T> = WoongCanvasLayerPropsForMarker<T> | WoongCanvasLayerPropsForPolygon<T>;
|
|
83
|
+
declare const WoongCanvasLayer: <T>(props: WoongCanvasLayerProps<T>) => React.ReactPortal;
|
|
83
84
|
/**
|
|
84
85
|
* 🚀 WoongCanvasLayer - Konva 기반 초고성능 마커/폴리곤 렌더링 컴포넌트
|
|
85
86
|
*
|
|
@@ -158,5 +159,4 @@ export declare type WoongCanvasLayerProps<T> = WoongCanvasLayerPropsForMarker<T>
|
|
|
158
159
|
*
|
|
159
160
|
* @see {@link https://github.com/your-repo/docs/WoongCanvasLayer.md} 전체 문서
|
|
160
161
|
*/
|
|
161
|
-
declare const WoongCanvasLayer: <T>(props: WoongCanvasLayerProps<T>) => React.ReactPortal;
|
|
162
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,
|
|
@@ -166,55 +166,11 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
166
166
|
var bbox = boundingBoxCacheRef.current.get(item.id);
|
|
167
167
|
|
|
168
168
|
if (!bbox) {
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
var minX = Infinity,
|
|
175
|
-
minY = Infinity,
|
|
176
|
-
maxX = -Infinity,
|
|
177
|
-
maxY = -Infinity;
|
|
178
|
-
|
|
179
|
-
for (var _i = 0, offsets_1 = offsets; _i < offsets_1.length; _i++) {
|
|
180
|
-
var multiPolygon = offsets_1[_i];
|
|
181
|
-
|
|
182
|
-
for (var _a = 0, multiPolygon_1 = multiPolygon; _a < multiPolygon_1.length; _a++) {
|
|
183
|
-
var polygonGroup = multiPolygon_1[_a];
|
|
184
|
-
|
|
185
|
-
for (var _b = 0, polygonGroup_1 = polygonGroup; _b < polygonGroup_1.length; _b++) {
|
|
186
|
-
var _c = polygonGroup_1[_b],
|
|
187
|
-
x = _c[0],
|
|
188
|
-
y = _c[1];
|
|
189
|
-
if (x < minX) minX = x;
|
|
190
|
-
if (y < minY) minY = y;
|
|
191
|
-
if (x > maxX) maxX = x;
|
|
192
|
-
if (y > maxY) maxY = y;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
bbox = {
|
|
198
|
-
minX: minX,
|
|
199
|
-
minY: minY,
|
|
200
|
-
maxX: maxX,
|
|
201
|
-
maxY: maxY
|
|
202
|
-
};
|
|
203
|
-
boundingBoxCacheRef.current.set(item.id, bbox);
|
|
204
|
-
} // 마커인 경우
|
|
205
|
-
else {
|
|
206
|
-
var offset = getOrComputeMarkerOffset(item);
|
|
207
|
-
if (!offset) return false;
|
|
208
|
-
var boxWidth = item.boxWidth || 50;
|
|
209
|
-
var boxHeight = item.boxHeight || 28;
|
|
210
|
-
bbox = {
|
|
211
|
-
minX: offset.x - boxWidth / 2,
|
|
212
|
-
minY: offset.y - boxHeight - 6,
|
|
213
|
-
maxX: offset.x + boxWidth / 2,
|
|
214
|
-
maxY: offset.y
|
|
215
|
-
};
|
|
216
|
-
boundingBoxCacheRef.current.set(item.id, bbox);
|
|
217
|
-
}
|
|
169
|
+
// 바운딩 박스 계산 (공통 함수 사용)
|
|
170
|
+
var computed = computeBoundingBox(item);
|
|
171
|
+
if (!computed) return false;
|
|
172
|
+
bbox = computed;
|
|
173
|
+
boundingBoxCacheRef.current.set(item.id, bbox);
|
|
218
174
|
} // 바운딩 박스와 viewport 교차 체크
|
|
219
175
|
|
|
220
176
|
|
|
@@ -260,6 +216,65 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
260
216
|
|
|
261
217
|
return result;
|
|
262
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
|
+
}; // --------------------------------------------------------------------------
|
|
263
278
|
// 유틸리티 함수: 공간 인덱싱
|
|
264
279
|
// --------------------------------------------------------------------------
|
|
265
280
|
|
|
@@ -274,52 +289,12 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
274
289
|
var currentMarkers = markersRef.current;
|
|
275
290
|
|
|
276
291
|
for (var _i = 0, currentMarkers_1 = currentMarkers; _i < currentMarkers_1.length; _i++) {
|
|
277
|
-
var item = currentMarkers_1[_i];
|
|
292
|
+
var item = currentMarkers_1[_i]; // 바운딩 박스 계산 (공통 함수 사용)
|
|
278
293
|
|
|
279
|
-
|
|
280
|
-
// 폴리곤: 바운딩 박스 계산 (최적화: 직접 비교)
|
|
281
|
-
var offsets = getOrComputePolygonOffsets(item);
|
|
282
|
-
|
|
283
|
-
if (offsets) {
|
|
284
|
-
var minX = Infinity,
|
|
285
|
-
minY = Infinity,
|
|
286
|
-
maxX = -Infinity,
|
|
287
|
-
maxY = -Infinity;
|
|
288
|
-
|
|
289
|
-
for (var _a = 0, offsets_2 = offsets; _a < offsets_2.length; _a++) {
|
|
290
|
-
var multiPolygon = offsets_2[_a];
|
|
291
|
-
|
|
292
|
-
for (var _b = 0, multiPolygon_2 = multiPolygon; _b < multiPolygon_2.length; _b++) {
|
|
293
|
-
var polygonGroup = multiPolygon_2[_b];
|
|
294
|
-
|
|
295
|
-
for (var _c = 0, polygonGroup_2 = polygonGroup; _c < polygonGroup_2.length; _c++) {
|
|
296
|
-
var _d = polygonGroup_2[_c],
|
|
297
|
-
x = _d[0],
|
|
298
|
-
y = _d[1];
|
|
299
|
-
if (x < minX) minX = x;
|
|
300
|
-
if (y < minY) minY = y;
|
|
301
|
-
if (x > maxX) maxX = x;
|
|
302
|
-
if (y > maxY) maxY = y;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
294
|
+
var bbox = computeBoundingBox(item);
|
|
306
295
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
} else {
|
|
310
|
-
// 마커: 점 기반 바운딩 박스
|
|
311
|
-
var offset = getOrComputeMarkerOffset(item);
|
|
312
|
-
|
|
313
|
-
if (offset) {
|
|
314
|
-
var boxWidth = item.boxWidth || 50;
|
|
315
|
-
var boxHeight = item.boxHeight || 28;
|
|
316
|
-
var tailHeight = 6;
|
|
317
|
-
var minX = offset.x - boxWidth / 2;
|
|
318
|
-
var minY = offset.y - boxHeight - tailHeight;
|
|
319
|
-
var maxX = offset.x + boxWidth / 2;
|
|
320
|
-
var maxY = offset.y;
|
|
321
|
-
spatial.insert(item, minX, minY, maxX, maxY);
|
|
322
|
-
}
|
|
296
|
+
if (bbox) {
|
|
297
|
+
spatial.insert(item, bbox.minX, bbox.minY, bbox.maxX, bbox.maxY);
|
|
323
298
|
}
|
|
324
299
|
}
|
|
325
300
|
}; // --------------------------------------------------------------------------
|
|
@@ -348,7 +323,7 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
348
323
|
var renderAnimation = dataType === types.CanvasDataType.MARKER ? props.renderAnimation : undefined;
|
|
349
324
|
var renderEvent = dataType === types.CanvasDataType.MARKER ? props.renderEvent : function () {
|
|
350
325
|
var polygonProps = props;
|
|
351
|
-
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);
|
|
352
327
|
}();
|
|
353
328
|
/**
|
|
354
329
|
* Base 레이어 렌더링 (뷰포트 컬링 적용, 선택된 마커 제외)
|
|
@@ -357,6 +332,10 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
357
332
|
* 1. Shape 재사용으로 객체 생성/파괴 오버헤드 제거
|
|
358
333
|
* 2. sceneFunc 한 번만 설정 (함수 재생성 제거)
|
|
359
334
|
* 3. 클로저로 최신 데이터 참조
|
|
335
|
+
*
|
|
336
|
+
* 🎯 topOnHover 지원:
|
|
337
|
+
* - renderEvent가 없을 때 Base Layer에서 hover 처리 (fallback)
|
|
338
|
+
* - renderEvent가 있으면 Event Layer에서 처리 (성능 최적화)
|
|
360
339
|
*/
|
|
361
340
|
|
|
362
341
|
var doRenderBase = function () {
|
|
@@ -371,17 +350,40 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
371
350
|
shape = new Konva__default["default"].Shape({
|
|
372
351
|
name: 'base-render-shape',
|
|
373
352
|
sceneFunc: function (context, shape) {
|
|
374
|
-
var ctx = context;
|
|
353
|
+
var ctx = context;
|
|
354
|
+
var hovered = hoveredItemRef.current; // 클로저로 최신 ref 값 참조
|
|
375
355
|
|
|
376
356
|
var visibleMarkers = enableViewportCulling ? markersRef.current.filter(function (item) {
|
|
377
357
|
return isInViewport(item);
|
|
378
|
-
}) : markersRef.current;
|
|
358
|
+
}) : markersRef.current; // topOnHover가 true이고 renderEvent가 없으면 Base Layer에서 hover 처리
|
|
359
|
+
|
|
360
|
+
if (topOnHover && !renderEvent && hovered) {
|
|
361
|
+
// hover된 항목 제외하고 렌더링
|
|
362
|
+
visibleMarkers = visibleMarkers.filter(function (item) {
|
|
363
|
+
return item.id !== hovered.id;
|
|
364
|
+
});
|
|
365
|
+
} // 일반 항목 렌더링
|
|
366
|
+
|
|
367
|
+
|
|
379
368
|
renderBase({
|
|
380
369
|
ctx: ctx,
|
|
381
370
|
items: visibleMarkers,
|
|
382
371
|
selectedIds: selectedIdsRef.current,
|
|
383
372
|
utils: renderUtils
|
|
384
|
-
});
|
|
373
|
+
}); // hover된 항목을 최상단에 렌더링 (renderEvent가 없을 때만)
|
|
374
|
+
|
|
375
|
+
if (topOnHover && !renderEvent && hovered) {
|
|
376
|
+
var isHoveredInViewport = enableViewportCulling ? isInViewport(hovered) : true;
|
|
377
|
+
|
|
378
|
+
if (isHoveredInViewport) {
|
|
379
|
+
renderBase({
|
|
380
|
+
ctx: ctx,
|
|
381
|
+
items: [hovered],
|
|
382
|
+
selectedIds: selectedIdsRef.current,
|
|
383
|
+
utils: renderUtils
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
}
|
|
385
387
|
},
|
|
386
388
|
perfectDrawEnabled: false,
|
|
387
389
|
listening: false,
|
|
@@ -426,13 +428,6 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
426
428
|
var doRenderEvent = function () {
|
|
427
429
|
var layer = eventLayerRef.current;
|
|
428
430
|
if (!layer) return;
|
|
429
|
-
|
|
430
|
-
if (!onClick && !onMouseOver && !onMouseOut) {
|
|
431
|
-
layer.destroyChildren();
|
|
432
|
-
layer.batchDraw();
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
431
|
if (!renderEvent) return; // 🔥 Shape 재사용: 이미 존재하면 재사용, 없으면 생성
|
|
437
432
|
|
|
438
433
|
var shape = layer.findOne('.event-render-shape');
|
|
@@ -621,17 +616,19 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
621
616
|
return null;
|
|
622
617
|
};
|
|
623
618
|
/**
|
|
624
|
-
* Hover 상태 설정 및
|
|
619
|
+
* Hover 상태 설정 및 레이어 렌더링
|
|
625
620
|
*
|
|
626
621
|
* @param data hover된 마커/폴리곤 데이터 또는 null
|
|
627
622
|
*
|
|
628
623
|
* 최적화: RAF 제거하여 즉시 렌더링 (16ms 지연 제거)
|
|
629
|
-
*
|
|
624
|
+
*
|
|
625
|
+
* 🎯 topOnHover 지원:
|
|
626
|
+
* - renderEvent가 있으면: Event Layer에서만 처리 (성능 최적화)
|
|
627
|
+
* - renderEvent가 없고 topOnHover=true면: Base Layer에서 처리
|
|
630
628
|
*/
|
|
631
629
|
|
|
632
630
|
|
|
633
631
|
var setHovered = function (data) {
|
|
634
|
-
if (!onMouseOver && !onMouseOut) return;
|
|
635
632
|
hoveredItemRef.current = data;
|
|
636
633
|
|
|
637
634
|
if (draggingRef.current) {
|
|
@@ -639,10 +636,15 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
639
636
|
} else {
|
|
640
637
|
controller.setMapCursor(data ? 'pointer' : 'grab');
|
|
641
638
|
} // 즉시 렌더링 (RAF 없이)
|
|
642
|
-
// topOnHover는 Event Layer에서만 처리 (Base Layer 재렌더링 제거로 성능 향상)
|
|
643
639
|
|
|
644
640
|
|
|
645
|
-
|
|
641
|
+
if (renderEvent) {
|
|
642
|
+
// renderEvent가 있으면 Event Layer에서만 처리 (성능 최적화)
|
|
643
|
+
doRenderEvent();
|
|
644
|
+
} else if (topOnHover) {
|
|
645
|
+
// renderEvent가 없고 topOnHover가 true면 Base Layer에서 처리
|
|
646
|
+
doRenderBase();
|
|
647
|
+
}
|
|
646
648
|
};
|
|
647
649
|
/**
|
|
648
650
|
* 클릭 처리 (단일/다중 선택)
|
|
@@ -656,8 +658,7 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
656
658
|
|
|
657
659
|
|
|
658
660
|
var handleLocalClick = function (data) {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
+
// 1. 선택 상태 업데이트
|
|
661
662
|
if (enableMultiSelect) {
|
|
662
663
|
// 다중 선택: Set과 Map 동시 업데이트
|
|
663
664
|
var newSelected = new Set(selectedIdsRef.current);
|
|
@@ -709,7 +710,6 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
709
710
|
|
|
710
711
|
if (disableInteractionRef.current) return; // 🚫 상호작용 비활성화 시 즉시 반환
|
|
711
712
|
|
|
712
|
-
if (!onClick) return;
|
|
713
713
|
if (context$1 || !((_a = event === null || event === void 0 ? void 0 : event.param) === null || _a === void 0 ? void 0 : _a.position)) return;
|
|
714
714
|
|
|
715
715
|
try {
|
|
@@ -718,7 +718,10 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
718
718
|
|
|
719
719
|
if (data_1) {
|
|
720
720
|
handleLocalClick(data_1);
|
|
721
|
-
|
|
721
|
+
|
|
722
|
+
if (onClick) {
|
|
723
|
+
onClick(data_1, selectedIdsRef.current);
|
|
724
|
+
}
|
|
722
725
|
}
|
|
723
726
|
} catch (error) {
|
|
724
727
|
console.error('[WoongKonvaMarker] handleClick error:', error);
|
|
@@ -734,7 +737,6 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
734
737
|
|
|
735
738
|
if (disableInteractionRef.current) return; // 🚫 상호작용 비활성화 시 즉시 반환
|
|
736
739
|
|
|
737
|
-
if (!onMouseOver && !onMouseOut) return;
|
|
738
740
|
if (context$1 || !((_a = event === null || event === void 0 ? void 0 : event.param) === null || _a === void 0 ? void 0 : _a.position)) return;
|
|
739
741
|
|
|
740
742
|
try {
|
|
@@ -777,7 +779,6 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
777
779
|
var handleMouseLeave = function () {
|
|
778
780
|
if (disableInteractionRef.current) return; // 🚫 상호작용 비활성화 시 즉시 반환
|
|
779
781
|
|
|
780
|
-
if (!onMouseOver && !onMouseOut) return;
|
|
781
782
|
var prevHovered = hoveredItemRef.current;
|
|
782
783
|
|
|
783
784
|
if (prevHovered) {
|
|
@@ -1062,116 +1063,6 @@ var WoongCanvasLayerComponent = function (props) {
|
|
|
1062
1063
|
}
|
|
1063
1064
|
}), divElement);
|
|
1064
1065
|
};
|
|
1065
|
-
/**
|
|
1066
|
-
* 🚀 WoongCanvasLayer - Konva 기반 초고성능 마커/폴리곤 렌더링 컴포넌트
|
|
1067
|
-
*
|
|
1068
|
-
* ## 📌 주요 특징
|
|
1069
|
-
* - **30,000개 이상의 폴리곤/마커를 60fps로 렌더링**
|
|
1070
|
-
* - **Multi-Layer 아키텍처**: Base/Animation/Event 레이어 분리
|
|
1071
|
-
* - **Spatial Hash Grid**: O(1) 수준의 빠른 Hit Test
|
|
1072
|
-
* - **LRU 캐시**: 좌표 변환 결과 캐싱으로 성능 최적화
|
|
1073
|
-
* - **Viewport Culling**: 화면에 보이는 영역만 렌더링
|
|
1074
|
-
* - **Discriminated Union Props**: 타입 안전한 MARKER/POLYGON 모드
|
|
1075
|
-
*
|
|
1076
|
-
* ## 🎯 사용 방법
|
|
1077
|
-
*
|
|
1078
|
-
* ### 1️⃣ POLYGON 모드 (자동 렌더링)
|
|
1079
|
-
* ```tsx
|
|
1080
|
-
* <WoongCanvasLayer
|
|
1081
|
-
* dataType={CanvasDataType.POLYGON}
|
|
1082
|
-
* data={polygons}
|
|
1083
|
-
* baseFillColor="rgba(255, 100, 100, 0.5)"
|
|
1084
|
-
* baseStrokeColor="rgba(200, 50, 50, 0.8)"
|
|
1085
|
-
* baseLineWidth={2}
|
|
1086
|
-
* selectedFillColor="rgba(255, 193, 7, 0.7)"
|
|
1087
|
-
* selectedStrokeColor="rgba(255, 152, 0, 1)"
|
|
1088
|
-
* selectedLineWidth={4}
|
|
1089
|
-
* hoveredFillColor="rgba(100, 150, 255, 0.8)" // optional
|
|
1090
|
-
* hoveredStrokeColor="rgba(0, 100, 200, 1)" // optional
|
|
1091
|
-
* hoveredLineWidth={3} // optional
|
|
1092
|
-
* enableMultiSelect={true}
|
|
1093
|
-
* onClick={handleClick}
|
|
1094
|
-
* />
|
|
1095
|
-
* ```
|
|
1096
|
-
*
|
|
1097
|
-
* ### 2️⃣ MARKER 모드 (커스텀 렌더링)
|
|
1098
|
-
* ```tsx
|
|
1099
|
-
* <WoongCanvasLayer
|
|
1100
|
-
* dataType={CanvasDataType.MARKER}
|
|
1101
|
-
* data={markers}
|
|
1102
|
-
* renderBase={renderMarkerBase} // required
|
|
1103
|
-
* renderAnimation={renderMarkerAnimation} // optional
|
|
1104
|
-
* renderEvent={renderMarkerEvent} // optional
|
|
1105
|
-
* topOnHover={true}
|
|
1106
|
-
* onClick={handleClick}
|
|
1107
|
-
* />
|
|
1108
|
-
* ```
|
|
1109
|
-
*
|
|
1110
|
-
* ## 📊 데이터 형식
|
|
1111
|
-
* ```typescript
|
|
1112
|
-
* const data: KonvaCanvasData<T>[] = [
|
|
1113
|
-
* {
|
|
1114
|
-
* id: 'unique-id',
|
|
1115
|
-
* position: new Position(lat, lng),
|
|
1116
|
-
* // POLYGON: paths 필수
|
|
1117
|
-
* paths: [[[lat, lng], [lat, lng], ...]],
|
|
1118
|
-
* // MARKER: boxWidth/boxHeight 권장 (Hit Test 정확도)
|
|
1119
|
-
* boxWidth: 60,
|
|
1120
|
-
* boxHeight: 75,
|
|
1121
|
-
* // 커스텀 데이터
|
|
1122
|
-
* ...customData
|
|
1123
|
-
* }
|
|
1124
|
-
* ];
|
|
1125
|
-
* ```
|
|
1126
|
-
*
|
|
1127
|
-
* ## ⚡ 성능 최적화 팁
|
|
1128
|
-
* 1. **동적 boxWidth 계산**: `measureText()`로 실제 너비 계산 후 전달
|
|
1129
|
-
* 2. **enableViewportCulling**: 대량 데이터 시 필수 (기본 true)
|
|
1130
|
-
* 3. **selectedItems 외부 관리**: 상태를 외부에서 관리하여 리렌더링 최소화
|
|
1131
|
-
* 4. **React.memo 최적화**: 컴포넌트가 자동으로 불필요한 리렌더링 방지
|
|
1132
|
-
*
|
|
1133
|
-
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
1134
|
-
*
|
|
1135
|
-
* @example
|
|
1136
|
-
* // 동적 boxWidth 계산 예시
|
|
1137
|
-
* const tempCtx = document.createElement('canvas').getContext('2d');
|
|
1138
|
-
* tempCtx.font = 'bold 15px Arial';
|
|
1139
|
-
* const boxWidth = Math.max(60, tempCtx.measureText(text).width + 20);
|
|
1140
|
-
*
|
|
1141
|
-
* @see {@link https://github.com/your-repo/docs/WoongCanvasLayer.md} 전체 문서
|
|
1142
|
-
*/
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
var WoongCanvasLayer = React__default["default"].memo(WoongCanvasLayerComponent, function (prevProps, nextProps) {
|
|
1146
|
-
// // 1. data 비교
|
|
1147
|
-
// const prevData = prevProps.data;
|
|
1148
|
-
// const nextData = nextProps.data;
|
|
1149
|
-
// // 참조가 같으면 스킵
|
|
1150
|
-
// if (prevData !== nextData) {
|
|
1151
|
-
// // 길이가 다르면 변경됨
|
|
1152
|
-
// if (prevData.length !== nextData.length) return false;
|
|
1153
|
-
// // 각 데이터의 ID 비교
|
|
1154
|
-
// for (let i = 0; i < prevData.length; i++) {
|
|
1155
|
-
// if (prevData[i].id !== nextData[i].id) {
|
|
1156
|
-
// return false; // 변경됨 → 리렌더링
|
|
1157
|
-
// }
|
|
1158
|
-
// }
|
|
1159
|
-
// }
|
|
1160
|
-
// 2. selectedItems 비교 (참조만 비교)
|
|
1161
|
-
if (prevProps.selectedItems !== nextProps.selectedItems) {
|
|
1162
|
-
return false; // 변경됨 → 리렌더링
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
if (prevProps.selectedItem !== nextProps.selectedItem) {
|
|
1166
|
-
return false; // 변경됨 → 리렌더링
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
if (prevProps.disableInteraction !== nextProps.disableInteraction) {
|
|
1170
|
-
return false; // 변경됨 → 리렌더링
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
return true; // 같음 → 리렌더링 스킵
|
|
1174
|
-
});
|
|
1175
1066
|
|
|
1176
1067
|
Object.defineProperty(exports, 'CanvasDataType', {
|
|
1177
1068
|
enumerable: true,
|
|
@@ -34,9 +34,12 @@ export declare const renderPolygonBase: <T = any>(baseFillColor: string, baseStr
|
|
|
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. 마지막 선택된 항목 그리기 (호버되지 않은 경우)
|
|
@@ -20,7 +20,7 @@ var polygon = require('../core/util/polygon.js');
|
|
|
20
20
|
require('../naver/NaverMintMapController.js');
|
|
21
21
|
require('../core/advanced/canvas/CanvasMarkerClaude.js');
|
|
22
22
|
require('../core/advanced/MapLoadingComponents.js');
|
|
23
|
-
require('
|
|
23
|
+
require('konva');
|
|
24
24
|
require('../core/advanced/woongCanvas/shared/types.js');
|
|
25
25
|
require('../core/advanced/woongCanvas/shared/utils.js');
|
|
26
26
|
require('../core/advanced/woongCanvas/shared/context.js');
|
|
@@ -21,7 +21,7 @@ var polygon = require('../core/util/polygon.js');
|
|
|
21
21
|
require('../naver/NaverMintMapController.js');
|
|
22
22
|
require('../core/advanced/canvas/CanvasMarkerClaude.js');
|
|
23
23
|
require('../core/advanced/MapLoadingComponents.js');
|
|
24
|
-
require('
|
|
24
|
+
require('konva');
|
|
25
25
|
require('../core/advanced/woongCanvas/shared/types.js');
|
|
26
26
|
require('../core/advanced/woongCanvas/shared/utils.js');
|
|
27
27
|
require('../core/advanced/woongCanvas/shared/context.js');
|
|
@@ -20,7 +20,7 @@ require('../core/util/geo.js');
|
|
|
20
20
|
var polygon = require('../core/util/polygon.js');
|
|
21
21
|
require('../core/advanced/canvas/CanvasMarkerClaude.js');
|
|
22
22
|
require('../core/advanced/MapLoadingComponents.js');
|
|
23
|
-
require('
|
|
23
|
+
require('konva');
|
|
24
24
|
require('../core/advanced/woongCanvas/shared/types.js');
|
|
25
25
|
require('../core/advanced/woongCanvas/shared/utils.js');
|
|
26
26
|
require('../core/advanced/woongCanvas/shared/context.js');
|