@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.
Files changed (133) hide show
  1. package/LICENSE +22 -0
  2. package/dist/index.cjs +0 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +0 -0
  6. package/dist/index.js.map +1 -0
  7. package/package.json +63 -0
  8. package/src/common/config-entity.ts +80 -0
  9. package/src/common/entity-data.ts +171 -0
  10. package/src/common/entity-manager-contribution.ts +12 -0
  11. package/src/common/entity-manager.ts +475 -0
  12. package/src/common/entity.ts +482 -0
  13. package/src/common/index.ts +22 -0
  14. package/src/common/playground-context.ts +35 -0
  15. package/src/common/playground-decorator-helper.ts +113 -0
  16. package/src/common/playground-decorators.ts +85 -0
  17. package/src/common/playground-schedule.ts +30 -0
  18. package/src/common/protect-wheel-area.ts +11 -0
  19. package/src/common/schema/index.ts +14 -0
  20. package/src/common/schema/node.ts +15 -0
  21. package/src/common/schema/opacity-schema.ts +19 -0
  22. package/src/common/schema/origin-schema.ts +35 -0
  23. package/src/common/schema/position-schema.ts +35 -0
  24. package/src/common/schema/rotation-schema.ts +19 -0
  25. package/src/common/schema/scale-schema.ts +35 -0
  26. package/src/common/schema/size-schema.ts +42 -0
  27. package/src/common/schema/skew-schema.ts +35 -0
  28. package/src/common/schema/transform-schema.ts +613 -0
  29. package/src/common/utils/bounds.spec.ts +229 -0
  30. package/src/common/utils/bounds.ts +176 -0
  31. package/src/common/utils/index.ts +6 -0
  32. package/src/composables/index.ts +16 -0
  33. package/src/composables/use-config-entity.ts +31 -0
  34. package/src/composables/use-entities.ts +26 -0
  35. package/src/composables/use-entity-data-from-context.ts +34 -0
  36. package/src/composables/use-entity-from-context.ts +31 -0
  37. package/src/composables/use-listen-events.ts +22 -0
  38. package/src/composables/use-playground-container.ts +16 -0
  39. package/src/composables/use-playground-context.ts +15 -0
  40. package/src/composables/use-playground-drag.ts +31 -0
  41. package/src/composables/use-playground.ts +16 -0
  42. package/src/composables/use-refresh.ts +6 -0
  43. package/src/composables/use-service.ts +17 -0
  44. package/src/core/index.ts +8 -0
  45. package/src/core/layer/config/editor-state-config-entity.ts +180 -0
  46. package/src/core/layer/config/index.ts +7 -0
  47. package/src/core/layer/config/playground-config-entity.ts +604 -0
  48. package/src/core/layer/index.ts +8 -0
  49. package/src/core/layer/layer.ts +248 -0
  50. package/src/core/layer/playground-layer.ts +547 -0
  51. package/src/core/pipeline/index.ts +10 -0
  52. package/src/core/pipeline/pipeline-entities-selector.ts +200 -0
  53. package/src/core/pipeline/pipeline-entities.ts +230 -0
  54. package/src/core/pipeline/pipeline-registry.ts +344 -0
  55. package/src/core/pipeline/pipeline-renderer.ts +248 -0
  56. package/src/core/pipeline/pipeline-vue-utils.ts +96 -0
  57. package/src/core/pipeline/pipeline.ts +28 -0
  58. package/src/core/utils/index.ts +12 -0
  59. package/src/core/utils/inject-provider-decorators.ts +27 -0
  60. package/src/core/utils/lazy-inject-decorators.ts +38 -0
  61. package/src/core/utils/mouse-touch-event.ts +120 -0
  62. package/src/core/utils/playground-drag.ts +511 -0
  63. package/src/core/utils/playground-gesture.spec.ts +135 -0
  64. package/src/core/utils/playground-gesture.ts +118 -0
  65. package/src/core/utils/tween.ts +156 -0
  66. package/src/core/utils/use-gesture/core/Controller.ts +212 -0
  67. package/src/core/utils/use-gesture/core/EventStore.ts +46 -0
  68. package/src/core/utils/use-gesture/core/TimeoutStore.ts +28 -0
  69. package/src/core/utils/use-gesture/core/actions.ts +63 -0
  70. package/src/core/utils/use-gesture/core/config/commonConfigResolver.ts +86 -0
  71. package/src/core/utils/use-gesture/core/config/coordinatesConfigResolver.ts +48 -0
  72. package/src/core/utils/use-gesture/core/config/dragConfigResolver.ts +140 -0
  73. package/src/core/utils/use-gesture/core/config/hoverConfigResolver.ts +11 -0
  74. package/src/core/utils/use-gesture/core/config/moveConfigResolver.ts +11 -0
  75. package/src/core/utils/use-gesture/core/config/pinchConfigResolver.ts +59 -0
  76. package/src/core/utils/use-gesture/core/config/resolver.ts +70 -0
  77. package/src/core/utils/use-gesture/core/config/scrollConfigResolver.ts +8 -0
  78. package/src/core/utils/use-gesture/core/config/sharedConfigResolver.ts +28 -0
  79. package/src/core/utils/use-gesture/core/config/support.ts +52 -0
  80. package/src/core/utils/use-gesture/core/config/wheelConfigResolver.ts +8 -0
  81. package/src/core/utils/use-gesture/core/engines/CoordinatesEngine.ts +78 -0
  82. package/src/core/utils/use-gesture/core/engines/DragEngine.ts +403 -0
  83. package/src/core/utils/use-gesture/core/engines/Engine.ts +406 -0
  84. package/src/core/utils/use-gesture/core/engines/HoverEngine.ts +43 -0
  85. package/src/core/utils/use-gesture/core/engines/MoveEngine.ts +52 -0
  86. package/src/core/utils/use-gesture/core/engines/PinchEngine.ts +345 -0
  87. package/src/core/utils/use-gesture/core/engines/ScrollEngine.ts +42 -0
  88. package/src/core/utils/use-gesture/core/engines/WheelEngine.ts +48 -0
  89. package/src/core/utils/use-gesture/core/index.ts +7 -0
  90. package/src/core/utils/use-gesture/core/parser.ts +92 -0
  91. package/src/core/utils/use-gesture/core/types/action.ts +19 -0
  92. package/src/core/utils/use-gesture/core/types/config.ts +255 -0
  93. package/src/core/utils/use-gesture/core/types/handlers.ts +73 -0
  94. package/src/core/utils/use-gesture/core/types/index.ts +11 -0
  95. package/src/core/utils/use-gesture/core/types/internalConfig.ts +80 -0
  96. package/src/core/utils/use-gesture/core/types/state.ts +275 -0
  97. package/src/core/utils/use-gesture/core/types/utils.ts +204 -0
  98. package/src/core/utils/use-gesture/core/types.ts +8 -0
  99. package/src/core/utils/use-gesture/core/utils/events.ts +158 -0
  100. package/src/core/utils/use-gesture/core/utils/fn.ts +32 -0
  101. package/src/core/utils/use-gesture/core/utils/maths.ts +63 -0
  102. package/src/core/utils/use-gesture/core/utils/state.ts +24 -0
  103. package/src/core/utils/use-gesture/core/utils.ts +8 -0
  104. package/src/core/utils/use-gesture/index.ts +6 -0
  105. package/src/core/utils/use-gesture/vanilla/DragGesture.ts +27 -0
  106. package/src/core/utils/use-gesture/vanilla/Gesture.ts +45 -0
  107. package/src/core/utils/use-gesture/vanilla/HoverGesture.ts +27 -0
  108. package/src/core/utils/use-gesture/vanilla/MoveGesture.ts +27 -0
  109. package/src/core/utils/use-gesture/vanilla/PinchGesture.ts +27 -0
  110. package/src/core/utils/use-gesture/vanilla/Recognizer.ts +43 -0
  111. package/src/core/utils/use-gesture/vanilla/ScrollGesture.ts +27 -0
  112. package/src/core/utils/use-gesture/vanilla/WheelGesture.ts +27 -0
  113. package/src/core/utils/use-gesture/vanilla/createGesture.ts +18 -0
  114. package/src/core/utils/use-gesture/vanilla/index.ts +18 -0
  115. package/src/env.d.ts +10 -0
  116. package/src/index.ts +17 -0
  117. package/src/playground-config.ts +70 -0
  118. package/src/playground-container.ts +129 -0
  119. package/src/playground-contribution.ts +81 -0
  120. package/src/playground-mock-tools.ts +143 -0
  121. package/src/playground.ts +401 -0
  122. package/src/plugin/index.ts +6 -0
  123. package/src/plugin/plugin.ts +226 -0
  124. package/src/services/clipboard-service.ts +40 -0
  125. package/src/services/context-menu-service.ts +25 -0
  126. package/src/services/index.ts +10 -0
  127. package/src/services/logger-service.ts +49 -0
  128. package/src/services/selection-service.ts +54 -0
  129. package/src/services/storage-service.ts +65 -0
  130. package/src/vue/index.ts +8 -0
  131. package/src/vue/playground-vue-context.ts +22 -0
  132. package/src/vue/playground-vue-provider.ts +115 -0
  133. package/src/vue/playground-vue-renderer.vue +44 -0
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ // nolint: cyclo_complexity,method_line
7
+ import { expect, describe, beforeEach, it } from 'vitest';
8
+ import { Container } from 'inversify';
9
+ import { Matrix, Rectangle } from '@flowgram-vue/utils';
10
+
11
+ import { Entity, EntityManager, PlaygroundContext, TransformData } from '..';
12
+ import { Bounds } from './bounds';
13
+
14
+ function createContainer(): Container {
15
+ const child = new Container({ defaultScope: 'Singleton' });
16
+ // child.bind(AbleManager).toSelf();
17
+ child.bind(PlaygroundContext).toConstantValue({});
18
+ child.bind(EntityManager).toSelf();
19
+ return child;
20
+ }
21
+
22
+ const container = createContainer();
23
+
24
+ function createEntity(): Entity {
25
+ return container.get<EntityManager>(EntityManager).createEntity<Entity>(Entity);
26
+ }
27
+
28
+ function expectRectangle(target: Rectangle, arr: number[]): void {
29
+ expect(target.x).toBeCloseTo(arr[0]);
30
+ expect(target.y).toBeCloseTo(arr[1]);
31
+ expect(target.width).toBeCloseTo(arr[2]);
32
+ expect(target.height).toBeCloseTo(arr[3]);
33
+ }
34
+
35
+ describe('bounds', () => {
36
+ let target: TransformData;
37
+ beforeEach(() => {
38
+ target = new TransformData(createEntity());
39
+ target.size.width = 100;
40
+ target.size.height = 100;
41
+ });
42
+
43
+ it('get points and bounds', () => {
44
+ target.origin.x = 0;
45
+ target.origin.y = 0;
46
+ expect(Bounds.getCenter(target, target.worldTransform)).toEqual({
47
+ x: 50,
48
+ y: 50,
49
+ });
50
+ expect(Bounds.getTopLeft(target, target.worldTransform)).toEqual({
51
+ x: 0,
52
+ y: 0,
53
+ });
54
+ expect(Bounds.getTopCenter(target, target.worldTransform)).toEqual({
55
+ x: 50,
56
+ y: 0,
57
+ });
58
+ expect(Bounds.getTopRight(target, target.worldTransform)).toEqual({
59
+ x: 100,
60
+ y: 0,
61
+ });
62
+ expect(Bounds.getLeftCenter(target, target.worldTransform)).toEqual({
63
+ x: 0,
64
+ y: 50,
65
+ });
66
+ expect(Bounds.getRightCenter(target, target.worldTransform)).toEqual({
67
+ x: 100,
68
+ y: 50,
69
+ });
70
+ expect(Bounds.getBottomLeft(target, target.worldTransform)).toEqual({
71
+ x: 0,
72
+ y: 100,
73
+ });
74
+ expect(Bounds.getBottomCenter(target, target.worldTransform)).toEqual({
75
+ x: 50,
76
+ y: 100,
77
+ });
78
+ expect(Bounds.getBottomRight(target, target.worldTransform)).toEqual({
79
+ x: 100,
80
+ y: 100,
81
+ });
82
+ expect(Bounds.getBounds(target, target.worldTransform)).toEqual(new Rectangle(0, 0, 100, 100));
83
+
84
+ target.origin.x = 0.5;
85
+ target.origin.y = 0.5;
86
+ expect(Bounds.getCenter(target, target.worldTransform)).toEqual({
87
+ x: 0,
88
+ y: 0,
89
+ });
90
+ expect(Bounds.getTopLeft(target, target.worldTransform)).toEqual({
91
+ x: -50,
92
+ y: -50,
93
+ });
94
+ expect(Bounds.getTopCenter(target, target.worldTransform)).toEqual({
95
+ x: 0,
96
+ y: -50,
97
+ });
98
+ expect(Bounds.getTopRight(target, target.worldTransform)).toEqual({
99
+ x: 50,
100
+ y: -50,
101
+ });
102
+ expect(Bounds.getLeftCenter(target, target.worldTransform)).toEqual({
103
+ x: -50,
104
+ y: 0,
105
+ });
106
+ expect(Bounds.getRightCenter(target, target.worldTransform)).toEqual({
107
+ x: 50,
108
+ y: 0,
109
+ });
110
+ expect(Bounds.getBottomLeft(target, target.worldTransform)).toEqual({
111
+ x: -50,
112
+ y: 50,
113
+ });
114
+ expect(Bounds.getBottomCenter(target, target.worldTransform)).toEqual({
115
+ x: 0,
116
+ y: 50,
117
+ });
118
+ expect(Bounds.getBottomRight(target, target.worldTransform)).toEqual({
119
+ x: 50,
120
+ y: 50,
121
+ });
122
+ expect(Bounds.getBounds(target, target.worldTransform)).toEqual(
123
+ new Rectangle(-50, -50, 100, 100),
124
+ );
125
+ });
126
+
127
+ it('transform position', () => {
128
+ target.position.x = 10;
129
+ target.position.y = 10;
130
+ expect(Bounds.getTopLeft(target)).toEqual({ x: -50, y: -50 });
131
+ expect(Bounds.getTopLeft(target, target.localTransform)).toEqual({
132
+ x: -40,
133
+ y: -40,
134
+ });
135
+ expect(Bounds.getTopLeft(target, target.worldTransform)).toEqual({
136
+ x: -40,
137
+ y: -40,
138
+ });
139
+ });
140
+
141
+ it('transform position with parent', () => {
142
+ const parent = new TransformData(createEntity());
143
+ parent.position.x = 10;
144
+ parent.position.y = 10;
145
+ target.setParent(parent);
146
+ expect(Bounds.getTopLeft(target)).toEqual({
147
+ x: -50,
148
+ y: -50,
149
+ });
150
+ expect(Bounds.getTopLeft(target, target.localTransform)).toEqual({
151
+ x: -50,
152
+ y: -50,
153
+ });
154
+ expect(Bounds.getTopLeft(target, target.worldTransform)).toEqual({
155
+ x: -40,
156
+ y: -40,
157
+ });
158
+ expect(Bounds.getLeftPointFromBounds(target, target.worldTransform)).toEqual({
159
+ x: -40,
160
+ y: -40,
161
+ });
162
+ expect(Bounds.getTopPointFromBounds(target, target.worldTransform)).toEqual({
163
+ x: -40,
164
+ y: -40,
165
+ });
166
+ expect(Bounds.getLeftPointFromBounds(parent, parent.worldTransform)).toEqual({
167
+ x: 10,
168
+ y: 10,
169
+ });
170
+ expect(Bounds.getTopPointFromBounds(parent, parent.worldTransform)).toEqual({
171
+ x: 10,
172
+ y: 10,
173
+ });
174
+
175
+ target.position.x = 10;
176
+ target.position.y = 10;
177
+ expect(Bounds.getTopLeft(target)).toEqual({
178
+ x: -50,
179
+ y: -50,
180
+ });
181
+ expect(Bounds.getTopLeft(target, target.localTransform)).toEqual({
182
+ x: -40,
183
+ y: -40,
184
+ });
185
+ expect(Bounds.getTopLeft(target, target.worldTransform)).toEqual({
186
+ x: -30,
187
+ y: -30,
188
+ });
189
+ });
190
+
191
+ it('transform rotation', () => {
192
+ // 中心点旋转 45 度
193
+ target.rotation = Math.PI / 4;
194
+ expectRectangle(
195
+ Bounds.getBounds(target, target.worldTransform),
196
+ [-70.71, -70.71, 141.42, 141.42],
197
+ );
198
+ });
199
+
200
+ it('trasnform scale', () => {
201
+ target.scale.x = 2;
202
+ const bounds = Bounds.getBounds(target, target.worldTransform);
203
+ expect(bounds.width).toEqual(200);
204
+ expect(bounds.height).toEqual(100);
205
+ });
206
+
207
+ it('applyMatrix - without rotation', () => {
208
+ target.position.x = 50;
209
+ target.position.y = 50;
210
+ expect(target.worldTransform).toEqual(new Matrix(1, 0, 0, 1, 50, 50));
211
+ expectRectangle(Bounds.getBounds(target, target.worldTransform), [0, 0, 100, 100]);
212
+ expectRectangle(
213
+ Bounds.applyMatrix(new Rectangle(-50, -50, 100, 100), target.worldTransform),
214
+ [0, 0, 100, 100],
215
+ );
216
+ });
217
+
218
+ it('applyMatrix - with rotation', () => {
219
+ target.position.x = 50;
220
+ target.position.y = 50;
221
+ target.scale.x = 4;
222
+ expect(target.worldTransform).toEqual(new Matrix(4, 0, 0, 1, 50, 50));
223
+ expectRectangle(Bounds.getBounds(target, target.worldTransform), [-150, 0, 400, 100]);
224
+ expectRectangle(
225
+ Bounds.applyMatrix(new Rectangle(-50, -50, 100, 100), target.worldTransform),
226
+ [-150, 0, 400, 100],
227
+ );
228
+ });
229
+ });
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { type Matrix, Point, Rectangle } from '@flowgram-vue/utils';
7
+
8
+ import type { PositionSchema, TransformSchema } from '../schema';
9
+
10
+ type TransformOriginAndSize = Pick<TransformSchema, 'origin'> & Pick<TransformSchema, 'size'>;
11
+
12
+ const { fixZero } = Point;
13
+
14
+ export namespace Bounds {
15
+ /**
16
+ * 位置做矩阵偏移
17
+ */
18
+ export function getPointWithMatrix(output: PositionSchema, matrix?: Matrix): PositionSchema {
19
+ // if (target.rotation !== 0) {
20
+ // rotateAround(output, target.position.x, target.position.y, target.rotation);
21
+ // }
22
+ if (matrix) {
23
+ matrix.apply(output, output);
24
+ }
25
+ // fix: -0
26
+ fixZero(output);
27
+ return output;
28
+ }
29
+ /**
30
+ * 获取外围边界矩形
31
+ */
32
+ export function getBounds(target: TransformOriginAndSize, matrix?: Matrix): Rectangle {
33
+ const output = new Rectangle();
34
+ if (!matrix || matrix.isSimple()) {
35
+ const { size, origin } = target;
36
+ output.x = -(size.width * origin.x) + (matrix?.tx || 0);
37
+ output.y = -(size.height * origin.y) + (matrix?.ty || 0);
38
+ output.width = size.width;
39
+ output.height = size.height;
40
+ // fix: -0
41
+ fixZero(output);
42
+ } else {
43
+ const topLeft = getTopLeft(target, matrix);
44
+ const topRight = getTopRight(target, matrix);
45
+ const bottomLeft = getBottomLeft(target, matrix);
46
+ const bottomRight = getBottomRight(target, matrix);
47
+ output.x = Math.min(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x);
48
+ output.y = Math.min(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y);
49
+ output.width = Math.max(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x) - output.x;
50
+ output.height = Math.max(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y) - output.y;
51
+ }
52
+ return output;
53
+ }
54
+ export function applyMatrix(bounds: Rectangle, matrix: Matrix): Rectangle {
55
+ const output = new Rectangle();
56
+ if (matrix.isSimple()) {
57
+ output.x = bounds.x + matrix.tx;
58
+ output.y = bounds.y + matrix.ty;
59
+ output.width = bounds.width;
60
+ output.height = bounds.height;
61
+ // fix: -0
62
+ fixZero(output);
63
+ } else {
64
+ const topLeft = getPointWithMatrix(bounds.leftTop, matrix);
65
+ const topRight = getPointWithMatrix(bounds.rightTop, matrix);
66
+ const bottomLeft = getPointWithMatrix(bounds.leftBottom, matrix);
67
+ const bottomRight = getPointWithMatrix(bounds.rightBottom, matrix);
68
+ output.x = Math.min(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x);
69
+ output.y = Math.min(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y);
70
+ output.width = Math.max(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x) - output.x;
71
+ output.height = Math.max(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y) - output.y;
72
+ }
73
+ return output;
74
+ }
75
+
76
+ /**
77
+ * 找到边框中最左边的点
78
+ */
79
+ export function getLeftPointFromBounds(
80
+ target: TransformOriginAndSize,
81
+ matrix?: Matrix,
82
+ ): PositionSchema {
83
+ const topLeft = getTopLeft(target, matrix);
84
+ const topRight = getTopRight(target, matrix);
85
+ const bottomLeft = getBottomLeft(target, matrix);
86
+ const bottomRight = getBottomRight(target, matrix);
87
+ const items = [topLeft, topRight, bottomLeft, bottomRight].sort((p1, p2) => p1.x - p2.x);
88
+ return items[0];
89
+ }
90
+ /**
91
+ * 找到边框中最上边的点
92
+ */
93
+ export function getTopPointFromBounds(
94
+ target: TransformOriginAndSize,
95
+ matrix?: Matrix,
96
+ ): PositionSchema {
97
+ const topLeft = getTopLeft(target, matrix);
98
+ const topRight = getTopRight(target, matrix);
99
+ const bottomLeft = getBottomLeft(target, matrix);
100
+ const bottomRight = getBottomRight(target, matrix);
101
+ const items = [topLeft, topRight, bottomLeft, bottomRight].sort((p1, p2) => p1.y - p2.y);
102
+ return items[0];
103
+ }
104
+ export function getCenter(target: TransformSchema, matrix?: Matrix): PositionSchema {
105
+ const { size, origin } = target;
106
+ const output = {
107
+ x: -(size.width * origin.x) + size.width / 2,
108
+ y: -(size.height * origin.y) + size.height / 2,
109
+ };
110
+ return getPointWithMatrix(output, matrix);
111
+ }
112
+ export function getTopLeft(target: TransformOriginAndSize, matrix?: Matrix): PositionSchema {
113
+ const { size, origin } = target;
114
+ const output = {
115
+ x: -(size.width * origin.x),
116
+ y: -(size.height * origin.y),
117
+ };
118
+ return getPointWithMatrix(output, matrix);
119
+ }
120
+ export function getTopCenter(target: TransformOriginAndSize, matrix?: Matrix): PositionSchema {
121
+ const { size, origin } = target;
122
+ const output = {
123
+ x: -(size.width * origin.x) + size.width / 2,
124
+ y: -(size.height * origin.y),
125
+ };
126
+ return getPointWithMatrix(output, matrix);
127
+ }
128
+ export function getTopRight(target: TransformOriginAndSize, matrix?: Matrix): PositionSchema {
129
+ const { size, origin } = target;
130
+ const output = {
131
+ x: -(size.width * origin.x) + size.width,
132
+ y: -(size.height * origin.y),
133
+ };
134
+ return getPointWithMatrix(output, matrix);
135
+ }
136
+ export function getLeftCenter(target: TransformOriginAndSize, matrix?: Matrix): PositionSchema {
137
+ const { size, origin } = target;
138
+ const output = {
139
+ x: -(size.width * origin.x),
140
+ y: -(size.height * origin.y) + size.height / 2,
141
+ };
142
+ return getPointWithMatrix(output, matrix);
143
+ }
144
+ export function getRightCenter(target: TransformOriginAndSize, matrix?: Matrix): PositionSchema {
145
+ const { size, origin } = target;
146
+ const output = {
147
+ x: -(size.width * origin.x) + size.width,
148
+ y: -(size.height * origin.y) + size.height / 2,
149
+ };
150
+ return getPointWithMatrix(output, matrix);
151
+ }
152
+ export function getBottomLeft(target: TransformOriginAndSize, matrix?: Matrix): PositionSchema {
153
+ const { size, origin } = target;
154
+ const output = {
155
+ x: -(size.width * origin.x),
156
+ y: -(size.height * origin.y) + size.height,
157
+ };
158
+ return getPointWithMatrix(output, matrix);
159
+ }
160
+ export function getBottomCenter(target: TransformOriginAndSize, matrix?: Matrix): PositionSchema {
161
+ const { size, origin } = target;
162
+ const output = {
163
+ x: -(size.width * origin.x) + size.width / 2,
164
+ y: -(size.height * origin.y) + size.height,
165
+ };
166
+ return getPointWithMatrix(output, matrix);
167
+ }
168
+ export function getBottomRight(target: TransformOriginAndSize, matrix?: Matrix): PositionSchema {
169
+ const { size, origin } = target;
170
+ const output = {
171
+ x: -(size.width * origin.x) + size.width,
172
+ y: -(size.height * origin.y) + size.height,
173
+ };
174
+ return getPointWithMatrix(output, matrix);
175
+ }
176
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export * from './bounds';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export * from './use-entities';
7
+ export * from './use-entity-data-from-context';
8
+ export * from './use-entity-from-context';
9
+ export * from './use-listen-events';
10
+ export * from './use-playground';
11
+ export * from './use-playground-container';
12
+ export * from './use-playground-context';
13
+ export * from './use-service';
14
+ export * from './use-refresh';
15
+ export * from './use-config-entity';
16
+ export * from './use-playground-drag';
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { onBeforeUnmount } from 'vue';
7
+
8
+ import { Disposable } from '@flowgram-vue/utils';
9
+
10
+ import { ConfigEntity, EntityManager, EntityRegistry } from '../common';
11
+ import { useRefresh } from './use-refresh';
12
+ import { usePlaygroundContainer } from './use-playground-container';
13
+
14
+ /**
15
+ * 获取 config entity
16
+ */
17
+ export function useConfigEntity<T extends ConfigEntity>(
18
+ entityRegistry: EntityRegistry<T>,
19
+ listenChange = false
20
+ ): T {
21
+ const entityManager = usePlaygroundContainer().get(EntityManager);
22
+ const entity = entityManager.getEntity<T>(entityRegistry, true) as T;
23
+ const refresh = useRefresh(entity.version);
24
+ const dispose = listenChange
25
+ ? entity.onEntityChange(() => {
26
+ refresh(entity.version);
27
+ })
28
+ : Disposable.NULL;
29
+ onBeforeUnmount(() => dispose.dispose());
30
+ return entity;
31
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { onBeforeUnmount } from 'vue';
7
+
8
+ import { Entity, EntityManager, EntityRegistry } from '../common';
9
+ import { useRefresh } from './use-refresh';
10
+ import { usePlaygroundContainer } from './use-playground-container';
11
+
12
+ /**
13
+ * 获取 entities 并监听变化
14
+ * @deprecated
15
+ */
16
+ export function useEntities<T extends Entity>(entityRegistry: EntityRegistry): T[] {
17
+ const entityManager = usePlaygroundContainer().get(EntityManager);
18
+ const refresh = useRefresh();
19
+ const dispose = entityManager.onEntityChange((entityKey) => {
20
+ if (entityKey === entityRegistry.type) {
21
+ refresh();
22
+ }
23
+ });
24
+ onBeforeUnmount(() => dispose.dispose());
25
+ return entityManager.getEntities<T>(entityRegistry);
26
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { onBeforeUnmount } from 'vue';
7
+
8
+ import { EntityData, type EntityDataRegistry, EntityManager } from '../common';
9
+ import { useRefresh } from './use-refresh';
10
+ import { usePlaygroundContainer } from './use-playground-container';
11
+ import { useEntityFromContext } from './use-entity-from-context';
12
+
13
+ /**
14
+ * 从上下 PlaygroundEntityContext 获取 entity data 并监听变化 (默认不监听)
15
+ */
16
+ export function useEntityDataFromContext<T extends EntityData>(
17
+ dataRegistry: EntityDataRegistry<any>,
18
+ listenChange = false
19
+ ): T {
20
+ const entityManager = usePlaygroundContainer().get(EntityManager);
21
+ const entityData = useEntityFromContext().getData<T>(dataRegistry)!;
22
+ if (!entityData) {
23
+ throw new Error(
24
+ `[useEntityDataFromContext] Unknown entity Data ${dataRegistry.name} from "PlaygroundEntityContext".`
25
+ );
26
+ }
27
+ const refresh = useRefresh(entityData.version);
28
+ const dispose = entityData.onDataChange(() => {
29
+ if (listenChange) refresh(entityData.version);
30
+ });
31
+ onBeforeUnmount(() => dispose.dispose());
32
+ void entityManager;
33
+ return entityData;
34
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { inject, onBeforeUnmount } from 'vue';
7
+
8
+ import { Disposable } from '@flowgram-vue/utils';
9
+
10
+ import { PlaygroundEntityContextKey } from '../vue';
11
+ import { Entity, EntityManager } from '../common';
12
+ import { useRefresh } from './use-refresh';
13
+ import { usePlaygroundContainer } from './use-playground-container';
14
+
15
+ /**
16
+ * 从上下 PlaygroundEntityContext 获取 entity 并监听变化(默认不监听)
17
+ */
18
+ export function useEntityFromContext<T extends Entity>(listenChange = false): T {
19
+ const entityManager = usePlaygroundContainer().get(EntityManager);
20
+ const entity = inject(PlaygroundEntityContextKey) as T;
21
+ if (!entity) {
22
+ throw new Error('[useEntityFromContext] Unknown entity from "PlaygroundEntityContext"');
23
+ }
24
+ const refresh = useRefresh(entity.version);
25
+ const dispose = listenChange
26
+ ? entity.onEntityChange(() => refresh(entity.version))
27
+ : Disposable.NULL;
28
+ onBeforeUnmount(() => dispose.dispose());
29
+ void entityManager;
30
+ return entity;
31
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { onBeforeUnmount } from 'vue';
7
+
8
+ import { DisposableCollection, type Event } from '@flowgram-vue/utils';
9
+
10
+ import { useRefresh } from './use-refresh';
11
+
12
+ /**
13
+ * 监听 event 事件变化
14
+ */
15
+
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ export function useListenEvents(...events: Event<any>[]): void {
18
+ const refresh = useRefresh();
19
+ const collection = new DisposableCollection();
20
+ collection.pushAll(events.map((e) => e(() => refresh())));
21
+ onBeforeUnmount(() => collection.dispose());
22
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { type interfaces } from 'inversify';
7
+ import { inject } from 'vue';
8
+
9
+ import { PlaygroundVueContainerKey } from '../vue/playground-vue-context';
10
+
11
+ /**
12
+ * 获取 playground inversify container
13
+ */
14
+ export function usePlaygroundContainer(): interfaces.Container {
15
+ return inject(PlaygroundVueContainerKey) as interfaces.Container;
16
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { inject } from 'vue';
7
+
8
+ import { PlaygroundVueContextKey } from '../vue/playground-vue-context';
9
+
10
+ /**
11
+ * 获取 playground context 数据
12
+ */
13
+ export function usePlaygroundContext<T>(): T {
14
+ return inject(PlaygroundVueContextKey) as T;
15
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { Disposable } from '@flowgram-vue/utils';
7
+
8
+ import { PlaygroundDragOptions, PlaygroundDrag } from '../core';
9
+ import { usePlayground } from './use-playground';
10
+
11
+ interface UsePlaygroundDragReturn {
12
+ start<T = undefined>(
13
+ e: { clientX: number; clientY: number },
14
+ opts: PlaygroundDragOptions<T> & { context?: T }
15
+ ): Disposable;
16
+ }
17
+
18
+ export function usePlaygroundDrag(): UsePlaygroundDragReturn {
19
+ const playground = usePlayground();
20
+ return {
21
+ start<T>(
22
+ e: { clientX: number; clientY: number },
23
+ opts: PlaygroundDragOptions<T> & { context?: T }
24
+ ): Disposable {
25
+ return PlaygroundDrag.startDrag(e.clientX, e.clientY, {
26
+ ...opts,
27
+ config: playground.config,
28
+ });
29
+ },
30
+ };
31
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { inject } from 'vue';
7
+
8
+ import { PlaygroundVueRefKey } from '../vue/playground-vue-context';
9
+ import { Playground } from '../playground';
10
+
11
+ /**
12
+ * 获取 playground
13
+ */
14
+ export function usePlayground(): Playground {
15
+ return inject(PlaygroundVueRefKey) as Playground;
16
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export { useRefresh } from '@flowgram-vue/utils';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { type interfaces } from 'inversify';
7
+
8
+ import { usePlaygroundContainer } from './use-playground-container';
9
+
10
+ /**
11
+ * 获取画布的 IOC 模块
12
+ * @param identifier
13
+ */
14
+ export function useService<T>(identifier: interfaces.ServiceIdentifier<T>): T {
15
+ const container = usePlaygroundContainer();
16
+ return container.get?.(identifier) as T;
17
+ }