@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.
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 +38 -4
  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 +16 -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 +533 -171
  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 +50 -5
  33. package/src/browser/playground/path-edit/path-edit-layer-svg-path.tsx +303 -26
  34. package/src/browser/playground/path-edit/utils.tsx +82 -17
  35. package/src/browser/playground/path-edit-layer.tsx +585 -216
  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 {
@@ -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 getBezierHullByPos = (
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 = new Bezier(...points);
115
- const { t = 0 } = bezier.project(pos);
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
- const hull = getBezierHullByPos(bezier, pos);
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
- const currentPoint = { x: pos.x, y: pos.y };
245
- path[x] = toFixedValue(pos.x, 2);
246
- path[y] = toFixedValue(pos.y, 2);
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;