@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.umd.js CHANGED
@@ -948,6 +948,46 @@
948
948
  var y = markerOffset.y - boxHeight - tailHeight;
949
949
  return clickedOffset.x >= x && clickedOffset.x <= x + boxWidth && clickedOffset.y >= y && clickedOffset.y <= y + boxHeight;
950
950
  };
951
+ var hexToRgba = function (hexColor, alpha) {
952
+ if (alpha === void 0) {
953
+ alpha = 1;
954
+ } // NOTE: 입력된 hexColor에서 "#" 제거
955
+
956
+
957
+ var hex = hexColor.replace('#', ''); // NOTE: 6자리일 경우 알파 값은 사용자가 제공한 alpha 값으로 설정
958
+
959
+ if (hex.length === 6) {
960
+ var r = parseInt(hex.substring(0, 2), 16);
961
+ var g = parseInt(hex.substring(2, 4), 16);
962
+ var b = parseInt(hex.substring(4, 6), 16);
963
+ return "rgba(".concat(r, ", ").concat(g, ", ").concat(b, ", ").concat(alpha, ")");
964
+ }
965
+
966
+ throw new Error('Invalid hex color format');
967
+ };
968
+ var tempCanvas = document.createElement('canvas');
969
+ var tempCtx = tempCanvas.getContext('2d');
970
+ /**
971
+ * 텍스트 박스의 너비를 계산합니다.
972
+ *
973
+ * @param {Object} params - 파라미터 객체
974
+ * @param {string} params.text - 측정할 텍스트
975
+ * @param {string} params.fontConfig - 폰트 설정 (예: 'bold 16px Arial')
976
+ * @param {number} params.padding - 텍스트 박스에 적용할 패딩 값
977
+ * @param {number} params.minWidth - 최소 너비
978
+ * @returns {number} 계산된 텍스트 박스의 너비
979
+ */
980
+
981
+ var calculateTextBoxWidth = function (_a) {
982
+ var text = _a.text,
983
+ fontConfig = _a.fontConfig,
984
+ padding = _a.padding,
985
+ minWidth = _a.minWidth;
986
+ if (!tempCtx) return 0;
987
+ tempCtx.font = fontConfig;
988
+ var textWidth = tempCtx.measureText(text).width;
989
+ return Math.max(minWidth, textWidth + padding);
990
+ };
951
991
 
952
992
  var KonvaMarkerContext = React.createContext(null);
953
993
  var KonvaMarkerProvider = function (_a) {
@@ -2758,7 +2798,7 @@
2758
2798
  var onMouseOverHandler = function (e) {
2759
2799
  var _a;
2760
2800
 
2761
- var marker = markerRef.current; //console.log('onMouseOverHandler', marker);
2801
+ var marker = markerRef.current;
2762
2802
 
2763
2803
  if (marker) {
2764
2804
  var mouseOverHandler = (_a = options === null || options === void 0 ? void 0 : options.event) === null || _a === void 0 ? void 0 : _a.get('mouseover');
@@ -2771,6 +2811,25 @@
2771
2811
 
2772
2812
  next && topOnHover && controller.markerToTheTop(marker);
2773
2813
  }
2814
+ }; // 20251014 | 장한별 | mouseleave 이벤트 추가, 마우스가 마커 위에서 떠날 때 원래 zindex 를 복구하기 위함
2815
+
2816
+
2817
+ var onMouseLeaveHandler = function (e) {
2818
+ var _a;
2819
+
2820
+ var marker = markerRef.current;
2821
+
2822
+ if (marker) {
2823
+ var mouseOutHandler = (_a = options === null || options === void 0 ? void 0 : options.event) === null || _a === void 0 ? void 0 : _a.get('mouseout');
2824
+ var next = true;
2825
+
2826
+ if (mouseOutHandler) {
2827
+ var hasNext = mouseOutHandler(e);
2828
+ hasNext !== undefined && (next = hasNext);
2829
+ }
2830
+
2831
+ next && topOnHover && controller.restoreMarkerZIndex(marker);
2832
+ }
2774
2833
  }; //create object
2775
2834
 
2776
2835
 
@@ -2788,10 +2847,12 @@
2788
2847
  }); //드래그 여부 초기화를 먼저 수행하기 위해 capture : true 처리
2789
2848
 
2790
2849
  divElement.addEventListener('mouseover', onMouseOverHandler);
2850
+ divElement.addEventListener('mouseleave', onMouseLeaveHandler);
2791
2851
  return function () {
2792
2852
  divElement.removeEventListener('click', onClickHandler);
2793
2853
  divElement.removeEventListener('mousedown', onMousedownHandler);
2794
2854
  divElement.removeEventListener('mouseover', onMouseOverHandler);
2855
+ divElement.removeEventListener('mouseleave', onMouseLeaveHandler);
2795
2856
 
2796
2857
  if (markerRef.current) {
2797
2858
  controller.clearDrawable(markerRef.current);
@@ -5357,45 +5418,249 @@
5357
5418
  }))));
