@gedit/editor-2d 0.2.46 → 0.2.48

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 (99) hide show
  1. package/lib/browser/model/editor2d-document.d.ts +11 -2
  2. package/lib/browser/model/editor2d-document.d.ts.map +1 -1
  3. package/lib/browser/model/editor2d-document.js +44 -8
  4. package/lib/browser/model/editor2d-document.js.map +1 -1
  5. package/lib/browser/model/editor2d-model-container.d.ts.map +1 -1
  6. package/lib/browser/model/editor2d-model-container.js +1 -1
  7. package/lib/browser/model/editor2d-model-container.js.map +1 -1
  8. package/lib/browser/model/editor2d-model.d.ts +2 -0
  9. package/lib/browser/model/editor2d-model.d.ts.map +1 -1
  10. package/lib/browser/model/editor2d-model.js +5 -0
  11. package/lib/browser/model/editor2d-model.js.map +1 -1
  12. package/lib/browser/model/editor2d.d.ts +2 -0
  13. package/lib/browser/model/editor2d.d.ts.map +1 -1
  14. package/lib/browser/model/editor2d.js +4 -2
  15. package/lib/browser/model/editor2d.js.map +1 -1
  16. package/lib/browser/playground/canvas-draw.d.ts +6 -2
  17. package/lib/browser/playground/canvas-draw.d.ts.map +1 -1
  18. package/lib/browser/playground/canvas-draw.js +174 -49
  19. package/lib/browser/playground/canvas-draw.js.map +1 -1
  20. package/lib/browser/playground/canvas-layer.d.ts +15 -3
  21. package/lib/browser/playground/canvas-layer.d.ts.map +1 -1
  22. package/lib/browser/playground/canvas-layer.js +134 -72
  23. package/lib/browser/playground/canvas-layer.js.map +1 -1
  24. package/lib/browser/playground/index.d.ts +2 -0
  25. package/lib/browser/playground/index.d.ts.map +1 -1
  26. package/lib/browser/playground/index.js +2 -0
  27. package/lib/browser/playground/index.js.map +1 -1
  28. package/lib/browser/playground/path-edit/index.d.ts +4 -0
  29. package/lib/browser/playground/path-edit/index.d.ts.map +1 -0
  30. package/lib/browser/playground/path-edit/index.js +20 -0
  31. package/lib/browser/playground/path-edit/index.js.map +1 -0
  32. package/lib/browser/playground/path-edit/path-edit-layer-move-point.d.ts +18 -0
  33. package/lib/browser/playground/path-edit/path-edit-layer-move-point.d.ts.map +1 -0
  34. package/lib/browser/playground/path-edit/path-edit-layer-move-point.js +52 -0
  35. package/lib/browser/playground/path-edit/path-edit-layer-move-point.js.map +1 -0
  36. package/lib/browser/playground/path-edit/path-edit-layer-svg-path.d.ts +21 -0
  37. package/lib/browser/playground/path-edit/path-edit-layer-svg-path.d.ts.map +1 -0
  38. package/lib/browser/playground/path-edit/path-edit-layer-svg-path.js +158 -0
  39. package/lib/browser/playground/path-edit/path-edit-layer-svg-path.js.map +1 -0
  40. package/lib/browser/playground/path-edit/utils.d.ts +37 -0
  41. package/lib/browser/playground/path-edit/utils.d.ts.map +1 -0
  42. package/lib/browser/playground/path-edit/utils.js +236 -0
  43. package/lib/browser/playground/path-edit/utils.js.map +1 -0
  44. package/lib/browser/playground/path-edit-layer.d.ts +32 -12
  45. package/lib/browser/playground/path-edit-layer.d.ts.map +1 -1
  46. package/lib/browser/playground/path-edit-layer.js +460 -146
  47. package/lib/browser/playground/path-edit-layer.js.map +1 -1
  48. package/lib/browser/playground/playground-context.d.ts +5 -2
  49. package/lib/browser/playground/playground-context.d.ts.map +1 -1
  50. package/lib/browser/playground/playground-context.js +13 -2
  51. package/lib/browser/playground/playground-context.js.map +1 -1
  52. package/lib/browser/playground/playground-contribution.d.ts +4 -1
  53. package/lib/browser/playground/playground-contribution.d.ts.map +1 -1
  54. package/lib/browser/playground/playground-contribution.js +23 -23
  55. package/lib/browser/playground/playground-contribution.js.map +1 -1
  56. package/lib/browser/playground/selection-entity-manager.d.ts +1 -1
  57. package/lib/browser/playground/selection-entity-manager.d.ts.map +1 -1
  58. package/lib/browser/playground/selection-entity-manager.js +40 -10
  59. package/lib/browser/playground/selection-entity-manager.js.map +1 -1
  60. package/lib/browser/playground/selector-extend-renderer.d.ts +2 -1
  61. package/lib/browser/playground/selector-extend-renderer.d.ts.map +1 -1
  62. package/lib/browser/playground/selector-extend-renderer.js +50 -21
  63. package/lib/browser/playground/selector-extend-renderer.js.map +1 -1
  64. package/lib/browser/utils/snapshot.d.ts +1 -0
  65. package/lib/browser/utils/snapshot.d.ts.map +1 -1
  66. package/lib/browser/utils/snapshot.js +12 -1
  67. package/lib/browser/utils/snapshot.js.map +1 -1
  68. package/package.json +9 -7
  69. package/src/browser/model/editor2d-document.ts +44 -6
  70. package/src/browser/model/editor2d-model-container.ts +2 -0
  71. package/src/browser/model/editor2d-model.ts +2 -0
  72. package/src/browser/model/editor2d.ts +4 -1
  73. package/src/browser/playground/canvas-draw.ts +331 -112
  74. package/src/browser/playground/canvas-layer.ts +120 -59
  75. package/src/browser/playground/index.ts +2 -0
  76. package/src/browser/playground/path-edit/index.ts +3 -0
  77. package/src/browser/playground/path-edit/path-edit-layer-move-point.tsx +108 -0
  78. package/src/browser/playground/path-edit/path-edit-layer-svg-path.tsx +283 -0
  79. package/src/browser/playground/path-edit/utils.tsx +285 -0
  80. package/src/browser/playground/path-edit-layer.tsx +563 -216
  81. package/src/browser/playground/playground-context.ts +7 -1
  82. package/src/browser/playground/playground-contribution.ts +17 -24
  83. package/src/browser/playground/selection-entity-manager.tsx +48 -8
  84. package/src/browser/playground/selector-extend-renderer.tsx +69 -37
  85. package/src/browser/style/index.less +6 -0
  86. package/src/browser/style/path-edit-layer.less +17 -30
  87. package/src/browser/svg/pen_close.svg +24 -0
  88. package/src/browser/utils/snapshot.ts +12 -1
  89. package/LICENSE +0 -21
  90. package/lib/browser/playground/path-edit-layer-move-point.d.ts +0 -15
  91. package/lib/browser/playground/path-edit-layer-move-point.d.ts.map +0 -1
  92. package/lib/browser/playground/path-edit-layer-move-point.js +0 -47
  93. package/lib/browser/playground/path-edit-layer-move-point.js.map +0 -1
  94. package/lib/browser/playground/path-edit-layer-svg-path.d.ts +0 -11
  95. package/lib/browser/playground/path-edit-layer-svg-path.d.ts.map +0 -1
  96. package/lib/browser/playground/path-edit-layer-svg-path.js +0 -21
  97. package/lib/browser/playground/path-edit-layer-svg-path.js.map +0 -1
  98. package/src/browser/playground/path-edit-layer-move-point.tsx +0 -71
  99. package/src/browser/playground/path-edit-layer-svg-path.tsx +0 -50
