@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.
Files changed (23) hide show
  1. package/dist/components/mint-map/core/MintMapController.d.ts +1 -0
  2. package/dist/components/mint-map/core/MintMapCore.js +1 -2
  3. package/dist/components/mint-map/core/advanced/woongCanvas/WoongCanvasLayer.d.ts +162 -0
  4. package/dist/components/mint-map/core/advanced/woongCanvas/{WoongKonvaMarker.js → WoongCanvasLayer.js} +136 -82
  5. package/dist/components/mint-map/core/advanced/woongCanvas/index.d.ts +2 -2
  6. package/dist/components/mint-map/core/advanced/woongCanvas/shared/renderer.d.ts +59 -0
  7. package/dist/components/mint-map/core/advanced/woongCanvas/shared/renderer.js +226 -0
  8. package/dist/components/mint-map/core/advanced/woongCanvas/shared/types.d.ts +95 -1
  9. package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.d.ts +17 -0
  10. package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.js +42 -0
  11. package/dist/components/mint-map/core/wrapper/MapMarkerWrapper.js +22 -1
  12. package/dist/components/mint-map/google/GoogleMintMapController.d.ts +1 -0
  13. package/dist/components/mint-map/google/GoogleMintMapController.js +6 -1
  14. package/dist/components/mint-map/kakao/KakaoMintMapController.d.ts +1 -0
  15. package/dist/components/mint-map/kakao/KakaoMintMapController.js +6 -1
  16. package/dist/components/mint-map/naver/NaverMintMapController.d.ts +3 -0
  17. package/dist/components/mint-map/naver/NaverMintMapController.js +39 -4
  18. package/dist/index.es.js +458 -83
  19. package/dist/index.js +4 -2
  20. package/dist/index.umd.js +460 -83
  21. package/package.json +1 -1
  22. package/dist/components/mint-map/core/advanced/woongCanvas/ClusterMarker.d.ts +0 -11
  23. 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; //console.log('onMouseOverHandler', marker);
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
- * Konva 기반 고성능 마커/폴리곤 렌더링 컴포넌트
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
- * - Base/Event 레이어 분리로 성능 최적화
5364
- * - LRU 캐시로 좌표 변환 결과 캐싱
5365
- * - Spatial Hash Grid로 빠른 Hit Test
5366
- * - Viewport Culling으로 보이는 영역만 렌더링
5497
+ * @param baseFillColor 기본 폴리곤 채우기 색상
5498
+ * @param baseStrokeColor 기본 폴리곤 테두리 색상
5499
+ * @param baseLineWidth 기본 폴리곤 테두리 두께
5500
+ * @returns Base Layer 렌더링 함수
5367
5501
  *
