@vvfx/sdk 0.2.8 → 0.2.10

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 (111) hide show
  1. package/dist/config.js +231 -0
  2. package/dist/exporter/config.js +18 -0
  3. package/dist/exporter/const.js +71 -0
  4. package/dist/exporter/export-media.js +878 -0
  5. package/dist/exporter/exporter.js +121 -0
  6. package/dist/exporter/index.js +1 -0
  7. package/dist/exporter/types.js +1 -0
  8. package/dist/exporter/utils.js +190 -0
  9. package/dist/exporter/wav-audio.js +50 -0
  10. package/dist/gesture-handler/gizmo/adsorption-gizmo.js +227 -0
  11. package/dist/gesture-handler/gizmo/control-gizmo.js +149 -0
  12. package/dist/gesture-handler/gizmo/gizmo.js +17 -0
  13. package/dist/gesture-handler/gizmo/icon-gizmo.js +189 -0
  14. package/dist/gesture-handler/gizmo/index.js +6 -0
  15. package/dist/gesture-handler/gizmo/item-create-gizmo.js +256 -0
  16. package/dist/gesture-handler/gizmo/loading-gizmo.js +320 -0
  17. package/dist/gesture-handler/gizmo/mask-gizmo.js +648 -0
  18. package/dist/gesture-handler/gizmo/picture-cut-gizmo.js +550 -0
  19. package/dist/gesture-handler/gizmo/picture-expand-gizmo.js +491 -0
  20. package/dist/gesture-handler/gizmo/preference-gizmo.js +148 -0
  21. package/dist/gesture-handler/gizmo/selector-gizmo.d.ts +1 -1
  22. package/dist/gesture-handler/gizmo/selector-gizmo.js +468 -0
  23. package/dist/gesture-handler/gizmo/sprite-text-edit-gizmo.js +247 -0
  24. package/dist/gesture-handler/gizmo/text-gizmo.js +1033 -0
  25. package/dist/gesture-handler/gizmo/transform-gizmo.js +1199 -0
  26. package/dist/gesture-handler/gizmo/type.js +18 -0
  27. package/dist/gesture-handler/index.js +3 -0
  28. package/dist/gesture-handler/src/gesture-handler.js +770 -0
  29. package/dist/gesture-handler/src/icons.js +24 -0
  30. package/dist/gesture-handler/utils.js +40 -0
  31. package/dist/html-overlay/anchor-navigation-runtime.js +27 -0
  32. package/dist/html-overlay/auto-height-layout.d.ts +6 -0
  33. package/dist/html-overlay/auto-height-layout.js +7 -0
  34. package/dist/html-overlay/auto-height-runtime.js +132 -0
  35. package/dist/html-overlay/document-runtime.js +71 -0
  36. package/dist/html-overlay/document-transform.js +96 -0
  37. package/dist/html-overlay/dom-order.js +8 -0
  38. package/dist/html-overlay/host-message-runtime.js +24 -0
  39. package/dist/html-overlay/html-capture-runtime.js +282 -0
  40. package/dist/html-overlay/html-viewport-style.js +10 -0
  41. package/dist/html-overlay/index.js +1 -0
  42. package/dist/html-overlay/manager.d.ts +1 -0
  43. package/dist/html-overlay/manager.js +1677 -0
  44. package/dist/html-overlay/mime-utils.js +21 -0
  45. package/dist/html-overlay/overlay-transform.js +57 -0
  46. package/dist/html-overlay/path-utils.js +35 -0
  47. package/dist/html-overlay/shell-runtime.js +12 -0
  48. package/dist/index.cjs +34 -8
  49. package/dist/index.cjs.map +1 -1
  50. package/dist/index.js +13 -75311
  51. package/dist/index.mjs +75337 -0
  52. package/dist/index.mjs.map +1 -0
  53. package/dist/layer-order.js +8 -0
  54. package/dist/math/box2.js +396 -0
  55. package/dist/math/circle.js +131 -0
  56. package/dist/math/euler.js +35 -0
  57. package/dist/math/index.js +13 -0
  58. package/dist/math/line2.js +153 -0
  59. package/dist/math/line3.js +36 -0
  60. package/dist/math/matrix4.js +207 -0
  61. package/dist/math/plane.js +52 -0
  62. package/dist/math/quaternion.js +3 -0
  63. package/dist/math/ray-caster.js +25 -0
  64. package/dist/math/ray.js +47 -0
  65. package/dist/math/type.js +1 -0
  66. package/dist/math/utils.js +77 -0
  67. package/dist/math/vector2.js +70 -0
  68. package/dist/math/vector3.js +60 -0
  69. package/dist/screen-shot/index.js +1 -0
  70. package/dist/screen-shot/screen-shot.js +113 -0
  71. package/dist/sdk-item/base-item.js +160 -0
  72. package/dist/sdk-item/card-item.js +131 -0
  73. package/dist/sdk-item/effects-item.js +144 -0
  74. package/dist/sdk-item/frame-item.js +217 -0
  75. package/dist/sdk-item/generator-item.js +188 -0
  76. package/dist/sdk-item/group-item.js +116 -0
  77. package/dist/sdk-item/index.js +39 -0
  78. package/dist/sdk-item/sprite-item.js +147 -0
  79. package/dist/sdk-item/text-item.js +223 -0
  80. package/dist/sdk-item/types.d.ts +1 -1
  81. package/dist/sdk-item/types.js +15 -0
  82. package/dist/sdk-item/video-item.js +174 -0
  83. package/dist/sdk.js +1908 -0
  84. package/dist/service/UndoRedo.js +79 -0
  85. package/dist/shared/index.d.ts +1 -0
  86. package/dist/shared/index.js +2 -0
  87. package/dist/shared/player.d.ts +1 -1
  88. package/dist/shared/player.js +9 -0
  89. package/dist/shared/spec.d.ts +1 -0
  90. package/dist/shared/spec.js +1 -0
  91. package/dist/size-adapte/index.js +1 -0
  92. package/dist/size-adapte/size-adapt.js +395 -0
  93. package/dist/types.d.ts +5 -1
  94. package/dist/types.js +17 -0
  95. package/dist/utils/background-manager.js +189 -0
  96. package/dist/utils/common-utils.js +183 -0
  97. package/dist/utils/index.js +8 -0
  98. package/dist/utils/interaction-utils.js +205 -0
  99. package/dist/utils/json-data-utils.js +1529 -0
  100. package/dist/utils/layout-utils.js +1217 -0
  101. package/dist/utils/page-data-utils.js +5397 -0
  102. package/dist/utils/player-data-utils.js +48 -0
  103. package/dist/utils/types.js +8 -0
  104. package/dist/wireframe/common/box.js +18 -0
  105. package/dist/wireframe/common/dashed-line.js +21 -0
  106. package/dist/wireframe/common/line.js +17 -0
  107. package/dist/wireframe/common/pixi-ext.js +1 -0
  108. package/dist/wireframe/common/pixi.js +31 -0
  109. package/dist/wireframe/index.js +4 -0
  110. package/package.json +10 -3
  111. package/dist/index.js.map +0 -1
