@gedit/editor-2d 0.3.14 → 0.3.17
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/lib/browser/editor2d-contribution.d.ts.map +1 -1
- package/lib/browser/editor2d-contribution.js +19 -18
- package/lib/browser/editor2d-contribution.js.map +1 -1
- package/lib/browser/playground/canvas-layer.d.ts +2 -1
- package/lib/browser/playground/canvas-layer.d.ts.map +1 -1
- package/lib/browser/playground/canvas-layer.js +8 -1
- package/lib/browser/playground/canvas-layer.js.map +1 -1
- package/lib/browser/playground/path-edit/path-edit-layer-move-point.d.ts.map +1 -1
- package/lib/browser/playground/path-edit/path-edit-layer-move-point.js +38 -4
- package/lib/browser/playground/path-edit/path-edit-layer-move-point.js.map +1 -1
- package/lib/browser/playground/path-edit/path-edit-layer-svg-path.d.ts +9 -2
- package/lib/browser/playground/path-edit/path-edit-layer-svg-path.d.ts.map +1 -1
- package/lib/browser/playground/path-edit/path-edit-layer-svg-path.js +232 -13
- package/lib/browser/playground/path-edit/path-edit-layer-svg-path.js.map +1 -1
- package/lib/browser/playground/path-edit/utils.d.ts +16 -3
- package/lib/browser/playground/path-edit/utils.d.ts.map +1 -1
- package/lib/browser/playground/path-edit/utils.js +63 -13
- package/lib/browser/playground/path-edit/utils.js.map +1 -1
- package/lib/browser/playground/path-edit-layer.d.ts +46 -3
- package/lib/browser/playground/path-edit-layer.d.ts.map +1 -1
- package/lib/browser/playground/path-edit-layer.js +533 -171
- package/lib/browser/playground/path-edit-layer.js.map +1 -1
- package/lib/browser/playground/playground-contribution.d.ts.map +1 -1
- package/lib/browser/playground/playground-contribution.js +2 -0
- package/lib/browser/playground/playground-contribution.js.map +1 -1
- package/lib/browser/utils/bezier.path.utils.d.ts.map +1 -1
- package/lib/browser/utils/bezier.path.utils.js +3 -0
- package/lib/browser/utils/bezier.path.utils.js.map +1 -1
- package/package.json +7 -7
- package/src/browser/editor2d-contribution.ts +19 -18
- package/src/browser/playground/canvas-layer.ts +6 -1
- package/src/browser/playground/path-edit/path-edit-layer-move-point.tsx +50 -5
- package/src/browser/playground/path-edit/path-edit-layer-svg-path.tsx +303 -26
- package/src/browser/playground/path-edit/utils.tsx +82 -17
- package/src/browser/playground/path-edit-layer.tsx +585 -216
- package/src/browser/playground/playground-contribution.ts +2 -0
- package/src/browser/style/path-edit-layer.less +17 -5
- package/src/browser/svg/drag_path.svg +17 -0
- package/src/browser/utils/bezier.path.utils.ts +3 -0
|
@@ -3,16 +3,21 @@ import {
|
|
|
3
3
|
PathChild,
|
|
4
4
|
PATH_FUNC_TYPE,
|
|
5
5
|
getPointsToPaths /* getPathToBezier */,
|
|
6
|
+
cubicToQuadratic,
|
|
6
7
|
} from '@gedit/canvas-draw';
|
|
7
8
|
import {
|
|
8
9
|
PointMoveDefault,
|
|
9
10
|
PointDefaultProps,
|
|
11
|
+
PointSchema,
|
|
10
12
|
} from './path-edit-layer-move-point';
|
|
11
13
|
import { PathEditLayerEventContext } from '../path-edit-layer';
|
|
12
14
|
import clsx from 'clsx';
|
|
13
15
|
import { generateUuid } from '@gedit/utils';
|
|
14
16
|
import { PathSelectMode, PathPointSelection } from '@gedit/playground';
|
|
15
17
|
import { Editor2dPathNode } from '../../model';
|
|
18
|
+
import { getParallelPositionByPoint } from '../../utils/bezier.path.utils';
|
|
19
|
+
import { getBezierPointArray, createBezier, getPathCenter } from './utils';
|
|
20
|
+
import { Bezier, Projection } from 'bezier-js';
|
|
16
21
|
|
|
17
22
|
export interface PathSVGProps {
|
|
18
23
|
width: number;
|
|
@@ -24,6 +29,10 @@ export interface PathSVGProps {
|
|
|
24
29
|
selectMode?: PathSelectMode;
|
|
25
30
|
getPosFromMouseEvent: PointDefaultProps['getPosFromMouseEvent'];
|
|
26
31
|
getPointIsStartOrEnd: () => boolean;
|
|
32
|
+
showAllBezier?: boolean;
|
|
33
|
+
getPathMousePos: (e: { clientX: number; clientY: number }) => PointSchema;
|
|
34
|
+
onUpdateNodeData: (b?: boolean) => void;
|
|
35
|
+
pathPosToCanvasPos: (c: PathChild) => PathChild;
|
|
27
36
|
}
|
|
28
37
|
|
|
29
38
|
export const SvgPath = ({
|
|
@@ -36,15 +45,39 @@ export const SvgPath = ({
|
|
|
36
45
|
selectMode,
|
|
37
46
|
getPosFromMouseEvent,
|
|
38
47
|
getPointIsStartOrEnd,
|
|
48
|
+
getPathMousePos,
|
|
49
|
+
showAllBezier,
|
|
50
|
+
onUpdateNodeData,
|
|
51
|
+
pathPosToCanvasPos,
|
|
39
52
|
}: PathSVGProps) => {
|
|
40
|
-
const {
|
|
41
|
-
path,
|
|
42
|
-
} = node || {};
|
|
53
|
+
const { path } = node || {};
|
|
43
54
|
const { closed } = path || {};
|
|
55
|
+
const {
|
|
56
|
+
onPointMouseDown,
|
|
57
|
+
onClosePath: onClosedPath,
|
|
58
|
+
onPathAddPoint,
|
|
59
|
+
onBezierPointMouseDown,
|
|
60
|
+
isCtrlKey,
|
|
61
|
+
isShiftKey,
|
|
62
|
+
} = React.useContext(PathEditLayerEventContext);
|
|
44
63
|
const isMultiple = selection.length > 1; // 多选模式;
|
|
45
64
|
const isSelect = selectMode !== PathSelectMode.ADD_PATH; // 选择点模式
|
|
46
65
|
const [hideMovePoint, setHideMovePoint] = React.useState(false);
|
|
47
66
|
const [closePath, setClosePath] = React.useState(false);
|
|
67
|
+
const [showPathAddPoint, setShowPathAddPoint] = React.useState<
|
|
68
|
+
false | { x: number; y: number; bezier: Bezier }
|
|
69
|
+
>(false);
|
|
70
|
+
const [lineHover, setLineHover] = React.useState(-1);
|
|
71
|
+
const noPathClickRef = React.useRef(false);
|
|
72
|
+
|
|
73
|
+
const pathDragStartRef = React.useRef<{
|
|
74
|
+
bezier: Bezier;
|
|
75
|
+
startPos: PointSchema;
|
|
76
|
+
point: Projection;
|
|
77
|
+
index: number;
|
|
78
|
+
nextIndex: number;
|
|
79
|
+
offset: PointSchema;
|
|
80
|
+
}>();
|
|
48
81
|
const onHideMovePoint = () => {
|
|
49
82
|
setHideMovePoint(true);
|
|
50
83
|
};
|
|
@@ -61,12 +94,206 @@ export const SvgPath = ({
|
|
|
61
94
|
e.preventDefault();
|
|
62
95
|
e.stopPropagation();
|
|
63
96
|
};
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
97
|
+
|
|
98
|
+
const onPathMove = (i: number, e: React.MouseEvent) => {
|
|
99
|
+
if (isCtrlKey) {
|
|
100
|
+
setShowPathAddPoint(false);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const { path = { paths: [] } } = node || {};
|
|
104
|
+
const { paths: p = [] } = path;
|
|
105
|
+
const point = p[i];
|
|
106
|
+
const nextPoint = p[i + 1] || p[0];
|
|
107
|
+
const pos = getPathMousePos(e);
|
|
108
|
+
const bezierPoint = getBezierPointArray(point, nextPoint);
|
|
109
|
+
const bezier =
|
|
110
|
+
showPathAddPoint !== false
|
|
111
|
+
? showPathAddPoint.bezier
|
|
112
|
+
: createBezier(bezierPoint);
|
|
113
|
+
// if (isShiftKey) {
|
|
114
|
+
// const centerT = getPathCenter(bezier);
|
|
115
|
+
// const centerPoint = bezier.get(centerT);
|
|
116
|
+
// const center = bezier.project(centerPoint);
|
|
117
|
+
// setShowPathAddPoint({ ...center, bezier });
|
|
118
|
+
// return;
|
|
119
|
+
// }
|
|
120
|
+
// const projectPos = bezier.project(pos);
|
|
121
|
+
setShowPathAddPoint({ ...pos, bezier });
|
|
122
|
+
};
|
|
123
|
+
const onPathMouseDown = (i: number, e: React.MouseEvent) => {
|
|
124
|
+
if (isCtrlKey) {
|
|
125
|
+
const { path = { paths: [] } } = node || {};
|
|
126
|
+
const { paths: p = [] } = path;
|
|
127
|
+
const point = p[i];
|
|
128
|
+
const nextIndex = p[i + 1] ? i + 1 : 0;
|
|
129
|
+
const nextPoint = p[nextIndex];
|
|
130
|
+
const pos = getPathMousePos(e);
|
|
131
|
+
const bezierPoint = getBezierPointArray(point, nextPoint);
|
|
132
|
+
const bezier = createBezier(bezierPoint);
|
|
133
|
+
const projectPos = bezier.project(pos);
|
|
134
|
+
const offset = {
|
|
135
|
+
x: pos.x - projectPos.x,
|
|
136
|
+
y: pos.y - projectPos.y,
|
|
137
|
+
};
|
|
138
|
+
noPathClickRef.current = false;
|
|
139
|
+
pathDragStartRef.current = {
|
|
140
|
+
bezier,
|
|
141
|
+
startPos: pos,
|
|
142
|
+
point: projectPos,
|
|
143
|
+
index: i,
|
|
144
|
+
nextIndex,
|
|
145
|
+
offset,
|
|
146
|
+
};
|
|
147
|
+
setLineHover(i);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const onPointDoubleClick = (point: PathChild) => (e: React.MouseEvent) => {
|
|
151
|
+
e.preventDefault();
|
|
152
|
+
e.stopPropagation();
|
|
153
|
+
// 双击切换点的 type
|
|
154
|
+
if (!path) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const index = path?.paths.findIndex(c => c.id === point.id);
|
|
158
|
+
if (typeof index === 'undefined') {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const currentPoint = path?.paths[index];
|
|
162
|
+
if (!currentPoint) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const v = currentPoint.type;
|
|
167
|
+
switch (v) {
|
|
168
|
+
case PATH_FUNC_TYPE.EQUAL:
|
|
169
|
+
case PATH_FUNC_TYPE.UNEQUAL:
|
|
170
|
+
case PATH_FUNC_TYPE.BREAK:
|
|
171
|
+
delete currentPoint.x1;
|
|
172
|
+
delete currentPoint.y1;
|
|
173
|
+
delete currentPoint.x2;
|
|
174
|
+
delete currentPoint.y2;
|
|
175
|
+
currentPoint.type = PATH_FUNC_TYPE.STRAIGHT;
|
|
176
|
+
break;
|
|
177
|
+
case PATH_FUNC_TYPE.STRAIGHT: {
|
|
178
|
+
const prevPoint = paths[index - 1] || paths[paths.length - 1];
|
|
179
|
+
const nextPoint = paths[index + 1] || paths[0];
|
|
180
|
+
|
|
181
|
+
const { p1, p2 } = getParallelPositionByPoint(
|
|
182
|
+
prevPoint,
|
|
183
|
+
nextPoint,
|
|
184
|
+
point
|
|
185
|
+
);
|
|
186
|
+
currentPoint.x1 = p1.x;
|
|
187
|
+
currentPoint.y1 = p1.y;
|
|
188
|
+
currentPoint.x2 = p2.x;
|
|
189
|
+
currentPoint.y2 = p2.y;
|
|
190
|
+
currentPoint.type = PATH_FUNC_TYPE.EQUAL;
|
|
191
|
+
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
default:
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
onUpdateNodeData();
|
|
198
|
+
};
|
|
199
|
+
// const t = getBezierPointArray(paths[0], paths[1]);
|
|
200
|
+
// console.log(paths[0], paths[1], t, cubicToQuadratic(paths[0], {x: t[2], y: t[3]}));
|
|
201
|
+
React.useEffect(() => {
|
|
202
|
+
const onMouseMove = (e: MouseEvent) => {
|
|
203
|
+
if (pathDragStartRef.current) {
|
|
204
|
+
noPathClickRef.current = true;
|
|
205
|
+
const pos = getPathMousePos(e);
|
|
206
|
+
const {
|
|
207
|
+
bezier,
|
|
208
|
+
nextIndex,
|
|
209
|
+
index,
|
|
210
|
+
point,
|
|
211
|
+
offset,
|
|
212
|
+
} = pathDragStartRef.current;
|
|
213
|
+
const currentPoint = bezier.get(point.t || 0);
|
|
214
|
+
const dx = pos.x - offset.x - currentPoint.x;
|
|
215
|
+
const dy = pos.y - offset.y - currentPoint.y;
|
|
216
|
+
|
|
217
|
+
bezier.points[1].x += dx;
|
|
218
|
+
bezier.points[1].y += dy;
|
|
219
|
+
bezier.points[2].x += dx;
|
|
220
|
+
bezier.points[2].y += dy;
|
|
221
|
+
bezier.update();
|
|
222
|
+
|
|
223
|
+
const start = path?.paths[index];
|
|
224
|
+
const end = path?.paths[nextIndex];
|
|
225
|
+
if (!start || !end) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
let pCenter;
|
|
229
|
+
const p1 = bezier.points[1];
|
|
230
|
+
const p2 = bezier.points[2];
|
|
231
|
+
|
|
232
|
+
// 全是 straight 时,转换为 unequal
|
|
233
|
+
if (
|
|
234
|
+
start.type === PATH_FUNC_TYPE.STRAIGHT &&
|
|
235
|
+
end.type === PATH_FUNC_TYPE.STRAIGHT
|
|
236
|
+
) {
|
|
237
|
+
start.type = PATH_FUNC_TYPE.BREAK;
|
|
238
|
+
start.x1 = p1.x;
|
|
239
|
+
start.y1 = p1.y;
|
|
240
|
+
start.x2 = start.x;
|
|
241
|
+
start.y2 = start.x;
|
|
242
|
+
end.type = PATH_FUNC_TYPE.BREAK;
|
|
243
|
+
end.x1 = p2.x;
|
|
244
|
+
end.y1 = p2.x;
|
|
245
|
+
end.x2 = end.x;
|
|
246
|
+
end.y2 = end.y;
|
|
247
|
+
}
|
|
248
|
+
if (
|
|
249
|
+
start.type === PATH_FUNC_TYPE.STRAIGHT &&
|
|
250
|
+
end.type !== PATH_FUNC_TYPE.STRAIGHT
|
|
251
|
+
) {
|
|
252
|
+
end.type = PATH_FUNC_TYPE.BREAK;
|
|
253
|
+
pCenter = cubicToQuadratic(start, p1);
|
|
254
|
+
end.x1 = pCenter.x;
|
|
255
|
+
end.y1 = pCenter.y;
|
|
256
|
+
}
|
|
257
|
+
if (
|
|
258
|
+
start.type !== PATH_FUNC_TYPE.STRAIGHT &&
|
|
259
|
+
end.type === PATH_FUNC_TYPE.STRAIGHT
|
|
260
|
+
) {
|
|
261
|
+
start.type = PATH_FUNC_TYPE.BREAK;
|
|
262
|
+
pCenter = cubicToQuadratic(end, p2);
|
|
263
|
+
start.x2 = pCenter.x;
|
|
264
|
+
start.y2 = pCenter.y;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (
|
|
268
|
+
start.type !== PATH_FUNC_TYPE.STRAIGHT &&
|
|
269
|
+
end.type !== PATH_FUNC_TYPE.STRAIGHT
|
|
270
|
+
) {
|
|
271
|
+
start.x2 = p1.x;
|
|
272
|
+
start.y2 = p1.y;
|
|
273
|
+
start.type = PATH_FUNC_TYPE.BREAK;
|
|
274
|
+
end.x1 = p2.x;
|
|
275
|
+
end.y1 = p2.y;
|
|
276
|
+
end.type = PATH_FUNC_TYPE.BREAK;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
onUpdateNodeData(true);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
const onMouseUp = (e: MouseEvent) => {
|
|
283
|
+
if (pathDragStartRef.current) {
|
|
284
|
+
pathDragStartRef.current = undefined;
|
|
285
|
+
setLineHover(-1);
|
|
286
|
+
onUpdateNodeData();
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
document.addEventListener('mousemove', onMouseMove);
|
|
290
|
+
document.addEventListener('mouseup', onMouseUp);
|
|
291
|
+
return () => {
|
|
292
|
+
document.removeEventListener('mousemove', onMouseMove);
|
|
293
|
+
document.removeEventListener('mouseup', onMouseUp);
|
|
294
|
+
};
|
|
295
|
+
}, [path?.paths]);
|
|
296
|
+
|
|
70
297
|
const p = [...paths];
|
|
71
298
|
if (closed) {
|
|
72
299
|
p.push({
|
|
@@ -128,7 +355,7 @@ export const SvgPath = ({
|
|
|
128
355
|
r={4 / scale}
|
|
129
356
|
key={item.id}
|
|
130
357
|
strokeWidth="1"
|
|
131
|
-
onDoubleClick={
|
|
358
|
+
onDoubleClick={onPointDoubleClick(item)}
|
|
132
359
|
onMouseDown={e => {
|
|
133
360
|
e.preventDefault();
|
|
134
361
|
e.stopPropagation();
|
|
@@ -147,8 +374,11 @@ export const SvgPath = ({
|
|
|
147
374
|
const bezierPointNodes: JSX.Element[] = [];
|
|
148
375
|
const bezierPathNodes: JSX.Element[] = [];
|
|
149
376
|
const bezierPoints: PathChild[] = [];
|
|
377
|
+
const selectionBezier: PathPointSelection[] = showAllBezier
|
|
378
|
+
? paths.map(c => ({ pointId: c.id }))
|
|
379
|
+
: selection;
|
|
150
380
|
// 插入贝塞尔点
|
|
151
|
-
|
|
381
|
+
selectionBezier.forEach(item => {
|
|
152
382
|
const { pointId: currentPointId } = item;
|
|
153
383
|
const index = paths.findIndex(c => c.id === currentPointId);
|
|
154
384
|
// 关闭路径把第一个贝赛尔点加入
|
|
@@ -171,7 +401,7 @@ export const SvgPath = ({
|
|
|
171
401
|
});
|
|
172
402
|
});
|
|
173
403
|
bezierPoints.forEach((p, i) => {
|
|
174
|
-
const selectionNode =
|
|
404
|
+
const selectionNode = selectionBezier.find(c => c.pointId === p.id);
|
|
175
405
|
const { bezierKey, pointId: currentPointId } = selectionNode || {};
|
|
176
406
|
if (p.type === PATH_FUNC_TYPE.STRAIGHT) {
|
|
177
407
|
return;
|
|
@@ -195,7 +425,7 @@ export const SvgPath = ({
|
|
|
195
425
|
cx={p.x1}
|
|
196
426
|
cy={p.y1}
|
|
197
427
|
r={3 / scale}
|
|
198
|
-
onDoubleClick={
|
|
428
|
+
onDoubleClick={onPointDoubleClick(p)}
|
|
199
429
|
onMouseDown={e => {
|
|
200
430
|
onBezierPointMouseDown(e, p, 'left');
|
|
201
431
|
}}
|
|
@@ -223,7 +453,7 @@ export const SvgPath = ({
|
|
|
223
453
|
cx={p.x2}
|
|
224
454
|
cy={p.y2}
|
|
225
455
|
r={3 / scale}
|
|
226
|
-
onDoubleClick={
|
|
456
|
+
onDoubleClick={onPointDoubleClick(p)}
|
|
227
457
|
onMouseDown={e => {
|
|
228
458
|
onBezierPointMouseDown(e, p, 'right');
|
|
229
459
|
}}
|
|
@@ -243,6 +473,23 @@ export const SvgPath = ({
|
|
|
243
473
|
pointIsStartOrEnd); // 选中起始点或结束点时
|
|
244
474
|
// const ppp = [...paths, paths[0]];
|
|
245
475
|
// const bezierBox = getPathToBezier(ppp).map(c => c.bbox());
|
|
476
|
+
|
|
477
|
+
const hoverPointPos = {
|
|
478
|
+
x: 0,
|
|
479
|
+
y: 0,
|
|
480
|
+
};
|
|
481
|
+
if (showPathAddPoint) {
|
|
482
|
+
const { bezier } = showPathAddPoint;
|
|
483
|
+
let pathPoint: { x: number; y: number } = showPathAddPoint;
|
|
484
|
+
if (isShiftKey) {
|
|
485
|
+
const centerT = getPathCenter(bezier);
|
|
486
|
+
pathPoint = bezier.get(centerT);
|
|
487
|
+
}
|
|
488
|
+
const pos = bezier.project(pathPoint);
|
|
489
|
+
const transitionPos = pathPosToCanvasPos(pos);
|
|
490
|
+
hoverPointPos.x = transitionPos.x;
|
|
491
|
+
hoverPointPos.y = transitionPos.y;
|
|
492
|
+
}
|
|
246
493
|
return (
|
|
247
494
|
<svg
|
|
248
495
|
width={width}
|
|
@@ -255,9 +502,10 @@ export const SvgPath = ({
|
|
|
255
502
|
}} */
|
|
256
503
|
className={clsx('gedit-path-edit-layer-svg', {
|
|
257
504
|
// 'gedit-path-edit-layer-pen': !closed,
|
|
505
|
+
'gedit-path-edit-layer-drag': lineHover !== -1,
|
|
258
506
|
})}
|
|
259
507
|
>
|
|
260
|
-
{showDefaultMovePoint && (
|
|
508
|
+
{showDefaultMovePoint && lineHover === -1 && (
|
|
261
509
|
<PointMoveDefault
|
|
262
510
|
getPosFromMouseEvent={getPosFromMouseEvent}
|
|
263
511
|
paths={paths}
|
|
@@ -266,27 +514,56 @@ export const SvgPath = ({
|
|
|
266
514
|
currentPointId={selection[0]?.pointId as string}
|
|
267
515
|
/>
|
|
268
516
|
)}
|
|
269
|
-
{pathsStringArray.map((
|
|
517
|
+
{pathsStringArray.map((pStr, i) => (
|
|
270
518
|
<path
|
|
271
|
-
className={clsx(
|
|
272
|
-
'gedit-path-edit-layer-
|
|
273
|
-
'gedit-path-edit-layer-
|
|
274
|
-
|
|
519
|
+
className={clsx('gedit-path-edit-layer-path', {
|
|
520
|
+
'gedit-path-edit-layer-pen': !isCtrlKey,
|
|
521
|
+
'gedit-path-edit-layer-drag': isCtrlKey,
|
|
522
|
+
'gedit-path-edit-layer-path-active': lineHover === i,
|
|
523
|
+
})}
|
|
275
524
|
key={i.toString()}
|
|
276
525
|
strokeLinecap="round"
|
|
277
|
-
strokeWidth={
|
|
278
|
-
d={
|
|
279
|
-
onMouseEnter={
|
|
280
|
-
|
|
281
|
-
|
|
526
|
+
strokeWidth={2 / scale}
|
|
527
|
+
d={pStr}
|
|
528
|
+
onMouseEnter={e => {
|
|
529
|
+
onHideMovePoint();
|
|
530
|
+
}}
|
|
531
|
+
onMouseLeave={() => {
|
|
532
|
+
onShowMovePoint();
|
|
533
|
+
setShowPathAddPoint(false);
|
|
534
|
+
}}
|
|
535
|
+
onMouseMove={e => {
|
|
536
|
+
onPathMove(i, e);
|
|
537
|
+
}}
|
|
538
|
+
onMouseDown={e => {
|
|
539
|
+
onClickStopPropagation(e);
|
|
540
|
+
onPathMouseDown(i, e);
|
|
541
|
+
}}
|
|
282
542
|
onDoubleClick={onClickStopPropagation}
|
|
283
543
|
onClick={e => {
|
|
284
544
|
e.preventDefault();
|
|
285
545
|
e.stopPropagation();
|
|
286
|
-
|
|
546
|
+
if (!noPathClickRef.current && !isCtrlKey) {
|
|
547
|
+
onPathAddPoint(i, e);
|
|
548
|
+
}
|
|
549
|
+
noPathClickRef.current = false;
|
|
287
550
|
}}
|
|
288
551
|
/>
|
|
289
552
|
))}
|
|
553
|
+
{showPathAddPoint && !isCtrlKey && (
|
|
554
|
+
<circle
|
|
555
|
+
className="gedit-path-edit-layer-hover-point"
|
|
556
|
+
cx={hoverPointPos.x}
|
|
557
|
+
cy={hoverPointPos.y}
|
|
558
|
+
r={4 / scale}
|
|
559
|
+
strokeWidth="1"
|
|
560
|
+
onMouseDown={e => {
|
|
561
|
+
e.preventDefault();
|
|
562
|
+
e.stopPropagation();
|
|
563
|
+
onPathAddPoint(paths.length - 1, e);
|
|
564
|
+
}}
|
|
565
|
+
/>
|
|
566
|
+
)}
|
|
290
567
|
{/* bezierBox.map(c => <rect stroke='#000' strokeWidth={2} fill="none" x={c.x.min} y={c.y.min} width={c.x.size} height={c.y.size} />) */}
|
|
291
568
|
{bezierPathNodes}
|
|
292
569
|
{allPoints}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
getPathBounds,
|
|
13
13
|
PathSchema,
|
|
14
14
|
getPathSizeBounds,
|
|
15
|
+
pedalPoint,
|
|
15
16
|
} from '@gedit/canvas-draw';
|
|
16
17
|
import { Bezier } from 'bezier-js';
|
|
17
18
|
import {
|
|
@@ -24,6 +25,8 @@ import { PointSchema } from './path-edit-layer-move-point';
|
|
|
24
25
|
import { Editor2dPathNode } from '../../model';
|
|
25
26
|
const cloneDeep = require('lodash.clonedeep');
|
|
26
27
|
|
|
28
|
+
export const shiftAngleArray = [0, 45, 90, 135, 180, 225, 270, 315, 360];
|
|
29
|
+
|
|
27
30
|
export const transformRotation = (p1: Point, p2: Point, rotation: number) => {
|
|
28
31
|
if (!rotation) {
|
|
29
32
|
return p1;
|
|
@@ -98,9 +101,42 @@ export const getLeftRightCenterPoint = (item: PathChild) => {
|
|
|
98
101
|
};
|
|
99
102
|
};
|
|
100
103
|
|
|
101
|
-
export const
|
|
104
|
+
export const createBezier = (points: BezierArray) => new Bezier(...points);
|
|
105
|
+
|
|
106
|
+
export const getPathCenter = (curve: Bezier) => {
|
|
107
|
+
const totalLength = curve.length();
|
|
108
|
+
const targetLength = totalLength / 2; // 中间点的长度
|
|
109
|
+
|
|
110
|
+
// 使用二分法找到对应的参数 t
|
|
111
|
+
let low = 0;
|
|
112
|
+
let high = 1;
|
|
113
|
+
let t = 0.5;
|
|
114
|
+
const epsilon = 0.001; // 精度
|
|
115
|
+
|
|
116
|
+
while (high - low > epsilon) {
|
|
117
|
+
t = (low + high) / 2;
|
|
118
|
+
const currentLength = curve.split(0, t).length();
|
|
119
|
+
if (currentLength < targetLength) {
|
|
120
|
+
low = t;
|
|
121
|
+
} else {
|
|
122
|
+
high = t;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return t;
|
|
127
|
+
};
|
|
128
|
+
export const getBezierProjectByPos = (
|
|
102
129
|
points: BezierArray,
|
|
103
130
|
pos: Point
|
|
131
|
+
): { x: number; y: number; t?: number } => {
|
|
132
|
+
const bezier = createBezier(points);
|
|
133
|
+
return bezier.project(pos);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export const getBezierHullByPos = (
|
|
137
|
+
points: BezierArray,
|
|
138
|
+
pos: Point,
|
|
139
|
+
isShiftKey: boolean = false
|
|
104
140
|
): { x: number; y: number }[] => {
|
|
105
141
|
// 判断是二次还是三次贝塞尔曲线
|
|
106
142
|
/* const [x1, y1, x2, y2, x3, y3, x4, y4] = points;
|
|
@@ -111,8 +147,11 @@ export const getBezierHullByPos = (
|
|
|
111
147
|
const yB = x1 === x2 && y1 === y2 ? y3 : y1;
|
|
112
148
|
p = [x1, y1, xB, yB, x4, y4];
|
|
113
149
|
} */
|
|
114
|
-
const bezier =
|
|
115
|
-
|
|
150
|
+
const bezier = createBezier(points);
|
|
151
|
+
let { t = 0 } = bezier.project(pos);
|
|
152
|
+
if (isShiftKey) {
|
|
153
|
+
t = getPathCenter(bezier);
|
|
154
|
+
}
|
|
116
155
|
const h = bezier.hull(t);
|
|
117
156
|
const hull = h.slice(-6);
|
|
118
157
|
return hull;
|
|
@@ -141,14 +180,7 @@ export const getExtendPositionByRadius = (
|
|
|
141
180
|
return { x, y };
|
|
142
181
|
};
|
|
143
182
|
|
|
144
|
-
|
|
145
|
-
* 获取点击线上的新增点
|
|
146
|
-
*/
|
|
147
|
-
export const getNewPoint = (
|
|
148
|
-
point: PathChild,
|
|
149
|
-
nextPoint: PathChild,
|
|
150
|
-
pos: PointSchema
|
|
151
|
-
): PathChild => {
|
|
183
|
+
export const getBezierPointArray = (point: PathChild, nextPoint: PathChild) => {
|
|
152
184
|
const afterQuadratic =
|
|
153
185
|
point.type === PATH_FUNC_TYPE.STRAIGHT &&
|
|
154
186
|
nextPoint.type !== PATH_FUNC_TYPE.STRAIGHT &&
|
|
@@ -191,7 +223,20 @@ export const getNewPoint = (
|
|
|
191
223
|
bezier[4] = cubic[2];
|
|
192
224
|
bezier[5] = cubic[3];
|
|
193
225
|
}
|
|
194
|
-
|
|
226
|
+
return bezier;
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* 获取点击线上的新增点
|
|
231
|
+
*/
|
|
232
|
+
export const getNewPoint = (
|
|
233
|
+
point: PathChild,
|
|
234
|
+
nextPoint: PathChild,
|
|
235
|
+
pos: PointSchema,
|
|
236
|
+
isShiftKey: boolean = false
|
|
237
|
+
): PathChild => {
|
|
238
|
+
const bezier = getBezierPointArray(point, nextPoint);
|
|
239
|
+
const hull = getBezierHullByPos(bezier, pos, isShiftKey);
|
|
195
240
|
/**
|
|
196
241
|
* 0, 1, 2: 二次贝赛尔点,1为中心点,没用
|
|
197
242
|
* 3, 4: 三次点,
|
|
@@ -233,17 +278,37 @@ export const getNewPoint = (
|
|
|
233
278
|
export const setBezierMovePoint = (
|
|
234
279
|
path: PathChild,
|
|
235
280
|
key: 'left' | 'right',
|
|
236
|
-
pos: PointSchema
|
|
281
|
+
pos: PointSchema,
|
|
282
|
+
startPos?: PointSchema,
|
|
283
|
+
keybinding: { shiftKey: boolean; ctrlKey: boolean } = {
|
|
284
|
+
shiftKey: false,
|
|
285
|
+
ctrlKey: false,
|
|
286
|
+
}
|
|
237
287
|
): PathChild => {
|
|
288
|
+
const { shiftKey, ctrlKey } = keybinding;
|
|
238
289
|
const { type } = path;
|
|
239
290
|
const x = key === 'left' ? 'x1' : 'x2';
|
|
240
291
|
const x1 = key === 'left' ? 'x2' : 'x1';
|
|
241
292
|
const y = key === 'left' ? 'y1' : 'y2';
|
|
242
293
|
const y1 = key === 'left' ? 'y2' : 'y1';
|
|
243
294
|
const center = { x: path.x, y: path.y };
|
|
244
|
-
|
|
245
|
-
path[x] =
|
|
246
|
-
path[y] =
|
|
295
|
+
let currentPoint = { x: toFixedValue(pos.x, 2), y: toFixedValue(pos.y, 2) };
|
|
296
|
+
path[x] = currentPoint.x;
|
|
297
|
+
path[y] = currentPoint.y;
|
|
298
|
+
// 按信 shift 键,锁定水平移动
|
|
299
|
+
if (shiftKey) {
|
|
300
|
+
// 垂直点
|
|
301
|
+
const end = pedalPoint(center, startPos || {x: 0, y: 0}, currentPoint);
|
|
302
|
+
path[x] = end.x;
|
|
303
|
+
path[y] = end.y;
|
|
304
|
+
currentPoint = { x: end.x, y: end.y };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// 按住 ctrl 键,转换成 BREAK 模式
|
|
308
|
+
if (ctrlKey) {
|
|
309
|
+
path.type = PATH_FUNC_TYPE.BREAK;
|
|
310
|
+
return path;
|
|
311
|
+
}
|
|
247
312
|
let p2: PointSchema | false = false;
|
|
248
313
|
const isOnly =
|
|
249
314
|
typeof path[x1] === 'undefined' && typeof path[y1] === 'undefined';
|
|
@@ -309,7 +374,7 @@ export const updatePathNodeData = (
|
|
|
309
374
|
// origin = { x: 0.5, y: 0.5 },
|
|
310
375
|
path,
|
|
311
376
|
style,
|
|
312
|
-
size = { width: 0, height: 0},
|
|
377
|
+
size = { width: 0, height: 0 },
|
|
313
378
|
// rotation = 0,
|
|
314
379
|
// scale = { x: 1, y: 1 },
|
|
315
380
|
} = node;
|