5368
- * @template T 마커 데이터의 추가 속성 타입
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 WoongKonvaMarkerComponent = function (_a) {
5372
- var markers = _a.markers,
5373
- dataType = _a.dataType,
5374
- onClick = _a.onClick,
5375
- onMouseOver = _a.onMouseOver,
5376
- onMouseOut = _a.onMouseOut,
5377
- renderBase = _a.renderBase,
5378
- renderAnimation = _a.renderAnimation,
5379
- renderEvent = _a.renderEvent,
5380
- _b = _a.enableMultiSelect,
5381
- enableMultiSelect = _b === void 0 ? false : _b,
5382
- _c = _a.topOnHover,
5383
- topOnHover = _c === void 0 ? false : _c,
5384
- _d = _a.enableViewportCulling,
5385
- enableViewportCulling = _d === void 0 ? true : _d,
5386
- _e = _a.cullingMargin,
5387
- cullingMargin = _e === void 0 ? DEFAULT_CULLING_MARGIN : _e,
5388
- _f = _a.maxCacheSize,
5389
- maxCacheSize = _f === void 0 ? DEFAULT_MAX_CACHE_SIZE : _f,
5390
- externalSelectedItems = _a.selectedItems,
5391
- externalSelectedItem = _a.selectedItem,
5392
- _g = _a.disableInteraction,
5393
- disableInteraction = _g === void 0 ? false : _g,
5394
- options = __rest(_a, ["markers", "dataType", "onClick", "onMouseOver", "onMouseOut", "renderBase", "renderAnimation", "renderEvent", "enableMultiSelect", "topOnHover", "enableViewportCulling", "cullingMargin", "maxCacheSize", "selectedItems", "selectedItem", "disableInteraction"]); // --------------------------------------------------------------------------
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
- /** markers prop을 ref로 추적 (stale closure 방지, useEffect에서 동기화) */
5684
+ /** data prop을 ref로 추적 (stale closure 방지, useEffect에서 동기화) */
5420
5685
 
5421
- var markersRef = useRef(markers); // --------------------------------------------------------------------------
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 data = findData(clickedOffset);
6329
+ var data_1 = findData(clickedOffset);
6052
6330
 
6053
- if (data) {
6054
- handleLocalClick(data);
6055
- onClick(data, selectedIdsRef.current);
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 = markers; // 데이터 변경 시 즉시 transform 제거 및 캐시 정리 (겹침 방지)
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
- * markers가 변경되면 selectedItemsMapRef도 업데이트 필요
6633
+ * data가 변경되면 selectedItemsMapRef도 업데이트 필요
6356
6634
  * (참조가 바뀌므로 기존 Map의 데이터는 stale 상태)
6357
6635
  *
6358
- * 🔥 중요: 화면 밖 마커도 선택 상태 유지!
6359
- * - 현재 markers에 있으면 최신 데이터로 업데이트
6636
+ * 🔥 중요: 화면 밖 데이터도 선택 상태 유지!
6637
+ * - 현재 data에 있으면 최신 데이터로 업데이트
6360
6638
  * - 없으면 기존 selectedItemsMapRef의 데이터 유지
6361
6639
  *
6362
- * 최적화: markers를 Map으로 먼저 변환하여 find() 순회 제거
6363
- * - O(전체 마커 수 + 선택된 개수) - 매우 효율적
6640
+ * 최적화: data를 Map으로 먼저 변환하여 find() 순회 제거
6641
+ * - O(전체 데이터 수 + 선택된 개수) - 매우 효율적
6364
6642
  */
6365
6643
 
6366
- var markersMap = new Map(markers.map(function (m) {
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
- }, [markers]);
6667
+ }, [data]);
6390
6668
  return createPortal(React.createElement("div", {
6391
6669
  ref: containerRef,
6392
- style: __assign({
6670
+ style: {
6393
6671
  position: 'absolute',
6394
6672
  width: '100%',
6395
6673
  height: '100%'
6396
- }, disableInteraction && {
6397
- pointerEvents: 'none'
6398
- })
6674
+ }
6399
6675
  }), divElement);
6400
6676
  };
6401
6677
  /**
6402
- * 🔥 React.memo 최적화: 마커 배열과 selectedItems 변경 체크
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
- * 1. markers 배열 비교
6406
- * 2. selectedItems 배열 비교 (외부 제어)
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
- * 주의: JSON.stringify() 사용 금지! (매우 느림)
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 WoongKonvaMarker = React.memo(WoongKonvaMarkerComponent, function (prevProps, nextProps) {
6413
- // 1. markers 비교
6414
- var prevMarkers = prevProps.markers;
6415
- var nextMarkers = nextProps.markers; // 참조가 같으면 스킵
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 (prevMarkers !== nextMarkers) {
6762
+ if (prevData !== nextData) {
6418
6763
  // 길이가 다르면 변경됨
6419
- if (prevMarkers.length !== nextMarkers.length) return false; // 각 마커의 ID 비교
6764
+ if (prevData.length !== nextData.length) return false; // 각 데이터의 ID 비교
6420
6765
 
6421
- for (var i = 0; i < prevMarkers.length; i++) {
6422
- if (prevMarkers[i].id !== nextMarkers[i].id) {
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.setMarkerZIndex = function (marker, zIndex) {
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
- parent_1.style.zIndex = String(zIndex);
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, WoongKonvaMarker, computeMarkerOffset, computePolygonOffsets, getClusterInfo, getMapOfType, isPointInMarkerData, isPointInPolygon, isPointInPolygonData, log, useKonvaMarkerContext, useMarkerMoving, useMintMapController, waiting };
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 };