5358
5419
  }
5359
5420
 
5360
- // 메인 컴포넌트
5361
- // ============================================================================
5421
+ /**
5422
+ * 폴리곤 렌더링 유틸리티
5423
+ *
5424
+ * 이 파일은 폴리곤 렌더링을 위한 헬퍼 함수와 팩토리 함수를 제공합니다.
5425
+ */
5362
5426
 
5363
5427
  /**
5364
- * Konva 기반 고성능 마커/폴리곤 렌더링 컴포넌트
5428
+ * 폴리곤 그리기 헬퍼 함수 (도넛 폴리곤 지원)
5429
+ */
5430
+ var drawPolygon = function (_a) {
5431
+ var ctx = _a.ctx,
5432
+ polygonOffsets = _a.polygonOffsets,
5433
+ isDonutPolygon = _a.isDonutPolygon,
5434
+ fillColor = _a.fillColor,
5435
+ strokeColor = _a.strokeColor,
5436
+ lineWidth = _a.lineWidth;
5437
+
5438
+ for (var _i = 0, polygonOffsets_1 = polygonOffsets; _i < polygonOffsets_1.length; _i++) {
5439
+ var multiPolygon = polygonOffsets_1[_i];
5440
+
5441
+ if (isDonutPolygon) {
5442
+ ctx.beginPath(); // 1. 외부 폴리곤 그리기
5443
+
5444
+ if (multiPolygon[0] && multiPolygon[0].length > 0) {
5445
+ ctx.moveTo(multiPolygon[0][0][0], multiPolygon[0][0][1]);
5446
+
5447
+ for (var i = 1; i < multiPolygon[0].length; i++) {
5448
+ ctx.lineTo(multiPolygon[0][i][0], multiPolygon[0][i][1]);
5449
+ }
5450
+
5451
+ ctx.closePath();
5452
+ } // 2. 내부 폴리곤 (구멍들) 그리기 - 같은 path에 추가
5453
+
5454
+
5455
+ for (var j = 1; j < multiPolygon.length; j++) {
5456
+ var innerPolygon = multiPolygon[j];
5457
+ if (innerPolygon.length === 0) continue;
5458
+ ctx.moveTo(innerPolygon[0][0], innerPolygon[0][1]);
5459
+
5460
+ for (var i = 1; i < innerPolygon.length; i++) {
5461
+ ctx.lineTo(innerPolygon[i][0], innerPolygon[i][1]);
5462
+ }
5463
+
5464
+ ctx.closePath();
5465
+ } // 3. evenodd fill rule로 구멍 뚫기
5466
+
5467
+
5468
+ ctx.fillStyle = fillColor;
5469
+ ctx.fill('evenodd'); // 4. 외곽선 그리기
5470
+
5471
+ ctx.strokeStyle = strokeColor;
5472
+ ctx.lineWidth = lineWidth;
5473
+ ctx.stroke();
5474
+ } else {
5475
+ // 일반 폴리곤
5476
+ for (var _b = 0, multiPolygon_1 = multiPolygon; _b < multiPolygon_1.length; _b++) {
5477
+ var polygonGroup = multiPolygon_1[_b];
5478
+ if (!polygonGroup.length) continue;
5479
+ ctx.beginPath();
5480
+ var firstPoint = polygonGroup[0];
5481
+ ctx.moveTo(firstPoint[0], firstPoint[1]);
5482
+
5483
+ for (var i = 1; i < polygonGroup.length; i++) {
5484
+ var point = polygonGroup[i];
5485
+ ctx.lineTo(point[0], point[1]);
5486
+ }
5487
+
5488
+ ctx.closePath();
5489
+ ctx.fillStyle = fillColor;
5490
+ ctx.strokeStyle = strokeColor;
5491
+ ctx.lineWidth = lineWidth;
5492
+ ctx.fill();
5493
+ ctx.stroke();
5494
+ }
5495
+ }
5496
+ }
5497
+ };
5498
+ /**
5499
+ * 폴리곤 Base 렌더링 함수
5365
5500
  *
5366
- * 특징:
5367
- * - Base/Event 레이어 분리로 성능 최적화
5368
- * - LRU 캐시로 좌표 변환 결과 캐싱
5369
- * - Spatial Hash Grid로 빠른 Hit Test
5370
- * - Viewport Culling으로 보이는 영역만 렌더링
5501
+ * @param baseFillColor 기본 폴리곤 채우기 색상
5502
+ * @param baseStrokeColor 기본 폴리곤 테두리 색상
5503
+ * @param baseLineWidth 기본 폴리곤 테두리 두께
5504
+ * @returns Base Layer 렌더링 함수
5371
5505
  *
5372
- * @template T 마커 데이터의 추가 속성 타입
5506
+ * @example
5507
+ * const renderBase = renderPolygonBase(
5508
+ * 'rgba(255, 100, 100, 0.5)',
5509
+ * 'rgba(200, 50, 50, 0.8)',
5510
+ * 2
5511
+ * );
5373
5512
  */
