@mint-ui/map 1.2.0-test.34 → 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.js +121 -206
- 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 +1062 -497
- package/dist/index.js +11 -0
- package/dist/index.umd.js +1068 -495
- 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 }; }
|
|
@@ -151,14 +154,7 @@ var WoongCanvasPolygon = function (props) {
|
|
|
151
154
|
*/
|
|
152
155
|
|
|
153
156
|
var updateViewport = function () {
|
|
154
|
-
|
|
155
|
-
var stage = stageRef.current;
|
|
156
|
-
viewportRef.current = {
|
|
157
|
-
minX: -cullingMargin,
|
|
158
|
-
maxX: stage.width() + cullingMargin,
|
|
159
|
-
minY: -cullingMargin,
|
|
160
|
-
maxY: stage.height() + cullingMargin
|
|
161
|
-
};
|
|
157
|
+
viewport.updateViewport(stageRef.current, cullingMargin, viewportRef);
|
|
162
158
|
};
|
|
163
159
|
/**
|
|
164
160
|
* 아이템이 현재 뷰포트 안에 있는지 확인 (바운딩 박스 캐싱)
|
|
@@ -166,21 +162,7 @@ var WoongCanvasPolygon = function (props) {
|
|
|
166
162
|
|
|
167
163
|
|
|
168
164
|
var isInViewport = function (item) {
|
|
169
|
-
|
|
170
|
-
var viewport = viewportRef.current; // 캐시된 바운딩 박스 확인
|
|
171
|
-
|
|
172
|
-
var bbox = boundingBoxCacheRef.current.get(item.id);
|
|
173
|
-
|
|
174
|
-
if (!bbox) {
|
|
175
|
-
// 바운딩 박스 계산 (공통 함수 사용)
|
|
176
|
-
var computed = computeBoundingBox(item);
|
|
177
|
-
if (!computed) return false;
|
|
178
|
-
bbox = computed;
|
|
179
|
-
boundingBoxCacheRef.current.set(item.id, bbox);
|
|
180
|
-
} // 바운딩 박스와 viewport 교차 체크
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
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);
|
|
184
166
|
}; // --------------------------------------------------------------------------
|
|
185
167
|
// 유틸리티 함수: 좌표 변환 캐싱
|
|
186
168
|
// --------------------------------------------------------------------------
|
|
@@ -209,8 +191,23 @@ var WoongCanvasPolygon = function (props) {
|
|
|
209
191
|
/**
|
|
210
192
|
* 폴리곤의 바운딩 박스 계산
|
|
211
193
|
*
|
|
194
|
+
* 폴리곤의 모든 좌표를 순회하여 최소/최대 X, Y 값을 계산합니다.
|
|
195
|
+
* Viewport Culling에 사용되며, MultiPolygon 형식을 지원합니다.
|
|
196
|
+
*
|
|
212
197
|
* @param item 폴리곤 데이터
|
|
213
|
-
* @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
|
+
* ```
|
|
214
211
|
*/
|
|
215
212
|
|
|
216
213
|
|
|
@@ -257,19 +254,7 @@ var WoongCanvasPolygon = function (props) {
|
|
|
257
254
|
|
|
258
255
|
|
|
259
256
|
var buildSpatialIndex = function () {
|
|
260
|
-
|
|
261
|
-
spatial.clear();
|
|
262
|
-
var currentData = dataRef.current;
|
|
263
|
-
|
|
264
|
-
for (var _i = 0, currentData_1 = currentData; _i < currentData_1.length; _i++) {
|
|
265
|
-
var item = currentData_1[_i]; // 바운딩 박스 계산 (공통 함수 사용)
|
|
266
|
-
|
|
267
|
-
var bbox = computeBoundingBox(item);
|
|
268
|
-
|
|
269
|
-
if (bbox) {
|
|
270
|
-
spatial.insert(item, bbox.minX, bbox.minY, bbox.maxX, bbox.maxY);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
257
|
+
hooks.buildSpatialIndex(dataRef.current, spatialIndexRef.current, computeBoundingBox);
|
|
273
258
|
}; // --------------------------------------------------------------------------
|
|
274
259
|
// 렌더링 함수 결정 (dataType에 따라)
|
|
275
260
|
// --------------------------------------------------------------------------
|
|
@@ -292,11 +277,8 @@ var WoongCanvasPolygon = function (props) {
|
|
|
292
277
|
|
|
293
278
|
var renderBase = renderer.renderPolygonBase(baseFillColor, baseStrokeColor, baseLineWidth);
|
|
294
279
|
var renderEvent = renderer.renderPolygonEvent(baseFillColor, baseStrokeColor, baseLineWidth, selectedFillColor, selectedStrokeColor, selectedLineWidth, activeFillColor, activeStrokeColor, activeLineWidth, hoveredFillColor, hoveredStrokeColor, hoveredLineWidth);
|
|
295
|
-
/** Base Layer에서 사용할 빈 Set (재사용) */
|
|
296
|
-
|
|
297
|
-
React.useRef(new Set());
|
|
298
280
|
/**
|
|
299
|
-
* Base 레이어 렌더링 (뷰포트 컬링
|
|
281
|
+
* Base 레이어 렌더링 (뷰포트 컬링 적용)
|
|
300
282
|
*
|
|
301
283
|
* 🔥 최적화:
|
|
302
284
|
* 1. Shape 재사용으로 객체 생성/파괴 오버헤드 제거
|
|
@@ -348,10 +330,16 @@ var WoongCanvasPolygon = function (props) {
|
|
|
348
330
|
/**
|
|
349
331
|
* Event 레이어 렌더링 (hover + 선택 상태 표시)
|
|
350
332
|
*
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
*
|
|
333
|
+
* 폴리곤의 hover 효과 및 선택 상태를 표시합니다.
|
|
334
|
+
* 자동 렌더링 방식으로 renderPolygonEvent를 사용합니다.
|
|
335
|
+
*
|
|
336
|
+
* @remarks
|
|
337
|
+
* - **성능 최적화**:
|
|
338
|
+
* 1. Shape 재사용으로 객체 생성/파괴 오버헤드 제거
|
|
339
|
+
* 2. sceneFunc 한 번만 설정 (함수 재생성 제거)
|
|
340
|
+
* 3. 클로저로 최신 데이터 참조
|
|
341
|
+
* - 선택된 항목은 Map에서 O(1)로 조회하여 성능 최적화
|
|
342
|
+
* - 자동 렌더링: 스타일 props(selectedFillColor, hoveredFillColor 등) 기반으로 자동 렌더링
|
|
355
343
|
*/
|
|
356
344
|
|
|
357
345
|
|
|
@@ -368,8 +356,9 @@ var WoongCanvasPolygon = function (props) {
|
|
|
368
356
|
name: 'event-render-shape',
|
|
369
357
|
sceneFunc: function (context, shape) {
|
|
370
358
|
var ctx = context; // 클로저로 최신 ref 값 참조
|
|
359
|
+
// 성능 최적화: Array.from 대신 직접 변환 (메모리 할당 최소화)
|
|
371
360
|
|
|
372
|
-
var selectedItems =
|
|
361
|
+
var selectedItems = helpers.mapValuesToArray(selectedItemsMapRef.current);
|
|
373
362
|
var hovered = hoveredItemRef.current; // 일반 렌더링
|
|
374
363
|
|
|
375
364
|
renderEvent({
|
|
@@ -392,6 +381,13 @@ var WoongCanvasPolygon = function (props) {
|
|
|
392
381
|
};
|
|
393
382
|
/**
|
|
394
383
|
* 전체 즉시 렌더링 (IDLE 시 호출)
|
|
384
|
+
*
|
|
385
|
+
* 뷰포트 업데이트, 공간 인덱스 빌드, 모든 레이어 렌더링을 순차적으로 수행합니다.
|
|
386
|
+
*
|
|
387
|
+
* @remarks
|
|
388
|
+
* - 호출 시점: 지도 이동/줌 완료 시, 데이터 변경 시, 리사이즈 시
|
|
389
|
+
* - 순서: 뷰포트 업데이트 → 공간 인덱스 빌드 → Base → Event 렌더링
|
|
390
|
+
* - Animation Layer는 사용하지 않음 (폴리곤 특성)
|
|
395
391
|
*/
|
|
396
392
|
|
|
397
393
|
|
|
@@ -404,89 +400,43 @@ var WoongCanvasPolygon = function (props) {
|
|
|
404
400
|
// 이벤트 핸들러: 지도 이벤트
|
|
405
401
|
// --------------------------------------------------------------------------
|
|
406
402
|
|
|
407
|
-
/**
|
|
408
|
-
* 지도 이동/줌 완료 시 처리
|
|
409
|
-
*/
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
var handleIdle = function () {
|
|
413
|
-
prevCenterOffsetRef.current = null;
|
|
414
|
-
accumTranslateRef.current = {
|
|
415
|
-
x: 0,
|
|
416
|
-
y: 0
|
|
417
|
-
}; // 2. 캐시 정리 (지도 이동/줌으로 좌표 변환 결과가 바뀜)
|
|
418
|
-
|
|
419
|
-
offsetCacheRef.current.clear();
|
|
420
|
-
boundingBoxCacheRef.current.clear(); // 3. 마커 위치 업데이트
|
|
421
|
-
|
|
422
|
-
var bounds = controller.getCurrBounds();
|
|
423
|
-
|
|
424
|
-
var markerOptions = tslib.__assign({
|
|
425
|
-
position: bounds.nw
|
|
426
|
-
}, options);
|
|
427
|
-
|
|
428
|
-
markerRef.current && controller.updateMarker(markerRef.current, markerOptions); // 4. transform 제거 전에 새 데이터로 즉시 렌더링 (겹침 방지)
|
|
429
|
-
|
|
430
|
-
if (containerRef.current) {
|
|
431
|
-
containerRef.current.style.transform = '';
|
|
432
|
-
containerRef.current.style.visibility = '';
|
|
433
|
-
} // 5. 새 위치에서 렌더링
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
renderAllImmediate();
|
|
437
|
-
};
|
|
438
|
-
/**
|
|
439
|
-
* 줌 시작 시 처리 (일시적으로 숨김)
|
|
440
|
-
*/
|
|
441
|
-
|
|
442
403
|
|
|
443
|
-
var
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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;
|
|
448
421
|
/**
|
|
449
|
-
*
|
|
422
|
+
* 드래그 시작 처리 (커서를 grabbing으로 변경)
|
|
450
423
|
*/
|
|
451
424
|
|
|
452
425
|
|
|
453
|
-
var
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
426
|
+
var handleDragStart = function () {
|
|
427
|
+
handleDragStartShared();
|
|
428
|
+
draggingRef.current = true;
|
|
429
|
+
controller.setMapCursor('grabbing');
|
|
457
430
|
};
|
|
458
431
|
/**
|
|
459
|
-
*
|
|
432
|
+
* 드래그 종료 처리 (커서를 기본으로 복원)
|
|
460
433
|
*/
|
|
461
434
|
|
|
462
435
|
|
|
463
|
-
var
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
if (!prev) {
|
|
469
|
-
prevCenterOffsetRef.current = {
|
|
470
|
-
x: curr.x,
|
|
471
|
-
y: curr.y
|
|
472
|
-
};
|
|
473
|
-
return;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
var dx = prev.x - curr.x;
|
|
477
|
-
var dy = prev.y - curr.y;
|
|
478
|
-
accumTranslateRef.current = {
|
|
479
|
-
x: accumTranslateRef.current.x + dx,
|
|
480
|
-
y: accumTranslateRef.current.y + dy
|
|
481
|
-
};
|
|
482
|
-
prevCenterOffsetRef.current = {
|
|
483
|
-
x: curr.x,
|
|
484
|
-
y: curr.y
|
|
485
|
-
};
|
|
486
|
-
|
|
487
|
-
if (containerRef.current) {
|
|
488
|
-
containerRef.current.style.transform = "translate(".concat(accumTranslateRef.current.x, "px, ").concat(accumTranslateRef.current.y, "px)");
|
|
489
|
-
}
|
|
436
|
+
var handleDragEnd = function () {
|
|
437
|
+
handleDragEndShared();
|
|
438
|
+
draggingRef.current = false;
|
|
439
|
+
controller.setMapCursor('grab');
|
|
490
440
|
}; // --------------------------------------------------------------------------
|
|
491
441
|
// Hit Test & 상태 관리
|
|
492
442
|
// --------------------------------------------------------------------------
|
|
@@ -516,13 +466,14 @@ var WoongCanvasPolygon = function (props) {
|
|
|
516
466
|
/**
|
|
517
467
|
* Hover 상태 설정 및 레이어 렌더링
|
|
518
468
|
*
|
|
519
|
-
*
|
|
469
|
+
* 마우스가 폴리곤 위에 올라갔을 때 hover 상태를 설정하고 즉시 렌더링합니다.
|
|
520
470
|
*
|
|
521
|
-
*
|
|
471
|
+
* @param data hover된 폴리곤 데이터 또는 null (hover 해제 시)
|
|
522
472
|
*
|
|
523
|
-
*
|
|
524
|
-
* -
|
|
525
|
-
* -
|
|
473
|
+
* @remarks
|
|
474
|
+
* - **성능 최적화**: RAF 없이 즉시 렌더링 (16ms 지연 제거)
|
|
475
|
+
* - Event Layer에서 hover 효과 표시
|
|
476
|
+
* - 커서 상태도 자동으로 업데이트됨 (pointer/grab)
|
|
526
477
|
*/
|
|
527
478
|
|
|
528
479
|
|
|
@@ -541,11 +492,17 @@ var WoongCanvasPolygon = function (props) {
|
|
|
541
492
|
/**
|
|
542
493
|
* 클릭 처리 (단일/다중 선택)
|
|
543
494
|
*
|
|
544
|
-
*
|
|
495
|
+
* 폴리곤 클릭 시 선택 상태를 업데이트하고 렌더링을 수행합니다.
|
|
496
|
+
*
|
|
497
|
+
* @param data 클릭된 폴리곤 데이터
|
|
545
498
|
*
|
|
546
|
-
*
|
|
547
|
-
* -
|
|
548
|
-
* -
|
|
499
|
+
* @remarks
|
|
500
|
+
* - **단일 선택**: 기존 선택 해제 후 새로 선택 (토글 가능)
|
|
501
|
+
* - **다중 선택**: enableMultiSelect가 true면 기존 선택 유지하며 추가/제거
|
|
502
|
+
* - **성능 최적화**:
|
|
503
|
+
* - 단일 Shape 렌더링으로 Base Layer 재렌더링 속도 향상
|
|
504
|
+
* - sceneFunc에서 selectedIds를 체크하여 선택된 폴리곤만 스킵
|
|
505
|
+
* - 객체 생성 오버헤드 제거로 1,000개 이상도 부드럽게 처리
|
|
549
506
|
*/
|
|
550
507
|
|
|
551
508
|
|
|
@@ -589,75 +546,63 @@ var WoongCanvasPolygon = function (props) {
|
|
|
589
546
|
|
|
590
547
|
/**
|
|
591
548
|
* 클릭 이벤트 처리
|
|
549
|
+
*
|
|
550
|
+
* @param event 클릭 이벤트 파라미터
|
|
551
|
+
*
|
|
552
|
+
* @remarks
|
|
553
|
+
* - Context가 있으면 전역 이벤트 핸들러가 처리하므로 스킵
|
|
554
|
+
* - 상호작용이 비활성화되어 있으면 스킵
|
|
555
|
+
* - Spatial Index를 사용하여 빠른 Hit Test 수행
|
|
592
556
|
*/
|
|
593
557
|
|
|
594
558
|
|
|
595
559
|
var handleClick = function (event) {
|
|
596
|
-
var _a;
|
|
597
|
-
|
|
598
560
|
if (disableInteractionRef.current) return; // 🚫 상호작용 비활성화 시 즉시 반환
|
|
599
561
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
var clickedOffset = controller.positionToOffset(event.param.position);
|
|
604
|
-
var data_1 = findData(clickedOffset);
|
|
562
|
+
var clickedOffset = helpers.validateEvent(event, context$1, controller);
|
|
563
|
+
if (!clickedOffset) return;
|
|
564
|
+
var data = findData(clickedOffset);
|
|
605
565
|
|
|
606
|
-
|
|
607
|
-
|
|
566
|
+
if (data) {
|
|
567
|
+
handleLocalClick(data);
|
|
608
568
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
}
|
|
569
|
+
if (onClick) {
|
|
570
|
+
onClick(data, selectedIdsRef.current);
|
|
612
571
|
}
|
|
613
|
-
} catch (error) {
|
|
614
|
-
console.error('[WoongCanvasPolygon] handleClick error:', error);
|
|
615
572
|
}
|
|
616
573
|
};
|
|
617
574
|
/**
|
|
618
575
|
* 마우스 이동 이벤트 처리 (hover 감지)
|
|
576
|
+
*
|
|
577
|
+
* @param event 마우스 이동 이벤트 파라미터
|
|
578
|
+
*
|
|
579
|
+
* @remarks
|
|
580
|
+
* - Context가 있으면 전역 이벤트 핸들러가 처리하므로 스킵
|
|
581
|
+
* - 상호작용이 비활성화되어 있으면 스킵
|
|
582
|
+
* - hover 상태 변경 시에만 렌더링 (최적화)
|
|
619
583
|
*/
|
|
620
584
|
|
|
621
585
|
|
|
622
586
|
var handleMouseMove = function (event) {
|
|
623
|
-
var _a;
|
|
624
|
-
|
|
625
587
|
if (disableInteractionRef.current) return; // 🚫 상호작용 비활성화 시 즉시 반환
|
|
626
588
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
var hoveredItem = findData(mouseOffset);
|
|
632
|
-
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;
|
|
633
593
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
}
|
|
637
|
-
} catch (error) {
|
|
638
|
-
console.error('[WoongCanvasPolygon] handleMouseMove error:', error);
|
|
594
|
+
if (prevHovered !== hoveredItem) {
|
|
595
|
+
setHovered(hoveredItem);
|
|
639
596
|
}
|
|
640
597
|
};
|
|
641
|
-
/**
|
|
642
|
-
* 드래그 시작 처리 (커서를 grabbing으로 변경)
|
|
643
|
-
*/
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
var handleDragStart = function () {
|
|
647
|
-
draggingRef.current = true;
|
|
648
|
-
controller.setMapCursor('grabbing');
|
|
649
|
-
};
|
|
650
|
-
/**
|
|
651
|
-
* 드래그 종료 처리 (커서를 기본으로 복원)
|
|
652
|
-
*/
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
var handleDragEnd = function () {
|
|
656
|
-
draggingRef.current = false;
|
|
657
|
-
controller.setMapCursor('grab');
|
|
658
|
-
};
|
|
659
598
|
/**
|
|
660
599
|
* 마우스가 canvas를 벗어날 때 hover cleanup
|
|
600
|
+
*
|
|
601
|
+
* 맵 영역 밖으로 마우스가 나갔을 때 hover 상태를 초기화합니다.
|
|
602
|
+
*
|
|
603
|
+
* @remarks
|
|
604
|
+
* - 상호작용이 비활성화되어 있으면 스킵
|
|
605
|
+
* - hover 상태 초기화 및 커서 복원
|
|
661
606
|
*/
|
|
662
607
|
|
|
663
608
|
|
|
@@ -837,18 +782,8 @@ var WoongCanvasPolygon = function (props) {
|
|
|
837
782
|
// --------------------------------------------------------------------------
|
|
838
783
|
|
|
839
784
|
React.useEffect(function () {
|
|
840
|
-
if (!stageRef.current) return;
|
|
841
|
-
|
|
842
|
-
if (externalSelectedItems === undefined) return; // 외부에서 전달된 selectedItems로 동기화
|
|
843
|
-
|
|
844
|
-
var newSelectedIds = new Set();
|
|
845
|
-
var newSelectedItemsMap = new Map();
|
|
846
|
-
externalSelectedItems.forEach(function (item) {
|
|
847
|
-
newSelectedIds.add(item.id);
|
|
848
|
-
newSelectedItemsMap.set(item.id, item);
|
|
849
|
-
});
|
|
850
|
-
selectedIdsRef.current = newSelectedIds;
|
|
851
|
-
selectedItemsMapRef.current = newSelectedItemsMap; // 렌더링
|
|
785
|
+
if (!stageRef.current) return;
|
|
786
|
+
hooks.syncExternalSelectedItems(externalSelectedItems, selectedIdsRef, selectedItemsMapRef); // 렌더링
|
|
852
787
|
|
|
853
788
|
doRenderBase();
|
|
854
789
|
doRenderEvent();
|
|
@@ -898,27 +833,7 @@ var WoongCanvasPolygon = function (props) {
|
|
|
898
833
|
* - O(전체 데이터 수 + 선택된 개수) - 매우 효율적
|
|
899
834
|
*/
|
|
900
835
|
|
|
901
|
-
|
|
902
|
-
return [m.id, m];
|
|
903
|
-
}));
|
|
904
|
-
var newSelectedItemsMap = new Map();
|
|
905
|
-
selectedIdsRef.current.forEach(function (id) {
|
|
906
|
-
// 현재 data에 있으면 최신 데이터 사용
|
|
907
|
-
var currentItem = dataMap.get(id);
|
|
908
|
-
|
|
909
|
-
if (currentItem) {
|
|
910
|
-
newSelectedItemsMap.set(id, currentItem);
|
|
911
|
-
} else {
|
|
912
|
-
// 화면 밖이면 기존 데이터 유지
|
|
913
|
-
var prevItem = selectedItemsMapRef.current.get(id);
|
|
914
|
-
|
|
915
|
-
if (prevItem) {
|
|
916
|
-
newSelectedItemsMap.set(id, prevItem);
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
}); // selectedIdsRef는 그대로 유지 (화면 밖 항목도 선택 상태 유지)
|
|
920
|
-
|
|
921
|
-
selectedItemsMapRef.current = newSelectedItemsMap; // 즉시 렌더링
|
|
836
|
+
selectedItemsMapRef.current = hooks.syncSelectedItems(data, selectedIdsRef.current, selectedItemsMapRef.current); // 즉시 렌더링
|
|
922
837
|
|
|
923
838
|
renderAllImmediate();
|
|
924
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 {};
|