@mint-ui/map 1.2.0-test.10 → 1.2.0-test.12
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/MintMapController.d.ts +1 -0
- package/dist/components/mint-map/core/MintMapCore.js +1 -2
- package/dist/components/mint-map/core/advanced/woongCanvas/WoongCanvasLayer.d.ts +162 -0
- package/dist/components/mint-map/core/advanced/woongCanvas/{WoongKonvaMarker.js → WoongCanvasLayer.js} +136 -82
- package/dist/components/mint-map/core/advanced/woongCanvas/index.d.ts +2 -2
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/renderer.d.ts +59 -0
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/renderer.js +226 -0
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/types.d.ts +95 -1
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.d.ts +17 -0
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.js +42 -0
- package/dist/components/mint-map/core/wrapper/MapMarkerWrapper.js +22 -1
- package/dist/components/mint-map/google/GoogleMintMapController.d.ts +1 -0
- package/dist/components/mint-map/google/GoogleMintMapController.js +6 -1
- package/dist/components/mint-map/kakao/KakaoMintMapController.d.ts +1 -0
- package/dist/components/mint-map/kakao/KakaoMintMapController.js +6 -1
- package/dist/components/mint-map/naver/NaverMintMapController.d.ts +3 -0
- package/dist/components/mint-map/naver/NaverMintMapController.js +39 -4
- package/dist/index.es.js +458 -83
- package/dist/index.js +4 -2
- package/dist/index.umd.js +460 -83
- package/package.json +1 -1
- package/dist/components/mint-map/core/advanced/woongCanvas/ClusterMarker.d.ts +0 -11
- package/dist/components/mint-map/core/advanced/woongCanvas/WoongKonvaMarker.d.ts +0 -54
package/dist/index.es.js
CHANGED
|
@@ -944,6 +944,46 @@ var isPointInMarkerData = function (clickedOffset, markerData, getMarkerOffset)
|
|
|
944
944
|
var y = markerOffset.y - boxHeight - tailHeight;
|
|
945
945
|
return clickedOffset.x >= x && clickedOffset.x <= x + boxWidth && clickedOffset.y >= y && clickedOffset.y <= y + boxHeight;
|
|
946
946
|
};
|
|
947
|
+
var hexToRgba = function (hexColor, alpha) {
|
|
948
|
+
if (alpha === void 0) {
|
|
949
|
+
alpha = 1;
|
|
950
|
+
} // NOTE: 입력된 hexColor에서 "#" 제거
|
|
951
|
+
|
|
952
|
+
|
|
953
|
+
var hex = hexColor.replace('#', ''); // NOTE: 6자리일 경우 알파 값은 사용자가 제공한 alpha 값으로 설정
|
|
954
|
+
|
|
955
|
+
if (hex.length === 6) {
|
|
956
|
+
var r = parseInt(hex.substring(0, 2), 16);
|
|
957
|
+
var g = parseInt(hex.substring(2, 4), 16);
|
|
958
|
+
var b = parseInt(hex.substring(4, 6), 16);
|
|
959
|
+
return "rgba(".concat(r, ", ").concat(g, ", ").concat(b, ", ").concat(alpha, ")");
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
throw new Error('Invalid hex color format');
|
|
963
|
+
};
|
|
964
|
+
var tempCanvas = document.createElement('canvas');
|
|
965
|
+
var tempCtx = tempCanvas.getContext('2d');
|
|
966
|
+
/**
|
|
967
|
+
* 텍스트 박스의 너비를 계산합니다.
|
|
968
|
+
*
|
|
969
|
+
* @param {Object} params - 파라미터 객체
|
|
970
|
+
* @param {string} params.text - 측정할 텍스트
|
|
971
|
+
* @param {string} params.fontConfig - 폰트 설정 (예: 'bold 16px Arial')
|
|
972
|
+
* @param {number} params.padding - 텍스트 박스에 적용할 패딩 값
|
|
973
|
+
* @param {number} params.minWidth - 최소 너비
|
|
974
|
+
* @returns {number} 계산된 텍스트 박스의 너비
|
|
975
|
+
*/
|
|
976
|
+
|
|
977
|
+
var calculateTextBoxWidth = function (_a) {
|
|
978
|
+
var text = _a.text,
|
|
979
|
+
fontConfig = _a.fontConfig,
|
|
980
|
+
padding = _a.padding,
|
|
981
|
+
minWidth = _a.minWidth;
|
|
982
|
+
if (!tempCtx) return 0;
|
|
983
|
+
tempCtx.font = fontConfig;
|
|
984
|
+
var textWidth = tempCtx.measureText(text).width;
|
|
985
|
+
return Math.max(minWidth, textWidth + padding);
|
|
986
|
+
};
|
|
947
987
|
|
|
948
988
|
var KonvaMarkerContext = createContext(null);
|
|
949
989
|
var KonvaMarkerProvider = function (_a) {
|
|
@@ -2754,7 +2794,7 @@ function MapMarkerWrapper(_a) {
|
|
|
2754
2794
|
var onMouseOverHandler = function (e) {
|
|
2755
2795
|
var _a;
|
|
2756
2796
|
|
|
2757
|
-
var marker = markerRef.current;
|
|
2797
|
+
var marker = markerRef.current;
|
|
2758
2798
|
|
|
2759
2799
|
if (marker) {
|
|
2760
2800
|
var mouseOverHandler = (_a = options === null || options === void 0 ? void 0 : options.event) === null || _a === void 0 ? void 0 : _a.get('mouseover');
|
|
@@ -2767,6 +2807,25 @@ function MapMarkerWrapper(_a) {
|
|
|
2767
2807
|
|
|
2768
2808
|
next && topOnHover && controller.markerToTheTop(marker);
|
|
2769
2809
|
}
|
|
2810
|
+
}; // 20251014 | 장한별 | mouseleave 이벤트 추가, 마우스가 마커 위에서 떠날 때 원래 zindex 를 복구하기 위함
|
|
2811
|
+
|
|
2812
|
+
|
|
2813
|
+
var onMouseLeaveHandler = function (e) {
|
|
2814
|
+
var _a;
|
|
2815
|
+
|
|
2816
|
+
var marker = markerRef.current;
|
|
2817
|
+
|
|
2818
|
+
if (marker) {
|
|
2819
|
+
var mouseOutHandler = (_a = options === null || options === void 0 ? void 0 : options.event) === null || _a === void 0 ? void 0 : _a.get('mouseout');
|
|
2820
|
+
var next = true;
|
|
2821
|
+
|
|
2822
|
+
if (mouseOutHandler) {
|
|
2823
|
+
var hasNext = mouseOutHandler(e);
|
|
2824
|
+
hasNext !== undefined && (next = hasNext);
|
|
2825
|
+
}
|
|
2826
|
+
|
|
2827
|
+
next && topOnHover && controller.restoreMarkerZIndex(marker);
|
|
2828
|
+
}
|
|
2770
2829
|
}; //create object
|
|
2771
2830
|
|
|
2772
2831
|
|
|
@@ -2784,10 +2843,12 @@ function MapMarkerWrapper(_a) {
|
|
|
2784
2843
|
}); //드래그 여부 초기화를 먼저 수행하기 위해 capture : true 처리
|
|
2785
2844
|
|
|
2786
2845
|
divElement.addEventListener('mouseover', onMouseOverHandler);
|
|
2846
|
+
divElement.addEventListener('mouseleave', onMouseLeaveHandler);
|
|
2787
2847
|
return function () {
|
|
2788
2848
|
divElement.removeEventListener('click', onClickHandler);
|
|
2789
2849
|
divElement.removeEventListener('mousedown', onMousedownHandler);
|
|
2790
2850
|
divElement.removeEventListener('mouseover', onMouseOverHandler);
|
|
2851
|
+
divElement.removeEventListener('mouseleave', onMouseLeaveHandler);
|
|
2791
2852
|
|
|
2792
2853
|
if (markerRef.current) {
|
|
2793
2854
|
controller.clearDrawable(markerRef.current);
|
|
@@ -5353,45 +5414,249 @@ function LoadingImage(_a) {
|
|
|
5353
5414
|
}))));
|
|
5354
5415
|
}
|
|
5355
5416
|
|
|
5356
|
-
|
|
5357
|
-
|
|
5417
|
+
/**
|
|
5418
|
+
* 폴리곤 렌더링 유틸리티
|
|
5419
|
+
*
|
|
5420
|
+
* 이 파일은 폴리곤 렌더링을 위한 헬퍼 함수와 팩토리 함수를 제공합니다.
|
|
5421
|
+
*/
|
|
5358
5422
|
|
|
5359
5423
|
/**
|
|
5360
|
-
*
|
|
5424
|
+
* 폴리곤 그리기 헬퍼 함수 (도넛 폴리곤 지원)
|
|
5425
|
+
*/
|
|
5426
|
+
var drawPolygon = function (_a) {
|
|
5427
|
+
var ctx = _a.ctx,
|
|
5428
|
+
polygonOffsets = _a.polygonOffsets,
|
|
5429
|
+
isDonutPolygon = _a.isDonutPolygon,
|
|
5430
|
+
fillColor = _a.fillColor,
|
|
5431
|
+
strokeColor = _a.strokeColor,
|
|
5432
|
+
lineWidth = _a.lineWidth;
|
|
5433
|
+
|
|
5434
|
+
for (var _i = 0, polygonOffsets_1 = polygonOffsets; _i < polygonOffsets_1.length; _i++) {
|
|
5435
|
+
var multiPolygon = polygonOffsets_1[_i];
|
|
5436
|
+
|
|
5437
|
+
if (isDonutPolygon) {
|
|
5438
|
+
ctx.beginPath(); // 1. 외부 폴리곤 그리기
|
|
5439
|
+
|
|
5440
|
+
if (multiPolygon[0] && multiPolygon[0].length > 0) {
|
|
5441
|
+
ctx.moveTo(multiPolygon[0][0][0], multiPolygon[0][0][1]);
|
|
5442
|
+
|
|
5443
|
+
for (var i = 1; i < multiPolygon[0].length; i++) {
|
|
5444
|
+
ctx.lineTo(multiPolygon[0][i][0], multiPolygon[0][i][1]);
|
|
5445
|
+
}
|
|
5446
|
+
|
|
5447
|
+
ctx.closePath();
|
|
5448
|
+
} // 2. 내부 폴리곤 (구멍들) 그리기 - 같은 path에 추가
|
|
5449
|
+
|
|
5450
|
+
|
|
5451
|
+
for (var j = 1; j < multiPolygon.length; j++) {
|
|
5452
|
+
var innerPolygon = multiPolygon[j];
|
|
5453
|
+
if (innerPolygon.length === 0) continue;
|
|
5454
|
+
ctx.moveTo(innerPolygon[0][0], innerPolygon[0][1]);
|
|
5455
|
+
|
|
5456
|
+
for (var i = 1; i < innerPolygon.length; i++) {
|
|
5457
|
+
ctx.lineTo(innerPolygon[i][0], innerPolygon[i][1]);
|
|
5458
|
+
}
|
|
5459
|
+
|
|
5460
|
+
ctx.closePath();
|
|
5461
|
+
} // 3. evenodd fill rule로 구멍 뚫기
|
|
5462
|
+
|
|
5463
|
+
|
|
5464
|
+
ctx.fillStyle = fillColor;
|
|
5465
|
+
ctx.fill('evenodd'); // 4. 외곽선 그리기
|
|
5466
|
+
|
|
5467
|
+
ctx.strokeStyle = strokeColor;
|
|
5468
|
+
ctx.lineWidth = lineWidth;
|
|
5469
|
+
ctx.stroke();
|
|
5470
|
+
} else {
|
|
5471
|
+
// 일반 폴리곤
|
|
5472
|
+
for (var _b = 0, multiPolygon_1 = multiPolygon; _b < multiPolygon_1.length; _b++) {
|
|
5473
|
+
var polygonGroup = multiPolygon_1[_b];
|
|
5474
|
+
if (!polygonGroup.length) continue;
|
|
5475
|
+
ctx.beginPath();
|
|
5476
|
+
var firstPoint = polygonGroup[0];
|
|
5477
|
+
ctx.moveTo(firstPoint[0], firstPoint[1]);
|
|
5478
|
+
|
|
5479
|
+
for (var i = 1; i < polygonGroup.length; i++) {
|
|
5480
|
+
var point = polygonGroup[i];
|
|
5481
|
+
ctx.lineTo(point[0], point[1]);
|
|
5482
|
+
}
|
|
5483
|
+
|
|
5484
|
+
ctx.closePath();
|
|
5485
|
+
ctx.fillStyle = fillColor;
|
|
5486
|
+
ctx.strokeStyle = strokeColor;
|
|
5487
|
+
ctx.lineWidth = lineWidth;
|
|
5488
|
+
ctx.fill();
|
|
5489
|
+
ctx.stroke();
|
|
5490
|
+
}
|
|
5491
|
+
}
|
|
5492
|
+
}
|
|
5493
|
+
};
|
|
5494
|
+
/**
|
|
5495
|
+
* 폴리곤 Base 렌더링 함수
|
|
5361
5496
|
*
|
|
5362
|
-
*
|
|
5363
|
-
*
|
|
5364
|
-
*
|
|
5365
|
-
*
|
|
5366
|
-
* - Viewport Culling으로 보이는 영역만 렌더링
|
|
5497
|
+
* @param baseFillColor 기본 폴리곤 채우기 색상
|
|
5498
|
+
* @param baseStrokeColor 기본 폴리곤 테두리 색상
|
|
5499
|
+
* @param baseLineWidth 기본 폴리곤 테두리 두께
|
|
5500
|
+
* @returns Base Layer 렌더링 함수
|
|
5367
5501
|
*
|
|
5368
|
-
* @
|
|
5502
|
+
* @example
|
|
5503
|
+
* const renderBase = renderPolygonBase(
|
|
5504
|
+
* 'rgba(255, 100, 100, 0.5)',
|
|
5505
|
+
* 'rgba(200, 50, 50, 0.8)',
|
|
5506
|
+
* 2
|
|
5507
|
+
* );
|
|
5369
5508
|
*/
|
|
5370
5509
|
|
|
5371
|
-
var
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5510
|
+
var renderPolygonBase = function (baseFillColor, baseStrokeColor, baseLineWidth) {
|
|
5511
|
+
return function (_a) {
|
|
5512
|
+
var ctx = _a.ctx,
|
|
5513
|
+
items = _a.items,
|
|
5514
|
+
selectedIds = _a.selectedIds,
|
|
5515
|
+
utils = _a.utils;
|
|
5516
|
+
|
|
5517
|
+
for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
|
|
5518
|
+
var item = items_1[_i]; // 선택된 항목은 Event Layer에서 그림
|
|
5519
|
+
|
|
5520
|
+
if (selectedIds.has(item.id)) continue;
|
|
5521
|
+
if (!item.paths) continue;
|
|
5522
|
+
var polygonOffsets = utils.getOrComputePolygonOffsets(item);
|
|
5523
|
+
if (!polygonOffsets) continue;
|
|
5524
|
+
drawPolygon({
|
|
5525
|
+
ctx: ctx,
|
|
5526
|
+
polygonOffsets: polygonOffsets,
|
|
5527
|
+
isDonutPolygon: item.isDonutPolygon || false,
|
|
5528
|
+
fillColor: baseFillColor,
|
|
5529
|
+
strokeColor: baseStrokeColor,
|
|
5530
|
+
lineWidth: baseLineWidth
|
|
5531
|
+
});
|
|
5532
|
+
}
|
|
5533
|
+
};
|
|
5534
|
+
};
|
|
5535
|
+
/**
|
|
5536
|
+
* 폴리곤 Event 렌더링 함수
|
|
5537
|
+
*
|
|
5538
|
+
* @param selectedFillColor 선택된 폴리곤 채우기 색상
|
|
5539
|
+
* @param selectedStrokeColor 선택된 폴리곤 테두리 색상
|
|
5540
|
+
* @param selectedLineWidth 선택된 폴리곤 테두리 두께
|
|
5541
|
+
* @param activeFillColor 마지막 선택된 폴리곤 채우기 색상 (선택, 기본값: selectedFillColor)
|
|
5542
|
+
* @param activeStrokeColor 마지막 선택된 폴리곤 테두리 색상 (선택, 기본값: selectedStrokeColor)
|
|
5543
|
+
* @param activeLineWidth 마지막 선택된 폴리곤 테두리 두께 (선택, 기본값: selectedLineWidth)
|
|
5544
|
+
* @param hoveredFillColor Hover 시 폴리곤 채우기 색상 (선택, 기본값: selectedFillColor)
|
|
5545
|
+
* @param hoveredStrokeColor Hover 시 폴리곤 테두리 색상 (선택, 기본값: selectedStrokeColor)
|
|
5546
|
+
* @param hoveredLineWidth Hover 시 폴리곤 테두리 두께 (선택, 기본값: selectedLineWidth)
|
|
5547
|
+
* @returns Event Layer 렌더링 함수
|
|
5548
|
+
*
|
|
5549
|
+
* @example
|
|
5550
|
+
* const renderEvent = renderPolygonEvent(
|
|
5551
|
+
* 'rgba(255, 193, 7, 0.7)',
|
|
5552
|
+
* 'rgba(255, 152, 0, 1)',
|
|
5553
|
+
* 4,
|
|
5554
|
+
* 'rgba(255, 0, 0, 0.8)',
|
|
5555
|
+
* undefined,
|
|
5556
|
+
* undefined,
|
|
5557
|
+
* 'rgba(100, 150, 255, 0.8)'
|
|
5558
|
+
* );
|
|
5559
|
+
*/
|
|
5560
|
+
|
|
5561
|
+
var renderPolygonEvent = function (selectedFillColor, selectedStrokeColor, selectedLineWidth, activeFillColor, activeStrokeColor, activeLineWidth, hoveredFillColor, hoveredStrokeColor, hoveredLineWidth) {
|
|
5562
|
+
// 기본값 설정 (selected 기준)
|
|
5563
|
+
var _activeFillColor = activeFillColor || selectedFillColor;
|
|
5564
|
+
|
|
5565
|
+
var _activeStrokeColor = activeStrokeColor || selectedStrokeColor;
|
|
5566
|
+
|
|
5567
|
+
var _activeLineWidth = activeLineWidth || selectedLineWidth;
|
|
5568
|
+
|
|
5569
|
+
var _hoveredFillColor = hoveredFillColor || selectedFillColor;
|
|
5570
|
+
|
|
5571
|
+
var _hoveredStrokeColor = hoveredStrokeColor || selectedStrokeColor;
|
|
5572
|
+
|
|
5573
|
+
var _hoveredLineWidth = hoveredLineWidth || selectedLineWidth;
|
|
5574
|
+
|
|
5575
|
+
return function (_a) {
|
|
5576
|
+
var ctx = _a.ctx,
|
|
5577
|
+
hoveredItem = _a.hoveredItem,
|
|
5578
|
+
utils = _a.utils,
|
|
5579
|
+
selectedItems = _a.selectedItems,
|
|
5580
|
+
selectedItem = _a.selectedItem; // 1. 선택된 항목들 그리기 (마지막 선택 항목과 호버된 항목 제외)
|
|
5581
|
+
|
|
5582
|
+
if (selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.length) {
|
|
5583
|
+
for (var _i = 0, selectedItems_1 = selectedItems; _i < selectedItems_1.length; _i++) {
|
|
5584
|
+
var item = selectedItems_1[_i]; // 마지막 선택 항목과 호버된 항목은 나중에 따로 그림
|
|
5585
|
+
|
|
5586
|
+
if (item.id === (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.id) || (hoveredItem === null || hoveredItem === void 0 ? void 0 : hoveredItem.id) === item.id) continue;
|
|
5587
|
+
if (!item.paths) continue;
|
|
5588
|
+
var polygonOffsets = utils.getOrComputePolygonOffsets(item);
|
|
5589
|
+
if (!polygonOffsets) continue;
|
|
5590
|
+
drawPolygon({
|
|
5591
|
+
ctx: ctx,
|
|
5592
|
+
polygonOffsets: polygonOffsets,
|
|
5593
|
+
isDonutPolygon: item.isDonutPolygon || false,
|
|
5594
|
+
fillColor: selectedFillColor,
|
|
5595
|
+
strokeColor: selectedStrokeColor,
|
|
5596
|
+
lineWidth: selectedLineWidth
|
|
5597
|
+
});
|
|
5598
|
+
}
|
|
5599
|
+
} // 2. 마지막 선택된 항목 그리기 (호버되지 않은 경우)
|
|
5600
|
+
|
|
5601
|
+
|
|
5602
|
+
if ((selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.paths) && (hoveredItem === null || hoveredItem === void 0 ? void 0 : hoveredItem.id) !== selectedItem.id) {
|
|
5603
|
+
var polygonOffsets = utils.getOrComputePolygonOffsets(selectedItem);
|
|
5604
|
+
|
|
5605
|
+
if (polygonOffsets) {
|
|
5606
|
+
drawPolygon({
|
|
5607
|
+
ctx: ctx,
|
|
5608
|
+
polygonOffsets: polygonOffsets,
|
|
5609
|
+
isDonutPolygon: selectedItem.isDonutPolygon || false,
|
|
5610
|
+
fillColor: _activeFillColor,
|
|
5611
|
+
strokeColor: _activeStrokeColor,
|
|
5612
|
+
lineWidth: _activeLineWidth
|
|
5613
|
+
});
|
|
5614
|
+
}
|
|
5615
|
+
} // 3. 호버된 항목 그리기 (가장 위에 표시)
|
|
5616
|
+
|
|
5617
|
+
|
|
5618
|
+
if (hoveredItem === null || hoveredItem === void 0 ? void 0 : hoveredItem.paths) {
|
|
5619
|
+
var polygonOffsets = utils.getOrComputePolygonOffsets(hoveredItem);
|
|
5620
|
+
if (!polygonOffsets) return;
|
|
5621
|
+
var isSelected = selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.some(function (item) {
|
|
5622
|
+
return item.id === hoveredItem.id;
|
|
5623
|
+
});
|
|
5624
|
+
drawPolygon({
|
|
5625
|
+
ctx: ctx,
|
|
5626
|
+
polygonOffsets: polygonOffsets,
|
|
5627
|
+
isDonutPolygon: hoveredItem.isDonutPolygon || false,
|
|
5628
|
+
fillColor: isSelected ? _activeFillColor : _hoveredFillColor,
|
|
5629
|
+
strokeColor: isSelected ? _activeStrokeColor : _hoveredStrokeColor,
|
|
5630
|
+
lineWidth: isSelected ? _activeLineWidth : _hoveredLineWidth
|
|
5631
|
+
});
|
|
5632
|
+
}
|
|
5633
|
+
};
|
|
5634
|
+
};
|
|
5635
|
+
|
|
5636
|
+
// 메인 컴포넌트
|
|
5637
|
+
// ============================================================================
|
|
5638
|
+
|
|
5639
|
+
var WoongCanvasLayerComponent = function (props) {
|
|
5640
|
+
var data = props.data,
|
|
5641
|
+
dataType = props.dataType,
|
|
5642
|
+
onClick = props.onClick,
|
|
5643
|
+
onMouseOver = props.onMouseOver,
|
|
5644
|
+
onMouseOut = props.onMouseOut,
|
|
5645
|
+
_a = props.enableMultiSelect,
|
|
5646
|
+
enableMultiSelect = _a === void 0 ? false : _a,
|
|
5647
|
+
_b = props.topOnHover,
|
|
5648
|
+
topOnHover = _b === void 0 ? false : _b,
|
|
5649
|
+
_c = props.enableViewportCulling,
|
|
5650
|
+
enableViewportCulling = _c === void 0 ? true : _c,
|
|
5651
|
+
_d = props.cullingMargin,
|
|
5652
|
+
cullingMargin = _d === void 0 ? DEFAULT_CULLING_MARGIN : _d,
|
|
5653
|
+
_e = props.maxCacheSize,
|
|
5654
|
+
maxCacheSize = _e === void 0 ? DEFAULT_MAX_CACHE_SIZE : _e,
|
|
5655
|
+
externalSelectedItems = props.selectedItems,
|
|
5656
|
+
externalSelectedItem = props.selectedItem,
|
|
5657
|
+
_f = props.disableInteraction,
|
|
5658
|
+
disableInteraction = _f === void 0 ? false : _f,
|
|
5659
|
+
options = __rest(props, ["data", "dataType", "onClick", "onMouseOver", "onMouseOut", "enableMultiSelect", "topOnHover", "enableViewportCulling", "cullingMargin", "maxCacheSize", "selectedItems", "selectedItem", "disableInteraction"]); // --------------------------------------------------------------------------
|
|
5395
5660
|
// Hooks & Context
|
|
5396
5661
|
// --------------------------------------------------------------------------
|
|
5397
5662
|
|
|
@@ -5416,9 +5681,9 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
5416
5681
|
// Data Refs - 선택 및 Hover 상태 관리
|
|
5417
5682
|
// --------------------------------------------------------------------------
|
|
5418
5683
|
|
|
5419
|
-
/**
|
|
5684
|
+
/** data prop을 ref로 추적 (stale closure 방지, useEffect에서 동기화) */
|
|
5420
5685
|
|
|
5421
|
-
var markersRef = useRef(
|
|
5686
|
+
var markersRef = useRef(data); // --------------------------------------------------------------------------
|
|
5422
5687
|
// State Refs - 선택 및 Hover 상태 관리
|
|
5423
5688
|
// --------------------------------------------------------------------------
|
|
5424
5689
|
|
|
@@ -5590,6 +5855,7 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
5590
5855
|
};
|
|
5591
5856
|
/**
|
|
5592
5857
|
* 마커 좌표 변환 결과를 캐시하고 반환
|
|
5858
|
+
*
|
|
5593
5859
|
* @param markerData 마커 데이터
|
|
5594
5860
|
* @returns 변환된 좌표 또는 null
|
|
5595
5861
|
*/
|
|
@@ -5669,7 +5935,7 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
5669
5935
|
}
|
|
5670
5936
|
}
|
|
5671
5937
|
}; // --------------------------------------------------------------------------
|
|
5672
|
-
// 렌더링 함수
|
|
5938
|
+
// 렌더링 함수 결정 (dataType에 따라)
|
|
5673
5939
|
// --------------------------------------------------------------------------
|
|
5674
5940
|
|
|
5675
5941
|
/**
|
|
@@ -5684,6 +5950,18 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
5684
5950
|
/** Base Layer에서 사용할 빈 Set (재사용) */
|
|
5685
5951
|
|
|
5686
5952
|
useRef(new Set());
|
|
5953
|
+
/**
|
|
5954
|
+
* 실제 사용할 렌더링 함수 결정
|
|
5955
|
+
* - MARKER: 외부에서 전달받은 renderBase 사용 (필수)
|
|
5956
|
+
* - POLYGON: renderer.ts의 팩토리 함수로 생성 (props 기반)
|
|
5957
|
+
*/
|
|
5958
|
+
|
|
5959
|
+
var renderBase = dataType === CanvasDataType.MARKER ? props.renderBase : renderPolygonBase(props.baseFillColor, props.baseStrokeColor, props.baseLineWidth);
|
|
5960
|
+
var renderAnimation = dataType === CanvasDataType.MARKER ? props.renderAnimation : undefined;
|
|
5961
|
+
var renderEvent = dataType === CanvasDataType.MARKER ? props.renderEvent : function () {
|
|
5962
|
+
var polygonProps = props;
|
|
5963
|
+
return renderPolygonEvent(polygonProps.selectedFillColor, polygonProps.selectedStrokeColor, polygonProps.selectedLineWidth, polygonProps.activeFillColor, polygonProps.activeStrokeColor, polygonProps.activeLineWidth, polygonProps.hoveredFillColor, polygonProps.hoveredStrokeColor, polygonProps.hoveredLineWidth);
|
|
5964
|
+
}();
|
|
5687
5965
|
/**
|
|
5688
5966
|
* Base 레이어 렌더링 (뷰포트 컬링 적용, 선택된 마커 제외)
|
|
5689
5967
|
*
|
|
@@ -6048,11 +6326,11 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
6048
6326
|
|
|
6049
6327
|
try {
|
|
6050
6328
|
var clickedOffset = controller.positionToOffset(event.param.position);
|
|
6051
|
-
var
|
|
6329
|
+
var data_1 = findData(clickedOffset);
|
|
6052
6330
|
|
|
6053
|
-
if (
|
|
6054
|
-
handleLocalClick(
|
|
6055
|
-
onClick(
|
|
6331
|
+
if (data_1) {
|
|
6332
|
+
handleLocalClick(data_1);
|
|
6333
|
+
onClick(data_1, selectedIdsRef.current);
|
|
6056
6334
|
}
|
|
6057
6335
|
} catch (error) {
|
|
6058
6336
|
console.error('[WoongKonvaMarker] handleClick error:', error);
|
|
@@ -6329,13 +6607,13 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
6329
6607
|
|
|
6330
6608
|
doRenderEvent();
|
|
6331
6609
|
}, [externalSelectedItem]); // --------------------------------------------------------------------------
|
|
6332
|
-
// Lifecycle:
|
|
6610
|
+
// Lifecycle: 데이터 변경 시 렌더링
|
|
6333
6611
|
// --------------------------------------------------------------------------
|
|
6334
6612
|
|
|
6335
6613
|
useEffect(function () {
|
|
6336
6614
|
if (!stageRef.current) return; // markersRef 동기화
|
|
6337
6615
|
|
|
6338
|
-
markersRef.current =
|
|
6616
|
+
markersRef.current = data; // 데이터 변경 시 즉시 transform 제거 및 캐시 정리 (겹침 방지)
|
|
6339
6617
|
|
|
6340
6618
|
if (containerRef.current) {
|
|
6341
6619
|
containerRef.current.style.transform = '';
|
|
@@ -6352,18 +6630,18 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
6352
6630
|
/**
|
|
6353
6631
|
* 선택 상태 동기화 (최적화 버전)
|
|
6354
6632
|
*
|
|
6355
|
-
*
|
|
6633
|
+
* data가 변경되면 selectedItemsMapRef도 업데이트 필요
|
|
6356
6634
|
* (참조가 바뀌므로 기존 Map의 데이터는 stale 상태)
|
|
6357
6635
|
*
|
|
6358
|
-
* 🔥 중요: 화면 밖
|
|
6359
|
-
* - 현재
|
|
6636
|
+
* 🔥 중요: 화면 밖 데이터도 선택 상태 유지!
|
|
6637
|
+
* - 현재 data에 있으면 최신 데이터로 업데이트
|
|
6360
6638
|
* - 없으면 기존 selectedItemsMapRef의 데이터 유지
|
|
6361
6639
|
*
|
|
6362
|
-
* 최적화:
|
|
6363
|
-
* - O(전체
|
|
6640
|
+
* 최적화: data를 Map으로 먼저 변환하여 find() 순회 제거
|
|
6641
|
+
* - O(전체 데이터 수 + 선택된 개수) - 매우 효율적
|
|
6364
6642
|
*/
|
|
6365
6643
|
|
|
6366
|
-
var markersMap = new Map(
|
|
6644
|
+
var markersMap = new Map(data.map(function (m) {
|
|
6367
6645
|
return [m.id, m];
|
|
6368
6646
|
}));
|
|
6369
6647
|
var newSelectedItemsMap = new Map();
|
|
@@ -6386,40 +6664,107 @@ var WoongKonvaMarkerComponent = function (_a) {
|
|
|
6386
6664
|
selectedItemsMapRef.current = newSelectedItemsMap; // 즉시 렌더링
|
|
6387
6665
|
|
|
6388
6666
|
renderAllImmediate();
|
|
6389
|
-
}, [
|
|
6667
|
+
}, [data]);
|
|
6390
6668
|
return createPortal(React.createElement("div", {
|
|
6391
6669
|
ref: containerRef,
|
|
6392
|
-
style:
|
|
6670
|
+
style: {
|
|
6393
6671
|
position: 'absolute',
|
|
6394
6672
|
width: '100%',
|
|
6395
6673
|
height: '100%'
|
|
6396
|
-
}
|
|
6397
|
-
pointerEvents: 'none'
|
|
6398
|
-
})
|
|
6674
|
+
}
|
|
6399
6675
|
}), divElement);
|
|
6400
6676
|
};
|
|
6401
6677
|
/**
|
|
6402
|
-
*
|
|
6678
|
+
* 🚀 WoongCanvasLayer - Konva 기반 초고성능 마커/폴리곤 렌더링 컴포넌트
|
|
6679
|
+
*
|
|
6680
|
+
* ## 📌 주요 특징
|
|
6681
|
+
* - **30,000개 이상의 폴리곤/마커를 60fps로 렌더링**
|
|
6682
|
+
* - **Multi-Layer 아키텍처**: Base/Animation/Event 레이어 분리
|
|
6683
|
+
* - **Spatial Hash Grid**: O(1) 수준의 빠른 Hit Test
|
|
6684
|
+
* - **LRU 캐시**: 좌표 변환 결과 캐싱으로 성능 최적화
|
|
6685
|
+
* - **Viewport Culling**: 화면에 보이는 영역만 렌더링
|
|
6686
|
+
* - **Discriminated Union Props**: 타입 안전한 MARKER/POLYGON 모드
|
|
6687
|
+
*
|
|
6688
|
+
* ## 🎯 사용 방법
|
|
6689
|
+
*
|
|
6690
|
+
* ### 1️⃣ POLYGON 모드 (자동 렌더링)
|
|
6691
|
+
* ```tsx
|
|
6692
|
+
* <WoongCanvasLayer
|
|
6693
|
+
* dataType={CanvasDataType.POLYGON}
|
|
6694
|
+
* data={polygons}
|
|
6695
|
+
* baseFillColor="rgba(255, 100, 100, 0.5)"
|
|
6696
|
+
* baseStrokeColor="rgba(200, 50, 50, 0.8)"
|
|
6697
|
+
* baseLineWidth={2}
|
|
6698
|
+
* selectedFillColor="rgba(255, 193, 7, 0.7)"
|
|
6699
|
+
* selectedStrokeColor="rgba(255, 152, 0, 1)"
|
|
6700
|
+
* selectedLineWidth={4}
|
|
6701
|
+
* hoveredFillColor="rgba(100, 150, 255, 0.8)" // optional
|
|
6702
|
+
* hoveredStrokeColor="rgba(0, 100, 200, 1)" // optional
|
|
6703
|
+
* hoveredLineWidth={3} // optional
|
|
6704
|
+
* enableMultiSelect={true}
|
|
6705
|
+
* onClick={handleClick}
|
|
6706
|
+
* />
|
|
6707
|
+
* ```
|
|
6708
|
+
*
|
|
6709
|
+
* ### 2️⃣ MARKER 모드 (커스텀 렌더링)
|
|
6710
|
+
* ```tsx
|
|
6711
|
+
* <WoongCanvasLayer
|
|
6712
|
+
* dataType={CanvasDataType.MARKER}
|
|
6713
|
+
* data={markers}
|
|
6714
|
+
* renderBase={renderMarkerBase} // required
|
|
6715
|
+
* renderAnimation={renderMarkerAnimation} // optional
|
|
6716
|
+
* renderEvent={renderMarkerEvent} // optional
|
|
6717
|
+
* topOnHover={true}
|
|
6718
|
+
* onClick={handleClick}
|
|
6719
|
+
* />
|
|
6720
|
+
* ```
|
|
6403
6721
|
*
|
|
6404
|
-
*
|
|
6405
|
-
*
|
|
6406
|
-
*
|
|
6722
|
+
* ## 📊 데이터 형식
|
|
6723
|
+
* ```typescript
|
|
6724
|
+
* const data: KonvaCanvasMarkerData<T>[] = [
|
|
6725
|
+
* {
|
|
6726
|
+
* id: 'unique-id',
|
|
6727
|
+
* position: new Position(lat, lng),
|
|
6728
|
+
* // POLYGON: paths 필수
|
|
6729
|
+
* paths: [[[lat, lng], [lat, lng], ...]],
|
|
6730
|
+
* // MARKER: boxWidth/boxHeight 권장 (Hit Test 정확도)
|
|
6731
|
+
* boxWidth: 60,
|
|
6732
|
+
* boxHeight: 75,
|
|
6733
|
+
* // 커스텀 데이터
|
|
6734
|
+
* ...customData
|
|
6735
|
+
* }
|
|
6736
|
+
* ];
|
|
6737
|
+
* ```
|
|
6407
6738
|
*
|
|
6408
|
-
*
|
|
6739
|
+
* ## ⚡ 성능 최적화 팁
|
|
6740
|
+
* 1. **동적 boxWidth 계산**: `measureText()`로 실제 너비 계산 후 전달
|
|
6741
|
+
* 2. **enableViewportCulling**: 대량 데이터 시 필수 (기본 true)
|
|
6742
|
+
* 3. **selectedItems 외부 관리**: 상태를 외부에서 관리하여 리렌더링 최소화
|
|
6743
|
+
* 4. **React.memo 최적화**: 컴포넌트가 자동으로 불필요한 리렌더링 방지
|
|
6744
|
+
*
|
|
6745
|
+
* @template T 마커/폴리곤 데이터의 추가 속성 타입
|
|
6746
|
+
*
|
|
6747
|
+
* @example
|
|
6748
|
+
* // 동적 boxWidth 계산 예시
|
|
6749
|
+
* const tempCtx = document.createElement('canvas').getContext('2d');
|
|
6750
|
+
* tempCtx.font = 'bold 15px Arial';
|
|
6751
|
+
* const boxWidth = Math.max(60, tempCtx.measureText(text).width + 20);
|
|
6752
|
+
*
|
|
6753
|
+
* @see {@link https://github.com/your-repo/docs/WoongCanvasLayer.md} 전체 문서
|
|
6409
6754
|
*/
|
|
6410
6755
|
|
|
6411
6756
|
|
|
6412
|
-
var
|
|
6413
|
-
// 1.
|
|
6414
|
-
var
|
|
6415
|
-
var
|
|
6757
|
+
var WoongCanvasLayer = React.memo(WoongCanvasLayerComponent, function (prevProps, nextProps) {
|
|
6758
|
+
// 1. data 비교
|
|
6759
|
+
var prevData = prevProps.data;
|
|
6760
|
+
var nextData = nextProps.data; // 참조가 같으면 스킵
|
|
6416
6761
|
|
|
6417
|
-
if (
|
|
6762
|
+
if (prevData !== nextData) {
|
|
6418
6763
|
// 길이가 다르면 변경됨
|
|
6419
|
-
if (
|
|
6764
|
+
if (prevData.length !== nextData.length) return false; // 각 데이터의 ID 비교
|
|
6420
6765
|
|
|
6421
|
-
for (var i = 0; i <
|
|
6422
|
-
if (
|
|
6766
|
+
for (var i = 0; i < prevData.length; i++) {
|
|
6767
|
+
if (prevData[i].id !== nextData[i].id) {
|
|
6423
6768
|
return false; // 변경됨 → 리렌더링
|
|
6424
6769
|
}
|
|
6425
6770
|
}
|
|
@@ -6434,18 +6779,6 @@ var WoongKonvaMarker = React.memo(WoongKonvaMarkerComponent, function (prevProps
|
|
|
6434
6779
|
return false; // 변경됨 → 리렌더링
|
|
6435
6780
|
}
|
|
6436
6781
|
|
|
6437
|
-
if (prevProps.onClick !== nextProps.onClick) {
|
|
6438
|
-
return false; // 변경됨 → 리렌더링
|
|
6439
|
-
}
|
|
6440
|
-
|
|
6441
|
-
if (prevProps.onMouseOver !== nextProps.onMouseOver) {
|
|
6442
|
-
return false; // 변경됨 → 리렌더링
|
|
6443
|
-
}
|
|
6444
|
-
|
|
6445
|
-
if (prevProps.onMouseOut !== nextProps.onMouseOut) {
|
|
6446
|
-
return false; // 변경됨 → 리렌더링
|
|
6447
|
-
}
|
|
6448
|
-
|
|
6449
6782
|
if (prevProps.disableInteraction !== nextProps.disableInteraction) {
|
|
6450
6783
|
return false; // 변경됨 → 리렌더링
|
|
6451
6784
|
}
|
|
@@ -7193,20 +7526,54 @@ function (_super) {
|
|
|
7193
7526
|
}
|
|
7194
7527
|
};
|
|
7195
7528
|
|
|
7196
|
-
NaverMintMapController.prototype.
|
|
7529
|
+
NaverMintMapController.prototype.getCurrentZIndex = function (marker) {
|
|
7197
7530
|
if (this.map && marker.element && marker.element instanceof HTMLElement) {
|
|
7198
7531
|
var parent_1 = marker.element.parentElement;
|
|
7199
7532
|
|
|
7200
|
-
if (parent_1) {
|
|
7201
|
-
|
|
7533
|
+
if (parent_1 && parent_1.style.zIndex) {
|
|
7534
|
+
var zIndex = Number(parent_1.style.zIndex);
|
|
7535
|
+
return isNaN(zIndex) ? undefined : zIndex;
|
|
7536
|
+
}
|
|
7537
|
+
}
|
|
7538
|
+
|
|
7539
|
+
return undefined;
|
|
7540
|
+
};
|
|
7541
|
+
|
|
7542
|
+
NaverMintMapController.prototype.setMarkerZIndex = function (marker, zIndex) {
|
|
7543
|
+
if (this.map && marker.element && marker.element instanceof HTMLElement) {
|
|
7544
|
+
var parent_2 = marker.element.parentElement;
|
|
7545
|
+
|
|
7546
|
+
if (parent_2) {
|
|
7547
|
+
parent_2.style.zIndex = String(zIndex);
|
|
7202
7548
|
}
|
|
7203
7549
|
}
|
|
7204
7550
|
};
|
|
7205
7551
|
|
|
7206
7552
|
NaverMintMapController.prototype.markerToTheTop = function (marker) {
|
|
7553
|
+
// 이미 최상위로 올라간 상태면 (원래 zIndex가 이미 저장됨) 중복 실행 방지
|
|
7554
|
+
if (this.markerOriginalZIndex !== undefined) {
|
|
7555
|
+
return;
|
|
7556
|
+
}
|
|
7557
|
+
|
|
7558
|
+
var currentZIndex = this.getCurrentZIndex(marker); // undefined면 null로 저장 (원래 zIndex가 없었음을 표시)
|
|
7559
|
+
|
|
7560
|
+
this.markerOriginalZIndex = currentZIndex !== undefined ? currentZIndex : null;
|
|
7207
7561
|
this.setMarkerZIndex(marker, this.getMaxZIndex(1));
|
|
7208
7562
|
};
|
|
7209
7563
|
|
|
7564
|
+
NaverMintMapController.prototype.restoreMarkerZIndex = function (marker) {
|
|
7565
|
+
if (this.markerOriginalZIndex !== undefined) {
|
|
7566
|
+
if (this.markerOriginalZIndex === null) {
|
|
7567
|
+
// 원래 zIndex가 없었으면 제거 (또는 초기값 0으로)
|
|
7568
|
+
this.setMarkerZIndex(marker, 0);
|
|
7569
|
+
} else {
|
|
7570
|
+
this.setMarkerZIndex(marker, this.markerOriginalZIndex);
|
|
7571
|
+
}
|
|
7572
|
+
|
|
7573
|
+
this.markerOriginalZIndex = undefined;
|
|
7574
|
+
}
|
|
7575
|
+
};
|
|
7576
|
+
|
|
7210
7577
|
NaverMintMapController.prototype.clearDrawable = function (drawable) {
|
|
7211
7578
|
var _a;
|
|
7212
7579
|
|
|
@@ -7961,6 +8328,10 @@ function (_super) {
|
|
|
7961
8328
|
}
|
|
7962
8329
|
};
|
|
7963
8330
|
|
|
8331
|
+
GoogleMintMapController.prototype.restoreMarkerZIndex = function (marker) {// Google Maps에서는 restoreMarkerZIndex 기능을 지원하지 않습니다.
|
|
8332
|
+
// 이 기능은 Naver Maps에서만 사용 가능합니다.
|
|
8333
|
+
};
|
|
8334
|
+
|
|
7964
8335
|
GoogleMintMapController.prototype.clearDrawable = function (drawable) {
|
|
7965
8336
|
if (drawable && drawable.native) {
|
|
7966
8337
|
if (drawable.native instanceof google.maps.Marker || drawable.native instanceof google.maps.Polygon || drawable.native instanceof google.maps.Polyline) {
|
|
@@ -8683,6 +9054,10 @@ function (_super) {
|
|
|
8683
9054
|
}
|
|
8684
9055
|
};
|
|
8685
9056
|
|
|
9057
|
+
KakaoMintMapController.prototype.restoreMarkerZIndex = function (marker) {// Kakao Maps에서는 restoreMarkerZIndex 기능을 지원하지 않습니다.
|
|
9058
|
+
// 이 기능은 Naver Maps에서만 사용 가능합니다.
|
|
9059
|
+
};
|
|
9060
|
+
|
|
8686
9061
|
KakaoMintMapController.prototype.clearDrawable = function (drawable) {
|
|
8687
9062
|
var _this = this;
|
|
8688
9063
|
|
|
@@ -9242,4 +9617,4 @@ function MintMap(_a) {
|
|
|
9242
9617
|
}), loading));
|
|
9243
9618
|
}
|
|
9244
9619
|
|
|
9245
|
-
export { AnimationPlayer, Bounds, CanvasDataType, CanvasMarker, CanvasMarkerClaude, CanvasMarkerHanquf, CircleMarker, DEFAULT_CULLING_MARGIN, DEFAULT_MAX_CACHE_SIZE, Drawable, GeoCalulator, GoogleMintMapController, KonvaMarkerProvider, LRUCache, MapBuildingProjection, MapCanvasMarkerWrapper, MapCanvasWrapper, MapControlWrapper, MapEvent, MapLoadingWithImage, MapMarkerWrapper, MapPolygonWrapper, MapPolylineWrapper, MapUIEvent, Marker, MintMap, MintMapCanvasRenderer, MintMapController, MintMapCore, MintMapProvider, NaverMintMapController, Offset, PointLoading, Polygon, PolygonCalculator, PolygonMarker, Polyline, Position, SPATIAL_GRID_CELL_SIZE, SVGCircle, SVGPolygon, SVGRect, Spacing, SpatialHashGrid, Status,
|
|
9620
|
+
export { AnimationPlayer, Bounds, CanvasDataType, CanvasMarker, CanvasMarkerClaude, CanvasMarkerHanquf, CircleMarker, DEFAULT_CULLING_MARGIN, DEFAULT_MAX_CACHE_SIZE, Drawable, GeoCalulator, GoogleMintMapController, KonvaMarkerProvider, LRUCache, MapBuildingProjection, MapCanvasMarkerWrapper, MapCanvasWrapper, MapControlWrapper, MapEvent, MapLoadingWithImage, MapMarkerWrapper, MapPolygonWrapper, MapPolylineWrapper, MapUIEvent, Marker, MintMap, MintMapCanvasRenderer, MintMapController, MintMapCore, MintMapProvider, NaverMintMapController, Offset, PointLoading, Polygon, PolygonCalculator, PolygonMarker, Polyline, Position, SPATIAL_GRID_CELL_SIZE, SVGCircle, SVGPolygon, SVGRect, Spacing, SpatialHashGrid, Status, WoongCanvasLayer, calculateTextBoxWidth, computeMarkerOffset, computePolygonOffsets, getClusterInfo, getMapOfType, hexToRgba, isPointInMarkerData, isPointInPolygon, isPointInPolygonData, log, useKonvaMarkerContext, useMarkerMoving, useMintMapController, waiting };
|