5374
5513
 
5375
- var WoongKonvaMarkerComponent = function (_a) {
5376
- var markers = _a.markers,
5377
- dataType = _a.dataType,
5378
- onClick = _a.onClick,
5379
- onMouseOver = _a.onMouseOver,
5380
- onMouseOut = _a.onMouseOut,
5381
- renderBase = _a.renderBase,
5382
- renderAnimation = _a.renderAnimation,
5383
- renderEvent = _a.renderEvent,
5384
- _b = _a.enableMultiSelect,
5385
- enableMultiSelect = _b === void 0 ? false : _b,
5386
- _c = _a.topOnHover,
5387
- topOnHover = _c === void 0 ? false : _c,
5388
- _d = _a.enableViewportCulling,
5389
- enableViewportCulling = _d === void 0 ? true : _d,
5390
- _e = _a.cullingMargin,
5391
- cullingMargin = _e === void 0 ? DEFAULT_CULLING_MARGIN : _e,
5392
- _f = _a.maxCacheSize,
5393
- maxCacheSize = _f === void 0 ? DEFAULT_MAX_CACHE_SIZE : _f,
5394
- externalSelectedItems = _a.selectedItems,
5395
- externalSelectedItem = _a.selectedItem,
5396
- _g = _a.disableInteraction,
5397
- disableInteraction = _g === void 0 ? false : _g,
5398
- options = tslib.__rest(_a, ["markers", "dataType", "onClick", "onMouseOver", "onMouseOut", "renderBase", "renderAnimation", "renderEvent", "enableMultiSelect", "topOnHover", "enableViewportCulling", "cullingMargin", "maxCacheSize", "selectedItems", "selectedItem", "disableInteraction"]); // --------------------------------------------------------------------------
5514
+ var renderPolygonBase = function (baseFillColor, baseStrokeColor, baseLineWidth) {
5515
+ return function (_a) {
5516
+ var ctx = _a.ctx,
5517
+ items = _a.items,
5518
+ selectedIds = _a.selectedIds,
5519
+ utils = _a.utils;
5520
+
5521
+ for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
5522
+ var item = items_1[_i]; // 선택된 항목은 Event Layer에서 그림
5523
+
5524
+ if (selectedIds.has(item.id)) continue;
5525
+ if (!item.paths) continue;
5526
+ var polygonOffsets = utils.getOrComputePolygonOffsets(item);
5527
+ if (!polygonOffsets) continue;
5528
+ drawPolygon({
5529
+ ctx: ctx,
5530
+ polygonOffsets: polygonOffsets,
5531
+ isDonutPolygon: item.isDonutPolygon || false,
5532
+ fillColor: baseFillColor,
5533
+ strokeColor: baseStrokeColor,
5534
+ lineWidth: baseLineWidth
5535
+ });
5536
+ }
5537
+ };
5538
+ };
5539
+ /**
5540
+ * 폴리곤 Event 렌더링 함수
5541
+ *
5542
+ * @param selectedFillColor 선택된 폴리곤 채우기 색상
5543
+ * @param selectedStrokeColor 선택된 폴리곤 테두리 색상
5544
+ * @param selectedLineWidth 선택된 폴리곤 테두리 두께
5545
+ * @param activeFillColor 마지막 선택된 폴리곤 채우기 색상 (선택, 기본값: selectedFillColor)
5546
+ * @param activeStrokeColor 마지막 선택된 폴리곤 테두리 색상 (선택, 기본값: selectedStrokeColor)
5547
+ * @param activeLineWidth 마지막 선택된 폴리곤 테두리 두께 (선택, 기본값: selectedLineWidth)
5548
+ * @param hoveredFillColor Hover 시 폴리곤 채우기 색상 (선택, 기본값: selectedFillColor)
5549
+ * @param hoveredStrokeColor Hover 시 폴리곤 테두리 색상 (선택, 기본값: selectedStrokeColor)
5550
+ * @param hoveredLineWidth Hover 시 폴리곤 테두리 두께 (선택, 기본값: selectedLineWidth)
5551
+ * @returns Event Layer 렌더링 함수
5552
+ *
5553
+ * @example
5554
+ * const renderEvent = renderPolygonEvent(
5555
+ * 'rgba(255, 193, 7, 0.7)',
5556
+ * 'rgba(255, 152, 0, 1)',
5557
+ * 4,
5558
+ * 'rgba(255, 0, 0, 0.8)',
5559
+ * undefined,
5560
+ * undefined,
5561
+ * 'rgba(100, 150, 255, 0.8)'
5562
+ * );
5563
+ */
5564
+
5565
+ var renderPolygonEvent = function (selectedFillColor, selectedStrokeColor, selectedLineWidth, activeFillColor, activeStrokeColor, activeLineWidth, hoveredFillColor, hoveredStrokeColor, hoveredLineWidth) {
5566
+ // 기본값 설정 (selected 기준)
5567
+ var _activeFillColor = activeFillColor || selectedFillColor;
5568
+
5569
+ var _activeStrokeColor = activeStrokeColor || selectedStrokeColor;
5570
+
5571
+ var _activeLineWidth = activeLineWidth || selectedLineWidth;
5572
+
5573
+ var _hoveredFillColor = hoveredFillColor || selectedFillColor;
5574
+
5575
+ var _hoveredStrokeColor = hoveredStrokeColor || selectedStrokeColor;
5576
+
5577
+ var _hoveredLineWidth = hoveredLineWidth || selectedLineWidth;
5578
+
5579
+ return function (_a) {
5580
+ var ctx = _a.ctx,
5581
+ hoveredItem = _a.hoveredItem,
5582
+ utils = _a.utils,
5583
+ selectedItems = _a.selectedItems,
5584
+ selectedItem = _a.selectedItem; // 1. 선택된 항목들 그리기 (마지막 선택 항목과 호버된 항목 제외)
5585
+
5586
+ if (selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.length) {
5587
+ for (var _i = 0, selectedItems_1 = selectedItems; _i < selectedItems_1.length; _i++) {
5588
+ var item = selectedItems_1[_i]; // 마지막 선택 항목과 호버된 항목은 나중에 따로 그림
5589
+
5590
+ if (item.id === (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.id) || (hoveredItem === null || hoveredItem === void 0 ? void 0 : hoveredItem.id) === item.id) continue;
5591
+ if (!item.paths) continue;
5592
+ var polygonOffsets = utils.getOrComputePolygonOffsets(item);
5593
+ if (!polygonOffsets) continue;
5594
+ drawPolygon({
5595
+ ctx: ctx,
5596
+ polygonOffsets: polygonOffsets,
5597
+ isDonutPolygon: item.isDonutPolygon || false,
5598
+ fillColor: selectedFillColor,
5599
+ strokeColor: selectedStrokeColor,
5600
+ lineWidth: selectedLineWidth
5601
+ });
5602
+ }
5603
+ } // 2. 마지막 선택된 항목 그리기 (호버되지 않은 경우)
5604
+
5605
+
5606
+ if ((selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.paths) && (hoveredItem === null || hoveredItem === void 0 ? void 0 : hoveredItem.id) !== selectedItem.id) {
5607
+ var polygonOffsets = utils.getOrComputePolygonOffsets(selectedItem);
5608
+
5609
+ if (polygonOffsets) {
5610
+ drawPolygon({
5611
+ ctx: ctx,
5612
+ polygonOffsets: polygonOffsets,
5613
+ isDonutPolygon: selectedItem.isDonutPolygon || false,
5614
+ fillColor: _activeFillColor,
5615
+ strokeColor: _activeStrokeColor,
5616
+ lineWidth: _activeLineWidth
5617
+ });
5618
+ }
5619
+ } // 3. 호버된 항목 그리기 (가장 위에 표시)
5620
+
5621
+
5622
+ if (hoveredItem === null || hoveredItem === void 0 ? void 0 : hoveredItem.paths) {
5623
+ var polygonOffsets = utils.getOrComputePolygonOffsets(hoveredItem);
5624
+ if (!polygonOffsets) return;
5625
+ var isSelected = selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.some(function (item) {
5626
+ return item.id === hoveredItem.id;
5627
+ });
5628
+ drawPolygon({
5629
+ ctx: ctx,
5630
+ polygonOffsets: polygonOffsets,
5631
+ isDonutPolygon: hoveredItem.isDonutPolygon || false,
5632
+ fillColor: isSelected ? _activeFillColor : _hoveredFillColor,
5633
+ strokeColor: isSelected ? _activeStrokeColor : _hoveredStrokeColor,
5634
+ lineWidth: isSelected ? _activeLineWidth : _hoveredLineWidth
5635
+ });
5636
+ }
5637
+ };
5638
+ };
5639
+
5640
+ // 메인 컴포넌트
5641
+ // ============================================================================
5642
+
5643
+ var WoongCanvasLayerComponent = function (props) {
5644
+ var data = props.data,
5645
+ dataType = props.dataType,
5646
+ onClick = props.onClick,
5647
+ onMouseOver = props.onMouseOver,
5648
+ onMouseOut = props.onMouseOut,
5649
+ _a = props.enableMultiSelect,
5650
+ enableMultiSelect = _a === void 0 ? false : _a,
5651
+ _b = props.topOnHover,
5652
+ topOnHover = _b === void 0 ? false : _b,
5653
+ _c = props.enableViewportCulling,
5654
+ enableViewportCulling = _c === void 0 ? true : _c,
5655
+ _d = props.cullingMargin,
5656
+ cullingMargin = _d === void 0 ? DEFAULT_CULLING_MARGIN : _d,
5657
+ _e = props.maxCacheSize,
5658
+ maxCacheSize = _e === void 0 ? DEFAULT_MAX_CACHE_SIZE : _e,
5659
+ externalSelectedItems = props.selectedItems,
5660
+ externalSelectedItem = props.selectedItem,
5661
+ _f = props.disableInteraction,
5662
+ disableInteraction = _f === void 0 ? false : _f,
5663
+ options = tslib.__rest(props, ["data", "dataType", "onClick", "onMouseOver", "onMouseOut", "enableMultiSelect", "topOnHover", "enableViewportCulling", "cullingMargin", "maxCacheSize", "selectedItems", "selectedItem", "disableInteraction"]); // --------------------------------------------------------------------------
5399
5664
  // Hooks & Context
5400
5665
  // --------------------------------------------------------------------------
5401
5666
 
@@ -5420,9 +5685,9 @@
5420
5685
  // Data Refs - 선택 및 Hover 상태 관리
5421
5686
  // --------------------------------------------------------------------------
5422
5687
 
5423
- /** markers prop을 ref로 추적 (stale closure 방지, useEffect에서 동기화) */
5688
+ /** data prop을 ref로 추적 (stale closure 방지, useEffect에서 동기화) */
5424
5689
 
5425
- var markersRef = React.useRef(markers); // --------------------------------------------------------------------------
5690
+ var markersRef = React.useRef(data); // --------------------------------------------------------------------------
5426
5691
  // State Refs - 선택 및 Hover 상태 관리
5427
5692
  // --------------------------------------------------------------------------
5428
5693
 
@@ -5594,6 +5859,7 @@
5594
5859
  };