@@ -0,0 +1,550 @@
1
+ import { Box2, getBoxByNormalizeBox, getNormalizeBoxByBoxes, isEqual, Line2, RAD2DEG, Vector2 } from '../../math';
2
+ import { SDK } from '../../sdk';
3
+ import { GizmoUndoRedo } from '../../service/UndoRedo';
4
+ import { assertExist } from '../../utils';
5
+ import { Graphics } from '../../wireframe';
6
+ import { Gizmo } from './gizmo';
7
+ export class PictureCutGizmo extends Gizmo {
8
+ result = {
9
+ type: 'invalid'
10
+ };
11
+ interactionParam = { type: 'none' };
12
+ graphics = new Graphics();
13
+ /**
14
+ * @description Shift按键是否按下,用于判断交互
15
+ */
16
+ isShiftDown = false;
17
+ _isLockScale = false;
18
+ _pageDataUtils;
19
+ _eventEmitter;
20
+ type = 'picture-cut';
21
+ /**
22
+ * 图片裁切工具独立的撤销重做实例
23
+ */
24
+ _undoRedo = new GizmoUndoRedo();
25
+ /**
26
+ * 存储操作开始前的数据,用于 undoRedo
27
+ */
28
+ _oldNormalizeCutBox;
29
+ /**
30
+ * 鼠标状态绘制结果
31
+ */
32
+ cursorResult = {
33
+ type: 'normal',
34
+ angle: 0,
35
+ };
36
+ /**
37
+ * 获取图片裁切工具的撤销重做实例
38
+ */
39
+ get undoRedo() {
40
+ return this._undoRedo;
41
+ }
42
+ get interactive() {
43
+ return SDK.config.gestureHandlerConfig.pictureCutGizmoEnabled;
44
+ }
45
+ set interactive(bool) {
46
+ if (bool === SDK.config.gestureHandlerConfig.pictureCutGizmoEnabled) {
47
+ return;
48
+ }
49
+ if (this._pageDataUtils.getPageData()?.activeData.selectedItems?.length !== 1) {
50
+ console.warn('Selected items` length is not one, Picture cut gizmo can not open.');
51
+ }
52
+ else {
53
+ SDK.config.gestureHandlerConfig.pictureCutGizmoEnabled = bool;
54
+ }
55
+ }
56
+ get isLockScale() {
57
+ return this._isLockScale;
58
+ }
59
+ set isLockScale(state) {
60
+ if (state === this.isLockScale) {
61
+ return;
62
+ }
63
+ this._isLockScale = state;
64
+ }
65
+ constructor(utils, eventEmitter) {
66
+ super();
67
+ this._pageDataUtils = utils;
68
+ this._eventEmitter = eventEmitter;
69
+ }
70
+ preparationAction(event) {
71
+ if (!this.interactive) {
72
+ return undefined;
73
+ }
74
+ const mouse = new Vector2(event.offsetX, event.offsetY);
75
+ const clinetMouse = new Vector2(event.clientX, event.clientY);
76
+ this.refreshInteractionType(mouse, clinetMouse);
77
+ return this.type;
78
+ }
79
+ preAction() {
80
+ if (!this.interactive || this.interactionParam.type === 'none') {
81
+ return undefined;
82
+ }
83
+ // 存储操作前的数据用于 undoRedo
84
+ if (this.result.type === 'valid') {
85
+ this._oldNormalizeCutBox = {
86
+ normalizeCutBox: this.result.normalizeCutBox.clone(),
87
+ };
88
+ }
89
+ return this.type;
90
+ }
91
+ action(event) {
92
+ if (!this.interactive
93
+ || this.interactionParam.type === 'none'
94
+ || this.result.type === 'invalid') {
95
+ return;
96
+ }
97
+ const currentClientMouse = new Vector2(event.clientX, event.clientY);
98
+ const { startMouse, box } = this.interactionParam;
99
+ const shift = new Vector2().subtractVectors(currentClientMouse, startMouse);
100
+ const { itemBox } = this.result;
101
+ const { min: itemBoxMin, max: itemBoxMax } = itemBox;
102
+ switch (this.interactionParam.type) {
103
+ case 'move': {
104
+ const { min: originMin, max: originMax } = box;
105
+ const xMinShift = itemBoxMin.x - originMin.x;
106
+ const xMaxShift = itemBoxMax.x - originMax.x;
107
+ const yMinShift = itemBoxMin.y - originMin.y;
108
+ const yMaxShift = itemBoxMax.y - originMax.y;
109
+ shift.x = Math.min(Math.max(shift.x, xMinShift), xMaxShift);
110
+ shift.y = Math.min(Math.max(shift.y, yMinShift), yMaxShift);
111
+ const resultBox = box.clone().translate(shift);
112
+ this.result.normalizeCutBox = getNormalizeBoxByBoxes(itemBox, resultBox);
113
+ this._eventEmitter.emit('cutBoxChange', this.getCutBox());
114
+ break;
115
+ }
116
+ case 'scale': {
117
+ const { startCorner, anchor } = this.interactionParam;
118
+ const resultCorner = new Vector2();
119
+ resultCorner.x = Math.min(Math.max(startCorner.x + shift.x, itemBoxMin.x), itemBoxMax.x);
120
+ resultCorner.y = Math.min(Math.max(startCorner.y + shift.y, itemBoxMin.y), itemBoxMax.y);
121
+ // Shift键按下时,锁定缩放
122
+ if (this.isShiftDown || this.isLockScale) {
123
+ const cutBox = this.getCutBox();
124
+ const cornerSignFactor = (startCorner.x - anchor.x) * (startCorner.y - anchor.y) >= 0 ? 1 : -1;
125
+ const { x: boxWidth, y: boxHeight } = cutBox.getSize();
126
+ const { x: originWidth, y: originHeight } = box.getSize();
127
+ this.interactionParam.lockedAspect ??= boxWidth / boxHeight;
128
+ if (Math.abs(resultCorner.x - anchor.x) / originWidth > Math.abs(resultCorner.y - anchor.y) / originHeight) {
129
+ const resultSignFactor = Math.abs(resultCorner.x - anchor.x) / (resultCorner.x - anchor.x);
130
+ const resultHeight = Math.abs(resultCorner.x - anchor.x) / this.interactionParam.lockedAspect;
131
+ if (isEqual(startCorner.y, anchor.y)) {
132
+ resultCorner.y = startCorner.y;
133
+ }
134
+ else {
135
+ resultCorner.y = resultSignFactor * cornerSignFactor * resultHeight + anchor.y;
136
+ }
137
+ resultCorner.y = Math.min(Math.max(resultCorner.y, itemBoxMin.y), itemBoxMax.y);
138
+ const shiftY = resultCorner.y - anchor.y;
139
+ if (isEqual(startCorner.y, anchor.y)) {
140
+ resultCorner.x = startCorner.x;
141
+ }
142
+ else {
143
+ resultCorner.x = cornerSignFactor * shiftY * this.interactionParam.lockedAspect + anchor.x;
144
+ }
145
+ }
146
+ else {
147
+ const resultWidth = Math.abs(resultCorner.y - anchor.y) * this.interactionParam.lockedAspect;
148
+ const resultSignFactor = Math.abs(resultCorner.y - anchor.y) / (resultCorner.y - anchor.y);
149
+ if (isEqual(startCorner.x, anchor.x)) {
150
+ resultCorner.x = startCorner.x;
151
+ }
152
+ else {
153
+ resultCorner.x = resultSignFactor * cornerSignFactor * resultWidth + anchor.x;
154
+ }
155
+ resultCorner.x = Math.min(Math.max(resultCorner.x, itemBoxMin.x), itemBoxMax.x);
156
+ const shiftX = resultCorner.x - anchor.x;
157
+ if (isEqual(startCorner.x, anchor.x)) {
158
+ resultCorner.y = startCorner.y;
159
+ }
160
+ else {
161
+ resultCorner.y = cornerSignFactor * shiftX / this.interactionParam.lockedAspect + anchor.y;
162
+ }
163
+ }
164
+ }
165
+ if (isEqual(startCorner.x, anchor.x) || isEqual(startCorner.y, anchor.y)) {
166
+ const farthestCorner = box.corners[0].clone();
167
+ let length = farthestCorner.distanceTo(startCorner);
168
+ box.corners.forEach(corner => {
169
+ if (corner.distanceTo(startCorner) > length) {
170
+ farthestCorner.copyFrom(corner);
171
+ length = corner.distanceTo(startCorner);
172
+ }
173
+ });
174
+ this.result.normalizeCutBox = getNormalizeBoxByBoxes(itemBox, new Box2().setFromVec2Array([farthestCorner, resultCorner]));
175
+ }
176
+ else {
177
+ const xScalar = (resultCorner.x - anchor.x) / (startCorner.x - anchor.x);
178
+ const yScalar = (resultCorner.y - anchor.y) / (startCorner.y - anchor.y);
179
+ const scalar = new Vector2(xScalar, yScalar);
180
+ this.result.normalizeCutBox = getNormalizeBoxByBoxes(itemBox, box.clone().scale(scalar, anchor));
181
+ }
182
+ this._eventEmitter.emit('cutBoxChange', this.getCutBox());
183
+ break;
184
+ }
185
+ case 'direction-scale': {
186
+ const { index } = this.interactionParam;
187
+ const cutBox = this.getCutBox();
188
+ const { x: boxWidth, y: boxHeight } = cutBox.getSize();
189
+ this.interactionParam.lockedAspect ??= boxWidth / boxHeight;
190
+ const startPoint = box.corners[index].clone();
191
+ const nextCorner = box.corners[(index + 1) % 4].clone();
192
+ const shiftDirection = index % 2 === 0 ? 'x' : 'y';
193
+ if (index % 2 === 0) {
194
+ shift.x = Math.min(Math.max(startPoint.x + shift.x, itemBoxMin.x), itemBoxMax.x) - startPoint.x;
195
+ if (this.isShiftDown || this.isLockScale) {
196
+ shift.y = shift.x / this.interactionParam.lockedAspect;
197
+ const resuleTargetCornerY = nextCorner.y + shift.y;
198
+ const clampResultCornerY = Math.min(Math.max(resuleTargetCornerY, itemBoxMin.y), itemBoxMax.y);
199
+ shift.y = clampResultCornerY - nextCorner.y;
200
+ shift.x = shift.y * this.interactionParam.lockedAspect;
201
+ }
202
+ else {
203
+ shift.y = 0;
204
+ }
205
+ }
206
+ else {
207
+ shift.y = Math.min(Math.max(startPoint.y + shift.y, itemBoxMin.y), itemBoxMax.y) - startPoint.y;
208
+ if (this.isShiftDown || this.isLockScale) {
209
+ shift.x = -shift.y * this.interactionParam.lockedAspect;
210
+ const resuleTargetCornerX = nextCorner.x + shift.x;
211
+ const clampResultCornerX = Math.min(Math.max(resuleTargetCornerX, itemBoxMin.x), itemBoxMax.x);
212
+ shift.x = clampResultCornerX - nextCorner.x;
213
+ shift.y = -shift.x / this.interactionParam.lockedAspect;
214
+ }
215
+ else {
216
+ shift.x = 0;
217
+ }
218
+ }
219
+ const resultCorners = [];
220
+ box.corners.forEach((corner, i) => {
221
+ const resultCorner = new Vector2();
222
+ if (index === i) {
223
+ if (shiftDirection === 'y') {
224
+ resultCorner.copyFrom(corner.clone().add(new Vector2(0, shift.y)));
225
+ }
226
+ else {
227
+ resultCorner.copyFrom(corner.clone().add(new Vector2(shift.x, 0)));
228
+ }
229
+ }
230
+ else if (index === (i + 3) % 4) {
231
+ resultCorner.copyFrom(corner.clone().add(shift));
232
+ }
233
+ else if (index === (i + 2) % 4) {
234
+ if (shiftDirection === 'x') {
235
+ resultCorner.copyFrom(corner.clone().add(new Vector2(0, shift.y)));
236
+ }
237
+ else {
238
+ resultCorner.copyFrom(corner.clone().add(new Vector2(shift.x, 0)));
239
+ }
240
+ }
241
+ else {
242
+ resultCorner.copyFrom(corner.clone());
243
+ }
244
+ resultCorners.push(resultCorner);
245
+ });
246
+ this.result.normalizeCutBox = getNormalizeBoxByBoxes(itemBox, new Box2().setFromVec2Array(resultCorners));
247
+ this._eventEmitter.emit('cutBoxChange', this.getCutBox());
248
+ break;
249
+ }
250
+ default:
251
+ break;
252
+ }
253
+ }
254
+ endAction(event) {
255
+ if (!this.interactive || this.interactionParam.type === 'none') {
256
+ return undefined;
257
+ }
258
+ // 记录操作到 undoRedo
259
+ if (this._oldNormalizeCutBox && this.result.type === 'valid') {
260
+ const operation = {
261
+ type: 'update',
262
+ oldData: this._oldNormalizeCutBox,
263
+ newData: {
264
+ normalizeCutBox: this.result.normalizeCutBox.clone(),
265
+ },
266
+ };
267
+ this._undoRedo.push(operation);
268
+ this._eventEmitter.emit('pictureCutGizmoUndoRedoChange', operation);
269
+ }
270
+ this._oldNormalizeCutBox = undefined;
271
+ const mouse = new Vector2(event.offsetX, event.offsetY);
272
+ const clinetMouse = new Vector2(event.clientX, event.clientY);
273
+ this.refreshInteractionType(mouse, clinetMouse);
274
+ return this.type;
275
+ }
276
+ interruption() {
277
+ this.interactionParam = { type: 'none' };
278
+ return undefined;
279
+ }
280
+ actionKey(keyCode) {
281
+ this.isShiftDown = keyCode.shiftKey;
282
+ }
283
+ endActionKey(keyCode) {
284
+ this.isShiftDown = keyCode.shiftKey;
285
+ if ('lockedAspect' in this.interactionParam) {
286
+ delete this.interactionParam.lockedAspect;
287
+ }
288
+ }
289
+ cancelPreparation() {
290
+ this.interactionParam = { type: 'none' };
291
+ }
292
+ refreshResults() {
293
+ if (this.interactive) {
294
+ const pageData = this._pageDataUtils.getPageData();
295
+ assertExist(pageData, 'You must call SDK#run() first');
296
+ if (pageData.activeData.selectedItems.length !== 1) {
297
+ console.warn('Picture Cut Gizmo can edit one picture at a time.');
298
+ }
299
+ else {
300
+ if (this.result.type === 'invalid') {
301
+ const itemViewBox = this._pageDataUtils.getViewBoxById(pageData.activeData.selectedItems[0]);
302
+ this.result = {
303
+ type: 'valid',
304
+ itemBox: itemViewBox.clone(),
305
+ normalizeCutBox: new Box2(new Vector2(), new Vector2(1, 1)),
306
+ };
307
+ }
308
+ else {
309
+ const currentViewBox = this._pageDataUtils.getViewBoxById(pageData.activeData.selectedItems[0]);
310
+ const shift = currentViewBox.getCenter().subtract(this.result.itemBox.getCenter());
311
+ const scaleValue = currentViewBox.getSize().x / this.result.itemBox.getSize().x;
312
+ this.result.itemBox.translate(shift);
313
+ this.result.itemBox.scale(scaleValue);
314
+ }
315
+ }
316
+ }
317
+ else {
318
+ this.result = { type: 'invalid' };
319
+ }
320
+ }
321
+ refreshRenderObjects() {
322
+ this.graphics.clear();
323
+ if (!this.interactive || this.result.type === 'invalid') {
324
+ return [];
325
+ }
326
+ const { maskColor, maskAlpha, cutBoxLineWidth, cutBoxLineColor, cutBoxLineAlpha, itemBoxLineWidth, itemBoxLineColor, itemBoxLineAlpha, cutBoxCornerRadius, cutBoxCornerFillColor, cutBoxCornerLineWidth, cutBoxCornerLineColor, cutBoxCornerLineAlpha, gridLineWidth, gridLineColor, gridLineAlpha, gridCount, } = SDK.config.gestureHandlerConfig.pictureCutGizmoConfig;
327
+ const { normalizeCutBox, itemBox, } = this.result;
328
+ const cutBox = getBoxByNormalizeBox(itemBox, normalizeCutBox);
329
+ const { min: cutMin, max: cutMax } = cutBox;
330
+ const { min: originMin, max: originMax } = itemBox;
331
+ // 绘制蒙版层
332
+ const topBox = new Box2(originMin.clone(), new Vector2(originMax.x, cutMin.y));
333
+ const leftBox = new Box2(new Vector2(originMin.x, cutMin.y), new Vector2(cutMin.x, originMax.y));
334
+ const rightBox = new Box2(new Vector2(cutMax.x, cutMin.y), new Vector2(originMax.x, cutMax.y));
335
+ const bottomBox = new Box2(new Vector2(cutMin.x, cutMax.y), originMax.clone());
336
+ this.graphics.beginFill(maskColor, maskAlpha);
337
+ this.graphics.fillBox(topBox);
338
+ this.graphics.fillBox(leftBox);
339
+ this.graphics.fillBox(rightBox);
340
+ this.graphics.fillBox(bottomBox);
341
+ this.graphics.endFill();
342
+ // 绘制网格线
343
+ const xShift = cutBox.getSize().x / (gridCount + 1);
344
+ const yShift = cutBox.getSize().y / (gridCount + 1);
345
+ this.graphics.lineStyle(gridLineWidth, gridLineColor, gridLineAlpha);
346
+ for (let i = 1; i <= gridCount; i++) {
347
+ const xGridLine = new Line2(new Vector2(cutMin.x + xShift * i, cutMin.y), new Vector2(cutMin.x + xShift * i, cutMax.y));
348
+ const yGridLine = new Line2(new Vector2(cutMin.x, cutMin.y + yShift * i), new Vector2(cutMax.x, cutMin.y + yShift * i));
349
+ this.graphics.drawLine(xGridLine);
350
+ this.graphics.drawLine(yGridLine);
351
+ }
352
+ // 绘制元素选包围盒
353
+ this.graphics.lineStyle(itemBoxLineWidth, itemBoxLineColor, itemBoxLineAlpha);
354
+ this.graphics.drawBox(itemBox);
355
+ // 绘制裁切包围盒
356
+ this.graphics.lineStyle(cutBoxLineWidth, cutBoxLineColor, cutBoxLineAlpha);
357
+ this.graphics.drawBox(cutBox);
358
+ // 绘制角点
359
+ this.graphics.beginFill(cutBoxCornerFillColor);
360
+ this.graphics.lineStyle(cutBoxCornerLineWidth, cutBoxCornerLineColor, cutBoxCornerLineAlpha);
361
+ cutBox.corners.forEach((corner, i) => {
362
+ this.graphics.drawCircle(corner.x, corner.y, cutBoxCornerRadius);
363
+ });
364
+ this.graphics.endFill();
365
+ return [this.graphics];
366
+ }
367
+ /**
368
+ * 刷新指针结果
369
+ * @param activeType 交互类型
370
+ * @param angle 指针方向
371
+ */
372
+ refreshCursorResult(activeType, angle = 0) {
373
+ switch (activeType) {
374
+ case 'scale': {
375
+ this.cursorResult = {
376
+ type: 'scale',
377
+ angle,
378
+ };
379
+ break;
380
+ }
381
+ case 'direction-scale': {
382
+ this.cursorResult = {
383
+ type: 'scale',
384
+ angle,
385
+ };
386
+ break;
387
+ }
388
+ case 'move':
389
+ case 'none': {
390
+ this.cursorResult = {
391
+ type: 'normal',
392
+ angle: 0,
393
+ };
394
+ break;
395
+ }
396
+ }
397
+ }
398
+ getRenderObjects() {
399
+ if (!this.interactive) {
400
+ return [];
401
+ }
402
+ else {
403
+ return this.refreshRenderObjects();
404
+ }
405
+ }
406
+ refreshInteractionType(point, clientMouse) {
407
+ this.interactionParam = {
408
+ type: 'none'
409
+ };
410
+ if (!this.interactive || this.result.type === 'invalid') {
411
+ return;
412
+ }
413
+ const { normalizeCutBox, itemBox } = this.result;
414
+ const cutBox = getBoxByNormalizeBox(itemBox, normalizeCutBox);
415
+ let hasInteractionType = false;
416
+ let angle = 0;
417
+ // 判定交互状态 - 缩放
418
+ cutBox.corners.forEach((corner, index) => {
419
+ if (hasInteractionType) {
420
+ return;
421
+ }
422
+ if (corner.distanceTo(point) < SDK.config.gestureHandlerConfig.pictureCutGizmoConfig.scaleInteractionDistance) {
423
+ hasInteractionType = true;
424
+ this.interactionParam = {
425
+ type: 'scale',
426
+ box: cutBox.clone(),
427
+ startMouse: clientMouse,
428
+ startCorner: corner.clone(),
429
+ anchor: cutBox.corners[(index + 2) % 4],
430
+ };
431
+ angle = Math.PI / 2 * index;
432
+ }
433
+ });
434
+ // 判定交互状态 - 单向缩放
435
+ cutBox.corners.forEach((corner, index) => {
436
+ if (hasInteractionType) {
437
+ return;
438
+ }
439
+ const edge = new Line2(corner.clone(), cutBox.corners[(index + 1) % 4]);
440
+ const dis = point.distanceToLine(edge);
441
+ const state = dis.d >= 0 && dis.d <= 8 && dis.t >= 0 && dis.t <= 1;
442
+ if (state) {
443
+ hasInteractionType = true;
444
+ this.interactionParam = {
445
+ type: 'direction-scale',
446
+ index,
447
+ box: cutBox.clone(),
448
+ startMouse: clientMouse,
449
+ };
450
+ angle = Math.PI / 2 * index + Math.PI / 4;
451
+ }
452
+ });
453
+ // 判定交互状态 - 移动
454
+ if (cutBox.containsPoint(point) && !hasInteractionType) {
455
+ this.interactionParam = { type: 'move', box: cutBox.clone(), startMouse: clientMouse };
456
+ hasInteractionType = true;
457
+ }
458
+ this.refreshCursorResult(this.interactionParam.type, angle * RAD2DEG);
459
+ }
460
+ getCutInfo() {
461
+ const [item] = this._pageDataUtils.getSelectedItems();
462
+ if (!this.interactive || this.result.type === 'invalid' || !item) {
463
+ return undefined;
464
+ }
465
+ // 真实包围盒信息
466
+ return {
467
+ cutBox: this.getCutBox(),
468
+ itemBox: this._pageDataUtils.getItemBoxById(item.id),
469
+ };
470
+ }
471
+ getCutBox() {
472
+ const [item] = this._pageDataUtils.getSelectedItems();
473
+ if (!this.interactive || this.result.type === 'invalid' || !item) {
474
+ return undefined;
475
+ }
476
+ const originBox = this._pageDataUtils.getItemBoxById(item.id);
477
+ const { normalizeCutBox } = this.result;
478
+ return getBoxByNormalizeBox(originBox, normalizeCutBox);
479
+ }
480
+ setCutBox(min, max) {
481
+ const [item] = this._pageDataUtils.getSelectedItems();
482
+ if (!this.interactive || this.result.type === 'invalid' || !item) {
483
+ return undefined;
484
+ }
485
+ // 记录操作到 undoRedo
486
+ const oldNormalizeCutBox = this.result.normalizeCutBox.clone();
487
+ const currentBox = new Box2(min, max);
488
+ const originBox = this._pageDataUtils.getItemBoxById(item.id);
489
+ const { min: cutBoxMin, max: cutBoxMax } = getNormalizeBoxByBoxes(originBox, currentBox);
490
+ this.result.normalizeCutBox.set(new Vector2(Math.max(cutBoxMin.x, 0), Math.max(cutBoxMin.y, 0)), new Vector2(Math.min(cutBoxMax.x, 1), Math.min(cutBoxMax.y, 1)));
491
+ const operation = {
492
+ type: 'update',
493
+ oldData: {
494
+ normalizeCutBox: oldNormalizeCutBox,
495
+ },
496
+ newData: {
497
+ normalizeCutBox: this.result.normalizeCutBox.clone(),
498
+ },
499
+ };
500
+ this._undoRedo.push(operation);
501
+ this._eventEmitter.emit('pictureCutGizmoUndoRedoChange', operation);
502
+ const cutBox = this.getCutBox();
503
+ this._eventEmitter.emit('cutBoxChange', cutBox);
504
+ return cutBox;
505
+ }
506
+ /**
507
+ * 撤销操作
508
+ * @returns 是否成功撤销
509
+ */
510
+ undo() {
511
+ const operation = this._undoRedo.undo();
512
+ if (operation && this.result.type === 'valid') {
513
+ this.result.normalizeCutBox = operation.oldData.normalizeCutBox.clone();
514
+ this._eventEmitter.emit('cutBoxChange', this.getCutBox());
515
+ return true;
516
+ }
517
+ return false;
518
+ }
519
+ /**
520
+ * 重做操作
521
+ * @returns 是否成功重做
522
+ */
523
+ redo() {
524
+ const operation = this._undoRedo.redo();
525
+ if (operation && this.result.type === 'valid') {
526
+ this.result.normalizeCutBox = operation.newData.normalizeCutBox.clone();
527
+ this._eventEmitter.emit('cutBoxChange', this.getCutBox());
528
+ return true;
529
+ }
530
+ return false;
531
+ }
532
+ /**
533
+ * 检查是否可以撤销
534
+ */
535
+ get canUndo() {
536
+ return this._undoRedo.canUndo;
537
+ }
538
+ /**
539
+ * 检查是否可以重做
540
+ */
541
+ get canRedo() {
542
+ return this._undoRedo.canRedo;
543
+ }
544
+ /**
545
+ * 清空 undoRedo 历史
546
+ */
547
+ clearUndoRedo() {
548
+ this._undoRedo.clear();
549
+ }
550
+ }