@flowgram-vue/core 0.2.0
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/LICENSE +22 -0
- package/dist/index.cjs +0 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +0 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
- package/src/common/config-entity.ts +80 -0
- package/src/common/entity-data.ts +171 -0
- package/src/common/entity-manager-contribution.ts +12 -0
- package/src/common/entity-manager.ts +475 -0
- package/src/common/entity.ts +482 -0
- package/src/common/index.ts +22 -0
- package/src/common/playground-context.ts +35 -0
- package/src/common/playground-decorator-helper.ts +113 -0
- package/src/common/playground-decorators.ts +85 -0
- package/src/common/playground-schedule.ts +30 -0
- package/src/common/protect-wheel-area.ts +11 -0
- package/src/common/schema/index.ts +14 -0
- package/src/common/schema/node.ts +15 -0
- package/src/common/schema/opacity-schema.ts +19 -0
- package/src/common/schema/origin-schema.ts +35 -0
- package/src/common/schema/position-schema.ts +35 -0
- package/src/common/schema/rotation-schema.ts +19 -0
- package/src/common/schema/scale-schema.ts +35 -0
- package/src/common/schema/size-schema.ts +42 -0
- package/src/common/schema/skew-schema.ts +35 -0
- package/src/common/schema/transform-schema.ts +613 -0
- package/src/common/utils/bounds.spec.ts +229 -0
- package/src/common/utils/bounds.ts +176 -0
- package/src/common/utils/index.ts +6 -0
- package/src/composables/index.ts +16 -0
- package/src/composables/use-config-entity.ts +31 -0
- package/src/composables/use-entities.ts +26 -0
- package/src/composables/use-entity-data-from-context.ts +34 -0
- package/src/composables/use-entity-from-context.ts +31 -0
- package/src/composables/use-listen-events.ts +22 -0
- package/src/composables/use-playground-container.ts +16 -0
- package/src/composables/use-playground-context.ts +15 -0
- package/src/composables/use-playground-drag.ts +31 -0
- package/src/composables/use-playground.ts +16 -0
- package/src/composables/use-refresh.ts +6 -0
- package/src/composables/use-service.ts +17 -0
- package/src/core/index.ts +8 -0
- package/src/core/layer/config/editor-state-config-entity.ts +180 -0
- package/src/core/layer/config/index.ts +7 -0
- package/src/core/layer/config/playground-config-entity.ts +604 -0
- package/src/core/layer/index.ts +8 -0
- package/src/core/layer/layer.ts +248 -0
- package/src/core/layer/playground-layer.ts +547 -0
- package/src/core/pipeline/index.ts +10 -0
- package/src/core/pipeline/pipeline-entities-selector.ts +200 -0
- package/src/core/pipeline/pipeline-entities.ts +230 -0
- package/src/core/pipeline/pipeline-registry.ts +344 -0
- package/src/core/pipeline/pipeline-renderer.ts +248 -0
- package/src/core/pipeline/pipeline-vue-utils.ts +96 -0
- package/src/core/pipeline/pipeline.ts +28 -0
- package/src/core/utils/index.ts +12 -0
- package/src/core/utils/inject-provider-decorators.ts +27 -0
- package/src/core/utils/lazy-inject-decorators.ts +38 -0
- package/src/core/utils/mouse-touch-event.ts +120 -0
- package/src/core/utils/playground-drag.ts +511 -0
- package/src/core/utils/playground-gesture.spec.ts +135 -0
- package/src/core/utils/playground-gesture.ts +118 -0
- package/src/core/utils/tween.ts +156 -0
- package/src/core/utils/use-gesture/core/Controller.ts +212 -0
- package/src/core/utils/use-gesture/core/EventStore.ts +46 -0
- package/src/core/utils/use-gesture/core/TimeoutStore.ts +28 -0
- package/src/core/utils/use-gesture/core/actions.ts +63 -0
- package/src/core/utils/use-gesture/core/config/commonConfigResolver.ts +86 -0
- package/src/core/utils/use-gesture/core/config/coordinatesConfigResolver.ts +48 -0
- package/src/core/utils/use-gesture/core/config/dragConfigResolver.ts +140 -0
- package/src/core/utils/use-gesture/core/config/hoverConfigResolver.ts +11 -0
- package/src/core/utils/use-gesture/core/config/moveConfigResolver.ts +11 -0
- package/src/core/utils/use-gesture/core/config/pinchConfigResolver.ts +59 -0
- package/src/core/utils/use-gesture/core/config/resolver.ts +70 -0
- package/src/core/utils/use-gesture/core/config/scrollConfigResolver.ts +8 -0
- package/src/core/utils/use-gesture/core/config/sharedConfigResolver.ts +28 -0
- package/src/core/utils/use-gesture/core/config/support.ts +52 -0
- package/src/core/utils/use-gesture/core/config/wheelConfigResolver.ts +8 -0
- package/src/core/utils/use-gesture/core/engines/CoordinatesEngine.ts +78 -0
- package/src/core/utils/use-gesture/core/engines/DragEngine.ts +403 -0
- package/src/core/utils/use-gesture/core/engines/Engine.ts +406 -0
- package/src/core/utils/use-gesture/core/engines/HoverEngine.ts +43 -0
- package/src/core/utils/use-gesture/core/engines/MoveEngine.ts +52 -0
- package/src/core/utils/use-gesture/core/engines/PinchEngine.ts +345 -0
- package/src/core/utils/use-gesture/core/engines/ScrollEngine.ts +42 -0
- package/src/core/utils/use-gesture/core/engines/WheelEngine.ts +48 -0
- package/src/core/utils/use-gesture/core/index.ts +7 -0
- package/src/core/utils/use-gesture/core/parser.ts +92 -0
- package/src/core/utils/use-gesture/core/types/action.ts +19 -0
- package/src/core/utils/use-gesture/core/types/config.ts +255 -0
- package/src/core/utils/use-gesture/core/types/handlers.ts +73 -0
- package/src/core/utils/use-gesture/core/types/index.ts +11 -0
- package/src/core/utils/use-gesture/core/types/internalConfig.ts +80 -0
- package/src/core/utils/use-gesture/core/types/state.ts +275 -0
- package/src/core/utils/use-gesture/core/types/utils.ts +204 -0
- package/src/core/utils/use-gesture/core/types.ts +8 -0
- package/src/core/utils/use-gesture/core/utils/events.ts +158 -0
- package/src/core/utils/use-gesture/core/utils/fn.ts +32 -0
- package/src/core/utils/use-gesture/core/utils/maths.ts +63 -0
- package/src/core/utils/use-gesture/core/utils/state.ts +24 -0
- package/src/core/utils/use-gesture/core/utils.ts +8 -0
- package/src/core/utils/use-gesture/index.ts +6 -0
- package/src/core/utils/use-gesture/vanilla/DragGesture.ts +27 -0
- package/src/core/utils/use-gesture/vanilla/Gesture.ts +45 -0
- package/src/core/utils/use-gesture/vanilla/HoverGesture.ts +27 -0
- package/src/core/utils/use-gesture/vanilla/MoveGesture.ts +27 -0
- package/src/core/utils/use-gesture/vanilla/PinchGesture.ts +27 -0
- package/src/core/utils/use-gesture/vanilla/Recognizer.ts +43 -0
- package/src/core/utils/use-gesture/vanilla/ScrollGesture.ts +27 -0
- package/src/core/utils/use-gesture/vanilla/WheelGesture.ts +27 -0
- package/src/core/utils/use-gesture/vanilla/createGesture.ts +18 -0
- package/src/core/utils/use-gesture/vanilla/index.ts +18 -0
- package/src/env.d.ts +10 -0
- package/src/index.ts +17 -0
- package/src/playground-config.ts +70 -0
- package/src/playground-container.ts +129 -0
- package/src/playground-contribution.ts +81 -0
- package/src/playground-mock-tools.ts +143 -0
- package/src/playground.ts +401 -0
- package/src/plugin/index.ts +6 -0
- package/src/plugin/plugin.ts +226 -0
- package/src/services/clipboard-service.ts +40 -0
- package/src/services/context-menu-service.ts +25 -0
- package/src/services/index.ts +10 -0
- package/src/services/logger-service.ts +49 -0
- package/src/services/selection-service.ts +54 -0
- package/src/services/storage-service.ts +65 -0
- package/src/vue/index.ts +8 -0
- package/src/vue/playground-vue-context.ts +22 -0
- package/src/vue/playground-vue-provider.ts +115 -0
- package/src/vue/playground-vue-renderer.vue +44 -0
|
@@ -0,0 +1,613 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
Angle,
|
|
8
|
+
Circle,
|
|
9
|
+
Disposable,
|
|
10
|
+
DisposableCollection,
|
|
11
|
+
Matrix,
|
|
12
|
+
PI_2,
|
|
13
|
+
RAD_TO_DEG,
|
|
14
|
+
Rectangle,
|
|
15
|
+
Schema,
|
|
16
|
+
TransformSchema,
|
|
17
|
+
TransformSchemaDecoration,
|
|
18
|
+
} from '@flowgram-vue/utils';
|
|
19
|
+
|
|
20
|
+
import { Bounds } from '../utils/bounds';
|
|
21
|
+
import { EntityData } from '../entity-data';
|
|
22
|
+
import type { Entity } from '../entity';
|
|
23
|
+
import { SkewData, type SkewSchema } from './skew-schema';
|
|
24
|
+
import { SizeData, type SizeSchema } from './size-schema';
|
|
25
|
+
import { ScaleData, type ScaleSchema } from './scale-schema';
|
|
26
|
+
import { RotationData } from './rotation-schema';
|
|
27
|
+
import { PositionData, type PositionSchema } from './position-schema';
|
|
28
|
+
import { OriginData, type OriginSchema } from './origin-schema';
|
|
29
|
+
|
|
30
|
+
export { TransformSchemaDecoration, TransformSchema };
|
|
31
|
+
|
|
32
|
+
export class TransformData extends EntityData<TransformSchema> implements TransformSchema {
|
|
33
|
+
static type = 'TransformData';
|
|
34
|
+
|
|
35
|
+
protected _worldTransform: Matrix = new Matrix();
|
|
36
|
+
|
|
37
|
+
protected _localTransform: Matrix = new Matrix();
|
|
38
|
+
|
|
39
|
+
protected _children: TransformData[] | undefined;
|
|
40
|
+
|
|
41
|
+
protected mutationCache: Map<string, any> = new Map();
|
|
42
|
+
|
|
43
|
+
public sizeToScale = false; // 标记 size 转成 scale
|
|
44
|
+
|
|
45
|
+
get children(): TransformData[] {
|
|
46
|
+
return this._children || [];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
clearChildren(): void {
|
|
50
|
+
if (this._children) {
|
|
51
|
+
this._children.slice().forEach((child) => {
|
|
52
|
+
child.setParent(undefined);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 容器选择框会动态计算子节点大小
|
|
59
|
+
*/
|
|
60
|
+
get isContainer(): boolean {
|
|
61
|
+
return !!this._children && this._children.length > 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The X-coordinate value of the normalized local X axis,
|
|
66
|
+
* the first column of the local transformation matrix without a scale.
|
|
67
|
+
*/
|
|
68
|
+
protected _cx = 1;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The Y-coordinate value of the normalized local X axis,
|
|
72
|
+
* the first column of the local transformation matrix without a scale.
|
|
73
|
+
*/
|
|
74
|
+
protected _sx = 0;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The X-coordinate value of the normalized local Y axis,
|
|
78
|
+
* the second column of the local transformation matrix without a scale.
|
|
79
|
+
*/
|
|
80
|
+
protected _cy = 0;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The Y-coordinate value of the normalized local Y axis,
|
|
84
|
+
* the second column of the local transformation matrix without a scale.
|
|
85
|
+
*/
|
|
86
|
+
protected _sy = 1;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The locally unique ID of the local transform.
|
|
90
|
+
*/
|
|
91
|
+
protected _localID = 0;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The locally unique ID of the local transform
|
|
95
|
+
* used to calculate the current local transformation matrix.
|
|
96
|
+
*/
|
|
97
|
+
protected _currentLocalID = 0;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The locally unique ID of the world transform.
|
|
101
|
+
*/
|
|
102
|
+
protected _worldID = 0;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The locally unique ID of the parent's world transform
|
|
106
|
+
* used to calculate the current world transformation matrix.
|
|
107
|
+
*/
|
|
108
|
+
protected _parentID = 0;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The parent transform
|
|
112
|
+
*/
|
|
113
|
+
protected _parent?: TransformData;
|
|
114
|
+
|
|
115
|
+
constructor(entity: Entity) {
|
|
116
|
+
super(entity);
|
|
117
|
+
// 默认添加
|
|
118
|
+
this.bindChange(this.entity.addData(PositionData));
|
|
119
|
+
this.bindChange(this.entity.addData(SizeData));
|
|
120
|
+
this.bindChange(this.entity.addData(OriginData));
|
|
121
|
+
this.bindChange(this.entity.addData(ScaleData));
|
|
122
|
+
this.bindChange(this.entity.addData(SkewData), () => this.updateSkew());
|
|
123
|
+
this.bindChange(this.entity.addData(RotationData), () => this.updateSkew());
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
fireChange(): void {
|
|
127
|
+
if (this.changeLocked) return;
|
|
128
|
+
this._localID++;
|
|
129
|
+
this.mutationCache.clear();
|
|
130
|
+
super.fireChange();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
get localTransform(): Matrix {
|
|
134
|
+
this.updateLocalTransformMatrix();
|
|
135
|
+
return this._localTransform;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
get worldTransform(): Matrix {
|
|
139
|
+
this.updateTransformMatrix();
|
|
140
|
+
return this._worldTransform;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
getDefaultData(): TransformSchema {
|
|
144
|
+
return Schema.createDefault<TransformSchema>(TransformSchemaDecoration);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
update(data: Partial<TransformSchema>): void {
|
|
148
|
+
if (data.position) {
|
|
149
|
+
this.entity.updateData(PositionData, data.position);
|
|
150
|
+
}
|
|
151
|
+
if (data.size) {
|
|
152
|
+
this.entity.updateData(SizeData, data.size);
|
|
153
|
+
}
|
|
154
|
+
if (data.origin) {
|
|
155
|
+
this.entity.updateData(OriginData, data.origin);
|
|
156
|
+
}
|
|
157
|
+
if (data.scale) {
|
|
158
|
+
this.entity.updateData(ScaleData, data.scale);
|
|
159
|
+
}
|
|
160
|
+
if (data.skew) {
|
|
161
|
+
this.entity.updateData(SkewData, data.skew);
|
|
162
|
+
}
|
|
163
|
+
if (data.rotation !== undefined) {
|
|
164
|
+
this.entity.updateData(RotationData, data.rotation);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
get position(): PositionSchema {
|
|
169
|
+
return this.entity.getData<PositionData>(PositionData)!;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
set position(position: PositionSchema) {
|
|
173
|
+
this.entity.updateData<PositionData>(PositionData, position);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
get size(): SizeSchema {
|
|
177
|
+
return this.entity.getData<SizeData>(SizeData)!;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
set size(size: SizeSchema) {
|
|
181
|
+
this.entity.updateData<SizeData>(SizeData, size);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
get origin(): OriginSchema {
|
|
185
|
+
return this.entity.getData<OriginData>(OriginData)!;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
set origin(origin: OriginSchema) {
|
|
189
|
+
this.entity.updateData<OriginData>(OriginData, origin);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
get scale(): ScaleSchema {
|
|
193
|
+
return this.entity.getData<ScaleData>(ScaleData)!;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
set scale(scale: ScaleSchema) {
|
|
197
|
+
this.entity.updateData<ScaleData>(ScaleData, scale);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
get skew(): SkewSchema {
|
|
201
|
+
return this.entity.getData<SkewData>(SkewData)!;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
set skew(skew: SkewSchema) {
|
|
205
|
+
this.entity.updateData<SkewData>(SkewData, skew);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
get rotation(): number {
|
|
209
|
+
return this.entity.getData<RotationData>(RotationData)!.data;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
set rotation(rotation: number) {
|
|
213
|
+
this.entity.updateData<RotationData>(RotationData, rotation);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
get data(): TransformSchema {
|
|
217
|
+
return TransformSchema.toJSON(this);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Called when the skew or the rotation changes.
|
|
222
|
+
*
|
|
223
|
+
* @protected
|
|
224
|
+
*/
|
|
225
|
+
protected updateSkew(): void {
|
|
226
|
+
const { rotation } = this;
|
|
227
|
+
this._cx = Math.cos(rotation + this.skew.y);
|
|
228
|
+
this._sx = Math.sin(rotation + this.skew.y);
|
|
229
|
+
this._cy = -Math.sin(rotation - this.skew.x); // cos, added PI/2
|
|
230
|
+
this._sy = Math.cos(rotation - this.skew.x); // sin, added PI/2
|
|
231
|
+
|
|
232
|
+
this._localID++;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Updates the local transformation matrix.
|
|
237
|
+
*/
|
|
238
|
+
protected updateLocalTransformMatrix(): void {
|
|
239
|
+
const lt = this._localTransform;
|
|
240
|
+
|
|
241
|
+
if (this._localID !== this._currentLocalID) {
|
|
242
|
+
// get the matrix values of the displayobject based on its transform properties..
|
|
243
|
+
lt.a = this._cx * this.scale.x;
|
|
244
|
+
lt.b = this._sx * this.scale.x;
|
|
245
|
+
lt.c = this._cy * this.scale.y;
|
|
246
|
+
lt.d = this._sy * this.scale.y;
|
|
247
|
+
|
|
248
|
+
// TODO 删除这个 origin 偏移,不然会有一像素的偏差
|
|
249
|
+
lt.tx = this.position.x; // - (this.origin.x * lt.a + this.origin.y * lt.c)
|
|
250
|
+
lt.ty = this.position.y; // - (this.origin.x * lt.b + this.origin.y * lt.d)
|
|
251
|
+
this._currentLocalID = this._localID;
|
|
252
|
+
|
|
253
|
+
// force an update..
|
|
254
|
+
this._parentID = -1;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
get localID() {
|
|
259
|
+
return this._localID;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
get worldID() {
|
|
263
|
+
return this._worldID;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Updates the local and the world transformation matrices.
|
|
268
|
+
*
|
|
269
|
+
*/
|
|
270
|
+
protected updateTransformMatrix(): void {
|
|
271
|
+
const lt = this._localTransform;
|
|
272
|
+
this.updateLocalTransformMatrix();
|
|
273
|
+
let parentTransform: Matrix = Matrix.TEMP_MATRIX;
|
|
274
|
+
let worldId = 0;
|
|
275
|
+
if (this.parent) {
|
|
276
|
+
parentTransform = this.parent.worldTransform;
|
|
277
|
+
worldId = this.parent._worldID;
|
|
278
|
+
}
|
|
279
|
+
if (this._parentID !== worldId) {
|
|
280
|
+
// concat the parent matrix with the objects transform.
|
|
281
|
+
const pt = parentTransform;
|
|
282
|
+
const wt = this._worldTransform;
|
|
283
|
+
|
|
284
|
+
wt.a = lt.a * pt.a + lt.b * pt.c;
|
|
285
|
+
wt.b = lt.a * pt.b + lt.b * pt.d;
|
|
286
|
+
wt.c = lt.c * pt.a + lt.d * pt.c;
|
|
287
|
+
wt.d = lt.c * pt.b + lt.d * pt.d;
|
|
288
|
+
wt.tx = lt.tx * pt.a + lt.ty * pt.c + pt.tx;
|
|
289
|
+
wt.ty = lt.tx * pt.b + lt.ty * pt.d + pt.ty;
|
|
290
|
+
this._parentID = worldId;
|
|
291
|
+
|
|
292
|
+
// update the id of the transform..
|
|
293
|
+
this._worldID++;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Decomposes a matrix and sets the transforms properties based on it.
|
|
299
|
+
*
|
|
300
|
+
* matrix - The matrix to decompose
|
|
301
|
+
*/
|
|
302
|
+
setFromMatrix(matrix: Matrix): void {
|
|
303
|
+
// sort out rotation / skew..
|
|
304
|
+
const { a, b, c, d } = matrix;
|
|
305
|
+
|
|
306
|
+
const skewX = -Math.atan2(-c, d);
|
|
307
|
+
const skewY = Math.atan2(b, a);
|
|
308
|
+
|
|
309
|
+
const delta = Math.abs(skewX + skewY);
|
|
310
|
+
|
|
311
|
+
if (delta < 0.00001 || Math.abs(PI_2 - delta) < 0.00001) {
|
|
312
|
+
this.rotation = skewY;
|
|
313
|
+
this.skew.x = this.skew.y = 0;
|
|
314
|
+
} else {
|
|
315
|
+
this.rotation = 0;
|
|
316
|
+
this.skew.x = skewX;
|
|
317
|
+
this.skew.y = skewY;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// next set scale
|
|
321
|
+
this.scale.x = Math.sqrt(a * a + b * b);
|
|
322
|
+
this.scale.y = Math.sqrt(c * c + d * d);
|
|
323
|
+
|
|
324
|
+
// next set position
|
|
325
|
+
this.position.x = matrix.tx;
|
|
326
|
+
this.position.y = matrix.ty;
|
|
327
|
+
this.fireChange();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* 缓存计算, 缓存只能针对 local, world 加缓存会出问题
|
|
332
|
+
*/
|
|
333
|
+
getMutationCache<T>(key: string, fn: () => T): T {
|
|
334
|
+
// 缓存设计有问题,先去掉
|
|
335
|
+
if (this.mutationCache.has(key)) return this.mutationCache.get(key) as T;
|
|
336
|
+
const item = fn();
|
|
337
|
+
this.mutationCache.set(key, item);
|
|
338
|
+
return item;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
get bounds(): Rectangle {
|
|
342
|
+
if (this.isContainer) {
|
|
343
|
+
const children = this._children!;
|
|
344
|
+
return Rectangle.enlarge(children.map((c) => c.bounds));
|
|
345
|
+
}
|
|
346
|
+
return Bounds.getBounds(this, this.worldTransform);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* 不旋转的 bounds
|
|
351
|
+
*/
|
|
352
|
+
get boundsWithoutRotation(): Rectangle {
|
|
353
|
+
const { center } = this.bounds;
|
|
354
|
+
const { worldScale } = this;
|
|
355
|
+
// TODO 目前 container 计算有误差,需要解决
|
|
356
|
+
const size = this.localSize;
|
|
357
|
+
const width = worldScale.x * size.width;
|
|
358
|
+
const height = worldScale.y * size.height;
|
|
359
|
+
const leftTop = {
|
|
360
|
+
x: center.x - width / 2,
|
|
361
|
+
y: center.y - height / 2,
|
|
362
|
+
};
|
|
363
|
+
return new Rectangle(leftTop.x, leftTop.y, width, height);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* 本身的大小
|
|
368
|
+
*/
|
|
369
|
+
get localSize(): SizeSchema {
|
|
370
|
+
let { size } = this;
|
|
371
|
+
if (this.isContainer) {
|
|
372
|
+
const childrenBounds = Rectangle.enlarge(this.children.map((c) => c.localBounds));
|
|
373
|
+
size = {
|
|
374
|
+
width: childrenBounds.width,
|
|
375
|
+
height: childrenBounds.height,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
width: size.width,
|
|
380
|
+
height: size.height,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
get worldSize(): SizeSchema {
|
|
385
|
+
const { localSize } = this;
|
|
386
|
+
const { worldScale } = this;
|
|
387
|
+
return {
|
|
388
|
+
width: localSize.width * worldScale.x,
|
|
389
|
+
height: localSize.height * worldScale.y,
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* 本地 bounds
|
|
395
|
+
*/
|
|
396
|
+
get localBounds(): Rectangle {
|
|
397
|
+
if (this.isContainer) {
|
|
398
|
+
const children = this._children!;
|
|
399
|
+
const childrenBounds = Rectangle.enlarge(children.map((c) => c.localBounds));
|
|
400
|
+
// 投射 local
|
|
401
|
+
return Bounds.applyMatrix(childrenBounds, this.localTransform);
|
|
402
|
+
}
|
|
403
|
+
return this.getMutationCache<Rectangle>('localBounds', () =>
|
|
404
|
+
Bounds.getBounds(this, this.localTransform)
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* 判断是否包含点
|
|
410
|
+
* @param x
|
|
411
|
+
* @param y
|
|
412
|
+
* @param asCircle - 以圆形来算,TODO 目前不支持椭圆形
|
|
413
|
+
*/
|
|
414
|
+
contains(x: number, y: number, asCircle?: boolean): boolean {
|
|
415
|
+
// Container 情况不支持 circle
|
|
416
|
+
if (this.isContainer) {
|
|
417
|
+
return this.bounds.contains(x, y);
|
|
418
|
+
}
|
|
419
|
+
const tempPoint = this.worldTransform.applyInverse({ x, y });
|
|
420
|
+
const { width, height } = this.size;
|
|
421
|
+
// 不包含空大小 TODO
|
|
422
|
+
if (width === 0 || height === 0) return false;
|
|
423
|
+
const x1 = -width * this.origin.x;
|
|
424
|
+
const y1 = -height * this.origin.y;
|
|
425
|
+
if (asCircle) {
|
|
426
|
+
const circle = new Circle(x1 + width / 2, y1 + height / 2, Math.min(width / 2, height / 2));
|
|
427
|
+
return circle.contains(tempPoint.x, tempPoint.y);
|
|
428
|
+
}
|
|
429
|
+
if (tempPoint.x >= x1 && tempPoint.x < x1 + width) {
|
|
430
|
+
if (tempPoint.y >= y1 && tempPoint.y < y1 + height) {
|
|
431
|
+
return true;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return false;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
get parent(): TransformData | undefined {
|
|
438
|
+
return this._parent;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
isParent(parent: TransformData): boolean {
|
|
442
|
+
let currentParent = this.parent;
|
|
443
|
+
while (currentParent) {
|
|
444
|
+
if (currentParent === parent) return true;
|
|
445
|
+
currentParent = currentParent.parent;
|
|
446
|
+
}
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
isParentTransform(parent?: TransformData): boolean {
|
|
451
|
+
let currentParent = this.parent;
|
|
452
|
+
while (currentParent) {
|
|
453
|
+
if (currentParent === parent) return true;
|
|
454
|
+
currentParent = currentParent.parent;
|
|
455
|
+
}
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
private _parentChangedDispose?: DisposableCollection;
|
|
460
|
+
|
|
461
|
+
private entityDispose?: Disposable;
|
|
462
|
+
|
|
463
|
+
setParent(parent: TransformData | undefined, listenParentData = true): void {
|
|
464
|
+
if (this._parent !== parent) {
|
|
465
|
+
if (this.entityDispose) {
|
|
466
|
+
this.entityDispose.dispose();
|
|
467
|
+
this.entityDispose = undefined;
|
|
468
|
+
}
|
|
469
|
+
if (this._parentChangedDispose) {
|
|
470
|
+
this._parentChangedDispose.dispose();
|
|
471
|
+
this._parentChangedDispose = undefined;
|
|
472
|
+
}
|
|
473
|
+
this._parentID = -1;
|
|
474
|
+
if (parent && listenParentData) {
|
|
475
|
+
if (!parent._children) parent._children = [];
|
|
476
|
+
parent._children.push(this);
|
|
477
|
+
this._parentChangedDispose = new DisposableCollection();
|
|
478
|
+
this.toDispose.push(this._parentChangedDispose);
|
|
479
|
+
this.entityDispose = this.entity.onDispose(() => {
|
|
480
|
+
parent.fireChange();
|
|
481
|
+
});
|
|
482
|
+
this._parentChangedDispose.pushAll([
|
|
483
|
+
parent.onDispose(() => {
|
|
484
|
+
this.setParent(undefined);
|
|
485
|
+
}),
|
|
486
|
+
Disposable.create(() => {
|
|
487
|
+
const index = parent._children!.indexOf(this);
|
|
488
|
+
if (index !== -1) {
|
|
489
|
+
parent._children!.splice(index, 1);
|
|
490
|
+
}
|
|
491
|
+
}),
|
|
492
|
+
]);
|
|
493
|
+
}
|
|
494
|
+
this._parent = parent;
|
|
495
|
+
this.fireChange();
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* 判断矩形碰撞
|
|
501
|
+
*/
|
|
502
|
+
intersects(rect: Rectangle): boolean {
|
|
503
|
+
if (!this.isContainer && (this.size.width === 0 || this.size.height === 0)) return false;
|
|
504
|
+
return Rectangle.intersectsWithRotation(
|
|
505
|
+
this.boundsWithoutRotation,
|
|
506
|
+
this.worldRotation,
|
|
507
|
+
rect,
|
|
508
|
+
0
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* 全局的 scale
|
|
514
|
+
*/
|
|
515
|
+
get worldScale(): ScaleSchema {
|
|
516
|
+
const { parent } = this;
|
|
517
|
+
const parentScale = parent ? parent.worldScale : { x: 1, y: 1 };
|
|
518
|
+
return {
|
|
519
|
+
x: this.scale.x * parentScale.x,
|
|
520
|
+
y: this.scale.y * parentScale.y,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* 全局的 rotation
|
|
526
|
+
*/
|
|
527
|
+
get worldRotation(): number {
|
|
528
|
+
const { parent } = this;
|
|
529
|
+
if (parent) {
|
|
530
|
+
return Angle.wrap(this.rotation + parent.worldRotation);
|
|
531
|
+
}
|
|
532
|
+
return Angle.wrap(this.rotation);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* 全局的角度
|
|
537
|
+
*/
|
|
538
|
+
get worldDegree(): number {
|
|
539
|
+
return Math.round(this.worldRotation * RAD_TO_DEG);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
get localOrigin(): PositionSchema {
|
|
543
|
+
const matrix = this.localTransform;
|
|
544
|
+
const bounds = this.localBounds;
|
|
545
|
+
return matrix.apply({
|
|
546
|
+
x: this.origin.x * bounds.width,
|
|
547
|
+
y: this.origin.y * bounds.height,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* 全局的原点位置
|
|
553
|
+
*/
|
|
554
|
+
get worldOrigin(): PositionSchema {
|
|
555
|
+
const matrix = this.worldTransform;
|
|
556
|
+
const { bounds } = this;
|
|
557
|
+
return matrix.apply({
|
|
558
|
+
x: this.origin.x * bounds.width,
|
|
559
|
+
y: this.origin.y * bounds.height,
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* 宽转换成 scale,用于图片等无法修改大小的场景
|
|
565
|
+
* @param isWorldSize 是否为绝对大小
|
|
566
|
+
*/
|
|
567
|
+
widthToScaleX(width: number, isWorldSize?: boolean): number {
|
|
568
|
+
const parentScaleX = isWorldSize && this.parent ? this.parent.worldScale.x : 1;
|
|
569
|
+
return width / parentScaleX / this.localSize.width;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* 绝对高转换成 scale,用于图片等无法修改大小的场景
|
|
574
|
+
* @param isWorldSize 是否为绝对大小
|
|
575
|
+
*/
|
|
576
|
+
heightToScaleY(height: number, isWorldSize?: boolean): number {
|
|
577
|
+
const parentScaleY = isWorldSize && this.parent ? this.parent.worldScale.y : 1;
|
|
578
|
+
return height / parentScaleY / this.localSize.height;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
sizeToScaleValue(
|
|
582
|
+
size: { width: number; height: number },
|
|
583
|
+
isWorldSize?: boolean
|
|
584
|
+
): { x: number; y: number } {
|
|
585
|
+
return {
|
|
586
|
+
x: this.widthToScaleX(size.width, isWorldSize),
|
|
587
|
+
y: this.heightToScaleY(size.height, isWorldSize),
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
export namespace TransformData {
|
|
593
|
+
/**
|
|
594
|
+
* @param dragableEntities
|
|
595
|
+
* @param target
|
|
596
|
+
*/
|
|
597
|
+
export function isParentOrChildrenTransform(dragableEntities: Entity[], target: Entity): boolean {
|
|
598
|
+
const targetTransform = target.getData<TransformData>(TransformData);
|
|
599
|
+
if (!targetTransform) return false;
|
|
600
|
+
for (const dragger of dragableEntities.values()) {
|
|
601
|
+
const draggerTransform = dragger.getData<TransformData>(TransformData);
|
|
602
|
+
// eslint-disable-next-line no-continue
|
|
603
|
+
if (!draggerTransform) continue;
|
|
604
|
+
if (
|
|
605
|
+
draggerTransform.isParent(targetTransform) ||
|
|
606
|
+
targetTransform.isParent(draggerTransform)
|
|
607
|
+
) {
|
|
608
|
+
return true;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
}
|