5595
5860
  /**
5596
5861
  * 마커 좌표 변환 결과를 캐시하고 반환
5862
+ *
5597
5863
  * @param markerData 마커 데이터
5598
5864
  * @returns 변환된 좌표 또는 null
5599
5865
  */
@@ -5673,7 +5939,7 @@
5673
5939
  }
5674
5940
  }
5675
5941
  }; // --------------------------------------------------------------------------
5676
- // 렌더링 함수
5942
+ // 렌더링 함수 결정 (dataType에 따라)
5677
5943
  // --------------------------------------------------------------------------
5678
5944
 
5679
5945
  /**
@@ -5688,6 +5954,18 @@
5688
5954
  /** Base Layer에서 사용할 빈 Set (재사용) */
5689
5955
 
5690
5956
  React.useRef(new Set());
5957
+ /**
5958
+ * 실제 사용할 렌더링 함수 결정
5959
+ * - MARKER: 외부에서 전달받은 renderBase 사용 (필수)
5960
+ * - POLYGON: renderer.ts의 팩토리 함수로 생성 (props 기반)
5961
+ */
5962
+
5963
+ var renderBase = dataType === exports.CanvasDataType.MARKER ? props.renderBase : renderPolygonBase(props.baseFillColor, props.baseStrokeColor, props.baseLineWidth);
5964
+ var renderAnimation = dataType === exports.CanvasDataType.MARKER ? props.renderAnimation : undefined;
5965
+ var renderEvent = dataType === exports.CanvasDataType.MARKER ? props.renderEvent : function () {
5966
+ var polygonProps = props;
5967
+ return renderPolygonEvent(polygonProps.selectedFillColor, polygonProps.selectedStrokeColor, polygonProps.selectedLineWidth, polygonProps.activeFillColor, polygonProps.activeStrokeColor, polygonProps.activeLineWidth, polygonProps.hoveredFillColor, polygonProps.hoveredStrokeColor, polygonProps.hoveredLineWidth);
5968
+ }();
5691
5969
  /**
5692
5970
  * Base 레이어 렌더링 (뷰포트 컬링 적용, 선택된 마커 제외)
5693
5971
  *
@@ -6052,11 +6330,11 @@
6052
6330
 
6053
6331
  try {
6054
6332
  var clickedOffset = controller.positionToOffset(event.param.position);
6055
- var data = findData(clickedOffset);
6333
+ var data_1 = findData(clickedOffset);
6056
6334
 
6057
- if (data) {
6058
- handleLocalClick(data);
6059
- onClick(data, selectedIdsRef.current);
6335
+ if (data_1) {
6336
+ handleLocalClick(data_1);
6337
+ onClick(data_1, selectedIdsRef.current);
6060
6338
  }
6061
6339
  } catch (error) {
6062
6340
  console.error('[WoongKonvaMarker] handleClick error:', error);
@@ -6333,13 +6611,13 @@
6333
6611
 
6334
6612
  doRenderEvent();
6335
6613
  }, [externalSelectedItem]); // --------------------------------------------------------------------------
6336
- // Lifecycle: 마커 데이터 변경 시 렌더링
6614
+ // Lifecycle: 데이터 변경 시 렌더링
6337
6615
  // --------------------------------------------------------------------------
6338
6616
 
6339
6617
  React.useEffect(function () {
6340
6618
  if (!stageRef.current) return; // markersRef 동기화
6341
6619
 
6342
- markersRef.current = markers; // 데이터 변경 시 즉시 transform 제거 및 캐시 정리 (겹침 방지)
6620
+ markersRef.current = data; // 데이터 변경 시 즉시 transform 제거 및 캐시 정리 (겹침 방지)
6343
6621
 
6344
6622
  if (containerRef.current) {
6345
6623
  containerRef.current.style.transform = '';
@@ -6356,18 +6634,18 @@
6356
6634
  /**
6357
6635
  * 선택 상태 동기화 (최적화 버전)
6358
6636
  *
6359
- * markers가 변경되면 selectedItemsMapRef도 업데이트 필요
6637
+ * data가 변경되면 selectedItemsMapRef도 업데이트 필요
6360
6638
  * (참조가 바뀌므로 기존 Map의 데이터는 stale 상태)
6361
6639
  *
6362
- * 🔥 중요: 화면 밖 마커도 선택 상태 유지!
6363
- * - 현재 markers에 있으면 최신 데이터로 업데이트
6640
+ * 🔥 중요: 화면 밖 데이터도 선택 상태 유지!
6641
+ * - 현재 data에 있으면 최신 데이터로 업데이트
6364
6642
  * - 없으면 기존 selectedItemsMapRef의 데이터 유지
6365
6643
  *
6366
- * 최적화: markers를 Map으로 먼저 변환하여 find() 순회 제거
6367
- * - O(전체 마커 수 + 선택된 개수) - 매우 효율적
6644
+ * 최적화: data를 Map으로 먼저 변환하여 find() 순회 제거
6645
+ * - O(전체 데이터 수 + 선택된 개수) - 매우 효율적
6368
6646
  */
