@gedit/editor-2d 0.3.14 → 0.3.16

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.
Files changed (39) hide show
  1. package/lib/browser/editor2d-contribution.d.ts.map +1 -1
  2. package/lib/browser/editor2d-contribution.js +19 -18
  3. package/lib/browser/editor2d-contribution.js.map +1 -1
  4. package/lib/browser/playground/canvas-layer.d.ts +2 -1
  5. package/lib/browser/playground/canvas-layer.d.ts.map +1 -1
  6. package/lib/browser/playground/canvas-layer.js +8 -1
  7. package/lib/browser/playground/canvas-layer.js.map +1 -1
  8. package/lib/browser/playground/path-edit/path-edit-layer-move-point.d.ts.map +1 -1
  9. package/lib/browser/playground/path-edit/path-edit-layer-move-point.js +29 -3
  10. package/lib/browser/playground/path-edit/path-edit-layer-move-point.js.map +1 -1
  11. package/lib/browser/playground/path-edit/path-edit-layer-svg-path.d.ts +9 -2
  12. package/lib/browser/playground/path-edit/path-edit-layer-svg-path.d.ts.map +1 -1
  13. package/lib/browser/playground/path-edit/path-edit-layer-svg-path.js +232 -13
  14. package/lib/browser/playground/path-edit/path-edit-layer-svg-path.js.map +1 -1
  15. package/lib/browser/playground/path-edit/utils.d.ts +15 -3
  16. package/lib/browser/playground/path-edit/utils.d.ts.map +1 -1
  17. package/lib/browser/playground/path-edit/utils.js +63 -13
  18. package/lib/browser/playground/path-edit/utils.js.map +1 -1
  19. package/lib/browser/playground/path-edit-layer.d.ts +46 -3
  20. package/lib/browser/playground/path-edit-layer.d.ts.map +1 -1
  21. package/lib/browser/playground/path-edit-layer.js +469 -110
  22. package/lib/browser/playground/path-edit-layer.js.map +1 -1
  23. package/lib/browser/playground/playground-contribution.d.ts.map +1 -1
  24. package/lib/browser/playground/playground-contribution.js +2 -0
  25. package/lib/browser/playground/playground-contribution.js.map +1 -1
  26. package/lib/browser/utils/bezier.path.utils.d.ts.map +1 -1
  27. package/lib/browser/utils/bezier.path.utils.js +3 -0
  28. package/lib/browser/utils/bezier.path.utils.js.map +1 -1
  29. package/package.json +7 -7
  30. package/src/browser/editor2d-contribution.ts +19 -18
  31. package/src/browser/playground/canvas-layer.ts +6 -1
  32. package/src/browser/playground/path-edit/path-edit-layer-move-point.tsx +38 -4
  33. package/src/browser/playground/path-edit/path-edit-layer-svg-path.tsx +303 -26
  34. package/src/browser/playground/path-edit/utils.tsx +80 -17
  35. package/src/browser/playground/path-edit-layer.tsx +526 -122
  36. package/src/browser/playground/playground-contribution.ts +2 -0
  37. package/src/browser/style/path-edit-layer.less +17 -5
  38. package/src/browser/svg/drag_path.svg +17 -0
  39. 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
