@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.
- package/lib/browser/model/editor2d-document.d.ts +11 -2
- package/lib/browser/model/editor2d-document.d.ts.map +1 -1
- package/lib/browser/model/editor2d-document.js +44 -8
- package/lib/browser/model/editor2d-document.js.map +1 -1
- package/lib/browser/model/editor2d-model-container.d.ts.map +1 -1
- package/lib/browser/model/editor2d-model-container.js +1 -1
- package/lib/browser/model/editor2d-model-container.js.map +1 -1
- package/lib/browser/model/editor2d-model.d.ts +2 -0
- package/lib/browser/model/editor2d-model.d.ts.map +1 -1
- package/lib/browser/model/editor2d-model.js +5 -0
- package/lib/browser/model/editor2d-model.js.map +1 -1
- package/lib/browser/model/editor2d.d.ts +2 -0
- package/lib/browser/model/editor2d.d.ts.map +1 -1
- package/lib/browser/model/editor2d.js +4 -2
- package/lib/browser/model/editor2d.js.map +1 -1
- package/lib/browser/playground/canvas-draw.d.ts +6 -2
- package/lib/browser/playground/canvas-draw.d.ts.map +1 -1
- package/lib/browser/playground/canvas-draw.js +174 -49
- package/lib/browser/playground/canvas-draw.js.map +1 -1
- package/lib/browser/playground/canvas-layer.d.ts +15 -3
- package/lib/browser/playground/canvas-layer.d.ts.map +1 -1
- package/lib/browser/playground/canvas-layer.js +134 -72
- package/lib/browser/playground/canvas-layer.js.map +1 -1
- package/lib/browser/playground/index.d.ts +2 -0
- package/lib/browser/playground/index.d.ts.map +1 -1
- package/lib/browser/playground/index.js +2 -0
- package/lib/browser/playground/index.js.map +1 -1
- package/lib/browser/playground/path-edit/index.d.ts +4 -0
- package/lib/browser/playground/path-edit/index.d.ts.map +1 -0
- package/lib/browser/playground/path-edit/index.js +20 -0
- package/lib/browser/playground/path-edit/index.js.map +1 -0
- package/lib/browser/playground/path-edit/path-edit-layer-move-point.d.ts +18 -0
- package/lib/browser/playground/path-edit/path-edit-layer-move-point.d.ts.map +1 -0
- package/lib/browser/playground/path-edit/path-edit-layer-move-point.js +52 -0
- package/lib/browser/playground/path-edit/path-edit-layer-move-point.js.map +1 -0
- package/lib/browser/playground/path-edit/path-edit-layer-svg-path.d.ts +21 -0
- package/lib/browser/playground/path-edit/path-edit-layer-svg-path.d.ts.map +1 -0
- package/lib/browser/playground/path-edit/path-edit-layer-svg-path.js +158 -0
- package/lib/browser/playground/path-edit/path-edit-layer-svg-path.js.map +1 -0
- package/lib/browser/playground/path-edit/utils.d.ts +37 -0
- package/lib/browser/playground/path-edit/utils.d.ts.map +1 -0
- package/lib/browser/playground/path-edit/utils.js +236 -0
- package/lib/browser/playground/path-edit/utils.js.map +1 -0
- package/lib/browser/playground/path-edit-layer.d.ts +32 -12
- package/lib/browser/playground/path-edit-layer.d.ts.map +1 -1
- package/lib/browser/playground/path-edit-layer.js +460 -146
- package/lib/browser/playground/path-edit-layer.js.map +1 -1
- package/lib/browser/playground/playground-context.d.ts +5 -2
- package/lib/browser/playground/playground-context.d.ts.map +1 -1
- package/lib/browser/playground/playground-context.js +13 -2
- package/lib/browser/playground/playground-context.js.map +1 -1
- package/lib/browser/playground/playground-contribution.d.ts +4 -1
- package/lib/browser/playground/playground-contribution.d.ts.map +1 -1
- package/lib/browser/playground/playground-contribution.js +23 -23
- package/lib/browser/playground/playground-contribution.js.map +1 -1
- package/lib/browser/playground/selection-entity-manager.d.ts +1 -1
- package/lib/browser/playground/selection-entity-manager.d.ts.map +1 -1
- package/lib/browser/playground/selection-entity-manager.js +40 -10
- package/lib/browser/playground/selection-entity-manager.js.map +1 -1
- package/lib/browser/playground/selector-extend-renderer.d.ts +2 -1
- package/lib/browser/playground/selector-extend-renderer.d.ts.map +1 -1
- package/lib/browser/playground/selector-extend-renderer.js +50 -21
- package/lib/browser/playground/selector-extend-renderer.js.map +1 -1
- package/lib/browser/utils/snapshot.d.ts +1 -0
- package/lib/browser/utils/snapshot.d.ts.map +1 -1
- package/lib/browser/utils/snapshot.js +12 -1
- package/lib/browser/utils/snapshot.js.map +1 -1
- package/package.json +9 -7
- package/src/browser/model/editor2d-document.ts +44 -6
- package/src/browser/model/editor2d-model-container.ts +2 -0
- package/src/browser/model/editor2d-model.ts +2 -0
- package/src/browser/model/editor2d.ts +4 -1
- package/src/browser/playground/canvas-draw.ts +331 -112
- package/src/browser/playground/canvas-layer.ts +120 -59
- package/src/browser/playground/index.ts +2 -0
- package/src/browser/playground/path-edit/index.ts +3 -0
- package/src/browser/playground/path-edit/path-edit-layer-move-point.tsx +108 -0
- package/src/browser/playground/path-edit/path-edit-layer-svg-path.tsx +283 -0
- package/src/browser/playground/path-edit/utils.tsx +285 -0
- package/src/browser/playground/path-edit-layer.tsx +563 -216
- package/src/browser/playground/playground-context.ts +7 -1
- package/src/browser/playground/playground-contribution.ts +17 -24
- package/src/browser/playground/selection-entity-manager.tsx +48 -8
- package/src/browser/playground/selector-extend-renderer.tsx +69 -37
- package/src/browser/style/index.less +6 -0
- package/src/browser/style/path-edit-layer.less +17 -30
- package/src/browser/svg/pen_close.svg +24 -0
- package/src/browser/utils/snapshot.ts +12 -1
- package/LICENSE +0 -21
- package/lib/browser/playground/path-edit-layer-move-point.d.ts +0 -15
- package/lib/browser/playground/path-edit-layer-move-point.d.ts.map +0 -1
- package/lib/browser/playground/path-edit-layer-move-point.js +0 -47
- package/lib/browser/playground/path-edit-layer-move-point.js.map +0 -1
- package/lib/browser/playground/path-edit-layer-svg-path.d.ts +0 -11
- package/lib/browser/playground/path-edit-layer-svg-path.d.ts.map +0 -1
- package/lib/browser/playground/path-edit-layer-svg-path.js +0 -21
- package/lib/browser/playground/path-edit-layer-svg-path.js.map +0 -1
- package/src/browser/playground/path-edit-layer-move-point.tsx +0 -71
- 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
|
|
126
|
+
const node = this.nodeCache.get(entity.id);
|
|
54
127
|
const type = node?.displayType;
|
|
55
128
|
// 分组与组件创建完后初始化中心点;
|
|
56
129
|
if (
|
|
57
|
-
node && (type === GameObjectBaseType.
|
|
58
|
-
type === GameObjectBaseType.COMPONENT)
|
|
130
|
+
node && (type === GameObjectBaseType.COMPONENT)
|
|
59
131
|
) {
|
|
60
132
|
const { transform } = entity;
|
|
61
133
|
const { origin: org, localBounds } = transform;
|
|
62
|
-
|
|
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,
|
|
175
|
+
const { gameObject, state, node } = e;
|
|
91
176
|
switch (e.type) {
|
|
92
177
|
case GameObjectEventType.CREATE:
|
|
93
|
-
this.document?.updateNode(
|
|
94
|
-
this.selectionEntityManager.createEntity(gameObject.id,
|
|
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
|
-
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
this.
|
|
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(
|
|
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()
|
|
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.
|
|
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;
|
|
@@ -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
|
+
};
|