6369
6647
 
6370
- var markersMap = new Map(markers.map(function (m) {
6648
+ var markersMap = new Map(data.map(function (m) {
6371
6649
  return [m.id, m];
6372
6650
  }));
6373
6651
  var newSelectedItemsMap = new Map();
@@ -6390,40 +6668,107 @@
6390
6668
  selectedItemsMapRef.current = newSelectedItemsMap; // 즉시 렌더링
6391
6669
 
6392
6670
  renderAllImmediate();
6393
- }, [markers]);
6671
+ }, [data]);
6394
6672
  return reactDom.createPortal(React__default["default"].createElement("div", {
6395
6673
  ref: containerRef,
6396
- style: tslib.__assign({
6674
+ style: {
6397
6675
  position: 'absolute',
6398
6676
  width: '100%',
6399
6677
  height: '100%'
6400
- }, disableInteraction && {
6401
- pointerEvents: 'none'
6402
- })
6678
+ }
6403
6679
  }), divElement);
6404
6680
  };
6405
6681
  /**
6406
- * 🔥 React.memo 최적화: 마커 배열과 selectedItems 변경 체크
6682
+ * 🚀 WoongCanvasLayer - Konva 기반 초고성능 마커/폴리곤 렌더링 컴포넌트
6683
+ *
6684
+ * ## 📌 주요 특징
6685
+ * - **30,000개 이상의 폴리곤/마커를 60fps로 렌더링**
6686
+ * - **Multi-Layer 아키텍처**: Base/Animation/Event 레이어 분리
6687
+ * - **Spatial Hash Grid**: O(1) 수준의 빠른 Hit Test
6688
+ * - **LRU 캐시**: 좌표 변환 결과 캐싱으로 성능 최적화
6689
+ * - **Viewport Culling**: 화면에 보이는 영역만 렌더링
6690
+ * - **Discriminated Union Props**: 타입 안전한 MARKER/POLYGON 모드
6691
+ *
6692
+ * ## 🎯 사용 방법
6693
+ *
6694
+ * ### 1️⃣ POLYGON 모드 (자동 렌더링)
6695
+ * ```tsx
6696
+ * <WoongCanvasLayer
6697
+ * dataType={CanvasDataType.POLYGON}
6698
+ * data={polygons}
6699
+ * baseFillColor="rgba(255, 100, 100, 0.5)"
6700
+ * baseStrokeColor="rgba(200, 50, 50, 0.8)"
6701
+ * baseLineWidth={2}
6702
+ * selectedFillColor="rgba(255, 193, 7, 0.7)"
6703
+ * selectedStrokeColor="rgba(255, 152, 0, 1)"
6704
+ * selectedLineWidth={4}
6705
+ * hoveredFillColor="rgba(100, 150, 255, 0.8)" // optional
6706
+ * hoveredStrokeColor="rgba(0, 100, 200, 1)" // optional
6707
+ * hoveredLineWidth={3} // optional
6708
+ * enableMultiSelect={true}
6709
+ * onClick={handleClick}
6710
+ * />
6711
+ * ```
6712
+ *
6713
+ * ### 2️⃣ MARKER 모드 (커스텀 렌더링)
6714
+ * ```tsx
6715
+ * <WoongCanvasLayer
6716
+ * dataType={CanvasDataType.MARKER}
6717
+ * data={markers}
6718
+ * renderBase={renderMarkerBase} // required
6719
+ * renderAnimation={renderMarkerAnimation} // optional
6720
+ * renderEvent={renderMarkerEvent} // optional
6721
+ * topOnHover={true}
6722
+ * onClick={handleClick}
6723
+ * />
6724
+ * ```
6407
6725
  *
6408
- * 비교 전략:
6409
- * 1. markers 배열 비교
6410
- * 2. selectedItems 배열 비교 (외부 제어)
6726
+ * ## 📊 데이터 형식
6727
+ * ```typescript
6728
+ * const data: KonvaCanvasMarkerData<T>[] = [
6729
+ * {
6730
+ * id: 'unique-id',
6731
+ * position: new Position(lat, lng),
6732
+ * // POLYGON: paths 필수
6733
+ * paths: [[[lat, lng], [lat, lng], ...]],
6734
+ * // MARKER: boxWidth/boxHeight 권장 (Hit Test 정확도)
6735
+ * boxWidth: 60,
6736
+ * boxHeight: 75,
6737
+ * // 커스텀 데이터
6738
+ * ...customData
6739
+ * }
6740
+ * ];
6741
+ * ```
6411
6742
  *
6412
- * 주의: JSON.stringify() 사용 금지! (매우 느림)
6743
+ * ## 성능 최적화
6744
+ * 1. **동적 boxWidth 계산**: `measureText()`로 실제 너비 계산 후 전달
6745
+ * 2. **enableViewportCulling**: 대량 데이터 시 필수 (기본 true)
6746
+ * 3. **selectedItems 외부 관리**: 상태를 외부에서 관리하여 리렌더링 최소화
6747
+ * 4. **React.memo 최적화**: 컴포넌트가 자동으로 불필요한 리렌더링 방지
6748
+ *
6749
+ * @template T 마커/폴리곤 데이터의 추가 속성 타입
6750
+ *
6751
+ * @example
6752
+ * // 동적 boxWidth 계산 예시
6753
+ * const tempCtx = document.createElement('canvas').getContext('2d');
6754
+ * tempCtx.font = 'bold 15px Arial';
6755
+ * const boxWidth = Math.max(60, tempCtx.measureText(text).width + 20);
6756
+ *
6757
+ * @see {@link https://github.com/your-repo/docs/WoongCanvasLayer.md} 전체 문서
6413
6758
  */