@@ -2,19 +2,83 @@ import { entity, Layer, PipelineDimension } from '@gedit/playground';
2
2
  import { DocumentEntity, Editor2dEntity } from './entities';
3
3
  import { domUtils } from '@gedit/utils/lib/browser';
4
4
  import { PlaygroundContext2d } from './playground-context';
5
- import { Editor2dDocument } from '../model';
5
+ import { Editor2dDocument, Editor2dNode } from '../model';
6
6
  import { Rectangle } from '@gedit/math';
7
7
  import { SelectionEntityManager } from './selection-entity-manager';
8
8
  import { CanvasDraw, CanvasDrawLoadingState, GameObjectChangeEvent, GameObjectEventType } from './canvas-draw';
9
9
  import { debounce, OriginSchema } from '@gedit/utils';
10
- import { GameObjectBaseType, GameWidgetIDE } from '@gedit/render-engine-ide';
10
+ import { GameObject, GameObjectBaseType, GameWidgetIDE } from '@gedit/render-engine-ide';
11
+ import { toFixedValue as toFixedValueFunc } from '@gedit/canvas-draw';
12
+ /**
13
+ * 四舍五入并保留小数点
14
+ * @param value
15
+ * @param fixed 需要保留的小数位,默认两位
16
+ */
17
+ export const toFixedValue = toFixedValueFunc;
11
18
 
