@mint-ui/map 1.2.0-test.8 → 1.2.0
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/.eslintrc.js +11 -4
- package/.vscode/settings.json +32 -9
- package/dist/components/mint-map/core/MintMapController.d.ts +1 -0
- package/dist/components/mint-map/core/MintMapCore.js +5 -6
- package/dist/components/mint-map/core/advanced/CanvasMarkerLayer/CanvasMarkerLayer.d.ts +12 -0
- package/dist/components/mint-map/core/advanced/CanvasMarkerLayer/CanvasMarkerLayer.js +962 -0
- package/dist/components/mint-map/core/advanced/CanvasMarkerLayer/index.d.ts +4 -0
- package/dist/components/mint-map/core/advanced/CanvasMarkerLayer/types.d.ts +280 -0
- package/dist/components/mint-map/core/advanced/CanvasPolygonLayer/CanvasPolygonLayer.d.ts +17 -0
- package/dist/components/mint-map/core/advanced/CanvasPolygonLayer/CanvasPolygonLayer.js +624 -0
- package/dist/components/mint-map/core/advanced/CanvasPolygonLayer/index.d.ts +4 -0
- package/dist/components/mint-map/core/advanced/CanvasPolygonLayer/renderer.d.ts +303 -0
- package/dist/components/mint-map/core/advanced/CanvasPolygonLayer/renderer.js +1091 -0
- package/dist/components/mint-map/core/advanced/CanvasPolygonLayer/types.d.ts +284 -0
- package/dist/components/mint-map/core/advanced/canvas/CanvasMarker.d.ts +7 -0
- package/dist/components/mint-map/core/advanced/canvas/CanvasMarkerClaude.js +7 -7
- package/dist/components/mint-map/core/advanced/canvas/index.d.ts +0 -1
- package/dist/components/mint-map/core/advanced/index.d.ts +4 -2
- package/dist/components/mint-map/core/advanced/shared/context.d.ts +44 -0
- package/dist/components/mint-map/core/advanced/shared/context.js +230 -0
- package/dist/components/mint-map/core/advanced/shared/helpers.d.ts +20 -0
- package/dist/components/mint-map/core/advanced/shared/helpers.js +41 -0
- package/dist/components/mint-map/core/advanced/shared/hooks.d.ts +74 -0
- package/dist/components/mint-map/core/advanced/shared/hooks.js +196 -0
- package/dist/components/mint-map/core/advanced/{woongCanvas/shared → shared}/index.d.ts +5 -2
- package/dist/components/mint-map/core/advanced/shared/performance.d.ts +82 -0
- package/dist/components/mint-map/core/advanced/shared/performance.js +288 -0
- package/dist/components/mint-map/core/advanced/shared/types.d.ts +150 -0
- package/dist/components/mint-map/core/advanced/shared/types.js +31 -0
- package/dist/components/mint-map/core/advanced/shared/utils.d.ts +173 -0
- package/dist/components/mint-map/core/advanced/shared/utils.js +382 -0
- package/dist/components/mint-map/core/advanced/shared/viewport.d.ts +42 -0
- package/dist/components/mint-map/core/advanced/shared/viewport.js +52 -0
- package/dist/components/mint-map/core/wrapper/MapMarkerWrapper.js +22 -1
- package/dist/components/mint-map/google/GoogleMintMapController.d.ts +1 -0
- package/dist/components/mint-map/google/GoogleMintMapController.js +13 -8
- package/dist/components/mint-map/kakao/KakaoMintMapController.d.ts +1 -0
- package/dist/components/mint-map/kakao/KakaoMintMapController.js +13 -8
- package/dist/components/mint-map/naver/NaverMintMapController.d.ts +3 -0
- package/dist/components/mint-map/naver/NaverMintMapController.js +46 -11
- package/dist/index.es.js +5605 -4056
- package/dist/index.js +47 -27
- package/dist/index.umd.js +5621 -4059
- package/package.json +1 -1
- package/CLAUDE.md +0 -100
- package/dist/components/mint-map/core/advanced/canvas/CanvasMarkerHanquf.d.ts +0 -22
- package/dist/components/mint-map/core/advanced/canvas/CanvasMarkerHanquf.js +0 -413
- package/dist/components/mint-map/core/advanced/woongCanvas/ClusterMarker.d.ts +0 -11
- package/dist/components/mint-map/core/advanced/woongCanvas/WoongKonvaMarker.d.ts +0 -53
- package/dist/components/mint-map/core/advanced/woongCanvas/WoongKonvaMarker.js +0 -1123
- package/dist/components/mint-map/core/advanced/woongCanvas/index.d.ts +0 -3
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/context.d.ts +0 -31
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/context.js +0 -164
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/performance.d.ts +0 -161
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/performance.js +0 -343
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/types.d.ts +0 -131
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/types.js +0 -14
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.d.ts +0 -31
- package/dist/components/mint-map/core/advanced/woongCanvas/shared/utils.js +0 -164
- package/dist/components/mint-map/core/util/geohash.js +0 -125
package/package.json
CHANGED
package/CLAUDE.md
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
# CLAUDE.md
|
|
2
|
-
|
|
3
|
-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
-
|
|
5
|
-
## Project Overview
|
|
6
|
-
|
|
7
|
-
@mint-ui/map is a React-based map library that provides a unified interface for controlling multiple map providers (Google Maps, Naver Maps, and Kakao Maps) with TypeScript support and advanced Canvas marker capabilities.
|
|
8
|
-
|
|
9
|
-
## Development Commands
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
# Development
|
|
13
|
-
npm run storybook # Start Storybook dev server on port 3000
|
|
14
|
-
|
|
15
|
-
# Building
|
|
16
|
-
npm run build # Build library for distribution (cleans dist/, runs rollup)
|
|
17
|
-
|
|
18
|
-
# NPM Publishing
|
|
19
|
-
npm run build # Always build before publishing
|
|
20
|
-
npm version patch # Increment version (patch/minor/major)
|
|
21
|
-
npm publish --access public # Publish to NPM (must use --access public for scoped package)
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Architecture Overview
|
|
25
|
-
|
|
26
|
-
### Map Provider Abstraction
|
|
27
|
-
The library uses a controller pattern to abstract different map providers:
|
|
28
|
-
- `GoogleMintMapController` - Google Maps implementation
|
|
29
|
-
- `NaverMintMapController` - Naver Maps implementation
|
|
30
|
-
- `KakaoMintMapController` - Kakao Maps implementation
|
|
31
|
-
|
|
32
|
-
Each controller implements a common interface, allowing seamless switching between map providers.
|
|
33
|
-
|
|
34
|
-
### Core Directory Structure
|
|
35
|
-
```
|
|
36
|
-
src/components/mint-map/
|
|
37
|
-
├── MintMap.tsx # Main entry component
|
|
38
|
-
├── core/
|
|
39
|
-
│ ├── advanced/ # Canvas markers, shapes, drawing tools
|
|
40
|
-
│ ├── hooks/ # React hooks for map interactions
|
|
41
|
-
│ ├── provider/ # React Context for state management
|
|
42
|
-
│ └── wrapper/ # Component wrappers (markers, overlays)
|
|
43
|
-
├── google/ # Google Maps specific implementation
|
|
44
|
-
├── naver/ # Naver Maps specific implementation
|
|
45
|
-
├── kakao/ # Kakao Maps specific implementation
|
|
46
|
-
└── types/ # TypeScript type definitions
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### Key Architectural Patterns
|
|
50
|
-
|
|
51
|
-
1. **Factory Pattern**: The `MintMap` component dynamically instantiates the appropriate controller based on the `mapType` prop.
|
|
52
|
-
|
|
53
|
-
2. **Provider Pattern**: Uses React Context (`MintMapProvider`) to share map state and controller instance across components.
|
|
54
|
-
|
|
55
|
-
3. **Wrapper Components**: Components like `MapMarkerWrapper` abstract the differences between map provider APIs.
|
|
56
|
-
|
|
57
|
-
4. **Canvas Rendering**: Advanced marker system using HTML5 Canvas for high-performance rendering of large datasets.
|
|
58
|
-
|
|
59
|
-
## TypeScript Configuration
|
|
60
|
-
|
|
61
|
-
- Target: ES5 with React JSX
|
|
62
|
-
- Strict mode enabled
|
|
63
|
-
- Declaration files generated for distribution
|
|
64
|
-
- Excludes `*.stories.tsx` and `*.test.tsx` from compilation
|
|
65
|
-
|
|
66
|
-
## Build System
|
|
67
|
-
|
|
68
|
-
Uses Rollup with multiple output formats:
|
|
69
|
-
- CommonJS: `dist/index.js`
|
|
70
|
-
- ES Module: `dist/index.es.js`
|
|
71
|
-
- UMD: `dist/index.umd.js`
|
|
72
|
-
- Type declarations: `dist/index.d.ts`
|
|
73
|
-
|
|
74
|
-
## Development with Storybook
|
|
75
|
-
|
|
76
|
-
The project uses Storybook for component development and documentation:
|
|
77
|
-
- Stories in `src/stories/` demonstrate usage patterns
|
|
78
|
-
- `basics/` - Basic map functionality examples
|
|
79
|
-
- `markerlab/` - Advanced marker experiments including canvas markers
|
|
80
|
-
- `sample/` - Complete implementation examples
|
|
81
|
-
|
|
82
|
-
## Code Style
|
|
83
|
-
|
|
84
|
-
- ESLint with Airbnb config + TypeScript rules
|
|
85
|
-
- Tab-based indentation (2-space equivalent)
|
|
86
|
-
- Alphabetical import ordering enforced
|
|
87
|
-
- SCSS modules for component styling
|
|
88
|
-
|
|
89
|
-
## Working with Canvas Markers
|
|
90
|
-
|
|
91
|
-
Canvas markers are a key feature for high-performance rendering:
|
|
92
|
-
- `CanvasMarker.tsx` - Main canvas marker component
|
|
93
|
-
- `CanvasMarkerHanquf.tsx` - Specialized canvas marker variant
|
|
94
|
-
- Renderer function pattern for custom drawing logic
|
|
95
|
-
- Supports geohash-based clustering
|
|
96
|
-
|
|
97
|
-
## External Resources
|
|
98
|
-
|
|
99
|
-
- Documentation site: https://dev-rsquare.github.io/mint-ui-map-guide
|
|
100
|
-
- NPM package: @mint-ui/map
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { MarkerOptions, Offset, Position } from "../../../types";
|
|
3
|
-
export interface CanvasMarkerRendererParamsHanquf<T> {
|
|
4
|
-
context: CanvasRenderingContext2D;
|
|
5
|
-
offset: Offset[];
|
|
6
|
-
payload?: CanvasMarkerDataHanquf<T>;
|
|
7
|
-
}
|
|
8
|
-
export interface CanvasMarkerOptionHanquf {
|
|
9
|
-
position?: Position[];
|
|
10
|
-
visible?: boolean;
|
|
11
|
-
hitRadius?: number;
|
|
12
|
-
}
|
|
13
|
-
export declare type CanvasMarkerDataHanquf<T> = T & CanvasMarkerOptionHanquf;
|
|
14
|
-
export declare type CanvasMarkerRenderFunctionHanquf<T> = (params: CanvasMarkerRendererParamsHanquf<T>) => void;
|
|
15
|
-
export interface CanvasMarkerPropsHanquf<T> extends Pick<MarkerOptions, 'zIndex' | 'anchor' | 'visible'> {
|
|
16
|
-
renderer: CanvasMarkerRenderFunctionHanquf<T>;
|
|
17
|
-
data: CanvasMarkerDataHanquf<T>[];
|
|
18
|
-
onMouseOver?: (item: CanvasMarkerDataHanquf<T>) => void;
|
|
19
|
-
onMouseOut?: (item: CanvasMarkerDataHanquf<T>) => void;
|
|
20
|
-
onClick?: (item: CanvasMarkerDataHanquf<T>) => void;
|
|
21
|
-
}
|
|
22
|
-
export declare function CanvasMarkerHanquf<T>({ renderer, data, onMouseOver, onMouseOut, onClick, ...options }: CanvasMarkerPropsHanquf<T>): React.ReactPortal;
|
|
@@ -1,413 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
|
-
var tslib = require('tslib');
|
|
6
|
-
var React = require('react');
|
|
7
|
-
var MintMapProvider = require('../../provider/MintMapProvider.js');
|
|
8
|
-
var MapDrawables = require('../../../types/MapDrawables.js');
|
|
9
|
-
require('../../../types/MapTypes.js');
|
|
10
|
-
require('../../../types/MapEventTypes.js');
|
|
11
|
-
var reactDom = require('react-dom');
|
|
12
|
-
var canvasUtil = require('./draw/canvas-util.js');
|
|
13
|
-
var geohash = require('../../util/geohash.js');
|
|
14
|
-
|
|
15
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
16
|
-
|
|
17
|
-
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
18
|
-
|
|
19
|
-
function CanvasMarkerHanquf(_a) {
|
|
20
|
-
var renderer = _a.renderer,
|
|
21
|
-
data = _a.data,
|
|
22
|
-
onMouseOver = _a.onMouseOver,
|
|
23
|
-
onMouseOut = _a.onMouseOut,
|
|
24
|
-
onClick = _a.onClick,
|
|
25
|
-
options = tslib.__rest(_a, ["renderer", "data", "onMouseOver", "onMouseOut", "onClick"]); //controller
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
var controller = MintMapProvider.useMintMapController(); //element
|
|
29
|
-
|
|
30
|
-
var divRef = React.useRef(document.createElement('div'));
|
|
31
|
-
var divElement = divRef.current; //canvas container ref
|
|
32
|
-
|
|
33
|
-
var containerRef = React.useRef(null); //canvas ref
|
|
34
|
-
|
|
35
|
-
var canvasRef = React.useRef(null); //canvas context
|
|
36
|
-
|
|
37
|
-
var contextRef = React.useRef(); //marker
|
|
38
|
-
|
|
39
|
-
var markerRef = React.useRef(); // interaction states
|
|
40
|
-
|
|
41
|
-
var hoveredRef = React.useRef(null);
|
|
42
|
-
var clickedRef = React.useRef(null); // geohash index: hash -> items
|
|
43
|
-
|
|
44
|
-
var geoIndexRef = React.useRef(new Map());
|
|
45
|
-
var geoPrecisionRef = React.useRef(6); // drag translate state
|
|
46
|
-
|
|
47
|
-
var prevCenterOffsetRef = React.useRef(null);
|
|
48
|
-
var accumTranslateRef = React.useRef({
|
|
49
|
-
x: 0,
|
|
50
|
-
y: 0
|
|
51
|
-
});
|
|
52
|
-
var draggingRef = React.useRef(false); //create object
|
|
53
|
-
|
|
54
|
-
React.useEffect(function () {
|
|
55
|
-
divElement.style.width = 'fit-content';
|
|
56
|
-
divElement.style.pointerEvents = 'none';
|
|
57
|
-
return function () {
|
|
58
|
-
if (markerRef.current) {
|
|
59
|
-
controller.clearDrawable(markerRef.current);
|
|
60
|
-
markerRef.current = undefined;
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
}, []); //create / update object
|
|
64
|
-
|
|
65
|
-
React.useEffect(function () {
|
|
66
|
-
if (options) {
|
|
67
|
-
var bounds = controller.getCurrBounds();
|
|
68
|
-
|
|
69
|
-
var markerOptions = tslib.__assign({
|
|
70
|
-
position: bounds.nw
|
|
71
|
-
}, options);
|
|
72
|
-
|
|
73
|
-
if (markerRef.current) {
|
|
74
|
-
controller.updateMarker(markerRef.current, markerOptions);
|
|
75
|
-
} else {
|
|
76
|
-
markerRef.current = new MapDrawables.Marker(markerOptions);
|
|
77
|
-
markerRef.current.element = divElement;
|
|
78
|
-
controller.createMarker(markerRef.current); //disablePointerEvent 처리
|
|
79
|
-
|
|
80
|
-
if (divElement.parentElement) {
|
|
81
|
-
divElement.style.pointerEvents = 'none';
|
|
82
|
-
divElement.parentElement.style.pointerEvents = 'none';
|
|
83
|
-
} //z-index 처리
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (options.zIndex !== undefined) {
|
|
87
|
-
controller.setMarkerZIndex(markerRef.current, options.zIndex);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}, [options]);
|
|
92
|
-
|
|
93
|
-
var handleIdle = function () {
|
|
94
|
-
// 클리어
|
|
95
|
-
canvasUtil.clearRect(canvasRef.current, contextRef.current); // 표시 복구 (드래그/줌 중 숨김 처리 복원)
|
|
96
|
-
|
|
97
|
-
containerRef.current && (containerRef.current.style.visibility = ''); // 드래그 종료 처리: 변환 초기화 및 기준 위치 갱신
|
|
98
|
-
|
|
99
|
-
draggingRef.current = false;
|
|
100
|
-
prevCenterOffsetRef.current = null;
|
|
101
|
-
accumTranslateRef.current = {
|
|
102
|
-
x: 0,
|
|
103
|
-
y: 0
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
if (containerRef.current) {
|
|
107
|
-
containerRef.current.style.transform = '';
|
|
108
|
-
} // 마커 이동
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
var bounds = controller.getCurrBounds();
|
|
112
|
-
|
|
113
|
-
var markerOptions = tslib.__assign({
|
|
114
|
-
position: bounds.nw
|
|
115
|
-
}, options);
|
|
116
|
-
|
|
117
|
-
markerRef.current && controller.updateMarker(markerRef.current, markerOptions); // 렌더링 (hover/click item last)
|
|
118
|
-
|
|
119
|
-
canvasUtil.renderMain(controller, rendererRef.current, containerRef.current, canvasRef.current, contextRef.current, buildOrderedData());
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
var handleZoomStart = function () {
|
|
123
|
-
containerRef.current && (containerRef.current.style.visibility = 'hidden');
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
var handleZoomEnd = function () {
|
|
127
|
-
containerRef.current && (containerRef.current.style.visibility = '');
|
|
128
|
-
}; //initialize
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
React.useEffect(function () {
|
|
132
|
-
var resizeObserver; // hover/out 공통 처리기 (mouse 좌표 기반)
|
|
133
|
-
|
|
134
|
-
var updateHoverByMouseXY = function (mouseX, mouseY) {
|
|
135
|
-
var hit = hitTest(mouseX, mouseY);
|
|
136
|
-
|
|
137
|
-
if ((hit === null || hit === void 0 ? void 0 : hit.item) !== hoveredRef.current) {
|
|
138
|
-
if (hoveredRef.current && onMouseOut) {
|
|
139
|
-
onMouseOut(hoveredRef.current);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
hoveredRef.current = (hit === null || hit === void 0 ? void 0 : hit.item) || null;
|
|
143
|
-
|
|
144
|
-
if ((hit === null || hit === void 0 ? void 0 : hit.item) && onMouseOver) {
|
|
145
|
-
onMouseOver(hit.item);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
canvasUtil.clearRect(canvasRef.current, contextRef.current);
|
|
149
|
-
canvasUtil.renderMain(controller, rendererRef.current, containerRef.current, canvasRef.current, contextRef.current, buildOrderedData());
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
var handleMouseLeave = function () {
|
|
154
|
-
console.log('handleMouseLeave');
|
|
155
|
-
|
|
156
|
-
if (hoveredRef.current && onMouseOut) {
|
|
157
|
-
onMouseOut(hoveredRef.current);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
hoveredRef.current = null;
|
|
161
|
-
canvasUtil.clearRect(canvasRef.current, contextRef.current);
|
|
162
|
-
canvasUtil.renderMain(controller, rendererRef.current, containerRef.current, canvasRef.current, contextRef.current, buildOrderedData());
|
|
163
|
-
}; // 지도 이벤트 → 화면 좌표 변환
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
var parseEventToOffset = function (e) {
|
|
167
|
-
var mapType = controller.getMapType();
|
|
168
|
-
var latlng = (e === null || e === void 0 ? void 0 : e.latlng) || (e === null || e === void 0 ? void 0 : e.latLng);
|
|
169
|
-
|
|
170
|
-
if (!latlng) {
|
|
171
|
-
return null;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
var pos = {
|
|
175
|
-
lat: 0,
|
|
176
|
-
lng: 0
|
|
177
|
-
}; //@ts-ignore
|
|
178
|
-
|
|
179
|
-
if (mapType === 'naver') {
|
|
180
|
-
pos.lat = latlng._lat;
|
|
181
|
-
pos.lng = latlng._lng; //@ts-ignore
|
|
182
|
-
} else if (mapType === 'google') {
|
|
183
|
-
pos.lat = latlng.lat();
|
|
184
|
-
pos.lng = latlng.lng(); //@ts-ignore
|
|
185
|
-
} else if (mapType === 'kakao') {
|
|
186
|
-
pos.lat = latlng.Ma;
|
|
187
|
-
pos.lng = latlng.La;
|
|
188
|
-
} else {
|
|
189
|
-
return null;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
var offset = controller.positionToOffset(pos);
|
|
193
|
-
return offset;
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
var handleMapMouseMove = function (e) {
|
|
197
|
-
if (draggingRef.current) {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
var offset = parseEventToOffset(e);
|
|
202
|
-
if (!offset) return;
|
|
203
|
-
updateHoverByMouseXY(offset.x, offset.y);
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
var handleMapClick = function (e) {
|
|
207
|
-
console.log('handleClick');
|
|
208
|
-
var offset = parseEventToOffset(e);
|
|
209
|
-
if (!offset) return;
|
|
210
|
-
var hit = hitTest(offset.x, offset.y);
|
|
211
|
-
|
|
212
|
-
if (hit === null || hit === void 0 ? void 0 : hit.item) {
|
|
213
|
-
clickedRef.current = hit.item;
|
|
214
|
-
onClick && onClick(hit.item);
|
|
215
|
-
canvasUtil.clearRect(canvasRef.current, contextRef.current);
|
|
216
|
-
canvasUtil.renderMain(controller, rendererRef.current, containerRef.current, canvasRef.current, contextRef.current, buildOrderedData());
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
if (canvasRef.current && containerRef.current) {
|
|
221
|
-
// 리사이즈 처리
|
|
222
|
-
resizeObserver = new ResizeObserver(function () {
|
|
223
|
-
// 클리어
|
|
224
|
-
canvasUtil.clearRect(canvasRef.current, contextRef.current); // 스케일링
|
|
225
|
-
|
|
226
|
-
canvasRef.current && contextRef.current && canvasUtil.scaleCanvas(controller, canvasRef.current, contextRef.current); // 렌더링 (respect hover/click ordering)
|
|
227
|
-
|
|
228
|
-
canvasUtil.renderMain(controller, rendererRef.current, containerRef.current, canvasRef.current, contextRef.current, buildOrderedData());
|
|
229
|
-
});
|
|
230
|
-
resizeObserver.observe(controller.mapDivElement); // IDLE 이벤트 등록
|
|
231
|
-
|
|
232
|
-
controller.addEventListener('IDLE', handleIdle); // 줌 처리
|
|
233
|
-
|
|
234
|
-
controller.addEventListener('ZOOMSTART', handleZoomStart);
|
|
235
|
-
controller.addEventListener('ZOOM_CHANGED', handleZoomEnd); // 2d 컨텍스트
|
|
236
|
-
|
|
237
|
-
contextRef.current = canvasRef.current.getContext('2d'); // 스케일링
|
|
238
|
-
|
|
239
|
-
if (contextRef.current) {
|
|
240
|
-
canvasUtil.scaleCanvas(controller, canvasRef.current, contextRef.current);
|
|
241
|
-
} // 지도 이벤트 구독 (부모 pointer-events:none 이어도 동작)
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
var map = controller.getMap();
|
|
245
|
-
|
|
246
|
-
if (map) {
|
|
247
|
-
//@ts-ignore
|
|
248
|
-
map.addListener('mousemove', handleMapMouseMove); //@ts-ignore
|
|
249
|
-
|
|
250
|
-
map.addListener('click', handleMapClick); //@ts-ignore
|
|
251
|
-
|
|
252
|
-
map.addListener('center_changed', function () {
|
|
253
|
-
// 드래그 중에는 리렌더 대신 transform 으로만 추종
|
|
254
|
-
var center = controller.getCurrBounds().getCenter();
|
|
255
|
-
var curr = controller.positionToOffset(center);
|
|
256
|
-
var prev = prevCenterOffsetRef.current;
|
|
257
|
-
|
|
258
|
-
if (!prev) {
|
|
259
|
-
prevCenterOffsetRef.current = {
|
|
260
|
-
x: curr.x,
|
|
261
|
-
y: curr.y
|
|
262
|
-
};
|
|
263
|
-
draggingRef.current = true;
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
var dx = prev.x - curr.x;
|
|
268
|
-
var dy = prev.y - curr.y;
|
|
269
|
-
accumTranslateRef.current = {
|
|
270
|
-
x: accumTranslateRef.current.x + dx,
|
|
271
|
-
y: accumTranslateRef.current.y + dy
|
|
272
|
-
};
|
|
273
|
-
prevCenterOffsetRef.current = {
|
|
274
|
-
x: curr.x,
|
|
275
|
-
y: curr.y
|
|
276
|
-
};
|
|
277
|
-
draggingRef.current = true;
|
|
278
|
-
|
|
279
|
-
if (containerRef.current) {
|
|
280
|
-
containerRef.current.style.transform = "translate(".concat(accumTranslateRef.current.x, "px, ").concat(accumTranslateRef.current.y, "px)");
|
|
281
|
-
}
|
|
282
|
-
}); //@ts-ignore
|
|
283
|
-
|
|
284
|
-
map.addListener('idle', handleIdle);
|
|
285
|
-
} // 마우스가 지도 영역을 벗어나는 경우 처리
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
controller.mapDivElement.addEventListener('mouseleave', handleMouseLeave);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
return function () {
|
|
292
|
-
resizeObserver && resizeObserver.disconnect();
|
|
293
|
-
controller.mapDivElement && controller.mapDivElement.removeEventListener('mouseleave', handleMouseLeave);
|
|
294
|
-
controller.removeEventListener('IDLE', handleIdle);
|
|
295
|
-
controller.removeEventListener('ZOOMSTART', handleZoomStart);
|
|
296
|
-
controller.removeEventListener('ZOOM_CHANGED', handleZoomEnd);
|
|
297
|
-
};
|
|
298
|
-
}, []); // data ref
|
|
299
|
-
|
|
300
|
-
var dataRef = React.useRef(data);
|
|
301
|
-
React.useEffect(function () {
|
|
302
|
-
dataRef.current = data; // rebuild geohash index
|
|
303
|
-
|
|
304
|
-
var map = new Map();
|
|
305
|
-
var precision = geoPrecisionRef.current;
|
|
306
|
-
|
|
307
|
-
for (var _i = 0, _a = data || []; _i < _a.length; _i++) {
|
|
308
|
-
var item = _a[_i];
|
|
309
|
-
var pos = item.position && item.position[0];
|
|
310
|
-
if (!pos) continue;
|
|
311
|
-
var hash = geohash.geohashEncode(pos.lat, pos.lng, precision);
|
|
312
|
-
var list = map.get(hash) || [];
|
|
313
|
-
list.push(item);
|
|
314
|
-
map.set(hash, list);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
geoIndexRef.current = map;
|
|
318
|
-
}, [data]); // renderer ref
|
|
319
|
-
|
|
320
|
-
var rendererRef = React.useRef(renderer);
|
|
321
|
-
React.useEffect(function () {
|
|
322
|
-
rendererRef.current = renderer;
|
|
323
|
-
}, [renderer]); // Build ordered list so hovered/clicked items render last (on top) within this canvas layer
|
|
324
|
-
|
|
325
|
-
var buildOrderedData = function () {
|
|
326
|
-
var base = dataRef.current || [];
|
|
327
|
-
var result = [];
|
|
328
|
-
var hoverItem;
|
|
329
|
-
var clickItem;
|
|
330
|
-
|
|
331
|
-
for (var _i = 0, base_1 = base; _i < base_1.length; _i++) {
|
|
332
|
-
var item = base_1[_i];
|
|
333
|
-
|
|
334
|
-
if (clickedRef.current && item === clickedRef.current) {
|
|
335
|
-
clickItem = item;
|
|
336
|
-
} else if (hoveredRef.current && item === hoveredRef.current) {
|
|
337
|
-
hoverItem = item;
|
|
338
|
-
} else {
|
|
339
|
-
result.push(item);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (hoverItem) result.push(hoverItem);
|
|
344
|
-
if (clickItem) result.push(clickItem);
|
|
345
|
-
return result;
|
|
346
|
-
}; // Geohash-accelerated hit-test
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
var hitTest = function (mouseX, mouseY) {
|
|
350
|
-
// convert mouse offset -> lat/lng then geohash it
|
|
351
|
-
var pos = controller.offsetToPosition({
|
|
352
|
-
x: mouseX,
|
|
353
|
-
y: mouseY
|
|
354
|
-
});
|
|
355
|
-
var precision = geoPrecisionRef.current;
|
|
356
|
-
var baseHash = geohash.geohashEncode(pos.lat, pos.lng, precision);
|
|
357
|
-
var buckets = geohash.geohashNeighbors(baseHash); // collect candidates from buckets (preserve ordering for top-most first)
|
|
358
|
-
|
|
359
|
-
var set = new Set();
|
|
360
|
-
var ordered = buildOrderedData();
|
|
361
|
-
|
|
362
|
-
for (var _i = 0, buckets_1 = buckets; _i < buckets_1.length; _i++) {
|
|
363
|
-
var b = buckets_1[_i];
|
|
364
|
-
var list = geoIndexRef.current.get(b);
|
|
365
|
-
if (!list) continue;
|
|
366
|
-
|
|
367
|
-
for (var _a = 0, list_1 = list; _a < list_1.length; _a++) {
|
|
368
|
-
var it = list_1[_a];
|
|
369
|
-
set.add(it);
|
|
370
|
-
}
|
|
371
|
-
} // iterate from top-most
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
for (var i = ordered.length - 1; i >= 0; i--) {
|
|
375
|
-
var item = ordered[i];
|
|
376
|
-
if (!set.has(item)) continue;
|
|
377
|
-
if (item.visible === false) continue;
|
|
378
|
-
var p = item.position && item.position[0];
|
|
379
|
-
if (!p) continue;
|
|
380
|
-
var off = controller.positionToOffset(p);
|
|
381
|
-
var r = Math.max(2, item.hitRadius || 20);
|
|
382
|
-
var dx = mouseX - off.x;
|
|
383
|
-
var dy = mouseY - off.y;
|
|
384
|
-
|
|
385
|
-
if (dx * dx + dy * dy <= r * r) {
|
|
386
|
-
return {
|
|
387
|
-
item: item
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
return null;
|
|
393
|
-
}; // Initial render
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
canvasUtil.renderMain(controller, renderer, containerRef.current, canvasRef.current, contextRef.current, buildOrderedData());
|
|
397
|
-
return reactDom.createPortal(React__default["default"].createElement("div", {
|
|
398
|
-
ref: containerRef,
|
|
399
|
-
style: {
|
|
400
|
-
position: 'absolute',
|
|
401
|
-
width: '100%',
|
|
402
|
-
height: '100%',
|
|
403
|
-
pointerEvents: 'none'
|
|
404
|
-
}
|
|
405
|
-
}, React__default["default"].createElement("canvas", {
|
|
406
|
-
ref: canvasRef,
|
|
407
|
-
style: {
|
|
408
|
-
pointerEvents: 'revert-layer'
|
|
409
|
-
}
|
|
410
|
-
})), divElement);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
exports.CanvasMarkerHanquf = CanvasMarkerHanquf;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
interface Cluster {
|
|
3
|
-
buildingCnt: number;
|
|
4
|
-
lat: number;
|
|
5
|
-
lng: number;
|
|
6
|
-
}
|
|
7
|
-
export interface ClusterMarkerProps {
|
|
8
|
-
cluster: Cluster;
|
|
9
|
-
}
|
|
10
|
-
declare const ClusterMarker: ({ cluster }: ClusterMarkerProps) => JSX.Element;
|
|
11
|
-
export default ClusterMarker;
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { MarkerOptions } from "../../../types";
|
|
3
|
-
import { KonvaCanvasMarkerData, CanvasDataType, CustomRenderBase, CustomRenderAnimation, CustomRenderEvent } from "./shared";
|
|
4
|
-
export { KonvaMarkerProvider, LRUCache, SpatialHashGrid, CanvasDataType } from "./shared";
|
|
5
|
-
export type { KonvaCanvasMarkerOption, Paths, KonvaCanvasMarkerData, CustomRenderBase, CustomRenderAnimation, CustomRenderEvent, RenderUtils, RenderBaseParams, RenderAnimationParams, RenderEventParams } from "./shared";
|
|
6
|
-
/**
|
|
7
|
-
* WoongKonvaMarker 컴포넌트 Props
|
|
8
|
-
* @template T 마커 데이터의 추가 속성 타입
|
|
9
|
-
*/
|
|
10
|
-
export interface WoongKonvaMarkerProps<T> extends Pick<MarkerOptions, 'zIndex' | 'anchor' | 'visible'> {
|
|
11
|
-
/** 렌더링할 마커 데이터 배열 */
|
|
12
|
-
markers: KonvaCanvasMarkerData<T>[];
|
|
13
|
-
/** 데이터 타입 (MARKER 또는 POLYGON) */
|
|
14
|
-
dataType: CanvasDataType;
|
|
15
|
-
/** 마커 클릭 시 호출되는 콜백 (선택) */
|
|
16
|
-
onClick?: (payload: KonvaCanvasMarkerData<T>, selectedIds: Set<string>) => void;
|
|
17
|
-
/** 마커에 마우스 오버 시 호출되는 콜백 (선택) */
|
|
18
|
-
onMouseOver?: (payload: KonvaCanvasMarkerData<T>) => void;
|
|
19
|
-
/** 마커에서 마우스 아웃 시 호출되는 콜백 (선택) */
|
|
20
|
-
onMouseOut?: (payload: KonvaCanvasMarkerData<T>) => void;
|
|
21
|
-
/** Base Layer 렌더링 함수 (필수) */
|
|
22
|
-
renderBase: CustomRenderBase<T>;
|
|
23
|
-
/** Animation Layer 렌더링 함수 (선택, 애니메이션용) */
|
|
24
|
-
renderAnimation?: CustomRenderAnimation<T>;
|
|
25
|
-
/** Event Layer 렌더링 함수 (선택) */
|
|
26
|
-
renderEvent?: CustomRenderEvent<T>;
|
|
27
|
-
/** 다중 선택 활성화 여부 (기본: false) */
|
|
28
|
-
enableMultiSelect?: boolean;
|
|
29
|
-
/** hover 시 마커를 최상단으로 표시 (기본: false) */
|
|
30
|
-
topOnHover?: boolean;
|
|
31
|
-
/** 뷰포트 컬링 활성화 여부 (기본: true) */
|
|
32
|
-
enableViewportCulling?: boolean;
|
|
33
|
-
/** 뷰포트 컬링 여유 공간 (기본: 100px) */
|
|
34
|
-
cullingMargin?: number;
|
|
35
|
-
/** LRU 캐시 최대 크기 (기본: 10000) */
|
|
36
|
-
maxCacheSize?: number;
|
|
37
|
-
/** 외부에서 제어하는 선택된 항목 배열 (선택) */
|
|
38
|
-
selectedItems?: KonvaCanvasMarkerData<T>[];
|
|
39
|
-
/** 외부에서 전달된 단일 선택 아이템 (특별한 효과용) */
|
|
40
|
-
selectedItem?: KonvaCanvasMarkerData<T> | null;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* 🔥 React.memo 최적화: 마커 배열과 selectedItems 변경 체크
|
|
44
|
-
*
|
|
45
|
-
* 비교 전략:
|
|
46
|
-
* 1. markers 배열 비교
|
|
47
|
-
* 2. selectedItems 배열 비교 (외부 제어)
|
|
48
|
-
* 3. 이벤트 핸들러 비교 (onClick, onMouseOver, onMouseOut)
|
|
49
|
-
*
|
|
50
|
-
* 주의: JSON.stringify() 사용 금지! (매우 느림)
|
|
51
|
-
*/
|
|
52
|
-
declare const WoongKonvaMarker: <T>({ markers, dataType, onClick, onMouseOver, onMouseOut, renderBase, renderAnimation, renderEvent, enableMultiSelect, topOnHover, enableViewportCulling, cullingMargin, maxCacheSize, selectedItems: externalSelectedItems, selectedItem: externalSelectedItem, ...options }: WoongKonvaMarkerProps<T>) => React.ReactPortal;
|
|
53
|
-
export default WoongKonvaMarker;
|