6414
6759
 
6415
6760
 
6416
- var WoongKonvaMarker = React__default["default"].memo(WoongKonvaMarkerComponent, function (prevProps, nextProps) {
6417
- // 1. markers 비교
6418
- var prevMarkers = prevProps.markers;
6419
- var nextMarkers = nextProps.markers; // 참조가 같으면 스킵
6761
+ var WoongCanvasLayer = React__default["default"].memo(WoongCanvasLayerComponent, function (prevProps, nextProps) {
6762
+ // 1. data 비교
6763
+ var prevData = prevProps.data;
6764
+ var nextData = nextProps.data; // 참조가 같으면 스킵
6420
6765
 
6421
- if (prevMarkers !== nextMarkers) {
6766
+ if (prevData !== nextData) {
6422
6767
  // 길이가 다르면 변경됨
6423
- if (prevMarkers.length !== nextMarkers.length) return false; // 각 마커의 ID 비교
6768
+ if (prevData.length !== nextData.length) return false; // 각 데이터의 ID 비교
6424
6769
 
6425
- for (var i = 0; i < prevMarkers.length; i++) {
6426
- if (prevMarkers[i].id !== nextMarkers[i].id) {
6770
+ for (var i = 0; i < prevData.length; i++) {
6771
+ if (prevData[i].id !== nextData[i].id) {
6427
6772
  return false; // 변경됨 → 리렌더링
6428
6773
  }
6429
6774
  }
@@ -6438,18 +6783,6 @@
6438
6783
  return false; // 변경됨 → 리렌더링
6439
6784
  }
6440
6785
 
6441
- if (prevProps.onClick !== nextProps.onClick) {
6442
- return false; // 변경됨 → 리렌더링
6443
- }
6444
-
6445
- if (prevProps.onMouseOver !== nextProps.onMouseOver) {
6446
- return false; // 변경됨 → 리렌더링
6447
- }
6448
-
6449
- if (prevProps.onMouseOut !== nextProps.onMouseOut) {
6450
- return false; // 변경됨 → 리렌더링
6451
- }
6452
-
6453
6786
  if (prevProps.disableInteraction !== nextProps.disableInteraction) {
6454
6787
  return false; // 변경됨 → 리렌더링
6455
6788
  }
@@ -7197,20 +7530,54 @@
7197
7530
  }
7198
7531
  };
7199
7532
 
7200
- NaverMintMapController.prototype.setMarkerZIndex = function (marker, zIndex) {
7533
+ NaverMintMapController.prototype.getCurrentZIndex = function (marker) {
7201
7534
  if (this.map && marker.element && marker.element instanceof HTMLElement) {
7202
7535
  var parent_1 = marker.element.parentElement;
7203
7536
 
7204
- if (parent_1) {
7205
- parent_1.style.zIndex = String(zIndex);
7537
+ if (parent_1 && parent_1.style.zIndex) {
7538
+ var zIndex = Number(parent_1.style.zIndex);
7539
+ return isNaN(zIndex) ? undefined : zIndex;
7540
+ }
7541
+ }
7542
+
7543
+ return undefined;
7544
+ };
7545
+
7546
+ NaverMintMapController.prototype.setMarkerZIndex = function (marker, zIndex) {
7547
+ if (this.map && marker.element && marker.element instanceof HTMLElement) {
7548
+ var parent_2 = marker.element.parentElement;
7549
+
7550
+ if (parent_2) {
7551
+ parent_2.style.zIndex = String(zIndex);
7206
7552
  }
7207
7553
  }
7208
7554
  };
7209
7555
 
7210
7556
  NaverMintMapController.prototype.markerToTheTop = function (marker) {
7557
+ // 이미 최상위로 올라간 상태면 (원래 zIndex가 이미 저장됨) 중복 실행 방지
7558
+ if (this.markerOriginalZIndex !== undefined) {
7559
+ return;
7560
+ }
7561
+
7562
+ var currentZIndex = this.getCurrentZIndex(marker); // undefined면 null로 저장 (원래 zIndex가 없었음을 표시)
7563
+
7564
+ this.markerOriginalZIndex = currentZIndex !== undefined ? currentZIndex : null;
7211
7565
  this.setMarkerZIndex(marker, this.getMaxZIndex(1));
7212
7566
  };
7213
7567
 
7568
+ NaverMintMapController.prototype.restoreMarkerZIndex = function (marker) {
7569
+ if (this.markerOriginalZIndex !== undefined) {
7570
+ if (this.markerOriginalZIndex === null) {
7571
+ // 원래 zIndex가 없었으면 제거 (또는 초기값 0으로)
7572
+ this.setMarkerZIndex(marker, 0);
7573
+ } else {
7574
+ this.setMarkerZIndex(marker, this.markerOriginalZIndex);
7575
+ }
7576
+
7577
+ this.markerOriginalZIndex = undefined;
7578
+ }
7579
+ };
7580
+
7214
7581
  NaverMintMapController.prototype.clearDrawable = function (drawable) {
7215
7582
  var _a;
7216
7583
 
@@ -7965,6 +8332,10 @@
7965
8332
  }
7966
8333
  };
7967
8334
 
8335
+ GoogleMintMapController.prototype.restoreMarkerZIndex = function (marker) {// Google Maps에서는 restoreMarkerZIndex 기능을 지원하지 않습니다.
8336
+ // 이 기능은 Naver Maps에서만 사용 가능합니다.
8337
+ };
8338
+
7968
8339
  GoogleMintMapController.prototype.clearDrawable = function (drawable) {
7969
8340
  if (drawable && drawable.native) {
7970
8341
  if (drawable.native instanceof google.maps.Marker || drawable.native instanceof google.maps.Polygon || drawable.native instanceof google.maps.Polyline) {
@@ -8687,6 +9058,10 @@
8687
9058
  }
8688
9059
  };
8689
9060
 
9061
+ KakaoMintMapController.prototype.restoreMarkerZIndex = function (marker) {// Kakao Maps에서는 restoreMarkerZIndex 기능을 지원하지 않습니다.
9062
+ // 이 기능은 Naver Maps에서만 사용 가능합니다.
9063
+ };
9064
+
8690
9065
  KakaoMintMapController.prototype.clearDrawable = function (drawable) {
8691
9066
  var _this = this;
8692
9067
 
@@ -9290,11 +9665,13 @@
9290
9665
  exports.Spacing = Spacing;
9291
9666
  exports.SpatialHashGrid = SpatialHashGrid;
9292
9667
  exports.Status = Status;
9293
- exports.WoongKonvaMarker = WoongKonvaMarker;
9668
+ exports.WoongCanvasLayer = WoongCanvasLayer;
9669
+ exports.calculateTextBoxWidth = calculateTextBoxWidth;
9294
9670
  exports.computeMarkerOffset = computeMarkerOffset;
9295
9671
  exports.computePolygonOffsets = computePolygonOffsets;
9296
9672
  exports.getClusterInfo = getClusterInfo;
9297
9673
  exports.getMapOfType = getMapOfType;
9674
+ exports.hexToRgba = hexToRgba;
9298
9675
  exports.isPointInMarkerData = isPointInMarkerData;
9299
9676
  exports.isPointInPolygon = isPointInPolygon;
9300
9677
  exports.isPointInPolygonData = isPointInPolygonData;