@mint-ui/map 1.2.0-test.33 → 1.2.0-test.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/mint-map/core/advanced/shared/context.d.ts +71 -2
- package/dist/components/mint-map/core/advanced/shared/context.js +74 -1
- package/dist/components/mint-map/core/advanced/shared/helpers.d.ts +28 -0
- package/dist/components/mint-map/core/advanced/shared/helpers.js +52 -0
- package/dist/components/mint-map/core/advanced/shared/hooks.d.ts +144 -0
- package/dist/components/mint-map/core/advanced/shared/hooks.js +283 -0
- package/dist/components/mint-map/core/advanced/shared/index.d.ts +3 -0
- package/dist/components/mint-map/core/advanced/shared/performance.d.ts +105 -24
- package/dist/components/mint-map/core/advanced/shared/performance.js +105 -24
- package/dist/components/mint-map/core/advanced/shared/utils.d.ts +128 -14
- package/dist/components/mint-map/core/advanced/shared/utils.js +128 -14
- package/dist/components/mint-map/core/advanced/shared/viewport.d.ts +72 -0
- package/dist/components/mint-map/core/advanced/shared/viewport.js +81 -0
- package/dist/components/mint-map/core/advanced/woongCanvasMarker/WoongCanvasMarker.js +142 -209
- package/dist/components/mint-map/core/advanced/woongCanvasPolygon/WoongCanvasPolygon.d.ts +0 -4
- package/dist/components/mint-map/core/advanced/woongCanvasPolygon/WoongCanvasPolygon.js +122 -217
- package/dist/components/mint-map/core/advanced/woongCanvasPolygon/renderer.d.ts +64 -5
- package/dist/components/mint-map/core/advanced/woongCanvasPolygon/renderer.js +81 -20
- package/dist/index.es.js +1066 -511
- package/dist/index.js +11 -0
- package/dist/index.umd.js +1072 -509
- package/package.json +1 -1
|
@@ -14,6 +14,9 @@ require('../shared/types.js');
|
|
|
14
14
|
var utils = require('../shared/utils.js');
|
|
15
15
|
var context = require('../shared/context.js');
|
|
16
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');
|
|
17
20
|
var renderer = require('./renderer.js');
|
|
18
21
|
|
|
19
22
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
@@ -27,8 +30,6 @@ var Konva__default = /*#__PURE__*/_interopDefaultLegacy(Konva);
|
|
|
27
30
|
var WoongCanvasPolygon = function (props) {
|
|
28
31
|
var data = props.data,
|
|
29
32
|
onClick = props.onClick,
|
|
30
|
-
onMouseOver = props.onMouseOver,
|
|
31
|
-
onMouseOut = props.onMouseOut,
|
|
32
33
|
_a = props.enableMultiSelect,
|
|
33
34
|
enableMultiSelect = _a === void 0 ? false : _a,
|
|
34
35
|
_b = props.enableViewportCulling,
|
|
@@ -53,7 +54,7 @@ var WoongCanvasPolygon = function (props) {
|
|
|
53
54
|
hoveredFillColor = props.hoveredFillColor,
|
|
54
55
|
hoveredStrokeColor = props.hoveredStrokeColor,
|
|
55
56
|
hoveredLineWidth = props.hoveredLineWidth,
|
|
56
|
-
options = tslib.__rest(props, ["data", "onClick", "
|
|
57
|
+
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"]); // --------------------------------------------------------------------------
|
|
57
58
|
// Hooks & Context
|
|
58
59
|
// --------------------------------------------------------------------------
|
|
59
60
|
|
|
@@ -153,14 +154,7 @@ var WoongCanvasPolygon = function (props) {
|
|
|
153
154
|
*/
|
|
154
155
|
|
|
155
156
|
var updateViewport = function () {
|
|
156
|
-
|
|
157
|
-
var stage = stageRef.current;
|
|
158
|
-
viewportRef.current = {
|
|
159
|
-
minX: -cullingMargin,
|
|
160
|
-
maxX: stage.width() + cullingMargin,
|
|
161
|
-
minY: -cullingMargin,
|
|
162
|
-
maxY: stage.height() + cullingMargin
|
|
163
|
-
};
|
|
157
|
+
viewport.updateViewport(stageRef.current, cullingMargin, viewportRef);
|
|
164
158
|
};
|
|
165
159
|
/**
|
|
166
160
|
* 아이템이 현재 뷰포트 안에 있는지 확인 (바운딩 박스 캐싱)
|
|
@@ -168,21 +162,7 @@ var WoongCanvasPolygon = function (props) {
|
|
|
168
162
|
|
|
169
163
|
|
|
170
164
|
var isInViewport = function (item) {
|
|
171
|
-
|
|
172
|
-
var viewport = viewportRef.current; // 캐시된 바운딩 박스 확인
|
|
173
|
-
|
|
174
|
-
var bbox = boundingBoxCacheRef.current.get(item.id);
|
|
175
|
-
|
|
176
|
-
if (!bbox) {
|
|
177
|
-
// 바운딩 박스 계산 (공통 함수 사용)
|
|
178
|
-
var computed = computeBoundingBox(item);
|
|
179
|
-
if (!computed) return false;
|
|
180
|
-
bbox = computed;
|
|
181
|
-
boundingBoxCacheRef.current.set(item.id, bbox);
|
|
182
|
-
} // 바운딩 박스와 viewport 교차 체크
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
return !(bbox.maxX < viewport.minX || bbox.minX > viewport.maxX || bbox.maxY < viewport.minY || bbox.minY > viewport.maxY);
|
|
165
|
+
return viewport.isInViewport(item, enableViewportCulling, viewportRef, boundingBoxCacheRef, computeBoundingBox);
|
|
186
166
|
}; // --------------------------------------------------------------------------
|
|
187
167
|
// 유틸리티 함수: 좌표 변환 캐싱
|
|
188
168
|
// --------------------------------------------------------------------------
|
|
@@ -211,8 +191,23 @@ var WoongCanvasPolygon = function (props) {
|
|
|
211
191
|
/**
|
|
212
192
|
* 폴리곤의 바운딩 박스 계산
|
|
213
193
|
*
|
|
194
|
+
* 폴리곤의 모든 좌표를 순회하여 최소/최대 X, Y 값을 계산합니다.
|
|
195
|
+
* Viewport Culling에 사용되며, MultiPolygon 형식을 지원합니다.
|
|
196
|
+
*
|
|
214
197
|
* @param item 폴리곤 데이터
|
|
215
|
-
* @returns 바운딩 박스 또는 null
|
|
198
|
+
* @returns 바운딩 박스 (minX, minY, maxX, maxY) 또는 null (좌표 변환 실패 시)
|
|
199
|
+
*
|
|
200
|
+
* @remarks
|
|
201
|
+
* - 성능: O(n), n은 폴리곤의 총 좌표 수
|
|
202
|
+
* - 바운딩 박스는 캐시되어 성능 최적화
|
|
203
|
+
* - MultiPolygon의 모든 좌표를 고려하여 계산
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```typescript
|
|
207
|
+
* const bbox = computeBoundingBox(item);
|
|
208
|
+
* if (!bbox) return; // 계산 실패
|
|
209
|
+
* // bbox.minX, bbox.minY, bbox.maxX, bbox.maxY 사용
|
|
210
|
+
* ```
|
|
216
211
|
*/
|
|
217
212
|
|
|
218
213
|
|
|
@@ -259,19 +254,7 @@ var WoongCanvasPolygon = function (props) {
|
|
|
259
254
|
|
|
260
255
|
|
|
261
256
|
var buildSpatialIndex = function () {
|
|
262
|
-
|
|
263
|
-
spatial.clear();
|
|
264
|
-
var currentData = dataRef.current;
|
|
265
|
-
|
|
266
|
-
for (var _i = 0, currentData_1 = currentData; _i < currentData_1.length; _i++) {
|
|
267
|
-
var item = currentData_1[_i]; // 바운딩 박스 계산 (공통 함수 사용)
|
|
268
|
-
|
|
269
|
-
var bbox = computeBoundingBox(item);
|
|
270
|
-
|
|
271
|
-
if (bbox) {
|
|
272
|
-
spatial.insert(item, bbox.minX, bbox.minY, bbox.maxX, bbox.maxY);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
257
|
+
hooks.buildSpatialIndex(dataRef.current, spatialIndexRef.current, computeBoundingBox);
|
|
275
258
|
}; // --------------------------------------------------------------------------
|
|
276
259
|
// 렌더링 함수 결정 (dataType에 따라)
|
|
277
260
|
// --------------------------------------------------------------------------
|
|
@@ -294,11 +277,8 @@ var WoongCanvasPolygon = function (props) {
|
|
|
294
277
|
|
|
295
278
|
var renderBase = renderer.renderPolygonBase(baseFillColor, baseStrokeColor, baseLineWidth);
|
|
296
279
|
var renderEvent = renderer.renderPolygonEvent(baseFillColor, baseStrokeColor, baseLineWidth, selectedFillColor, selectedStrokeColor, selectedLineWidth, activeFillColor, activeStrokeColor, activeLineWidth, hoveredFillColor, hoveredStrokeColor, hoveredLineWidth);
|
|
297
|
-
/** Base Layer에서 사용할 빈 Set (재사용) */
|
|
298
|
-
|
|
299
|
-
React.useRef(new Set());
|
|
300
280
|
/**
|
|
301
|
-
* Base 레이어 렌더링 (뷰포트 컬링
|
|
281
|
+
* Base 레이어 렌더링 (뷰포트 컬링 적용)
|
|
302
282
|
*
|
|
303
283
|
* 🔥 최적화:
|
|
304
284
|
* 1. Shape 재사용으로 객체 생성/파괴 오버헤드 제거
|
|
@@ -350,10 +330,16 @@ var WoongCanvasPolygon = function (props) {
|
|
|
350
330
|
/**
|
|
351
331
|
* Event 레이어 렌더링 (hover + 선택 상태 표시)
|
|
352
332
|
*
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
*
|
|
333
|
+
* 폴리곤의 hover 효과 및 선택 상태를 표시합니다.
|
|
334
|
+
* 자동 렌더링 방식으로 renderPolygonEvent를 사용합니다.
|
|
335
|
+
*
|
|
336
|
+
* @remarks
|
|
337
|
+
* - **성능 최적화**:
|
|
338
|
+
* 1. Shape 재사용으로 객체 생성/파괴 오버헤드 제거
|
|
339
|
+
* 2. sceneFunc 한 번만 설정 (함수 재생성 제거)
|
|
340
|
+
* 3. 클로저로 최신 데이터 참조
|
|
341
|
+
* - 선택된 항목은 Map에서 O(1)로 조회하여 성능 최적화
|
|
342
|
+
* - 자동 렌더링: 스타일 props(selectedFillColor, hoveredFillColor 등) 기반으로 자동 렌더링
|
|
357
343
|
*/
|
|
358
344
|
|
|
359
345
|
|
|
@@ -370,8 +356,9 @@ var WoongCanvasPolygon = function (props) {
|
|
|
370
356
|
name: 'event-render-shape',
|
|
371
357
|
sceneFunc: function (context, shape) {
|
|
372
358
|
var ctx = context; // 클로저로 최신 ref 값 참조
|
|
359
|
+
// 성능 최적화: Array.from 대신 직접 변환 (메모리 할당 최소화)
|
|
373
360
|
|
|
374
|
-
var selectedItems =
|
|
361
|
+
var selectedItems = helpers.mapValuesToArray(selectedItemsMapRef.current);
|
|
375
362
|
var hovered = hoveredItemRef.current; // 일반 렌더링
|
|
376
363
|
|
|
377
364
|
renderEvent({
|
|
@@ -394,6 +381,13 @@ var WoongCanvasPolygon = function (props) {
|
|
|
394
381
|
};
|
|
395
382
|
/**
|
|
396
383
|
* 전체 즉시 렌더링 (IDLE 시 호출)
|
|
384
|
+
*
|
|
385
|
+
* 뷰포트 업데이트, 공간 인덱스 빌드, 모든 레이어 렌더링을 순차적으로 수행합니다.
|
|
386
|
+
*
|
|
387
|
+
* @remarks
|
|
388
|
+
* - 호출 시점: 지도 이동/줌 완료 시, 데이터 변경 시, 리사이즈 시
|
|
389
|
+
* - 순서: 뷰포트 업데이트 → 공간 인덱스 빌드 → Base → Event 렌더링
|
|
390
|
+
* - Animation Layer는 사용하지 않음 (폴리곤 특성)
|
|
397
391
|
*/
|
|
398
392
|
|
|
399
393
|
|
|
@@ -406,89 +400,43 @@ var WoongCanvasPolygon = function (props) {
|
|
|
406
400
|
// 이벤트 핸들러: 지도 이벤트
|
|
407
401
|
// --------------------------------------------------------------------------
|
|
408
402
|
|
|
409
|
-
/**
|
|
410
|
-
* 지도 이동/줌 완료 시 처리
|
|
411
|
-
*/
|
|
412
403
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
markerRef.current && controller.updateMarker(markerRef.current, markerOptions); // 4. transform 제거 전에 새 데이터로 즉시 렌더링 (겹침 방지)
|
|
431
|
-
|
|
432
|
-
if (containerRef.current) {
|
|
433
|
-
containerRef.current.style.transform = '';
|
|
434
|
-
containerRef.current.style.visibility = '';
|
|
435
|
-
} // 5. 새 위치에서 렌더링
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
renderAllImmediate();
|
|
439
|
-
};
|
|
440
|
-
/**
|
|
441
|
-
* 줌 시작 시 처리 (일시적으로 숨김)
|
|
442
|
-
*/
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
var handleZoomStart = function () {
|
|
446
|
-
if (containerRef.current) {
|
|
447
|
-
containerRef.current.style.visibility = 'hidden';
|
|
448
|
-
}
|
|
449
|
-
};
|
|
404
|
+
var _f = hooks.createMapEventHandlers({
|
|
405
|
+
controller: controller,
|
|
406
|
+
containerRef: containerRef,
|
|
407
|
+
markerRef: markerRef,
|
|
408
|
+
options: options,
|
|
409
|
+
prevCenterOffsetRef: prevCenterOffsetRef,
|
|
410
|
+
accumTranslateRef: accumTranslateRef,
|
|
411
|
+
offsetCacheRef: offsetCacheRef,
|
|
412
|
+
boundingBoxCacheRef: boundingBoxCacheRef,
|
|
413
|
+
renderAllImmediate: renderAllImmediate
|
|
414
|
+
}),
|
|
415
|
+
handleIdle = _f.handleIdle,
|
|
416
|
+
handleZoomStart = _f.handleZoomStart,
|
|
417
|
+
handleZoomEnd = _f.handleZoomEnd,
|
|
418
|
+
handleCenterChanged = _f.handleCenterChanged,
|
|
419
|
+
handleDragStartShared = _f.handleDragStart,
|
|
420
|
+
handleDragEndShared = _f.handleDragEnd;
|
|
450
421
|
/**
|
|
451
|
-
*
|
|
422
|
+
* 드래그 시작 처리 (커서를 grabbing으로 변경)
|
|
452
423
|
*/
|
|
453
424
|
|
|
454
425
|
|
|
455
|
-
var
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
426
|
+
var handleDragStart = function () {
|
|
427
|
+
handleDragStartShared();
|
|
428
|
+
draggingRef.current = true;
|
|
429
|
+
controller.setMapCursor('grabbing');
|
|
459
430
|
};
|
|
460
431
|
/**
|
|
461
|
-
*
|
|
432
|
+
* 드래그 종료 처리 (커서를 기본으로 복원)
|
|
462
433
|
*/
|
|
463
434
|
|
|
464
435
|
|
|
465
|
-
var
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
if (!prev) {
|
|
471
|
-
prevCenterOffsetRef.current = {
|
|
472
|
-
x: curr.x,
|
|
473
|
-
y: curr.y
|
|
474
|
-
};
|
|
475
|
-
return;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
var dx = prev.x - curr.x;
|
|
479
|
-
var dy = prev.y - curr.y;
|
|
480
|
-
accumTranslateRef.current = {
|
|
481
|
-
x: accumTranslateRef.current.x + dx,
|
|
482
|
-
y: accumTranslateRef.current.y + dy
|
|
483
|
-
};
|
|
484
|
-
prevCenterOffsetRef.current = {
|
|
485
|
-
x: curr.x,
|
|
486
|
-
y: curr.y
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
if (containerRef.current) {
|
|
490
|
-
containerRef.current.style.transform = "translate(".concat(accumTranslateRef.current.x, "px, ").concat(accumTranslateRef.current.y, "px)");
|
|
491
|
-
}
|
|
436
|
+
var handleDragEnd = function () {
|
|
437
|
+
handleDragEndShared();
|
|
438
|
+
draggingRef.current = false;
|
|
439
|
+
controller.setMapCursor('grab');
|
|
492
440
|
}; // --------------------------------------------------------------------------
|
|
493
441
|
// Hit Test & 상태 관리
|
|
494
442
|
// --------------------------------------------------------------------------
|
|
@@ -518,13 +466,14 @@ var WoongCanvasPolygon = function (props) {
|
|
|
518
466
|
/**
|
|
519
467
|
* Hover 상태 설정 및 레이어 렌더링
|
|
520
468
|
*
|
|
521
|
-
*
|
|
469
|
+
* 마우스가 폴리곤 위에 올라갔을 때 hover 상태를 설정하고 즉시 렌더링합니다.
|
|
522
470
|
*
|
|
523
|
-
*
|
|
471
|
+
* @param data hover된 폴리곤 데이터 또는 null (hover 해제 시)
|
|
524
472
|
*
|
|
525
|
-
*
|
|
526
|
-
* -
|
|
527
|
-
* -
|
|
473
|
+
* @remarks
|
|
474
|
+
* - **성능 최적화**: RAF 없이 즉시 렌더링 (16ms 지연 제거)
|
|
475
|
+
* - Event Layer에서 hover 효과 표시
|
|
476
|
+
* - 커서 상태도 자동으로 업데이트됨 (pointer/grab)
|
|
528
477
|
*/
|
|
529
478
|
|
|
530
479
|
|
|
@@ -543,11 +492,17 @@ var WoongCanvasPolygon = function (props) {
|
|
|
543
492
|
/**
|
|
544
493
|
* 클릭 처리 (단일/다중 선택)
|
|
545
494
|
*
|
|
546
|
-
*
|
|
495
|
+
* 폴리곤 클릭 시 선택 상태를 업데이트하고 렌더링을 수행합니다.
|
|
496
|
+
*
|
|
497
|
+
* @param data 클릭된 폴리곤 데이터
|
|
547
498
|
*
|
|
548
|
-
*
|
|
549
|
-
* -
|
|
550
|
-
* -
|
|
499
|
+
* @remarks
|
|
500
|
+
* - **단일 선택**: 기존 선택 해제 후 새로 선택 (토글 가능)
|
|
501
|
+
* - **다중 선택**: enableMultiSelect가 true면 기존 선택 유지하며 추가/제거
|
|
502
|
+
* - **성능 최적화**:
|
|
503
|
+
* - 단일 Shape 렌더링으로 Base Layer 재렌더링 속도 향상
|
|
504
|
+
* - sceneFunc에서 selectedIds를 체크하여 선택된 폴리곤만 스킵
|
|
505
|
+
* - 객체 생성 오버헤드 제거로 1,000개 이상도 부드럽게 처리
|
|
551
506
|
*/
|
|
552
507
|
|
|
553
508
|
|
|
@@ -591,77 +546,63 @@ var WoongCanvasPolygon = function (props) {
|
|
|
591
546
|
|
|
592
547
|
/**
|
|
593
548
|
* 클릭 이벤트 처리
|
|
549
|
+
*
|
|
550
|
+
* @param event 클릭 이벤트 파라미터
|
|
551
|
+
*
|
|
552
|
+
* @remarks
|
|
553
|
+
* - Context가 있으면 전역 이벤트 핸들러가 처리하므로 스킵
|
|
554
|
+
* - 상호작용이 비활성화되어 있으면 스킵
|
|
555
|
+
* - Spatial Index를 사용하여 빠른 Hit Test 수행
|
|
594
556
|
*/
|
|
595
557
|
|
|
596
558
|
|
|
597
559
|
var handleClick = function (event) {
|
|
598
|
-
var _a;
|
|
599
|
-
|
|
600
560
|
if (disableInteractionRef.current) return; // 🚫 상호작용 비활성화 시 즉시 반환
|
|
601
561
|
|
|
602
|
-
|
|
562
|
+
var clickedOffset = helpers.validateEvent(event, context$1, controller);
|
|
563
|
+
if (!clickedOffset) return;
|
|
564
|
+
var data = findData(clickedOffset);
|
|
603
565
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
var data_1 = findData(clickedOffset);
|
|
566
|
+
if (data) {
|
|
567
|
+
handleLocalClick(data);
|
|
607
568
|
|
|
608
|
-
if (
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
if (onClick) {
|
|
612
|
-
onClick(data_1, selectedIdsRef.current);
|
|
613
|
-
}
|
|
569
|
+
if (onClick) {
|
|
570
|
+
onClick(data, selectedIdsRef.current);
|
|
614
571
|
}
|
|
615
|
-
} catch (error) {
|
|
616
|
-
console.error('[WoongCanvasPolygon] handleClick error:', error);
|
|
617
572
|
}
|
|
618
573
|
};
|
|
619
574
|
/**
|
|
620
575
|
* 마우스 이동 이벤트 처리 (hover 감지)
|
|
576
|
+
*
|
|
577
|
+
* @param event 마우스 이동 이벤트 파라미터
|
|
578
|
+
*
|
|
579
|
+
* @remarks
|
|
580
|
+
* - Context가 있으면 전역 이벤트 핸들러가 처리하므로 스킵
|
|
581
|
+
* - 상호작용이 비활성화되어 있으면 스킵
|
|
582
|
+
* - hover 상태 변경 시에만 렌더링 (최적화)
|
|
621
583
|
*/
|
|
622
584
|
|
|
623
585
|
|
|
624
586
|
var handleMouseMove = function (event) {
|
|
625
|
-
var _a;
|
|
626
|
-
|
|
627
587
|
if (disableInteractionRef.current) return; // 🚫 상호작용 비활성화 시 즉시 반환
|
|
628
588
|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
var hoveredItem = findData(mouseOffset);
|
|
634
|
-
var prevHovered = hoveredItemRef.current;
|
|
589
|
+
var mouseOffset = helpers.validateEvent(event, context$1, controller);
|
|
590
|
+
if (!mouseOffset) return;
|
|
591
|
+
var hoveredItem = findData(mouseOffset);
|
|
592
|
+
var prevHovered = hoveredItemRef.current;
|
|
635
593
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
if (prevHovered && onMouseOut) onMouseOut(prevHovered);
|
|
639
|
-
if (hoveredItem && onMouseOver) onMouseOver(hoveredItem);
|
|
640
|
-
}
|
|
641
|
-
} catch (error) {
|
|
642
|
-
console.error('[WoongCanvasPolygon] handleMouseMove error:', error);
|
|
594
|
+
if (prevHovered !== hoveredItem) {
|
|
595
|
+
setHovered(hoveredItem);
|
|
643
596
|
}
|
|
644
597
|
};
|
|
645
|
-
/**
|
|
646
|
-
* 드래그 시작 처리 (커서를 grabbing으로 변경)
|
|
647
|
-
*/
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
var handleDragStart = function () {
|
|
651
|
-
draggingRef.current = true;
|
|
652
|
-
controller.setMapCursor('grabbing');
|
|
653
|
-
};
|
|
654
|
-
/**
|
|
655
|
-
* 드래그 종료 처리 (커서를 기본으로 복원)
|
|
656
|
-
*/
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
var handleDragEnd = function () {
|
|
660
|
-
draggingRef.current = false;
|
|
661
|
-
controller.setMapCursor('grab');
|
|
662
|
-
};
|
|
663
598
|
/**
|
|
664
599
|
* 마우스가 canvas를 벗어날 때 hover cleanup
|
|
600
|
+
*
|
|
601
|
+
* 맵 영역 밖으로 마우스가 나갔을 때 hover 상태를 초기화합니다.
|
|
602
|
+
*
|
|
603
|
+
* @remarks
|
|
604
|
+
* - 상호작용이 비활성화되어 있으면 스킵
|
|
605
|
+
* - hover 상태 초기화 및 커서 복원
|
|
665
606
|
*/
|
|
666
607
|
|
|
667
608
|
|
|
@@ -674,10 +615,6 @@ var WoongCanvasPolygon = function (props) {
|
|
|
674
615
|
hoveredItemRef.current = null;
|
|
675
616
|
controller.setMapCursor('grab');
|
|
676
617
|
doRenderEvent();
|
|
677
|
-
|
|
678
|
-
if (onMouseOut) {
|
|
679
|
-
onMouseOut(prevHovered);
|
|
680
|
-
}
|
|
681
618
|
}
|
|
682
619
|
}; // --------------------------------------------------------------------------
|
|
683
620
|
// Lifecycle: DOM 초기화
|
|
@@ -786,8 +723,6 @@ var WoongCanvasPolygon = function (props) {
|
|
|
786
723
|
return findData(offset) !== null;
|
|
787
724
|
},
|
|
788
725
|
onClick: onClick,
|
|
789
|
-
onMouseOver: onMouseOver,
|
|
790
|
-
onMouseOut: onMouseOut,
|
|
791
726
|
findData: findData,
|
|
792
727
|
setHovered: setHovered,
|
|
793
728
|
handleLocalClick: handleLocalClick,
|
|
@@ -847,18 +782,8 @@ var WoongCanvasPolygon = function (props) {
|
|
|
847
782
|
// --------------------------------------------------------------------------
|
|
848
783
|
|
|
849
784
|
React.useEffect(function () {
|
|
850
|
-
if (!stageRef.current) return;
|
|
851
|
-
|
|
852
|
-
if (externalSelectedItems === undefined) return; // 외부에서 전달된 selectedItems로 동기화
|
|
853
|
-
|
|
854
|
-
var newSelectedIds = new Set();
|
|
855
|
-
var newSelectedItemsMap = new Map();
|
|
856
|
-
externalSelectedItems.forEach(function (item) {
|
|
857
|
-
newSelectedIds.add(item.id);
|
|
858
|
-
newSelectedItemsMap.set(item.id, item);
|
|
859
|
-
});
|
|
860
|
-
selectedIdsRef.current = newSelectedIds;
|
|
861
|
-
selectedItemsMapRef.current = newSelectedItemsMap; // 렌더링
|
|
785
|
+
if (!stageRef.current) return;
|
|
786
|
+
hooks.syncExternalSelectedItems(externalSelectedItems, selectedIdsRef, selectedItemsMapRef); // 렌더링
|
|
862
787
|
|
|
863
788
|
doRenderBase();
|
|
864
789
|
doRenderEvent();
|
|
@@ -908,27 +833,7 @@ var WoongCanvasPolygon = function (props) {
|
|
|
908
833
|
* - O(전체 데이터 수 + 선택된 개수) - 매우 효율적
|
|
909
834
|
*/
|
|
910
835
|
|
|
911
|
-
|
|
912
|
-
return [m.id, m];
|
|
913
|
-
}));
|
|
914
|
-
var newSelectedItemsMap = new Map();
|
|
915
|
-
selectedIdsRef.current.forEach(function (id) {
|
|
916
|
-
// 현재 data에 있으면 최신 데이터 사용
|
|
917
|
-
var currentItem = dataMap.get(id);
|
|
918
|
-
|
|
919
|
-
if (currentItem) {
|
|
920
|
-
newSelectedItemsMap.set(id, currentItem);
|
|
921
|
-
} else {
|
|
922
|
-
// 화면 밖이면 기존 데이터 유지
|
|
923
|
-
var prevItem = selectedItemsMapRef.current.get(id);
|
|
924
|
-
|
|
925
|
-
if (prevItem) {
|
|
926
|
-
newSelectedItemsMap.set(id, prevItem);
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
}); // selectedIdsRef는 그대로 유지 (화면 밖 항목도 선택 상태 유지)
|
|
930
|
-
|
|
931
|
-
selectedItemsMapRef.current = newSelectedItemsMap; // 즉시 렌더링
|
|
836
|
+
selectedItemsMapRef.current = hooks.syncSelectedItems(data, selectedIdsRef.current, selectedItemsMapRef.current); // 즉시 렌더링
|
|
932
837
|
|
|
933
838
|
renderAllImmediate();
|
|
934
839
|
}, [data]);
|
|
@@ -2,38 +2,88 @@
|
|
|
2
2
|
* 폴리곤 렌더링 유틸리티
|
|
3
3
|
*
|
|
4
4
|
* 이 파일은 폴리곤 렌더링을 위한 헬퍼 함수와 팩토리 함수를 제공합니다.
|
|
5
|
+
* GeoJSON MultiPolygon 형식을 지원하며, 도넛 폴리곤(구멍이 있는 폴리곤)도 처리할 수 있습니다.
|
|
5
6
|
*/
|
|
6
7
|
import { CustomRenderBase, CustomRenderEvent, KonvaCanvasData } from "../shared/types";
|
|
7
8
|
/**
|
|
8
|
-
* 폴리곤 그리기
|
|
9
|
+
* 폴리곤 그리기 파라미터 인터페이스
|
|
9
10
|
*/
|
|
10
|
-
|
|
11
|
+
interface DrawPolygonParams {
|
|
12
|
+
/** Canvas 2D 렌더링 컨텍스트 */
|
|
11
13
|
ctx: CanvasRenderingContext2D;
|
|
14
|
+
/** 변환된 폴리곤 좌표 배열 (4차원: [MultiPolygon][Polygon][Point][x/y]) */
|
|
12
15
|
polygonOffsets: number[][][][];
|
|
16
|
+
/** 도넛 폴리곤 여부 (구멍이 있는 폴리곤) */
|
|
13
17
|
isDonutPolygon: boolean;
|
|
18
|
+
/** 채우기 색상 */
|
|
14
19
|
fillColor: string;
|
|
20
|
+
/** 테두리 색상 */
|
|
15
21
|
strokeColor: string;
|
|
22
|
+
/** 테두리 두께 */
|
|
16
23
|
lineWidth: number;
|
|
17
|
-
}
|
|
24
|
+
}
|
|
18
25
|
/**
|
|
19
|
-
* 폴리곤
|
|
26
|
+
* 폴리곤 그리기 헬퍼 함수 (도넛 폴리곤 지원)
|
|
27
|
+
*
|
|
28
|
+
* Canvas 2D Context를 사용하여 폴리곤을 그립니다.
|
|
29
|
+
* 도넛 폴리곤의 경우 evenodd fill rule을 사용하여 구멍을 처리합니다.
|
|
30
|
+
*
|
|
31
|
+
* @param params 폴리곤 그리기 파라미터
|
|
20
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 폴리곤 데이터의 추가 속성 타입
|
|
21
60
|
* @param baseFillColor 기본 폴리곤 채우기 색상
|
|
22
61
|
* @param baseStrokeColor 기본 폴리곤 테두리 색상
|
|
23
62
|
* @param baseLineWidth 기본 폴리곤 테두리 두께
|
|
24
63
|
* @returns Base Layer 렌더링 함수
|
|
25
64
|
*
|
|
65
|
+
* @remarks
|
|
66
|
+
* - 선택된 항목은 Event Layer에서 그려지므로 Base Layer에서는 스킵
|
|
67
|
+
* - 성능: O(n), n은 렌더링할 폴리곤 개수
|
|
68
|
+
* - 좌표 변환은 자동으로 캐싱되어 성능 최적화됨
|
|
69
|
+
*
|
|
26
70
|
* @example
|
|
71
|
+
* ```typescript
|
|
27
72
|
* const renderBase = renderPolygonBase(
|
|
28
73
|
* 'rgba(255, 100, 100, 0.5)',
|
|
29
74
|
* 'rgba(200, 50, 50, 0.8)',
|
|
30
75
|
* 2
|
|
31
76
|
* );
|
|
77
|
+
* ```
|
|
32
78
|
*/
|
|
33
79
|
export declare const renderPolygonBase: <T = any>(baseFillColor: string, baseStrokeColor: string, baseLineWidth: number) => CustomRenderBase<KonvaCanvasData<T>>;
|
|
34
80
|
/**
|
|
35
|
-
* 폴리곤 Event 렌더링 함수
|
|
81
|
+
* 폴리곤 Event 렌더링 함수 팩토리
|
|
82
|
+
*
|
|
83
|
+
* Event Layer에서 사용할 렌더링 함수를 생성합니다.
|
|
84
|
+
* 선택된 항목, hover된 항목, 마지막 선택된 항목을 각각 다른 스타일로 렌더링합니다.
|
|
36
85
|
*
|
|
86
|
+
* @template T 폴리곤 데이터의 추가 속성 타입
|
|
37
87
|
* @param baseFillColor 기본 폴리곤 채우기 색상 (필수, fallback용)
|
|
38
88
|
* @param baseStrokeColor 기본 폴리곤 테두리 색상 (필수, fallback용)
|
|
39
89
|
* @param baseLineWidth 기본 폴리곤 테두리 두께 (필수, fallback용)
|
|
@@ -48,7 +98,14 @@ export declare const renderPolygonBase: <T = any>(baseFillColor: string, baseStr
|
|
|
48
98
|
* @param hoveredLineWidth Hover 시 폴리곤 테두리 두께 (선택, 기본값: selectedLineWidth)
|
|
49
99
|
* @returns Event Layer 렌더링 함수
|
|
50
100
|
*
|
|
101
|
+
* @remarks
|
|
102
|
+
* - **렌더링 순서**: 선택된 항목 → 마지막 선택된 항목 → hover된 항목 (최상단)
|
|
103
|
+
* - **성능**: O(m), m은 선택된 항목 수 + hover된 항목 수
|
|
104
|
+
* - 좌표 변환은 자동으로 캐싱되어 성능 최적화됨
|
|
105
|
+
* - hover된 항목이 선택되어 있으면 active 스타일 적용
|
|
106
|
+
*
|
|
51
107
|
* @example
|
|
108
|
+
* ```typescript
|
|
52
109
|
* const renderEvent = renderPolygonEvent(
|
|
53
110
|
* 'rgba(255, 100, 100, 0.5)', // baseFillColor
|
|
54
111
|
* 'rgba(200, 50, 50, 0.8)', // baseStrokeColor
|
|
@@ -57,5 +114,7 @@ export declare const renderPolygonBase: <T = any>(baseFillColor: string, baseStr
|
|
|
57
114
|
* 'rgba(255, 152, 0, 1)', // selectedStrokeColor
|
|
58
115
|
* 4 // selectedLineWidth
|
|
59
116
|
* );
|
|
117
|
+
* ```
|
|
60
118
|
*/
|
|
61
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<KonvaCanvasData<T>>;
|
|
120
|
+
export {};
|