@mint-ui/map 1.2.0-test.4 → 1.2.0-test.41

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 (42) hide show
  1. package/dist/components/mint-map/core/MintMapCore.js +5 -6
  2. package/dist/components/mint-map/core/advanced/index.d.ts +2 -1
  3. package/dist/components/mint-map/core/advanced/shared/context.d.ts +39 -0
  4. package/dist/components/mint-map/core/advanced/{woongCanvas/shared → shared}/context.js +62 -79
  5. package/dist/components/mint-map/core/advanced/shared/helpers.d.ts +20 -0
  6. package/dist/components/mint-map/core/advanced/shared/helpers.js +40 -0
  7. package/dist/components/mint-map/core/advanced/shared/hooks.d.ts +74 -0
  8. package/dist/components/mint-map/core/advanced/shared/hooks.js +189 -0
  9. package/dist/components/mint-map/core/advanced/{woongCanvas/shared → shared}/index.d.ts +3 -0
  10. package/dist/components/mint-map/core/advanced/shared/performance.d.ts +77 -0
  11. package/dist/components/mint-map/core/advanced/shared/performance.js +262 -0
  12. package/dist/components/mint-map/core/advanced/shared/types.d.ts +126 -0
  13. package/dist/components/mint-map/core/advanced/{woongCanvas/shared → shared}/types.js +4 -1
  14. package/dist/components/mint-map/core/advanced/shared/utils.d.ts +95 -0
  15. package/dist/components/mint-map/core/advanced/shared/utils.js +261 -0
  16. package/dist/components/mint-map/core/advanced/shared/viewport.d.ts +42 -0
  17. package/dist/components/mint-map/core/advanced/shared/viewport.js +51 -0
  18. package/dist/components/mint-map/core/advanced/woongCanvasMarker/WoongCanvasMarker.d.ts +47 -0
  19. package/dist/components/mint-map/core/advanced/woongCanvasMarker/WoongCanvasMarker.js +620 -0
  20. package/dist/components/mint-map/core/advanced/woongCanvasMarker/index.d.ts +3 -0
  21. package/dist/components/mint-map/core/advanced/woongCanvasPolygon/WoongCanvasPolygon.d.ts +61 -0
  22. package/dist/components/mint-map/core/advanced/woongCanvasPolygon/WoongCanvasPolygon.js +582 -0
  23. package/dist/components/mint-map/core/advanced/woongCanvasPolygon/index.d.ts +3 -0
  24. package/dist/components/mint-map/core/advanced/woongCanvasPolygon/renderer.d.ts +120 -0
  25. package/dist/components/mint-map/core/advanced/woongCanvasPolygon/renderer.js +295 -0
  26. package/dist/components/mint-map/google/GoogleMintMapController.js +5 -4
  27. package/dist/components/mint-map/kakao/KakaoMintMapController.js +5 -4
  28. package/dist/components/mint-map/naver/NaverMintMapController.js +5 -4
  29. package/dist/index.es.js +1734 -1041
  30. package/dist/index.js +24 -8
  31. package/dist/index.umd.js +1747 -1042
  32. package/package.json +1 -1
  33. package/dist/components/mint-map/core/advanced/woongCanvas/ClusterMarker.d.ts +0 -11
  34. package/dist/components/mint-map/core/advanced/woongCanvas/WoongKonvaMarker.d.ts +0 -50
  35. package/dist/components/mint-map/core/advanced/woongCanvas/WoongKonvaMarker.js +0 -1065
  36. package/dist/components/mint-map/core/advanced/woongCanvas/index.d.ts +0 -3
  37. package/dist/components/mint-map/core/advanced/woongCanvas/shared/context.d.ts +0 -31
  38. package/dist/components/mint-map/core/advanced/woongCanvas/shared/performance.d.ts +0 -161
  39. package/dist/components/mint-map/core/advanced/woongCanvas/shared/performance.js +0 -343
  40. package/dist/components/mint-map/core/advanced/woongCanvas/shared/types.d.ts +0 -131
  41. package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.d.ts +0 -23
  42. package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.js +0 -115