- const {
65
- onPointMouseDown,
66
- onClosePath: onClosedPath,
67
- onPathAddPoint,
68
- onBezierPointMouseDown,
69
- } = React.useContext(PathEditLayerEventContext);
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={onClickStopPropagation}
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
- selection.forEach(item => {
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 = selection.find(c => c.pointId === p.id);
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={onClickStopPropagation}
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={onClickStopPropagation}
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((p, i) => (
517
+ {pathsStringArray.map((pStr, i) => (
270
518
  <path
271
- className={clsx(
272
- 'gedit-path-edit-layer-path',
273
- 'gedit-path-edit-layer-pen'
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={1.5 / scale}
278
- d={p}
279
- onMouseEnter={onHideMovePoint}
280
- onMouseLeave={onShowMovePoint}
281
- onMouseDown={onClickStopPropagation}
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
- onPathAddPoint(i, e);
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 {
@@ -98,9 +99,42 @@ export const getLeftRightCenterPoint = (item: PathChild) => {
98
99
  };
99
100
  };
100
101
 
101
- export const getBezierHullByPos = (
102
+ export const createBezier = (points: BezierArray) => new Bezier(...points);
103
+
104
+ export const getPathCenter = (curve: Bezier) => {
105
+ const totalLength = curve.length();
106
+ const targetLength = totalLength / 2; // 中间点的长度
107
+
108
+ // 使用二分法找到对应的参数 t
109
+ let low = 0;
110
+ let high = 1;
111
+ let t = 0.5;
112
+ const epsilon = 0.001; // 精度
113
+
114
+ while (high - low > epsilon) {
115
+ t = (low + high) / 2;
116
+ const currentLength = curve.split(0, t).length();
117
+ if (currentLength < targetLength) {
118
+ low = t;
119
+ } else {
120
+ high = t;
121
+ }
122
+ }
123
+
124
+ return t;
125
+ };
126
+ export const getBezierProjectByPos = (
102
127
  points: BezierArray,
103
128
  pos: Point
129
+ ): { x: number; y: number; t?: number } => {
130
+ const bezier = createBezier(points);
131
+ return bezier.project(pos);
132
+ };
133
+
134
+ export const getBezierHullByPos = (
135
+ points: BezierArray,
136
+ pos: Point,
137
+ isShiftKey: boolean = false
104
138
  ): { x: number; y: number }[] => {
105
139
  // 判断是二次还是三次贝塞尔曲线
106
140
  /* const [x1, y1, x2, y2, x3, y3, x4, y4] = points;
@@ -111,8 +145,11 @@ export const getBezierHullByPos = (
111
145
  const yB = x1 === x2 && y1 === y2 ? y3 : y1;
112
146
  p = [x1, y1, xB, yB, x4, y4];
113
147
  } */
114
- const bezier = new Bezier(...points);
115
- const { t = 0 } = bezier.project(pos);
148
+ const bezier = createBezier(points);
149
+ let { t = 0 } = bezier.project(pos);
150
+ if (isShiftKey) {
151
+ t = getPathCenter(bezier);
152
+ }
116
153
  const h = bezier.hull(t);
117
154
  const hull = h.slice(-6);
118
155
  return hull;
@@ -141,14 +178,7 @@ export const getExtendPositionByRadius = (
141
178
  return { x, y };
142
179
  };
143
180
 
144
- /**
145
- * 获取点击线上的新增点
146
- */
147
- export const getNewPoint = (
148
- point: PathChild,
149
- nextPoint: PathChild,
150
- pos: PointSchema
151
- ): PathChild => {
181
+ export const getBezierPointArray = (point: PathChild, nextPoint: PathChild) => {
152
182
  const afterQuadratic =
153
183
  point.type === PATH_FUNC_TYPE.STRAIGHT &&
154
184
  nextPoint.type !== PATH_FUNC_TYPE.STRAIGHT &&
@@ -191,7 +221,20 @@ export const getNewPoint = (
191
221
  bezier[4] = cubic[2];
192
222
  bezier[5] = cubic[3];
193
223
  }
194
- const hull = getBezierHullByPos(bezier, pos);
224
+ return bezier;
225
+ };
226
+
227
+ /**
228
+ * 获取点击线上的新增点
229
+ */
230
+ export const getNewPoint = (
231
+ point: PathChild,
232
+ nextPoint: PathChild,
233
+ pos: PointSchema,
234
+ isShiftKey: boolean = false,
235
+ ): PathChild => {
236
+ const bezier = getBezierPointArray(point, nextPoint);
237
+ const hull = getBezierHullByPos(bezier, pos, isShiftKey);
195
238
  /**
196
239
  * 0, 1, 2: 二次贝赛尔点,1为中心点,没用
197
240
  * 3, 4: 三次点,
@@ -233,17 +276,37 @@ export const getNewPoint = (
233
276
  export const setBezierMovePoint = (
234
277
  path: PathChild,
235
278
  key: 'left' | 'right',
236
- pos: PointSchema
279
+ pos: PointSchema,
280
+ keybinding: { shiftKey: boolean; ctrlKey: boolean } = {
281
+ shiftKey: false,
282
+ ctrlKey: false,
283
+ }
237
284
  ): PathChild => {
285
+ const { shiftKey, ctrlKey } = keybinding;
238
286
  const { type } = path;
239
287
  const x = key === 'left' ? 'x1' : 'x2';
240
288
  const x1 = key === 'left' ? 'x2' : 'x1';
241
289
  const y = key === 'left' ? 'y1' : 'y2';
242
290
  const y1 = key === 'left' ? 'y2' : 'y1';
243
291
  const center = { x: path.x, y: path.y };
244
- const currentPoint = { x: pos.x, y: pos.y };
245
- path[x] = toFixedValue(pos.x, 2);
246
- path[y] = toFixedValue(pos.y, 2);
292
+ let currentPoint = { x: toFixedValue(pos.x, 2), y: toFixedValue(pos.y, 2) };
293
+ const start = { x: path[x] || 0, y: path[y] || 0 };
294
+ path[x] = currentPoint.x;
295
+ path[y] = currentPoint.y;
296
+ // 按信 shift 键,锁定水平移动
297
+ if (shiftKey) {
298
+ // 垂直点
299
+ const end = pedalPoint(center, start, currentPoint);
300
+ path[x] = end.x;
301
+ path[y] = end.y;
302
+ currentPoint = { x: end.x, y: end.y };
303
+ }
304
+
305
+ // 按住 ctrl 键,转换成 BREAK 模式
306
+ if (ctrlKey) {
307
+ path.type = PATH_FUNC_TYPE.BREAK;
308
+ return path;
309
+ }
247
310
  let p2: PointSchema | false = false;
248
311
  const isOnly =
249
312
  typeof path[x1] === 'undefined' && typeof path[y1] === 'undefined';
@@ -309,7 +372,7 @@ export const updatePathNodeData = (
309
372
  // origin = { x: 0.5, y: 0.5 },
310
373
  path,
311
374
  style,
312
- size = { width: 0, height: 0},
375
+ size = { width: 0, height: 0 },
313
376
  // rotation = 0,
314
377
  // scale = { x: 1, y: 1 },
315
378
  } = node;