react-floor-mapper 0.1.6 → 0.1.8
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/{index.mjs → index.cjs} +156 -127
- package/dist/index.cjs.map +1 -0
- package/dist/{index.d.mts → index.d.cts} +7 -19
- package/dist/index.d.ts +7 -19
- package/dist/index.js +127 -152
- package/dist/index.js.map +1 -1
- package/dist/lite.cjs +480 -0
- package/dist/lite.cjs.map +1 -0
- package/dist/lite.d.cts +16 -0
- package/dist/lite.d.ts +16 -0
- package/dist/lite.js +473 -0
- package/dist/lite.js.map +1 -0
- package/package.json +7 -5
- package/dist/index.mjs.map +0 -1
package/dist/lite.cjs
ADDED
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var reactKonva = require('react-konva');
|
|
5
|
+
var useImage = require('use-image');
|
|
6
|
+
var lucideReact = require('lucide-react');
|
|
7
|
+
var styled = require('styled-components');
|
|
8
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
+
|
|
10
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
|
|
12
|
+
var useImage__default = /*#__PURE__*/_interopDefault(useImage);
|
|
13
|
+
var styled__default = /*#__PURE__*/_interopDefault(styled);
|
|
14
|
+
|
|
15
|
+
// src/components/MapperEditor/Mapper.tsx
|
|
16
|
+
|
|
17
|
+
// src/utils/closest-segment-point.ts
|
|
18
|
+
var getClosestPointOnSegment = (px, py, x1, y1, x2, y2) => {
|
|
19
|
+
const dx = x2 - x1;
|
|
20
|
+
const dy = y2 - y1;
|
|
21
|
+
const lengthSquared = dx * dx + dy * dy;
|
|
22
|
+
if (lengthSquared === 0) return { x: x1, y: y1, t: 0 };
|
|
23
|
+
let t = ((px - x1) * dx + (py - y1) * dy) / lengthSquared;
|
|
24
|
+
t = Math.max(0, Math.min(1, t));
|
|
25
|
+
return {
|
|
26
|
+
x: x1 + t * dx,
|
|
27
|
+
y: y1 + t * dy,
|
|
28
|
+
t
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
var usePoints = (initialPoints) => {
|
|
32
|
+
const [points, setPoints] = react.useState(
|
|
33
|
+
() => initialPoints.map((p, i) => ({ id: i + 1, x: p.x, y: p.y }))
|
|
34
|
+
);
|
|
35
|
+
return { points, setPoints };
|
|
36
|
+
};
|
|
37
|
+
var useZoom = (stage) => {
|
|
38
|
+
const MIN_SCALE = 0.5;
|
|
39
|
+
const MAX_SCALE = 5;
|
|
40
|
+
const DEFAULT_SCALE = 1;
|
|
41
|
+
const [stageScale, setStageScale] = react.useState(DEFAULT_SCALE);
|
|
42
|
+
return {
|
|
43
|
+
stageScale,
|
|
44
|
+
setStageScale,
|
|
45
|
+
MIN_SCALE,
|
|
46
|
+
MAX_SCALE
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
var Container = styled__default.default.div`
|
|
50
|
+
overflow: hidden;
|
|
51
|
+
width:1200px;
|
|
52
|
+
height:1200px;
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: stretch;
|
|
55
|
+
border:1px solid #ccc;
|
|
56
|
+
border-radius:4px;
|
|
57
|
+
`;
|
|
58
|
+
var NavContainer = styled__default.default.div`
|
|
59
|
+
width:80px;
|
|
60
|
+
height:100%;
|
|
61
|
+
background:red;
|
|
62
|
+
flex-shrink:0;
|
|
63
|
+
display: flex;
|
|
64
|
+
justify-content: flex-start;
|
|
65
|
+
align-items: center;
|
|
66
|
+
flex-direction:column;
|
|
67
|
+
gap:20px;
|
|
68
|
+
padding:20px 0;
|
|
69
|
+
background:#ebebeb;
|
|
70
|
+
border-left:1px solid #ccc;
|
|
71
|
+
`;
|
|
72
|
+
var CanvasContainer = styled__default.default.div`
|
|
73
|
+
width:calc(100% - 80px);
|
|
74
|
+
height:100%;
|
|
75
|
+
overflow: hidden;
|
|
76
|
+
`;
|
|
77
|
+
var ButtonBase = styled__default.default.button`
|
|
78
|
+
padding:2px;
|
|
79
|
+
background:white;
|
|
80
|
+
border:none;
|
|
81
|
+
border-radius:8px;
|
|
82
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
83
|
+
cursor: pointer;
|
|
84
|
+
display: flex;
|
|
85
|
+
justify-content: center;
|
|
86
|
+
align-items: center;
|
|
87
|
+
font-size:12px;
|
|
88
|
+
min-width:50px;
|
|
89
|
+
min-height:50px;
|
|
90
|
+
border-left:1px solid #ccc;
|
|
91
|
+
&:disabled:{
|
|
92
|
+
opacity:0.5;
|
|
93
|
+
cursor:not-allowed;
|
|
94
|
+
}
|
|
95
|
+
`;
|
|
96
|
+
var Button = styled__default.default(ButtonBase)``;
|
|
97
|
+
var Mapper = ({
|
|
98
|
+
src = "https://konvajs.org/assets/line-building.png",
|
|
99
|
+
initialPoints = [],
|
|
100
|
+
maxWidth = 1200
|
|
101
|
+
}) => {
|
|
102
|
+
const stageRef = react.useRef(null);
|
|
103
|
+
const { points, setPoints } = usePoints(initialPoints);
|
|
104
|
+
const { stageScale, setStageScale, MAX_SCALE, MIN_SCALE } = useZoom(stageRef == null ? void 0 : stageRef.current);
|
|
105
|
+
const SCALE_BY = 1.2;
|
|
106
|
+
const [closed, setClosed] = react.useState(initialPoints.length >= 3);
|
|
107
|
+
const [hoveringFirst, setHoveringFirst] = react.useState(false);
|
|
108
|
+
const [stagePosition, setStagePosition] = react.useState({ x: 0, y: 0 });
|
|
109
|
+
const [dragStart, setDragStart] = react.useState(null);
|
|
110
|
+
const [isDraggingPoint, setIsDraggingPoint] = react.useState(false);
|
|
111
|
+
const [image] = useImage__default.default(src, "anonymous");
|
|
112
|
+
const imgW = (image == null ? void 0 : image.width) || 1;
|
|
113
|
+
const imgH = (image == null ? void 0 : image.height) || 1;
|
|
114
|
+
const scale = maxWidth / imgW;
|
|
115
|
+
const stageSize = { width: maxWidth, height: imgH * scale };
|
|
116
|
+
const DRAG_THRESHOLD = 5;
|
|
117
|
+
const LINE_HIT_THRESHOLD = 10;
|
|
118
|
+
const handleZoomIn = () => {
|
|
119
|
+
const stage = stageRef.current;
|
|
120
|
+
if (!stage) return;
|
|
121
|
+
const oldScale = stageScale;
|
|
122
|
+
const newScale = Math.min(oldScale * SCALE_BY, MAX_SCALE);
|
|
123
|
+
if (newScale === oldScale) return;
|
|
124
|
+
const centerX = stage.width() / 2;
|
|
125
|
+
const centerY = stage.height() / 2;
|
|
126
|
+
const pointTo = {
|
|
127
|
+
x: (centerX - stagePosition.x) / oldScale,
|
|
128
|
+
y: (centerY - stagePosition.y) / oldScale
|
|
129
|
+
};
|
|
130
|
+
const newPos = {
|
|
131
|
+
x: centerX - pointTo.x * newScale,
|
|
132
|
+
y: centerY - pointTo.y * newScale
|
|
133
|
+
};
|
|
134
|
+
const constrainedPos = getConstrainedPosition(newPos, newScale);
|
|
135
|
+
setStageScale(newScale);
|
|
136
|
+
setStagePosition(constrainedPos);
|
|
137
|
+
};
|
|
138
|
+
const handleZoomOut = () => {
|
|
139
|
+
const stage = stageRef.current;
|
|
140
|
+
if (!stage) return;
|
|
141
|
+
const oldScale = stageScale;
|
|
142
|
+
const newScale = Math.max(oldScale / SCALE_BY, MIN_SCALE);
|
|
143
|
+
if (newScale === oldScale) return;
|
|
144
|
+
const centerX = stage.width() / 2;
|
|
145
|
+
const centerY = stage.height() / 2;
|
|
146
|
+
const pointTo = {
|
|
147
|
+
x: (centerX - stagePosition.x) / oldScale,
|
|
148
|
+
y: (centerY - stagePosition.y) / oldScale
|
|
149
|
+
};
|
|
150
|
+
const newPos = {
|
|
151
|
+
x: centerX - pointTo.x * newScale,
|
|
152
|
+
y: centerY - pointTo.y * newScale
|
|
153
|
+
};
|
|
154
|
+
const constrainedPos = getConstrainedPosition(newPos, newScale);
|
|
155
|
+
setStageScale(newScale);
|
|
156
|
+
setStagePosition(constrainedPos);
|
|
157
|
+
};
|
|
158
|
+
const handleResetZoom = () => {
|
|
159
|
+
const newScale = 1;
|
|
160
|
+
const constrainedPos = getConstrainedPosition({ x: 0, y: 0 }, newScale);
|
|
161
|
+
setStageScale(newScale);
|
|
162
|
+
setStagePosition(constrainedPos);
|
|
163
|
+
};
|
|
164
|
+
const handleWheel = (e) => {
|
|
165
|
+
e.evt.preventDefault();
|
|
166
|
+
const stage = stageRef.current;
|
|
167
|
+
if (!stage) return;
|
|
168
|
+
const oldScale = stageScale;
|
|
169
|
+
const pointer = stage.getPointerPosition();
|
|
170
|
+
if (!pointer) return;
|
|
171
|
+
const mousePointTo = {
|
|
172
|
+
x: (pointer.x - stagePosition.x) / oldScale,
|
|
173
|
+
y: (pointer.y - stagePosition.y) / oldScale
|
|
174
|
+
};
|
|
175
|
+
const direction = e.evt.deltaY > 0 ? -1 : 1;
|
|
176
|
+
const newScale = direction > 0 ? Math.min(oldScale * SCALE_BY, MAX_SCALE) : Math.max(oldScale / SCALE_BY, MIN_SCALE);
|
|
177
|
+
if (newScale === oldScale) return;
|
|
178
|
+
const newPos = {
|
|
179
|
+
x: pointer.x - mousePointTo.x * newScale,
|
|
180
|
+
y: pointer.y - mousePointTo.y * newScale
|
|
181
|
+
};
|
|
182
|
+
const constrainedPos = getConstrainedPosition(newPos, newScale);
|
|
183
|
+
setStageScale(newScale);
|
|
184
|
+
setStagePosition(constrainedPos);
|
|
185
|
+
};
|
|
186
|
+
const getConstrainedPosition = (pos, currentScale) => {
|
|
187
|
+
const stage = stageRef.current;
|
|
188
|
+
if (!stage) return pos;
|
|
189
|
+
const stageWidth = stage.width();
|
|
190
|
+
const stageHeight = stage.height();
|
|
191
|
+
const imageWidth = stageSize.width * currentScale;
|
|
192
|
+
const imageHeight = stageSize.height * currentScale;
|
|
193
|
+
let newX = pos.x;
|
|
194
|
+
let newY = pos.y;
|
|
195
|
+
if (imageWidth > stageWidth) {
|
|
196
|
+
if (newX > 0) newX = 0;
|
|
197
|
+
if (newX < stageWidth - imageWidth) newX = stageWidth - imageWidth;
|
|
198
|
+
} else {
|
|
199
|
+
newX = (stageWidth - imageWidth) / 2;
|
|
200
|
+
}
|
|
201
|
+
if (imageHeight > stageHeight) {
|
|
202
|
+
if (newY > 0) newY = 0;
|
|
203
|
+
if (newY < stageHeight - imageHeight) newY = stageHeight - imageHeight;
|
|
204
|
+
} else {
|
|
205
|
+
newY = (stageHeight - imageHeight) / 2;
|
|
206
|
+
}
|
|
207
|
+
return { x: newX, y: newY };
|
|
208
|
+
};
|
|
209
|
+
const findLineSegmentNearClick = (clickX, clickY) => {
|
|
210
|
+
if (points.length < 2) return null;
|
|
211
|
+
const threshold = LINE_HIT_THRESHOLD / (scale * stageScale);
|
|
212
|
+
const segments = [];
|
|
213
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
214
|
+
segments.push({ start: i, end: i + 1 });
|
|
215
|
+
}
|
|
216
|
+
if (closed) {
|
|
217
|
+
segments.push({ start: points.length - 1, end: 0 });
|
|
218
|
+
}
|
|
219
|
+
for (const segment of segments) {
|
|
220
|
+
const p1 = points[segment.start];
|
|
221
|
+
const p2 = points[segment.end];
|
|
222
|
+
const closest = getClosestPointOnSegment(clickX, clickY, p1.x, p1.y, p2.x, p2.y);
|
|
223
|
+
const distance = Math.hypot(closest.x - clickX, closest.y - clickY);
|
|
224
|
+
if (distance < threshold) {
|
|
225
|
+
return {
|
|
226
|
+
segmentIndex: segment.start,
|
|
227
|
+
insertPosition: closest.t,
|
|
228
|
+
point: { x: closest.x, y: closest.y }
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return null;
|
|
233
|
+
};
|
|
234
|
+
react.useEffect(() => {
|
|
235
|
+
if (image) {
|
|
236
|
+
const initialPos = getConstrainedPosition({ x: 0, y: 0 }, 1);
|
|
237
|
+
setStagePosition(initialPos);
|
|
238
|
+
}
|
|
239
|
+
}, [image]);
|
|
240
|
+
react.useEffect(() => {
|
|
241
|
+
const handleKeyDown = (e) => {
|
|
242
|
+
if (e.ctrlKey || e.metaKey) {
|
|
243
|
+
if (e.key === "=" || e.key === "+") {
|
|
244
|
+
e.preventDefault();
|
|
245
|
+
handleZoomIn();
|
|
246
|
+
} else if (e.key === "-") {
|
|
247
|
+
e.preventDefault();
|
|
248
|
+
handleZoomOut();
|
|
249
|
+
} else if (e.key === "0") {
|
|
250
|
+
e.preventDefault();
|
|
251
|
+
handleResetZoom();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
256
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
257
|
+
}, [stageScale, stagePosition]);
|
|
258
|
+
const handleStageDragStart = (e) => {
|
|
259
|
+
const clickedShape = e.target;
|
|
260
|
+
if (clickedShape && clickedShape.name() === "point") {
|
|
261
|
+
e.target.stopDrag();
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const stage = e.target.getStage();
|
|
265
|
+
if (!stage) return;
|
|
266
|
+
const pos = stage.getPointerPosition();
|
|
267
|
+
if (pos) {
|
|
268
|
+
setDragStart(pos);
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
const handleStageDragEnd = (e) => {
|
|
272
|
+
const newPos = {
|
|
273
|
+
x: e.target.x(),
|
|
274
|
+
y: e.target.y()
|
|
275
|
+
};
|
|
276
|
+
const constrainedPos = getConstrainedPosition(newPos, stageScale);
|
|
277
|
+
setStagePosition(constrainedPos);
|
|
278
|
+
setDragStart(null);
|
|
279
|
+
};
|
|
280
|
+
const toImageCoords = (stage) => {
|
|
281
|
+
if (!stage) return { x: 0, y: 0 };
|
|
282
|
+
const pos = stage.getPointerPosition();
|
|
283
|
+
if (!pos) return { x: 0, y: 0 };
|
|
284
|
+
const x = (pos.x - stagePosition.x) / (scale * stageScale);
|
|
285
|
+
const y = (pos.y - stagePosition.y) / (scale * stageScale);
|
|
286
|
+
return { x, y };
|
|
287
|
+
};
|
|
288
|
+
const linePointsScaled = react.useMemo(() => {
|
|
289
|
+
const flat = points.flatMap((p) => [p.x * scale, p.y * scale]);
|
|
290
|
+
return flat;
|
|
291
|
+
}, [points, scale]);
|
|
292
|
+
const commit = (nextPoints) => {
|
|
293
|
+
setPoints(nextPoints);
|
|
294
|
+
};
|
|
295
|
+
const handlePointDragStart = (e) => {
|
|
296
|
+
e.cancelBubble = true;
|
|
297
|
+
setIsDraggingPoint(true);
|
|
298
|
+
};
|
|
299
|
+
const handlePointDragMove = (id, e) => {
|
|
300
|
+
const newX = e.target.x() / scale;
|
|
301
|
+
const newY = e.target.y() / scale;
|
|
302
|
+
const updatedPoints = points.map(
|
|
303
|
+
(p) => p.id === id ? { ...p, x: newX, y: newY } : p
|
|
304
|
+
);
|
|
305
|
+
setPoints(updatedPoints);
|
|
306
|
+
};
|
|
307
|
+
const handlePointDragEnd = (e) => {
|
|
308
|
+
e.cancelBubble = true;
|
|
309
|
+
setIsDraggingPoint(false);
|
|
310
|
+
};
|
|
311
|
+
const handleStageMouseDown = (e) => {
|
|
312
|
+
if (!image) return;
|
|
313
|
+
const clickedShape = e.target;
|
|
314
|
+
if (clickedShape && clickedShape.name() === "point") {
|
|
315
|
+
if (!closed) {
|
|
316
|
+
const clickedIndex = points.findIndex(
|
|
317
|
+
(p) => Math.abs(p.x * scale - clickedShape.x()) < 1 && Math.abs(p.y * scale - clickedShape.y()) < 1
|
|
318
|
+
);
|
|
319
|
+
if (clickedIndex === 0 && points.length >= 3) {
|
|
320
|
+
setClosed(true);
|
|
321
|
+
setHoveringFirst(false);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const stage = e.target.getStage();
|
|
327
|
+
if (!stage) return;
|
|
328
|
+
const pos = stage.getPointerPosition();
|
|
329
|
+
if (pos) {
|
|
330
|
+
setDragStart(pos);
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
const handleStageMouseUp = (e) => {
|
|
334
|
+
if (!image || isDraggingPoint) return;
|
|
335
|
+
const clickedShape = e.target;
|
|
336
|
+
if (clickedShape && clickedShape.name() === "point") {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (dragStart) {
|
|
340
|
+
const stage = e.target.getStage();
|
|
341
|
+
if (!stage) return;
|
|
342
|
+
const currentPos = stage.getPointerPosition();
|
|
343
|
+
if (currentPos) {
|
|
344
|
+
const dx = currentPos.x - dragStart.x;
|
|
345
|
+
const dy = currentPos.y - dragStart.y;
|
|
346
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
347
|
+
if (distance < DRAG_THRESHOLD) {
|
|
348
|
+
const p = toImageCoords(stage);
|
|
349
|
+
const lineHit = findLineSegmentNearClick(p.x, p.y);
|
|
350
|
+
if (lineHit) {
|
|
351
|
+
const newPoint = {
|
|
352
|
+
id: Date.now(),
|
|
353
|
+
x: lineHit.point.x,
|
|
354
|
+
y: lineHit.point.y
|
|
355
|
+
};
|
|
356
|
+
const newPoints = [...points];
|
|
357
|
+
newPoints.splice(lineHit.segmentIndex + 1, 0, newPoint);
|
|
358
|
+
commit(newPoints);
|
|
359
|
+
} else if (!closed) {
|
|
360
|
+
const next = [...points, { id: Date.now(), x: p.x, y: p.y }];
|
|
361
|
+
commit(next);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
setDragStart(null);
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
const handleMouseMove = (e) => {
|
|
369
|
+
if (closed || points.length < 3) {
|
|
370
|
+
setHoveringFirst(false);
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
const stage = e.target.getStage();
|
|
374
|
+
const p = toImageCoords(stage);
|
|
375
|
+
const fp = points[0];
|
|
376
|
+
const dx = (p.x - fp.x) * scale * stageScale;
|
|
377
|
+
const dy = (p.y - fp.y) * scale * stageScale;
|
|
378
|
+
const dist = Math.hypot(dx, dy);
|
|
379
|
+
setHoveringFirst(dist < 15);
|
|
380
|
+
};
|
|
381
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Container, { children: [
|
|
382
|
+
/* @__PURE__ */ jsxRuntime.jsx(CanvasContainer, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
383
|
+
reactKonva.Stage,
|
|
384
|
+
{
|
|
385
|
+
ref: stageRef,
|
|
386
|
+
width: 1200,
|
|
387
|
+
height: 1200,
|
|
388
|
+
onMouseDown: handleStageMouseDown,
|
|
389
|
+
onMouseUp: handleStageMouseUp,
|
|
390
|
+
onMouseMove: handleMouseMove,
|
|
391
|
+
onWheel: handleWheel,
|
|
392
|
+
scaleX: stageScale,
|
|
393
|
+
scaleY: stageScale,
|
|
394
|
+
x: stagePosition.x,
|
|
395
|
+
y: stagePosition.y,
|
|
396
|
+
draggable: !isDraggingPoint,
|
|
397
|
+
onDragStart: handleStageDragStart,
|
|
398
|
+
onDragEnd: handleStageDragEnd,
|
|
399
|
+
dragBoundFunc: (pos) => getConstrainedPosition(pos, stageScale),
|
|
400
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(reactKonva.Layer, { children: [
|
|
401
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
402
|
+
reactKonva.Image,
|
|
403
|
+
{
|
|
404
|
+
image,
|
|
405
|
+
width: stageSize.width,
|
|
406
|
+
height: stageSize.height,
|
|
407
|
+
listening: false
|
|
408
|
+
}
|
|
409
|
+
),
|
|
410
|
+
points.length >= 2 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
411
|
+
reactKonva.Line,
|
|
412
|
+
{
|
|
413
|
+
points: linePointsScaled,
|
|
414
|
+
closed,
|
|
415
|
+
stroke: "#2563eb",
|
|
416
|
+
strokeWidth: 2 / stageScale,
|
|
417
|
+
lineCap: "round",
|
|
418
|
+
lineJoin: "round",
|
|
419
|
+
tension: 0,
|
|
420
|
+
fill: closed ? "rgba(37, 99, 235, 0.3)" : void 0,
|
|
421
|
+
hitStrokeWidth: LINE_HIT_THRESHOLD / stageScale
|
|
422
|
+
}
|
|
423
|
+
),
|
|
424
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactKonva.Group, { children: points.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
425
|
+
reactKonva.Circle,
|
|
426
|
+
{
|
|
427
|
+
name: "point",
|
|
428
|
+
x: p.x * scale,
|
|
429
|
+
y: p.y * scale,
|
|
430
|
+
radius: (i === 0 && hoveringFirst ? 10 : 6) / stageScale,
|
|
431
|
+
fill: i === 0 ? "#ef4444" : "#7e9de1",
|
|
432
|
+
stroke: i === 0 && hoveringFirst ? "#fbbf24" : void 0,
|
|
433
|
+
strokeWidth: i === 0 && hoveringFirst ? 2 / stageScale : 0,
|
|
434
|
+
draggable: true,
|
|
435
|
+
onDragStart: handlePointDragStart,
|
|
436
|
+
onDragMove: (e) => handlePointDragMove(p.id, e),
|
|
437
|
+
onDragEnd: handlePointDragEnd
|
|
438
|
+
},
|
|
439
|
+
p.id
|
|
440
|
+
)) })
|
|
441
|
+
] })
|
|
442
|
+
}
|
|
443
|
+
) }),
|
|
444
|
+
/* @__PURE__ */ jsxRuntime.jsxs(NavContainer, { children: [
|
|
445
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
446
|
+
Button,
|
|
447
|
+
{
|
|
448
|
+
onClick: handleZoomIn,
|
|
449
|
+
disabled: stageScale >= MAX_SCALE,
|
|
450
|
+
title: "Zoom In (Ctrl/Cmd + +)",
|
|
451
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomIn, { style: { width: "20px", height: "20px" } })
|
|
452
|
+
}
|
|
453
|
+
),
|
|
454
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
455
|
+
Button,
|
|
456
|
+
{
|
|
457
|
+
onClick: handleZoomOut,
|
|
458
|
+
disabled: stageScale <= MIN_SCALE,
|
|
459
|
+
title: "Zoom Out (Ctrl/Cmd + -)",
|
|
460
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomOut, { style: { width: "20px", height: "20px" } })
|
|
461
|
+
}
|
|
462
|
+
),
|
|
463
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
464
|
+
Button,
|
|
465
|
+
{
|
|
466
|
+
onClick: handleResetZoom,
|
|
467
|
+
title: "Reset Zoom (Ctrl/Cmd + 0)",
|
|
468
|
+
children: [
|
|
469
|
+
Math.round(stageScale * 100),
|
|
470
|
+
"%"
|
|
471
|
+
]
|
|
472
|
+
}
|
|
473
|
+
)
|
|
474
|
+
] })
|
|
475
|
+
] });
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
exports.Mapper = Mapper;
|
|
479
|
+
//# sourceMappingURL=lite.cjs.map
|
|
480
|
+
//# sourceMappingURL=lite.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/closest-segment-point.ts","../src/components/MapperEditor/hooks/usePoints.ts","../src/components/MapperEditor/hooks/useZoom.ts","../src/components/MapperEditor/Mapper.style.tsx","../src/components/MapperEditor/Mapper.tsx"],"names":["useState","styled","useRef","useImage","useEffect","useMemo","jsx","Stage","Layer","KonvaImage","Line","Group","Circle","ZoomIn","ZoomOut","jsxs"],"mappings":"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","file":"lite.cjs","sourcesContent":["export const getClosestPointOnSegment = (\n px: number, py: number,\n x1: number, y1: number,\n x2: number, y2: number\n) => {\n const dx = x2 - x1;\n const dy = y2 - y1;\n const lengthSquared = dx * dx + dy * dy;\n \n if (lengthSquared === 0) return { x: x1, y: y1, t: 0 };\n \n let t = ((px - x1) * dx + (py - y1) * dy) / lengthSquared;\n t = Math.max(0, Math.min(1, t));\n \n return {\n x: x1 + t * dx,\n y: y1 + t * dy,\n t\n };\n};","import { useState } from \"react\";\nimport { Point, Points } from \"../../../types/points.type\";\n\nexport const usePoints = (initialPoints: Omit<Point, \"id\">[]) => {\n const [points, setPoints] = useState<Points>(() =>\n initialPoints.map((p, i) => ({ id: i + 1, x: p.x, y: p.y }))\n );\n\n return { points, setPoints };\n}","import Konva from \"konva\";\nimport { KonvaEventObject } from \"konva/lib/Node\";\nimport { useState } from \"react\";\n\nexport const useZoom = (stage:Konva.Stage | null) => {\n const MIN_SCALE = 0.5;\n const MAX_SCALE = 5;\n const DEFAULT_SCALE = 1;\n \n const [stageScale, setStageScale] = useState(DEFAULT_SCALE);\n\n return{\n stageScale,\n setStageScale,\n MIN_SCALE,\n MAX_SCALE,\n }\n}","import styled from \"styled-components\";\n\nexport const Container = styled.div`\n overflow: hidden;\n width:1200px;\n height:1200px;\n display: flex;\n align-items: stretch;\n border:1px solid #ccc;\n border-radius:4px;\n`;\n\nexport const NavContainer = styled.div`\n width:80px;\n height:100%;\n background:red;\n flex-shrink:0;\n display: flex;\n justify-content: flex-start;\n align-items: center;\n flex-direction:column;\n gap:20px;\n padding:20px 0;\n background:#ebebeb;\n border-left:1px solid #ccc;\n`\n\nexport const CanvasContainer = styled.div`\n width:calc(100% - 80px);\n height:100%;\n overflow: hidden;\n`\n\nexport const ButtonBase = styled.button`\n padding:2px;\n background:white;\n border:none;\n border-radius:8px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n cursor: pointer;\n display: flex;\n justify-content: center;\n align-items: center;\n font-size:12px;\n min-width:50px;\n min-height:50px;\n border-left:1px solid #ccc;\n &:disabled:{\n opacity:0.5;\n cursor:not-allowed;\n }\n`\n\nexport const Button = styled(ButtonBase)``;","import { KonvaEventObject } from \"konva/lib/Node\";\nimport React, { useMemo, useState, useRef, useEffect } from \"react\";\nimport { Stage, Layer, Image as KonvaImage, Circle, Line, Group } from \"react-konva\";\nimport useImage from \"use-image\";\nimport Konva from \"konva\";\nimport { ZoomIn, ZoomOut } from \"lucide-react\";\nimport { getClosestPointOnSegment } from \"../../utils/closest-segment-point\";\nimport { usePoints } from \"./hooks/usePoints\";\nimport { Point, Points } from \"../../types/points.type\";\nimport { useZoom } from \"./hooks/useZoom\";\nimport { Button, CanvasContainer, Container, NavContainer } from \"./Mapper.style\";\n\nexport interface MapperProps {\n src?: string;\n initialPoints?: Omit<Point, \"id\">[];\n maxWidth?: number;\n}\n\nexport const Mapper = ({\n src = \"https://konvajs.org/assets/line-building.png\",\n initialPoints = [], \n maxWidth = 1200,\n}: MapperProps) => {\n const stageRef = useRef<Konva.Stage>(null);\n const { points, setPoints } = usePoints(initialPoints);\n const { stageScale, setStageScale, MAX_SCALE, MIN_SCALE } = useZoom(stageRef?.current);\n const SCALE_BY = 1.2;\n\n const [closed, setClosed] = useState(initialPoints.length >= 3);\n \n const [hoveringFirst, setHoveringFirst] = useState(false);\n const [stagePosition, setStagePosition] = useState({ x: 0, y: 0 });\n const [dragStart, setDragStart] = useState<{ x: number; y: number } | null>(null);\n const [isDraggingPoint, setIsDraggingPoint] = useState(false);\n \n \n const [image] = useImage(src, \"anonymous\");\n const imgW = image?.width || 1;\n const imgH = image?.height || 1;\n const scale = maxWidth / imgW;\n const stageSize = { width: maxWidth, height: imgH * scale } ;\n\n \n const DRAG_THRESHOLD = 5;\n const LINE_HIT_THRESHOLD = 10;\n\n const handleZoomIn = () => {\n const stage = stageRef.current;\n if (!stage) return;\n\n const oldScale = stageScale;\n const newScale = Math.min(oldScale * SCALE_BY, MAX_SCALE);\n\n if (newScale === oldScale) return;\n\n const centerX = stage.width() / 2;\n const centerY = stage.height() / 2;\n\n const pointTo = {\n x: (centerX - stagePosition.x) / oldScale,\n y: (centerY - stagePosition.y) / oldScale,\n };\n\n const newPos = {\n x: centerX - pointTo.x * newScale,\n y: centerY - pointTo.y * newScale,\n };\n\n const constrainedPos = getConstrainedPosition(newPos, newScale);\n setStageScale(newScale);\n setStagePosition(constrainedPos);\n };\n \n const handleZoomOut = () => {\n const stage = stageRef.current;\n if (!stage) return;\n \n const oldScale = stageScale;\n const newScale = Math.max(oldScale / SCALE_BY, MIN_SCALE);\n \n if (newScale === oldScale) return;\n \n const centerX = stage.width() / 2;\n const centerY = stage.height() / 2;\n \n const pointTo = {\n x: (centerX - stagePosition.x) / oldScale,\n y: (centerY - stagePosition.y) / oldScale,\n };\n \n const newPos = {\n x: centerX - pointTo.x * newScale,\n y: centerY - pointTo.y * newScale,\n };\n \n const constrainedPos = getConstrainedPosition(newPos, newScale);\n setStageScale(newScale);\n setStagePosition(constrainedPos);\n };\n \n const handleResetZoom = () => {\n const newScale = 1;\n const constrainedPos = getConstrainedPosition({ x: 0, y: 0 }, newScale);\n setStageScale(newScale);\n setStagePosition(constrainedPos);\n };\n \n const handleWheel = (e: KonvaEventObject<WheelEvent>) => {\n e.evt.preventDefault();\n \n const stage = stageRef.current;\n if (!stage) return;\n \n const oldScale = stageScale;\n const pointer = stage.getPointerPosition();\n if (!pointer) return;\n \n const mousePointTo = {\n x: (pointer.x - stagePosition.x) / oldScale,\n y: (pointer.y - stagePosition.y) / oldScale,\n };\n \n const direction = e.evt.deltaY > 0 ? -1 : 1;\n const newScale = direction > 0 \n ? Math.min(oldScale * SCALE_BY, MAX_SCALE)\n : Math.max(oldScale / SCALE_BY, MIN_SCALE);\n \n if (newScale === oldScale) return;\n \n const newPos = {\n x: pointer.x - mousePointTo.x * newScale,\n y: pointer.y - mousePointTo.y * newScale,\n };\n \n const constrainedPos = getConstrainedPosition(newPos, newScale);\n setStageScale(newScale);\n setStagePosition(constrainedPos);\n };\n\n // Function to constrain position within bounds\n const getConstrainedPosition = (pos: { x: number; y: number }, currentScale: number) => {\n const stage = stageRef.current;\n if (!stage) return pos;\n\n const stageWidth = stage.width();\n const stageHeight = stage.height();\n const imageWidth = stageSize.width * currentScale;\n const imageHeight = stageSize.height * currentScale;\n\n let newX = pos.x;\n let newY = pos.y;\n\n // Constrain X axis\n if (imageWidth > stageWidth) {\n if (newX > 0) newX = 0;\n if (newX < stageWidth - imageWidth) newX = stageWidth - imageWidth;\n } else {\n newX = (stageWidth - imageWidth) / 2;\n }\n\n // Constrain Y axis\n if (imageHeight > stageHeight) {\n if (newY > 0) newY = 0;\n if (newY < stageHeight - imageHeight) newY = stageHeight - imageHeight;\n } else {\n newY = (stageHeight - imageHeight) / 2;\n }\n\n return { x: newX, y: newY };\n };\n\n\n // Function to check if click is near a line segment\n const findLineSegmentNearClick = (clickX: number, clickY: number) => {\n if (points.length < 2) return null;\n\n const threshold = LINE_HIT_THRESHOLD / (scale * stageScale);\n \n const segments = [];\n for (let i = 0; i < points.length - 1; i++) {\n segments.push({ start: i, end: i + 1 });\n }\n \n // If closed, add segment from last to first\n if (closed) {\n segments.push({ start: points.length - 1, end: 0 });\n }\n\n for (const segment of segments) {\n const p1 = points[segment.start];\n const p2 = points[segment.end];\n \n const closest = getClosestPointOnSegment(clickX, clickY, p1.x, p1.y, p2.x, p2.y);\n const distance = Math.hypot(closest.x - clickX, closest.y - clickY);\n \n if (distance < threshold) {\n return {\n segmentIndex: segment.start,\n insertPosition: closest.t,\n point: { x: closest.x, y: closest.y }\n };\n }\n }\n \n return null;\n };\n\n // Initialize position on image load\n useEffect(() => {\n if (image) {\n const initialPos = getConstrainedPosition({ x: 0, y: 0 }, 1);\n setStagePosition(initialPos);\n }\n }, [image]);\n\n // Keyboard shortcuts\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.ctrlKey || e.metaKey) {\n if (e.key === \"=\" || e.key === \"+\") {\n e.preventDefault();\n handleZoomIn();\n } else if (e.key === \"-\") {\n e.preventDefault();\n handleZoomOut();\n } else if (e.key === \"0\") {\n e.preventDefault();\n handleResetZoom();\n }\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [stageScale, stagePosition]);\n\n const handleStageDragStart = (e: KonvaEventObject<MouseEvent>) => {\n // Only allow stage dragging if not clicking on a point\n const clickedShape = e.target;\n if (clickedShape && clickedShape.name() === \"point\") {\n e.target.stopDrag();\n return;\n }\n\n const stage = e.target.getStage();\n if (!stage) return;\n \n const pos = stage.getPointerPosition();\n if (pos) {\n setDragStart(pos);\n }\n };\n\n const handleStageDragEnd = (e: KonvaEventObject<DragEvent>) => {\n const newPos = {\n x: e.target.x(),\n y: e.target.y(),\n };\n const constrainedPos = getConstrainedPosition(newPos, stageScale);\n setStagePosition(constrainedPos);\n setDragStart(null);\n };\n\n const toImageCoords = (stage: Konva.Stage | null): { x: number; y: number } => {\n if (!stage) return { x: 0, y: 0 };\n const pos = stage.getPointerPosition();\n if (!pos) return { x: 0, y: 0 };\n \n const x = (pos.x - stagePosition.x) / (scale * stageScale);\n const y = (pos.y - stagePosition.y) / (scale * stageScale);\n \n return { x, y };\n };\n\n const linePointsScaled = useMemo(() => {\n const flat = points.flatMap((p) => [p.x * scale, p.y * scale]);\n return flat;\n }, [points, scale]);\n\n const commit = (nextPoints: Points) => {\n setPoints(nextPoints);\n };\n\n const handlePointDragStart = (e: KonvaEventObject<DragEvent>) => {\n e.cancelBubble = true; // Prevent stage from dragging\n setIsDraggingPoint(true);\n };\n\n const handlePointDragMove = (id: number, e: KonvaEventObject<DragEvent>) => {\n const newX = e.target.x() / scale;\n const newY = e.target.y() / scale;\n \n const updatedPoints = points.map((p) => \n p.id === id ? { ...p, x: newX, y: newY } : p\n );\n \n setPoints(updatedPoints);\n };\n\n const handlePointDragEnd = (e: KonvaEventObject<DragEvent>) => {\n e.cancelBubble = true; // Prevent stage from processing this event\n setIsDraggingPoint(false);\n };\n\n const handleStageMouseDown = (e: KonvaEventObject<MouseEvent>) => {\n if (!image) return;\n\n const clickedShape = e.target;\n \n // Check if we clicked on a point\n if (clickedShape && clickedShape.name() === \"point\") {\n if (!closed) {\n const clickedIndex = points.findIndex((p) => \n Math.abs(p.x * scale - clickedShape.x()) < 1 && \n Math.abs(p.y * scale - clickedShape.y()) < 1\n );\n \n if (clickedIndex === 0 && points.length >= 3) {\n setClosed(true);\n setHoveringFirst(false);\n }\n }\n return;\n }\n\n // Track drag start for stage\n const stage = e.target.getStage();\n if (!stage) return;\n \n const pos = stage.getPointerPosition();\n if (pos) {\n setDragStart(pos);\n }\n };\n\n const handleStageMouseUp = (e: KonvaEventObject<MouseEvent>) => {\n if (!image || isDraggingPoint) return;\n\n const clickedShape = e.target;\n \n // Don't add point if clicked on a point\n if (clickedShape && clickedShape.name() === \"point\") {\n return;\n }\n\n // Check if this was a drag or a click\n if (dragStart) {\n const stage = e.target.getStage();\n if (!stage) return;\n \n const currentPos = stage.getPointerPosition();\n if (currentPos) {\n const dx = currentPos.x - dragStart.x;\n const dy = currentPos.y - dragStart.y;\n const distance = Math.sqrt(dx * dx + dy * dy);\n \n // If moved less than threshold, it's a click\n if (distance < DRAG_THRESHOLD) {\n const p = toImageCoords(stage);\n \n // Check if click is near an existing line\n const lineHit = findLineSegmentNearClick(p.x, p.y);\n \n if (lineHit) {\n // Insert point into the line\n const newPoint = {\n id: Date.now(),\n x: lineHit.point.x,\n y: lineHit.point.y\n };\n \n const newPoints = [...points];\n newPoints.splice(lineHit.segmentIndex + 1, 0, newPoint);\n commit(newPoints);\n } else if (!closed) {\n // Add point to the end (only if not closed)\n const next = [...points, { id: Date.now(), x: p.x, y: p.y }];\n commit(next);\n }\n }\n }\n \n setDragStart(null);\n }\n };\n\n const handleMouseMove = (e: KonvaEventObject<MouseEvent>) => {\n if (closed || points.length < 3) {\n setHoveringFirst(false);\n return;\n }\n\n const stage = e.target.getStage();\n const p = toImageCoords(stage);\n const fp = points[0];\n const dx = (p.x - fp.x) * scale * stageScale;\n const dy = (p.y - fp.y) * scale * stageScale;\n const dist = Math.hypot(dx, dy);\n\n setHoveringFirst(dist < 15);\n };\n\n return (\n <Container>\n <CanvasContainer>\n <Stage\n ref={stageRef}\n width={1200}\n height={1200}\n onMouseDown={handleStageMouseDown}\n onMouseUp={handleStageMouseUp}\n onMouseMove={handleMouseMove}\n onWheel={handleWheel}\n scaleX={stageScale}\n scaleY={stageScale}\n x={stagePosition.x}\n y={stagePosition.y}\n draggable={!isDraggingPoint}\n onDragStart={handleStageDragStart}\n onDragEnd={handleStageDragEnd}\n dragBoundFunc={(pos) => getConstrainedPosition(pos, stageScale)}\n >\n <Layer>\n <KonvaImage \n image={image} \n width={stageSize.width} \n height={stageSize.height} \n listening={false} \n />\n\n {points.length >= 2 && (\n <Line\n points={linePointsScaled}\n closed={closed}\n stroke=\"#2563eb\"\n strokeWidth={2 / stageScale}\n lineCap=\"round\"\n lineJoin=\"round\"\n tension={0}\n fill={closed ? \"rgba(37, 99, 235, 0.3)\" : undefined}\n hitStrokeWidth={LINE_HIT_THRESHOLD / stageScale}\n />\n )}\n\n <Group>\n {points.map((p, i) => (\n <Circle\n key={p.id}\n name=\"point\"\n x={p.x * scale}\n y={p.y * scale}\n radius={(i === 0 && hoveringFirst ? 10 : 6) / stageScale}\n fill={i === 0 ? \"#ef4444\" : \"#7e9de1\"}\n stroke={i === 0 && hoveringFirst ? \"#fbbf24\" : undefined}\n strokeWidth={i === 0 && hoveringFirst ? 2 / stageScale : 0}\n draggable={true}\n onDragStart={handlePointDragStart}\n onDragMove={(e) => handlePointDragMove(p.id, e)}\n onDragEnd={handlePointDragEnd}\n />\n ))}\n </Group>\n </Layer>\n </Stage>\n </CanvasContainer>\n <NavContainer>\n <Button\n onClick={handleZoomIn}\n disabled={stageScale >= MAX_SCALE}\n title=\"Zoom In (Ctrl/Cmd + +)\"\n >\n <ZoomIn style={{ width: '20px', height: '20px' }} />\n </Button>\n <Button\n onClick={handleZoomOut}\n disabled={stageScale <= MIN_SCALE}\n title=\"Zoom Out (Ctrl/Cmd + -)\"\n >\n <ZoomOut style={{ width: '20px', height: '20px' }} />\n </Button>\n <Button\n onClick={handleResetZoom}\n title=\"Reset Zoom (Ctrl/Cmd + 0)\"\n >\n {Math.round(stageScale * 100)}%\n </Button>\n </NavContainer>\n </Container>\n );\n};"]}
|
package/dist/lite.d.cts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
type Point = {
|
|
4
|
+
id: number;
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
interface MapperProps {
|
|
10
|
+
src?: string;
|
|
11
|
+
initialPoints?: Omit<Point, "id">[];
|
|
12
|
+
maxWidth?: number;
|
|
13
|
+
}
|
|
14
|
+
declare const Mapper: ({ src, initialPoints, maxWidth, }: MapperProps) => react_jsx_runtime.JSX.Element;
|
|
15
|
+
|
|
16
|
+
export { Mapper, type MapperProps };
|
package/dist/lite.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
type Point = {
|
|
4
|
+
id: number;
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
interface MapperProps {
|
|
10
|
+
src?: string;
|
|
11
|
+
initialPoints?: Omit<Point, "id">[];
|
|
12
|
+
maxWidth?: number;
|
|
13
|
+
}
|
|
14
|
+
declare const Mapper: ({ src, initialPoints, maxWidth, }: MapperProps) => react_jsx_runtime.JSX.Element;
|
|
15
|
+
|
|
16
|
+
export { Mapper, type MapperProps };
|