19
+ const childrenMap = (list: GameObject[], c: GameObject) => {
20
+ if (c.disposed) {
21
+ return;
22
+ }
23
+ if (!list.includes(c)) {
24
+ list.push(c);
25
+ }
26
+ if (c.children) {
27
+ c.children.forEach(d => {
28
+ childrenMap(list, d);
29
+ });
30
+ }
31
+ };
32
+ const parentMap = (list: GameObject[], p: GameObject) => {
33
+ if (p.disposed) {
34
+ return;
35
+ }
36
+ if (!list.includes(p)) {
37
+ list.push(p);
38
+ }
39
+ if (p.parent) {
40
+ parentMap(list , p.parent);
41
+ }
42
+ };
43
+
44
+ const getListData = (list: GameObject[]) => {
45
+ let updateList: GameObject[] = [];
46
+
47
+ // 遍历更新节点;
48
+ list.forEach(item => {
49
+ if (item.disposed) {
50
+ return;
51
+ }
52
+ if (!updateList.includes(item)) {
53
+ updateList.push(item);
54
+ }
55
+ // 子级遍历
56
+ if (item.children) {
57
+ item.children.forEach(c => {
58
+ childrenMap(updateList, c);
59
+ });
60
+ }
61
+ // 父级遍历
62
+ if (item.parent) {
63
+ childrenMap(updateList, item.parent);
64
+ }
65
+ });
66
+ updateList = updateList.filter(c => !c.disposed).sort((a, b) => {
67
+ const aa = a.getDepth?.() || 0;
68
+ const bb = b.getDepth?.() || 0;
69
+ return aa - bb;
70
+ });
71
+ return updateList;
72
+ };
12
73
  export class CanvasLayer extends Layer<PlaygroundContext2d> {
13
74
  @entity(DocumentEntity) documentEntity: DocumentEntity;
14
75
  node = domUtils.createDivWithClass('gedit-canvas-layer');
15
76
  protected scene?: HTMLElement;
16
77
  protected selectionEntityManager: SelectionEntityManager;
17
78
  protected canvasDrawer?: CanvasDraw;
79
+ protected updateList: GameObject[] = [];
80
+ protected nodeCache: Map<string, Editor2dNode> = new Map();
81
+ protected updateTimeout: NodeJS.Timeout;
18
82
  onReady(): void {
19
83
  this.selectionEntityManager = new SelectionEntityManager(
20
84
  this.entityManager,
@@ -24,6 +88,7 @@ export class CanvasLayer extends Layer<PlaygroundContext2d> {
24
88
  () => !!this.documentEntity.config?.visible
25
89
  );
26
90
  this.canvasDrawer = new CanvasDraw({
91
+ entityManager: this.entityManager,
27
92
  host: this.node,
28
93
  renderEngine: this.context.renderEngine,
29
94
  assetsURI: this.getAssetsURI(),
@@ -41,6 +106,14 @@ export class CanvasLayer extends Layer<PlaygroundContext2d> {
41
106
  ]);
42
107
  // this.entityManager.getEntity<RulerConfigEntity>(RulerConfigEntity)?.customizeOriginClick(this.config.scrollPageBoundsToCenter.bind(this));
43
108
  this.config.loading = true;
109
+ if (this.stateService) {
110
+ this.toDispose.push(this.stateService?.onStateChanged(state => {
111
+ // 布局完成后再归位画布;
112
+ if (state === 'ready') {
113
+ this.tryToResizeToCenter();
114
+ }
115
+ }));
116
+ }
44
117
  }
45
118
  onContainerInitOrigin(
46
119
  entity?: Editor2dEntity,
@@ -50,19 +123,19 @@ export class CanvasLayer extends Layer<PlaygroundContext2d> {
50
123
  if (config.appConfig?.engine !== 'pixi' || !entity) {
51
124
  return;
52
125
  }
53
- const { node } = entity;
126
+ const node = this.nodeCache.get(entity.id);
54
127
  const type = node?.displayType;
55
128
  // 分组与组件创建完后初始化中心点;
56
129
  if (
57
- node && (type === GameObjectBaseType.GROUP ||
58
- type === GameObjectBaseType.COMPONENT)
130
+ node && (type === GameObjectBaseType.COMPONENT)
59
131
  ) {
60
132
  const { transform } = entity;
61
133
  const { origin: org, localBounds } = transform;
62
- const { x: minX, y: minY, width, height } = localBounds;
134
+ // console.log(localBounds, entity.gameObject.rendererObject._localBoundsRect);
135
+ const { x: minX, y: minY, width, height } = localBounds; // entity.gameObject.rendererObject._localBoundsRect;
63
136
  // 算出组件与组的 0 点位置;
64
- const x = (-minX / width) || 0;
65
- const y = (-minY / height) || 0;
137
+ const x = toFixedValue((-minX / width) || 0, 6);
138
+ const y = toFixedValue((-minY / height) || 0, 6);
66
139
  const initOrigin = { x, y };
67
140
  const o: OriginSchema = update ? org : initOrigin;
68
141
  if (update || typeof o.initX === 'undefined') {
@@ -74,72 +147,51 @@ export class CanvasLayer extends Layer<PlaygroundContext2d> {
74
147
  initY: initOrigin.y || 0
75
148
  };
76
149
  // group origin 始终为 0;
77
- if (type === GameObjectBaseType.GROUP) {
78
- origin.x = initOrigin.x || 0;
79
- origin.y = initOrigin.y || 0;
80
- }
81
150
  // transform.update({ origin });
82
151
  this.document?.updateNode(node, {
83
152
  origin,
84
153
  });
154
+ // console.log('--------------origin--------------', origin);
155
+ // obj.data.origin = origin;
85
156
  // this.selectionEntityManager.updateEntity(obj.id, obj);
86
157
  }
87
158
  }
88
159
  };
160
+ onUpdateEntity = debounce((update: boolean) => {
161
+ const updateList = getListData(this.updateList);
162
+ updateList.forEach(item => {
163
+ if (item.disposed) {
164
+ return;
165
+ }
166
+ // console.log('------------------updateddddddddddddddd-----------', item);
167
+ this.selectionEntityManager.updateEntity(item.id, item, this.config.config.zoom);
168
+ const entity = this.selectionEntityManager.nodeEntitiesCache.get(item.id);
169
+ this.onContainerInitOrigin(entity, update);
170
+ });
171
+ this.updateList = [];
172
+ });
173
+
89
174
  onGameObjectChange(e: GameObjectChangeEvent): void {
90
- const { gameObject, parentObject, parentNode, state } = e;
175
+ const { gameObject, state, node } = e;
91
176
  switch (e.type) {
92
177
  case GameObjectEventType.CREATE:
93
- this.document?.updateNode(e.node, { error: undefined });
94
- this.selectionEntityManager.createEntity(gameObject.id, e.node, gameObject!, !!state?.selectable, !!state?.adsorbable);
95
- break;
96
- case GameObjectEventType.CREATE_READY:
97
- // 避免元素创后的回调;必须在元素创建完实例后执行;
98
- setTimeout(() => {
99
- const entity = this.selectionEntityManager.nodeEntitiesCache.get(gameObject.id);
100
- // 旧的没有中心点
101
- if (typeof entity?.transform.origin.initX === 'undefined') {
102
- this.selectionEntityManager.updateEntity(gameObject.id, gameObject!);
103
- this.onContainerInitOrigin(entity);
104
- }
105
- if (
106
- parentObject &&
107
- parentNode &&
108
- (parentObject.type === GameObjectBaseType.GROUP ||
109
- parentObject.type === GameObjectBaseType.COMPONENT)
110
- ) {
111
- this.document?.updateNode(parentNode, undefined, true);
112
- }
113
- });
178
+ this.document?.updateNode(node, { error: undefined });
179
+ this.selectionEntityManager.createEntity(gameObject.id, node, gameObject!, !!state?.selectable, !!state?.adsorbable);
114
180
  break;
115
181
  case GameObjectEventType.DESTROY:
116
182
  this.selectionEntityManager.removeEntity(gameObject.id);
117
- // destroy 后 gameObject 没有 parent;
118
- if (parentNode) {
119
- this.document?.updateNode(parentNode, undefined, true);
120
- }
183
+ this.nodeCache.delete(gameObject.id);
121
184
  break;
122
185
  case GameObjectEventType.UPDATE:
123
- this.selectionEntityManager.updateEntity(gameObject.id, gameObject!);
124
- // TODO 父节点更新则通知子节点更新, 用于刷新transform
125
- gameObject!.children.forEach(c => {
126
- this.selectionEntityManager.updateEntity(c.id as string, c);
127
- });
128
- if (
129
- parentObject &&
130
- parentObject.parent &&
131
- (parentObject.type === GameObjectBaseType.GROUP ||
132
- parentObject.type === GameObjectBaseType.COMPONENT)
133
- ) {
134
- // 需要等 parent 数据没有更后再执行;
135
- setTimeout(() => {
136
- const entity = this.selectionEntityManager.nodeEntitiesCache.get(parentObject.id);
137
- this.onContainerInitOrigin(entity, true);
138
- });
186
+ // console.log('------------------update-----------', gameObject.name);
187
+ if (!this.updateList.includes(gameObject)) {
188
+ this.updateList.push(gameObject);
189
+ this.nodeCache.set(gameObject.id, node);
139
190
  }
191
+ this.onUpdateEntity(true);
140
192
  break;
141
193
  case GameObjectEventType.ERROR:
142
- this.document?.updateNode(e.node, {error: e.error});
194
+ this.document?.updateNode(node, {error: e.error});
143
195
  break;
144
196
  }
145
197
  this.context.onCanvasDataChangedEmitter.fire(this.canvasDrawer!);
@@ -162,7 +214,7 @@ export class CanvasLayer extends Layer<PlaygroundContext2d> {
162
214
  if (!this.config.loading && !reload) return;
163
215
  if (loaded || allCount <= currentCount || allCount === 0) {
164
216
  this.config.loading = false;
165
- this.tryToResizeToCenter();
217
+ // this.tryToResizeToCenter();
166
218
  this.node.classList.add('ready');
167
219
  this.loaded();
168
220
  } else {
@@ -191,6 +243,15 @@ export class CanvasLayer extends Layer<PlaygroundContext2d> {
191
243
  onZoom = debounce(() => {
192
244
  const config = this.config.config;
193
245
  this.canvasDrawer?.refreshScale(true, config.zoom);
246
+ const selectedEntities = this.selectionEntityManager.getSelectedEntities();
247
+ if (this.document?.engineName === 'dom' && selectedEntities?.length) {
248
+ selectedEntities.forEach(c => {
249
+ const {gameObject} = c;
250
+ if (gameObject) {
251
+ this.selectionEntityManager.updateEntity(gameObject.id, gameObject, this.config.config.zoom);
252
+ }
253
+ });
254
+ }
194
255
  });
195
256
  onResize = debounce((size: PipelineDimension) => {
196
257
  const renderWidget = this.canvasDrawer?.renderWidget;
@@ -209,11 +270,11 @@ export class CanvasLayer extends Layer<PlaygroundContext2d> {
209
270
  private currentRectangle: Rectangle | undefined;
210
271
  // private currentResolution = 1;
211
272
 
212
- tryToResizeToCenter(): void {
273
+ tryToResizeToCenter = debounce(() => {
213
274
  const {visible } = this.documentEntity.config;
214
275
  // const resolution = appConfig?.resolution || 1;
215
276
  const size = this.canvasDrawer?.getSceneSize();
216
- if (!visible || !size || this.config.loading || this.config.config.width === 0 || this.config.config.height === 0) return;
277
+ if (!visible || !size || this.config.config.width === 0 || this.config.config.height === 0) return;
217
278
  const newRect = new Rectangle(0, 0, size.width, size.height);
218
279
  if (!this.currentRectangle || !this.currentRectangle.isEqual(newRect)) {
219
280
  this.currentRectangle = newRect;
@@ -223,7 +284,7 @@ export class CanvasLayer extends Layer<PlaygroundContext2d> {
223
284
  this.config.scrollPageBoundsToCenter(true, 16, !this.context.options.isTemplate)
224
285
  .then(() => this.onZoom());
225
286
  }
226
- }
287
+ }, 100); // 打开时会有一次 tag 大小的视图,宽是 98px,,dom 下没有引擎加载,会响应 98 宽,加 100 ms 延时
227
288
  draw(): void {
228
289
  const config = this.documentEntity.config;
229
290
  const document = config.document;
@@ -7,3 +7,5 @@ export * from './canvas-draw';
7
7
  export { SelectorExtendType } from './selector-extend-icons';
8
8
  export * from './selector-extend-renderer';
9
9
  export * from './extend-edit-layer';
10
+ export * from './path-edit';
11
+ export * from './path-edit-layer';
@@ -0,0 +1,3 @@
1
+ export * from './path-edit-layer-move-point';
2
+ export * from './path-edit-layer-svg-path';
3
+ export * from './utils';
@@ -0,0 +1,108 @@
1
+ import * as React from 'react';
2
+ import { PathChild, PATH_FUNC_TYPE, getPointsToPath } from '@gedit/canvas-draw';
3
+ import { PositionSchema } from '@gedit/playground';
4
+ import { PathEditLayerEventContext } from '../path-edit-layer';
5
+ import clsx from 'clsx';
6
+
7
+ export interface PointSchema extends PositionSchema {
8
+ id?: string;
9
+ }
10
+
11
+ export interface PointDefaultProps {
12
+ getPosFromMouseEvent: (
13
+ event: {
14
+ clientX: number;
15
+ clientY: number;
16
+ },
17
+ addScale?: boolean
18
+ ) => PositionSchema;
19
+ paths: PathChild[];
20
+ scale: number;
21
+ closePath: boolean; // 显示闭合路径图标
22
+ currentPointId?: string;
23
+ }
24
+
25
+ export const PointMoveDefault = ({
26
+ getPosFromMouseEvent,
27
+ paths,
28
+ scale,
29
+ closePath,
30
+ currentPointId,
31
+ }: PointDefaultProps) => {
32
+ const [movePoint, setMovePoint] = React.useState<PathChild>();
33
+ const { onSceneAddEvent } = React.useContext(PathEditLayerEventContext);
34
+ const endPoint = paths[paths.length - 1];
35
+ const startPoint = paths[0];
36
+ /**
37
+ * 选中起始点的情况,显示移动点,绘制起点到移动点的路径,反转点的 x1=x2, y1=y2;
38
+ * @param lineStartPoint 选中的起始点
39
+ * @param lineEndPoint 选中的结束点
40
+ * @param reverse 是否反转
41
+ */
42
+ let lineStartPoint = paths.find(c => c.id === currentPointId);
43
+ let lineEndPoint = lineStartPoint === startPoint ? endPoint : startPoint;
44
+ const reverse = lineStartPoint === startPoint && lineStartPoint !== endPoint;
45
+ if (reverse && lineStartPoint) {
46
+ const { x1, x2, y1, y2 } = lineStartPoint;
47
+ lineStartPoint = {
48
+ ...lineStartPoint,
49
+ x1: x2,
50
+ x2: x1,
51
+ y1: y2,
52
+ y2: y1,
53
+ };
54
+ const { x1: e1, x2: e2, y1: r1, y2: r2 } = lineEndPoint;
55
+ lineEndPoint = {
56
+ ...lineEndPoint,
57
+ x1: e2,
58
+ x2: e1,
59
+ y1: r2,
60
+ y2: r1,
61
+ };
62
+ }
63
+ const onMove = (e: MouseEvent) => {
64
+ const pos = getPosFromMouseEvent(e);
65
+ setMovePoint({
66
+ ...pos,
67
+ type: PATH_FUNC_TYPE.STRAIGHT,
68
+ });
69
+ };
70
+ React.useEffect(() => {
71
+ const event = onSceneAddEvent('mousemove', onMove);
72
+ const event2 = onSceneAddEvent('mouseleave', () => {
73
+ setMovePoint(undefined);
74
+ });
75
+ return () => {
76
+ event.dispose();
77
+ event2.dispose();
78
+ };
79
+ }, []);
80
+ if (!movePoint) {
81
+ return null;
82
+ }
83
+ const line =
84
+ lineStartPoint &&
85
+ getPointsToPath([lineStartPoint, closePath ? lineEndPoint : movePoint]);
86
+ return (
87
+ <>
88
+ {line && (
89
+ <path
90
+ className="gedit-path-edit-layer-line"
91
+ d={line}
92
+ strokeLinecap="round"
93
+ strokeWidth={1.5 / scale}
94
+ />
95
+ )}
96
+ <circle
97
+ className={clsx(
98
+ 'gedit-path-edit-layer-point',
99
+ 'gedit-path-edit-layer-point-move',
100
+ 'gedit-path-edit-layer-pen'
101
+ )}
102
+ cx={closePath ? startPoint.x : movePoint.x}
103
+ cy={closePath ? startPoint.y : movePoint.y}
104
+ r={4 / scale}
105
+ />
106
+ </>
107
+ );
108
+ };
@@ -0,0 +1,283 @@
1
+ import * as React from 'react';
2
+ import {
3
+ PathChild,
4
+ PATH_FUNC_TYPE,
5
+ getPointsToPaths /* getPathToBezier */,
6
+ } from '@gedit/canvas-draw';
7
+ import {
8
+ PointMoveDefault,
9
+ PointDefaultProps,
10
+ } from './path-edit-layer-move-point';
11
+ import { PathEditLayerEventContext } from '../path-edit-layer';
12
+ import clsx from 'clsx';
13
+ import { generateUuid } from '@gedit/utils';
14
+ import { PathSelectMode } from '@gedit/playground';
15
+
16
+ export interface PointSelection {
17
+ pointId?: string;
18
+ bezierKey?: string;
19
+ }
20
+ export interface PathSVGProps {
21
+ width: number;
22
+ height: number;
23
+ scale: number;
24
+ paths: PathChild[];
25
+ closed: boolean; // 是否闭合路径
26
+ selection?: PointSelection[];
27
+ selectMode?: PathSelectMode;
28
+ getPosFromMouseEvent: PointDefaultProps['getPosFromMouseEvent'];
29
+ getPointIsStartOrEnd: () => boolean;
30
+ }
31
+
32
+ export const SvgPath = ({
33
+ width,
34
+ height,
35
+ paths = [],
36
+ closed,
37
+ scale,
38
+ selection = [],
39
+ selectMode,
40
+ getPosFromMouseEvent,
41
+ getPointIsStartOrEnd,
42
+ }: PathSVGProps) => {
43
+ const isMultiple = selection.length > 1; // 多选模式;
44
+ const isSelect = selectMode !== PathSelectMode.ADD_PATH; // 选择点模式
45
+ const [hideMovePoint, setHideMovePoint] = React.useState(false);
46
+ const [closePath, setClosePath] = React.useState(false);
47
+ const onHideMovePoint = () => {
48
+ setHideMovePoint(true);
49
+ };
50
+ const onShowMovePoint = () => {
51
+ setHideMovePoint(false);
52
+ };
53
+ const onClosePath = () => {
54
+ setClosePath(true);
55
+ };
56
+ const onReClosePath = () => {
57
+ setClosePath(false);
58
+ };
59
+ const {
60
+ onPointMouseDown,
61
+ onClosePath: onClosedPath,
62
+ onPathAddPoint,
63
+ onBezierPointMouseDown,
64
+ } = React.useContext(PathEditLayerEventContext);
65
+ const p = [...paths];
66
+ if (closed) {
67
+ p.push({
68
+ ...paths[0],
69
+ id: generateUuid(),
70
+ });
71
+ }
72
+ const pathsStringArray = getPointsToPaths(p);
73
+ /**
74
+ * 路径点
75
+ * 1. 没有任何点的情况,显示默认移动点,不绘制路径;
76
+ * 2. 有点的情况,显示所有点,绘制最后点到移动点的路径;
77
+ * 3. 选中中间点的情况,不显示移动点与路径;
78
+ * 4. 选中起始点的情况,显示移动点,绘制起点到移动点的路径,反转点的 x1=x2, y1=y2;
79
+ * 5. 选中贝赛尔点时,不显示移动点与路径;
80
+ * @param bezierSelect 是否选中贝赛尔点
81
+ * @param pointIsStartOrEnd 是否选中起始点或结束点
82
+ * @param currentPointIndex 当前选中点的索引
83
+ * @param closePointIndex 当前选中点的闭合点索引
84
+ */
85
+ const bezierSelect =
86
+ !isMultiple &&
87
+ selection[0] &&
88
+ typeof selection[0].bezierKey !== 'undefined';
89
+ const pointIsStartOrEnd = getPointIsStartOrEnd();
90
+ const currentPointIndex =
91
+ !isSelect && selection.length
92
+ ? paths.findIndex(c => c.id === selection[0].pointId)
93
+ : undefined;
94
+ const closePointIndex =
95
+ currentPointIndex === paths.length - 1 ? 0 : paths.length - 1;
96
+ const allPoints = paths.map((item, i) => {
97
+ /**
98
+ * 经过点时,是否关闭路径;
99
+ * 条件:
100
+ * 1. 点的数量大于2; 或者点的数量等于2,但是有一点不是直线时;
101
+ * 2. 不是闭合路径时; 闭合路径了选择器是 select_bezier;
102
+ * 3. 不是多选模式;
103
+ * 4. 第一帧或最后一帧时;
104
+ * 5. 选中的点是起始点时,最后一点是闭合点;选中的点是结束点时,第一点是闭合点;
105
+ */
106
+ const closePoint =
107
+ (paths.length > 2 ||
108
+ (paths.length === 2 &&
109
+ paths.some(c => c.type !== PATH_FUNC_TYPE.STRAIGHT))) &&
110
+ !closed &&
111
+ !isMultiple &&
112
+ pointIsStartOrEnd &&
113
+ closePointIndex === i;
114
+ return (
115
+ <circle
116
+ className={clsx('gedit-path-edit-layer-point', {
117
+ 'gedit-path-edit-layer-point-closed': closePoint,
118
+ 'gedit-path-edit-layer-point-active':
119
+ selection.some(c => c.pointId === item.id) && !bezierSelect,
120
+ })}
121
+ cx={item.x}
122
+ cy={item.y}
123
+ r={4 / scale}
124
+ key={item.id}
125
+ strokeWidth="1"
126
+ onMouseDown={e => {
127
+ e.preventDefault();
128
+ e.stopPropagation();
129
+ if (closePoint) {
130
+ onClosedPath();
131
+ return;
132
+ }
133
+ onPointMouseDown?.(e, item);
134
+ }}
135
+ onMouseEnter={closePoint ? onClosePath : onHideMovePoint}
136
+ onMouseLeave={closePoint ? onReClosePath : onShowMovePoint}
137
+ />
138
+ );
139
+ });
140
+ // 贝塞尔点
141
+ const bezierPointNodes: JSX.Element[] = [];
142
+ const bezierPathNodes: JSX.Element[] = [];
143
+ const bezierPoints: PathChild[] = [];
144
+ // 插入贝塞尔点
145
+ selection.forEach(item => {
146
+ const { pointId: currentPointId } = item;
147
+ const index = paths.findIndex(c => c.id === currentPointId);
148
+ // 关闭路径把第一个贝赛尔点加入
149
+ if (closed) {
150
+ if (index === paths.length - 1) {
151
+ bezierPoints.push(paths[0]);
152
+ }
153
+ if (index === 0) {
154
+ bezierPoints.push(paths[paths.length - 1]);
155
+ }
156
+ }
157
+ // 前后两点加当前开启贝赛尔点
158
+ paths.filter((_, i) => i >= index - 1 && i <= index + 1).forEach(c => {
159
+ if (bezierPoints.some(d => d.id === c.id)) {
160
+ return;
161
+ }
162
+ bezierPoints.push(c);
163
+ });
164
+ });
165
+ bezierPoints.forEach((p, i) => {
166
+ const selectionNode = selection.find(c => c.pointId === p.id);
167
+ const { bezierKey, pointId: currentPointId } = selectionNode || {};
168
+ if (p.type === PATH_FUNC_TYPE.STRAIGHT) {
169
+ return;
170
+ }
171
+ if ('x1' in p && 'y1' in p) {
172
+ bezierPathNodes.push(
173
+ <path
174
+ key={`${p.id}_${i}_x1-line`}
175
+ className="gedit-path-edit-layer-point-bezier-line"
176
+ strokeWidth={1 / scale}
177
+ d={`M${p.x},${p.y} L${p.x1},${p.y1}`}
178
+ />
179
+ );
180
+ bezierPointNodes.push(
181
+ <circle
182
+ key={`${p.id}_${i}_x1_point`}
183
+ className={clsx('gedit-path-edit-layer-point-bezier', {
184
+ 'gedit-path-edit-layer-point-active':
185
+ bezierKey === 'left' && currentPointId === p.id,
186
+ })}
187
+ cx={p.x1}
188
+ cy={p.y1}
189
+ r={3 / scale}
190
+ onMouseDown={e => {
191
+ onBezierPointMouseDown(e, p, 'left');
192
+ }}
193
+ onMouseEnter={onHideMovePoint}
194
+ onMouseLeave={onShowMovePoint}
195
+ />
196
+ );
197
+ }
198
+ if ('x2' in p && 'y2' in p) {
199
+ bezierPathNodes.push(
200
+ <path
201
+ key={`${p.id}_${i}_x2-line`}
202
+ className="gedit-path-edit-layer-point-bezier-line"
203
+ strokeWidth={1 / scale}
204
+ d={`M${p.x},${p.y} L${p.x2},${p.y2}`}
205
+ />
206
+ );
207
+ bezierPointNodes.push(
208
+ <circle
209
+ key={`${p.id}_${i}x2_point`}
210
+ className={clsx('gedit-path-edit-layer-point-bezier', {
211
+ 'gedit-path-edit-layer-point-active':
212
+ bezierKey === 'right' && currentPointId === p.id,
213
+ })}
214
+ cx={p.x2}
215
+ cy={p.y2}
216
+ r={3 / scale}
217
+ onMouseDown={e => {
218
+ onBezierPointMouseDown(e, p, 'right');
219
+ }}
220
+ onMouseEnter={onHideMovePoint}
221
+ onMouseLeave={onShowMovePoint}
222
+ />
223
+ );
224
+ }
225
+ });
226
+
227
+ const showDefaultMovePoint =
228
+ !isMultiple && // 不是多选模式
229
+ !isSelect && // 不是选择模式
230
+ !hideMovePoint && // 没经过点时
231
+ !closed && // 不是关闭路径时
232
+ (!paths.length || // 没有点时
233
+ pointIsStartOrEnd); // 选中起始点或结束点时
234
+ // const ppp = [...paths, paths[0]];
235
+ // const bezierBox = getPathToBezier(ppp).map(c => c.bbox());
236
+
237
+ return (
238
+ <svg
239
+ width={width || 300}
240
+ height={height || 300}
241
+ className={clsx('gedit-path-edit-layer-svg', {
242
+ // 'gedit-path-edit-layer-pen': !closed,
243
+ })}
244
+ >
245
+ {showDefaultMovePoint && (
246
+ <PointMoveDefault
247
+ getPosFromMouseEvent={getPosFromMouseEvent}
248
+ paths={paths}
249
+ scale={scale}
250
+ closePath={closePath}
251
+ currentPointId={selection[0]?.pointId}
252
+ />
253
+ )}
254
+ {pathsStringArray.map((p, i) => (
255
+ <path
256
+ className={clsx(
257
+ 'gedit-path-edit-layer-path',
258
+ 'gedit-path-edit-layer-pen'
259
+ )}
260
+ key={i.toString()}
261
+ strokeLinecap="round"
262
+ strokeWidth={1.5 / scale}
263
+ d={p}
264
+ onMouseEnter={onHideMovePoint}
265
+ onMouseLeave={onShowMovePoint}
266
+ onMouseDown={e => {
267
+ e.preventDefault();
268
+ e.stopPropagation();
269
+ }}
270
+ onClick={e => {
271
+ e.preventDefault();
272
+ e.stopPropagation();
273
+ onPathAddPoint(i, e);
274
+ }}
275
+ />
276
+ ))}
277
+ {/* 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} />) */}
278
+ {bezierPathNodes}
279
+ {allPoints}
280
+ {bezierPointNodes}
281
+ </svg>
282
+ );
283
+ };