@@ -0,0 +1,582 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var tslib = require('tslib');
6
+ var React = require('react');
7
+ var Konva = require('konva');
8
+ var MintMapProvider = require('../../provider/MintMapProvider.js');
9
+ var MapDrawables = require('../../../types/MapDrawables.js');
10
+ require('../../../types/MapTypes.js');
11
+ require('../../../types/MapEventTypes.js');
12
+ var reactDom = require('react-dom');
13
+ require('../shared/types.js');
14
+ var utils = require('../shared/utils.js');
15
+ var context = require('../shared/context.js');
16
+ var performance = require('../shared/performance.js');
17
+ var viewport = require('../shared/viewport.js');
18
+ var hooks = require('../shared/hooks.js');
19
+ var helpers = require('../shared/helpers.js');
20
+ var renderer = require('./renderer.js');
21
+
22
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
23
+
24
+ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
25
+ var Konva__default = /*#__PURE__*/_interopDefaultLegacy(Konva);
26
+
27
+ var WoongCanvasPolygon = function (props) {
28
+ var data = props.data,
29
+ onClick = props.onClick,
30
+ _a = props.enableMultiSelect,
31
+ enableMultiSelect = _a === void 0 ? false : _a,
32
+ _b = props.enableViewportCulling,
33
+ enableViewportCulling = _b === void 0 ? false : _b,
34
+ _c = props.cullingMargin,
35
+ cullingMargin = _c === void 0 ? performance.DEFAULT_CULLING_MARGIN : _c,
36
+ _d = props.maxCacheSize,
37
+ maxCacheSize = _d === void 0 ? performance.DEFAULT_MAX_CACHE_SIZE : _d,
38
+ externalSelectedItems = props.selectedItems,
39
+ externalSelectedItem = props.selectedItem,
40
+ _e = props.disableInteraction,
41
+ disableInteraction = _e === void 0 ? false : _e,
42
+ baseFillColor = props.baseFillColor,
43
+ baseStrokeColor = props.baseStrokeColor,
44
+ baseLineWidth = props.baseLineWidth,
45
+ selectedFillColor = props.selectedFillColor,
46
+ selectedStrokeColor = props.selectedStrokeColor,
47
+ selectedLineWidth = props.selectedLineWidth,
48
+ activeFillColor = props.activeFillColor,
49
+ activeStrokeColor = props.activeStrokeColor,
50
+ activeLineWidth = props.activeLineWidth,
51
+ hoveredFillColor = props.hoveredFillColor,
52
+ hoveredStrokeColor = props.hoveredStrokeColor,
53
+ hoveredLineWidth = props.hoveredLineWidth,
54
+ options = tslib.__rest(props, ["data", "onClick", "enableMultiSelect", "enableViewportCulling", "cullingMargin", "maxCacheSize", "selectedItems", "selectedItem", "disableInteraction", "baseFillColor", "baseStrokeColor", "baseLineWidth", "selectedFillColor", "selectedStrokeColor", "selectedLineWidth", "activeFillColor", "activeStrokeColor", "activeLineWidth", "hoveredFillColor", "hoveredStrokeColor", "hoveredLineWidth"]); // --------------------------------------------------------------------------
55
+ // Hooks & Context
56
+ // --------------------------------------------------------------------------
57
+
58
+
59
+ var controller = MintMapProvider.useMintMapController();
60
+ var context$1 = context.useWoongCanvasContext();
61
+ var currentZIndex = options.zIndex !== undefined ? options.zIndex : 0; // DOM Refs
62
+
63
+ var divRef = React.useRef(document.createElement('div'));
64
+ var divElement = divRef.current;
65
+ var containerRef = React.useRef(null);
66
+ var markerRef = React.useRef(); // Konva Refs
67
+
68
+ var stageRef = React.useRef(null);
69
+ var baseLayerRef = React.useRef(null);
70
+ var eventLayerRef = React.useRef(null); // 상태 관리 Refs (React 리렌더링 최소화)
71
+
72
+ var dataRef = React.useRef(data);
73
+ var disableInteractionRef = React.useRef(disableInteraction);
74
+ var enableViewportCullingRef = React.useRef(enableViewportCulling);
75
+ var hoveredItemRef = React.useRef(null);
76
+ var selectedItemRef = React.useRef(externalSelectedItem);
77
+ var selectedIdsRef = React.useRef(new Set());
78
+ var selectedItemsMapRef = React.useRef(new Map()); // 드래그 상태 Refs
79
+
80
+ var draggingRef = React.useRef(false);
81
+ var prevCenterOffsetRef = React.useRef(null);
82
+ var accumTranslateRef = React.useRef({
83
+ x: 0,
84
+ y: 0
85
+ }); // 성능 최적화 Refs
86
+
87
+ var offsetCacheRef = React.useRef(new performance.LRUCache(maxCacheSize));
88
+ var spatialIndexRef = React.useRef(new performance.SpatialHashGrid(performance.SPATIAL_GRID_CELL_SIZE));
89
+ var boundingBoxCacheRef = React.useRef(new Map());
90
+ var viewportRef = React.useRef(null); // 뷰포트 영역 계산 (Viewport Culling용)
91
+
92
+ var updateViewport = function () {
93
+ viewport.updateViewport(stageRef.current, cullingMargin, viewportRef);
94
+ }; // 뷰포트 내부 여부 확인 (바운딩 박스 캐싱)
95
+
96
+
97
+ var isInViewport = function (item) {
98
+ return viewport.isInViewport(item, viewportRef, boundingBoxCacheRef, computeBoundingBox);
99
+ }; // 폴리곤 좌표 변환 (위경도 → 화면 좌표, LRU 캐시 사용)
100
+
101
+
102
+ var getOrComputePolygonOffsets = function (polygonData) {
103
+ var cached = offsetCacheRef.current.get(polygonData.id);
104
+ if (cached && Array.isArray(cached)) return cached;
105
+ var result = utils.computePolygonOffsets(polygonData, controller);
106
+ if (!result) return null;
107
+ offsetCacheRef.current.set(polygonData.id, result);
108
+ return result;
109
+ }; // 폴리곤 바운딩 박스 계산 (Viewport Culling 및 Hit Test용)
110
+
111
+
112
+ var computeBoundingBox = function (item) {
113
+ var offsets = getOrComputePolygonOffsets(item);
114
+ if (!offsets) return null; // 모든 좌표를 순회하며 최소/최대값 찾기
115
+
116
+ var minX = Infinity,
117
+ minY = Infinity,
118
+ maxX = -Infinity,
119
+ maxY = -Infinity;
120
+
121
+ for (var _i = 0, offsets_1 = offsets; _i < offsets_1.length; _i++) {
122
+ var multiPolygon = offsets_1[_i];
123
+
124
+ for (var _a = 0, multiPolygon_1 = multiPolygon; _a < multiPolygon_1.length; _a++) {
125
+ var polygonGroup = multiPolygon_1[_a];
126
+
127
+ for (var _b = 0, polygonGroup_1 = polygonGroup; _b < polygonGroup_1.length; _b++) {
128
+ var _c = polygonGroup_1[_b],
129
+ x = _c[0],
130
+ y = _c[1];
131
+ if (x < minX) minX = x;
132
+ if (y < minY) minY = y;
133
+ if (x > maxX) maxX = x;
134
+ if (y > maxY) maxY = y;
135
+ }
136
+ }
137
+ }
138
+
139
+ return {
140
+ minX: minX,
141
+ minY: minY,
142
+ maxX: maxX,
143
+ maxY: maxY
144
+ };
145
+ }; // 공간 인덱스 빌드 (빠른 Hit Test용)
146
+
147
+
148
+ var buildSpatialIndex = function () {
149
+ hooks.buildSpatialIndex(dataRef.current, spatialIndexRef.current, computeBoundingBox);
150
+ }; // 렌더링 유틸리티 객체
151
+
152
+
153
+ var renderUtils = {
154
+ getOrComputePolygonOffsets: getOrComputePolygonOffsets,
155
+ getOrComputeMarkerOffset: function () {
156
+ return null;
157
+ }
158
+ }; // 렌더링 함수 생성
159
+
160
+ var renderBase = renderer.renderPolygonBase(baseFillColor, baseStrokeColor, baseLineWidth);
161
+ var renderEvent = renderer.renderPolygonEvent(baseFillColor, baseStrokeColor, baseLineWidth, selectedFillColor, selectedStrokeColor, selectedLineWidth, activeFillColor, activeStrokeColor, activeLineWidth, hoveredFillColor, hoveredStrokeColor, hoveredLineWidth); // Base Layer 렌더링 (뷰포트 컬링 적용)
162
+
163
+ var doRenderBase = function () {
164
+ var layer = baseLayerRef.current;
165
+ if (!layer) return;
166
+ var shape = layer.findOne('.base-render-shape');
167
+
168
+ if (!shape) {
169
+ shape = new Konva__default["default"].Shape({
170
+ name: 'base-render-shape',
171
+ sceneFunc: function (context, shape) {
172
+ var ctx = context;
173
+ var hovered = hoveredItemRef.current; // 뷰포트 컬링: 화면에 보이는 항목만 필터링
174
+
175
+ var visibleItems = enableViewportCullingRef.current ? dataRef.current.filter(function (item) {
176
+ return isInViewport(item);
177
+ }) : dataRef.current;
178
+ renderBase({
179
+ ctx: ctx,
180
+ items: visibleItems,
181
+ selectedIds: selectedIdsRef.current,
182
+ hoveredItem: hovered,
183
+ utils: renderUtils
184
+ });
185
+ },
186
+ perfectDrawEnabled: false,
187
+ listening: false,
188
+ hitStrokeWidth: 0
189
+ });
190
+ layer.add(shape);
191
+ }
192
+
193
+ layer.batchDraw();
194
+ }; // Event Layer 렌더링 (hover 효과 및 선택 상태 표시)
195
+
196
+
197
+ var doRenderEvent = function () {
198
+ var layer = eventLayerRef.current;
199
+ if (!layer) return;
200
+ var shape = layer.findOne('.event-render-shape');
201
+
202
+ if (!shape) {
203
+ shape = new Konva__default["default"].Shape({
204
+ name: 'event-render-shape',
205
+ sceneFunc: function (context, shape) {
206
+ var ctx = context;
207
+ var selectedItems = helpers.mapValuesToArray(selectedItemsMapRef.current);
208
+ var hovered = hoveredItemRef.current;
209
+ renderEvent({
210
+ ctx: ctx,
211
+ hoveredItem: hovered,
212
+ utils: renderUtils,
213
+ selectedItems: selectedItems,
214
+ selectedItem: selectedItemRef.current
215
+ });
216
+ },
217
+ perfectDrawEnabled: false,
218
+ listening: false,
219
+ hitStrokeWidth: 0
220
+ });
221
+ layer.add(shape);
222
+ }
223
+
224
+ layer.batchDraw();
225
+ }; // 전체 즉시 렌더링
226
+
227
+
228
+ var renderAllImmediate = function () {
229
+ if (enableViewportCullingRef.current) {
230
+ updateViewport();
231
+ }
232
+
233
+ buildSpatialIndex();
234
+ doRenderBase();
235
+ doRenderEvent();
236
+ }; // 지도 이벤트 핸들러 생성
237
+
238
+
239
+ var _f = hooks.createMapEventHandlers({
240
+ controller: controller,
241
+ containerRef: containerRef,
242
+ markerRef: markerRef,
243
+ options: options,
244
+ prevCenterOffsetRef: prevCenterOffsetRef,
245
+ accumTranslateRef: accumTranslateRef,
246
+ offsetCacheRef: offsetCacheRef,
247
+ boundingBoxCacheRef: boundingBoxCacheRef,
248
+ renderAllImmediate: renderAllImmediate
249
+ }),
250
+ handleIdle = _f.handleIdle,
251
+ handleZoomStart = _f.handleZoomStart,
252
+ handleZoomEnd = _f.handleZoomEnd,
253
+ handleCenterChanged = _f.handleCenterChanged,
254
+ handleDragStartShared = _f.handleDragStart,
255
+ handleDragEndShared = _f.handleDragEnd;
256
+
257
+ var handleDragStart = function () {
258
+ handleDragStartShared();
259
+ draggingRef.current = true;
260
+ controller.setMapCursor('grabbing');
261
+ };
262
+
263
+ var handleDragEnd = function () {
264
+ handleDragEndShared();
265
+ draggingRef.current = false;
266
+ controller.setMapCursor('grab');
267
+ }; // Hit Test: 특정 좌표의 폴리곤 찾기
268
+
269
+
270
+ var findData = function (offset) {
271
+ // 공간 인덱스에서 후보 항목 조회 (O(1) 수준의 빠른 조회)
272
+ var candidates = spatialIndexRef.current.queryPoint(offset.x, offset.y); // 역순 순회: 나중에 추가된 항목(최상위)이 먼저 선택되도록
273
+
274
+ for (var i = candidates.length - 1; i >= 0; i--) {
275
+ var item = candidates[i]; // 정확한 Hit Test: Ray Casting 알고리즘으로 폴리곤 내부 여부 확인
276
+
277
+ if (utils.isPointInPolygonData(offset, item, getOrComputePolygonOffsets)) {
278
+ return item;
279
+ }
280
+ }
281
+
282
+ return null;
283
+ }; // Hover 상태 설정 및 렌더링
284
+
285
+
286
+ var setHovered = function (data) {
287
+ hoveredItemRef.current = data;
288
+
289
+ if (draggingRef.current) {
290
+ controller.setMapCursor('grabbing');
291
+ } else {
292
+ controller.setMapCursor(data ? 'pointer' : 'grab');
293
+ }
294
+
295
+ doRenderEvent();
296
+ }; // 클릭 처리: 선택 상태 업데이트
297
+
298
+
299
+ var handleLocalClick = function (data) {
300
+ if (enableMultiSelect) {
301
+ var newSelected = new Set(selectedIdsRef.current);
302
+
303
+ if (newSelected.has(data.id)) {
304
+ newSelected.delete(data.id);
305
+ selectedItemsMapRef.current.delete(data.id);
306
+ } else {
307
+ newSelected.add(data.id);
308
+ selectedItemsMapRef.current.set(data.id, data);
309
+ }
310
+
311
+ selectedIdsRef.current = newSelected;
312
+ } else {
313
+ var newSelected = new Set();
314
+
315
+ if (!selectedIdsRef.current.has(data.id)) {
316
+ newSelected.add(data.id);
317
+ selectedItemsMapRef.current.clear();
318
+ selectedItemsMapRef.current.set(data.id, data);
319
+ } else {
320
+ selectedItemsMapRef.current.clear();
321
+ }
322
+
323
+ selectedIdsRef.current = newSelected;
324
+ }
325
+
326
+ doRenderBase();
327
+ doRenderEvent();
328
+ }; // 클릭 이벤트 핸들러
329
+
330
+
331
+ var handleClick = function (event) {
332
+ if (disableInteractionRef.current) return;
333
+ var clickedOffset = helpers.validateEvent(event, context$1, controller);
334
+ if (!clickedOffset) return;
335
+ var data = findData(clickedOffset);
336
+ if (!data) return;
337
+ handleLocalClick(data);
338
+ onClick === null || onClick === void 0 ? void 0 : onClick(data, selectedIdsRef.current);
339
+ }; // 마우스 이동 이벤트 핸들러 (hover 감지)
340
+
341
+
342
+ var handleMouseMove = function (event) {
343
+ if (disableInteractionRef.current) return;
344
+ var mouseOffset = helpers.validateEvent(event, context$1, controller);
345
+ if (!mouseOffset) return;
346
+ var hoveredItem = findData(mouseOffset);
347
+ var prevHovered = hoveredItemRef.current;
348
+ if (prevHovered === hoveredItem) return;
349
+ setHovered(hoveredItem);
350
+ }; // 마우스가 맵 영역을 벗어날 때 hover 상태 초기화
351
+
352
+
353
+ var handleMouseLeave = function () {
354
+ if (disableInteractionRef.current) return;
355
+ var prevHovered = hoveredItemRef.current;
356
+ if (!prevHovered) return;
357
+ hoveredItemRef.current = null;
358
+ controller.setMapCursor('grab');
359
+ doRenderEvent();
360
+ }; // DOM 초기화
361
+
362
+
363
+ React.useEffect(function () {
364
+ divElement.style.width = 'fit-content';
365
+ return function () {
366
+ if (!markerRef.current) return;
367
+ controller.clearDrawable(markerRef.current);
368
+ markerRef.current = undefined;
369
+ };
370
+ }, []); // 마커 생성/업데이트
371
+
372
+ React.useEffect(function () {
373
+ if (!options) return;
374
+ var bounds = controller.getCurrBounds();
375
+
376
+ var markerOptions = tslib.__assign({
377
+ position: bounds.nw
378
+ }, options);
379
+
380
+ if (markerRef.current) {
381
+ controller.updateMarker(markerRef.current, markerOptions);
382
+ return;
383
+ }
384
+
385
+ markerRef.current = new MapDrawables.Marker(markerOptions);
386
+ markerRef.current.element = divElement;
387
+ controller.createMarker(markerRef.current);
388
+
389
+ if (divElement.parentElement) {
390
+ divElement.parentElement.style.pointerEvents = 'none';
391
+ }
392
+
393
+ if (options.zIndex !== undefined) {
394
+ controller.setMarkerZIndex(markerRef.current, options.zIndex);
395
+ }
396
+ }, [options]); // Konva 초기화 및 이벤트 리스너 등록
397
+
398
+ React.useEffect(function () {
399
+ var mapDiv = controller.mapDivElement;
400
+ var stage = new Konva__default["default"].Stage({
401
+ container: containerRef.current,
402
+ width: mapDiv.offsetWidth,
403
+ height: mapDiv.offsetHeight
404
+ });
405
+ stageRef.current = stage;
406
+ var baseLayer = new Konva__default["default"].Layer({
407
+ listening: false
408
+ });
409
+ var eventLayer = new Konva__default["default"].Layer({
410
+ listening: false
411
+ });
412
+ baseLayerRef.current = baseLayer;
413
+ eventLayerRef.current = eventLayer;
414
+ stage.add(baseLayer);
415
+ stage.add(eventLayer);
416
+
417
+ if (enableViewportCulling) {
418
+ updateViewport();
419
+ } // ResizeObserver: 맵 크기 변경 감지 (RAF로 debounce)
420
+
421
+
422
+ var resizeRafId = null;
423
+ var resizeObserver = new ResizeObserver(function () {
424
+ if (resizeRafId !== null) {
425
+ cancelAnimationFrame(resizeRafId);
426
+ }
427
+
428
+ resizeRafId = requestAnimationFrame(function () {
429
+ stage.width(mapDiv.offsetWidth);
430
+ stage.height(mapDiv.offsetHeight);
431
+ offsetCacheRef.current.clear();
432
+ boundingBoxCacheRef.current.clear();
433
+
434
+ if (enableViewportCullingRef.current) {
435
+ updateViewport();
436
+ }
437
+
438
+ renderAllImmediate();
439
+ resizeRafId = null;
440
+ });
441
+ });
442
+ resizeObserver.observe(mapDiv);
443
+ controller.addEventListener('IDLE', handleIdle);
444
+ controller.addEventListener('ZOOMSTART', handleZoomStart);
445
+ controller.addEventListener('ZOOM_CHANGED', handleZoomEnd);
446
+ controller.addEventListener('CENTER_CHANGED', handleCenterChanged);
447
+ controller.addEventListener('CLICK', handleClick);
448
+ controller.addEventListener('MOUSEMOVE', handleMouseMove);
449
+ controller.addEventListener('DRAGSTART', handleDragStart);
450
+ controller.addEventListener('DRAGEND', handleDragEnd);
451
+ mapDiv.addEventListener('mouseleave', handleMouseLeave);
452
+ renderAllImmediate(); // Context 사용 시 컴포넌트 등록
453
+
454
+ var componentInstance = null;
455
+
456
+ if (context$1) {
457
+ componentInstance = {
458
+ zIndex: currentZIndex,
459
+ hitTest: function (offset) {
460
+ return findData(offset) !== null;
461
+ },
462
+ onClick: onClick,
463
+ findData: findData,
464
+ setHovered: setHovered,
465
+ handleLocalClick: handleLocalClick,
466
+ getSelectedIds: function () {
467
+ return selectedIdsRef.current;
468
+ },
469
+ isInteractionDisabled: function () {
470
+ return disableInteractionRef.current;
471
+ }
472
+ };
473
+ context$1.registerComponent(componentInstance);
474
+ }
475
+
476
+ return function () {
477
+ if (resizeRafId !== null) {
478
+ cancelAnimationFrame(resizeRafId);
479
+ }
480
+
481
+ resizeObserver.disconnect();
482
+ controller.removeEventListener('IDLE', handleIdle);
483
+ controller.removeEventListener('ZOOMSTART', handleZoomStart);
484
+ controller.removeEventListener('ZOOM_CHANGED', handleZoomEnd);
485
+ controller.removeEventListener('CENTER_CHANGED', handleCenterChanged);
486
+ controller.removeEventListener('CLICK', handleClick);
487
+ controller.removeEventListener('MOUSEMOVE', handleMouseMove);
488
+ controller.removeEventListener('DRAGSTART', handleDragStart);
489
+ controller.removeEventListener('DRAGEND', handleDragEnd);
490
+ mapDiv.removeEventListener('mouseleave', handleMouseLeave);
491
+
492
+ if (context$1 && componentInstance) {
493
+ context$1.unregisterComponent(componentInstance);
494
+ }
495
+
496
+ baseLayer.destroyChildren();
497
+ eventLayer.destroyChildren();
498
+ stage.destroy();
499
+ offsetCacheRef.current.clear();
500
+ boundingBoxCacheRef.current.clear();
501
+ spatialIndexRef.current.clear();
502
+ };
503
+ }, []); // disableInteraction 동기화
504
+
505
+ React.useEffect(function () {
506
+ disableInteractionRef.current = disableInteraction;
507
+ }, [disableInteraction]); // enableViewportCulling 동기화
508
+
509
+ React.useEffect(function () {
510
+ enableViewportCullingRef.current = enableViewportCulling;
511
+
512
+ if (stageRef.current) {
513
+ // 뷰포트 컬링 설정이 변경되면 shape 재생성 필요
514
+ var baseLayer = baseLayerRef.current;
515
+
516
+ if (baseLayer) {
517
+ var shape = baseLayer.findOne('.base-render-shape');
518
+
519
+ if (shape) {
520
+ shape.destroy();
521
+ }
522
+ }
523
+
524
+ var eventLayer = eventLayerRef.current;
525
+
526
+ if (eventLayer) {
527
+ var shape = eventLayer.findOne('.event-render-shape');
528
+
529
+ if (shape) {
530
+ shape.destroy();
531
+ }
532
+ }
533
+
534
+ renderAllImmediate();
535
+ }
536
+ }, [enableViewportCulling]); // 외부 selectedItems 동기화
537
+
538
+ React.useEffect(function () {
539
+ if (!stageRef.current) return;
540
+ hooks.syncExternalSelectedItems(externalSelectedItems, selectedIdsRef, selectedItemsMapRef);
541
+ doRenderBase();
542
+ doRenderEvent();
543
+ }, [externalSelectedItems]); // 외부 selectedItem 변경 시 Event Layer 리렌더링
544
+
545
+ React.useEffect(function () {
546
+ if (!stageRef.current) return;
547
+ selectedItemRef.current = externalSelectedItem;
548
+ doRenderEvent();
549
+ }, [externalSelectedItem]); // 데이터 변경 시 렌더링 (캐시 정리 및 선택 상태 동기화)
550
+
551
+ React.useEffect(function () {
552
+ if (!stageRef.current) return;
553
+ dataRef.current = data;
554
+
555
+ if (containerRef.current) {
556
+ containerRef.current.style.transform = '';
557
+ }
558
+
559
+ prevCenterOffsetRef.current = null;
560
+ accumTranslateRef.current = {
561
+ x: 0,
562
+ y: 0
563
+ };
564
+ offsetCacheRef.current.clear();
565
+ boundingBoxCacheRef.current.clear();
566
+ selectedItemsMapRef.current = hooks.syncSelectedItems(data, selectedIdsRef.current, selectedItemsMapRef.current);
567
+ renderAllImmediate();
568
+ }, [data]);
569
+ return reactDom.createPortal(React__default["default"].createElement("div", {
570
+ ref: containerRef,
571
+ style: {
572
+ position: 'absolute',
573
+ width: '100%',
574
+ height: '100%'
575
+ }
576
+ }), divElement);
577
+ };
578
+
579
+ exports.WoongCanvasProvider = context.WoongCanvasProvider;
580
+ exports.LRUCache = performance.LRUCache;
581
+ exports.SpatialHashGrid = performance.SpatialHashGrid;
582
+ exports["default"] = WoongCanvasPolygon;
@@ -0,0 +1,3 @@
1
+ export { default as WoongCanvasPolygon } from "./WoongCanvasPolygon";
2
+ export * from "./WoongCanvasPolygon";
3
+ export * from "../shared";
@@ -0,0 +1,120 @@
1
+ /**
2
+ * 폴리곤 렌더링 유틸리티
3
+ *
4
+ * 이 파일은 폴리곤 렌더링을 위한 헬퍼 함수와 팩토리 함수를 제공합니다.
5
+ * GeoJSON MultiPolygon 형식을 지원하며, 도넛 폴리곤(구멍이 있는 폴리곤)도 처리할 수 있습니다.
6
+ */
7
+ import { CustomRenderBase, CustomRenderEvent } from "../shared/types";
8
+ /**
9
+ * 폴리곤 그리기 파라미터 인터페이스
10
+ */
11
+ interface DrawPolygonParams {
12
+ /** Canvas 2D 렌더링 컨텍스트 */
13
+ ctx: CanvasRenderingContext2D;
14
+ /** 변환된 폴리곤 좌표 배열 (4차원: [MultiPolygon][Polygon][Point][x/y]) */
15
+ polygonOffsets: number[][][][];
16
+ /** 도넛 폴리곤 여부 (구멍이 있는 폴리곤) */
17
+ isDonutPolygon: boolean;
18
+ /** 채우기 색상 */
19
+ fillColor: string;
20
+ /** 테두리 색상 */
21
+ strokeColor: string;
22
+ /** 테두리 두께 */
23
+ lineWidth: number;
24
+ }
25
+ /**
26
+ * 폴리곤 그리기 헬퍼 함수 (도넛 폴리곤 지원)
27
+ *
28
+ * Canvas 2D Context를 사용하여 폴리곤을 그립니다.
29
+ * 도넛 폴리곤의 경우 evenodd fill rule을 사용하여 구멍을 처리합니다.
30
+ *
31
+ * @param params 폴리곤 그리기 파라미터
32
+ *
33
+ * @remarks
34
+ * - **도넛 폴리곤 처리**:
35
+ * - 외부 폴리곤과 내부 구멍들을 같은 path에 추가
36
+ * - `fill('evenodd')`를 사용하여 구멍 뚫기
37
+ * - **일반 폴리곤 처리**: 각 폴리곤 그룹을 개별적으로 그리기
38
+ * - **성능**: O(n), n은 폴리곤의 총 좌표 수
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * drawPolygon({
43
+ * ctx,
44
+ * polygonOffsets: [[[[100, 200], [200, 200], [200, 100], [100, 100]]]],
45
+ * isDonutPolygon: false,
46
+ * fillColor: 'rgba(255, 0, 0, 0.5)',
47
+ * strokeColor: 'rgba(255, 0, 0, 1)',
48
+ * lineWidth: 2
49
+ * });
50
+ * ```
51
+ */
52
+ export declare const drawPolygon: ({ ctx, polygonOffsets, isDonutPolygon, fillColor, strokeColor, lineWidth }: DrawPolygonParams) => void;
53
+ /**
54
+ * 폴리곤 Base 렌더링 함수 팩토리
55
+ *
56
+ * Base Layer에서 사용할 렌더링 함수를 생성합니다.
57
+ * 선택되지 않은 폴리곤만 렌더링하며, 선택된 항목은 Event Layer에서 처리됩니다.
58
+ *
59
+ * @template T 폴리곤 데이터의 추가 속성 타입
60
+ * @param baseFillColor 기본 폴리곤 채우기 색상
61
+ * @param baseStrokeColor 기본 폴리곤 테두리 색상
62
+ * @param baseLineWidth 기본 폴리곤 테두리 두께
63
+ * @returns Base Layer 렌더링 함수
64
+ *
65
+ * @remarks
66
+ * - 선택된 항목은 Event Layer에서 그려지므로 Base Layer에서는 스킵
67
+ * - 성능: O(n), n은 렌더링할 폴리곤 개수
68
+ * - 좌표 변환은 자동으로 캐싱되어 성능 최적화됨
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const renderBase = renderPolygonBase(
73
+ * 'rgba(255, 100, 100, 0.5)',
74
+ * 'rgba(200, 50, 50, 0.8)',
75
+ * 2
76
+ * );
77
+ * ```
78
+ */
79
+ export declare const renderPolygonBase: <T = any>(baseFillColor: string, baseStrokeColor: string, baseLineWidth: number) => CustomRenderBase<T>;
80
+ /**
81
+ * 폴리곤 Event 렌더링 함수 팩토리
82
+ *
83
+ * Event Layer에서 사용할 렌더링 함수를 생성합니다.
84
+ * 선택된 항목, hover된 항목, 마지막 선택된 항목을 각각 다른 스타일로 렌더링합니다.
85
+ *
86
+ * @template T 폴리곤 데이터의 추가 속성 타입
87
+ * @param baseFillColor 기본 폴리곤 채우기 색상 (필수, fallback용)
88
+ * @param baseStrokeColor 기본 폴리곤 테두리 색상 (필수, fallback용)
89
+ * @param baseLineWidth 기본 폴리곤 테두리 두께 (필수, fallback용)
90
+ * @param selectedFillColor 선택된 폴리곤 채우기 색상 (선택, 기본값: baseFillColor)
91
+ * @param selectedStrokeColor 선택된 폴리곤 테두리 색상 (선택, 기본값: baseStrokeColor)
92
+ * @param selectedLineWidth 선택된 폴리곤 테두리 두께 (선택, 기본값: baseLineWidth)
93
+ * @param activeFillColor 마지막 선택된 폴리곤 채우기 색상 (선택, 기본값: selectedFillColor)
94
+ * @param activeStrokeColor 마지막 선택된 폴리곤 테두리 색상 (선택, 기본값: selectedStrokeColor)
95
+ * @param activeLineWidth 마지막 선택된 폴리곤 테두리 두께 (선택, 기본값: selectedLineWidth)
96
+ * @param hoveredFillColor Hover 시 폴리곤 채우기 색상 (선택, 기본값: selectedFillColor)
97
+ * @param hoveredStrokeColor Hover 시 폴리곤 테두리 색상 (선택, 기본값: selectedStrokeColor)
98
+ * @param hoveredLineWidth Hover 시 폴리곤 테두리 두께 (선택, 기본값: selectedLineWidth)
99
+ * @returns Event Layer 렌더링 함수
100
+ *
101
+ * @remarks
102
+ * - **렌더링 순서**: 선택된 항목 → 마지막 선택된 항목 → hover된 항목 (최상단)
103
+ * - **성능**: O(m), m은 선택된 항목 수 + hover된 항목 수
104
+ * - 좌표 변환은 자동으로 캐싱되어 성능 최적화됨
105
+ * - hover된 항목이 선택되어 있으면 active 스타일 적용
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * const renderEvent = renderPolygonEvent(
110
+ * 'rgba(255, 100, 100, 0.5)', // baseFillColor
111
+ * 'rgba(200, 50, 50, 0.8)', // baseStrokeColor
112
+ * 2, // baseLineWidth
113
+ * 'rgba(255, 193, 7, 0.7)', // selectedFillColor
114
+ * 'rgba(255, 152, 0, 1)', // selectedStrokeColor
115
+ * 4 // selectedLineWidth
116
+ * );
117
+ * ```
118
+ */
119
+ export declare const renderPolygonEvent: <T = any>(baseFillColor: string, baseStrokeColor: string, baseLineWidth: number, selectedFillColor?: string, selectedStrokeColor?: string, selectedLineWidth?: number, activeFillColor?: string, activeStrokeColor?: string, activeLineWidth?: number, hoveredFillColor?: string, hoveredStrokeColor?: string, hoveredLineWidth?: number) => CustomRenderEvent<T>;
120
+ export {};