@vvfx/sdk 0.2.8 → 0.2.9

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 (107) 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-runtime.js +132 -0
  33. package/dist/html-overlay/document-runtime.js +71 -0
  34. package/dist/html-overlay/document-transform.js +96 -0
  35. package/dist/html-overlay/dom-order.js +8 -0
  36. package/dist/html-overlay/host-message-runtime.js +24 -0
  37. package/dist/html-overlay/html-capture-runtime.js +282 -0
  38. package/dist/html-overlay/html-viewport-style.js +10 -0
  39. package/dist/html-overlay/index.js +1 -0
  40. package/dist/html-overlay/manager.js +1663 -0
  41. package/dist/html-overlay/mime-utils.js +21 -0
  42. package/dist/html-overlay/overlay-transform.js +57 -0
  43. package/dist/html-overlay/path-utils.js +35 -0
  44. package/dist/html-overlay/shell-runtime.js +12 -0
  45. package/dist/index.cjs +1 -1
  46. package/dist/index.cjs.map +1 -1
  47. package/dist/index.js +13 -75311
  48. package/dist/index.mjs +75311 -0
  49. package/dist/{index.js.map → index.mjs.map} +1 -1
  50. package/dist/layer-order.js +8 -0
  51. package/dist/math/box2.js +396 -0
  52. package/dist/math/circle.js +131 -0
  53. package/dist/math/euler.js +35 -0
  54. package/dist/math/index.js +13 -0
  55. package/dist/math/line2.js +153 -0
  56. package/dist/math/line3.js +36 -0
  57. package/dist/math/matrix4.js +207 -0
  58. package/dist/math/plane.js +52 -0
  59. package/dist/math/quaternion.js +3 -0
  60. package/dist/math/ray-caster.js +25 -0
  61. package/dist/math/ray.js +47 -0
  62. package/dist/math/type.js +1 -0
  63. package/dist/math/utils.js +77 -0
  64. package/dist/math/vector2.js +70 -0
  65. package/dist/math/vector3.js +60 -0
  66. package/dist/screen-shot/index.js +1 -0
  67. package/dist/screen-shot/screen-shot.js +113 -0
  68. package/dist/sdk-item/base-item.js +160 -0
  69. package/dist/sdk-item/card-item.js +131 -0
  70. package/dist/sdk-item/effects-item.js +144 -0
  71. package/dist/sdk-item/frame-item.js +217 -0
  72. package/dist/sdk-item/generator-item.js +188 -0
  73. package/dist/sdk-item/group-item.js +116 -0
  74. package/dist/sdk-item/index.js +39 -0
  75. package/dist/sdk-item/sprite-item.js +147 -0
  76. package/dist/sdk-item/text-item.js +223 -0
  77. package/dist/sdk-item/types.d.ts +1 -1
  78. package/dist/sdk-item/types.js +15 -0
  79. package/dist/sdk-item/video-item.js +174 -0
  80. package/dist/sdk.js +1903 -0
  81. package/dist/service/UndoRedo.js +79 -0
  82. package/dist/shared/index.d.ts +1 -0
  83. package/dist/shared/index.js +2 -0
  84. package/dist/shared/player.d.ts +1 -1
  85. package/dist/shared/player.js +9 -0
  86. package/dist/shared/spec.d.ts +1 -0
  87. package/dist/shared/spec.js +1 -0
  88. package/dist/size-adapte/index.js +1 -0
  89. package/dist/size-adapte/size-adapt.js +395 -0
  90. package/dist/types.d.ts +5 -1
  91. package/dist/types.js +17 -0
  92. package/dist/utils/background-manager.js +189 -0
  93. package/dist/utils/common-utils.js +183 -0
  94. package/dist/utils/index.js +8 -0
  95. package/dist/utils/interaction-utils.js +205 -0
  96. package/dist/utils/json-data-utils.js +1529 -0
  97. package/dist/utils/layout-utils.js +1217 -0
  98. package/dist/utils/page-data-utils.js +5397 -0
  99. package/dist/utils/player-data-utils.js +48 -0
  100. package/dist/utils/types.js +8 -0
  101. package/dist/wireframe/common/box.js +18 -0
  102. package/dist/wireframe/common/dashed-line.js +21 -0
  103. package/dist/wireframe/common/line.js +17 -0
  104. package/dist/wireframe/common/pixi-ext.js +1 -0
  105. package/dist/wireframe/common/pixi.js +31 -0
  106. package/dist/wireframe/index.js +4 -0
  107. package/package.json +10 -3
package/dist/sdk.js ADDED
@@ -0,0 +1,1903 @@
1
+ import { merge } from 'lodash-es';
2
+ import { assertExist, EventEmitter, Player } from './shared';
3
+ import { SDKItemType } from './sdk-item/types';
4
+ import { FrameLayoutMode } from './types';
5
+ import { GestureHandler } from './gesture-handler/src/gesture-handler';
6
+ import { PageDataUtils } from './utils/page-data-utils';
7
+ import { Exporter } from './exporter';
8
+ import { BackgroundManager, getUniqueName } from './utils';
9
+ import { clearPlayerAssets } from './exporter/utils';
10
+ import { ScreenShot } from './screen-shot';
11
+ import { SizeAdapt } from './size-adapte';
12
+ import { BaseConfig } from './config';
13
+ import { arrAdd } from './utils/common-utils';
14
+ import { getBasicScene } from './utils/json-data-utils';
15
+ import { Vector2, Vector3 } from './math';
16
+ import { UndoRedo } from './service/UndoRedo';
17
+ import { isCardItem, isEffectsItem, isFrameItem } from './sdk-item';
18
+ import { HTMLOverlayManager } from './html-overlay';
19
+ import { orderSDKCanvasLayers } from './layer-order';
20
+ const HTML_CARD_EDITING_VIEWPORT_PADDING = 48;
21
+ export class SDK {
22
+ static config = BaseConfig;
23
+ _eventEmitter = new EventEmitter();
24
+ _pageData;
25
+ _screenShot;
26
+ _exporter;
27
+ _htmlOverlayManager;
28
+ _pageDataUtils;
29
+ _sizeAdapt;
30
+ _gestureHandler;
31
+ disposables = [];
32
+ _isSwitchScene = false;
33
+ _undoRedo = new UndoRedo();
34
+ _backgroundManager = new BackgroundManager();
35
+ player;
36
+ _container;
37
+ _playerContainer;
38
+ constructor(container, mode = 'template') {
39
+ this._container = container;
40
+ SDK.config.mode = mode;
41
+ this.initPlayer(mode);
42
+ this._eventEmitter.on('pageDataChange', (pageDate) => {
43
+ this._pageData = pageDate;
44
+ this._gestureHandler.render();
45
+ });
46
+ this._eventEmitter.on('preSelectedItemChange', (id) => {
47
+ assertExist(this._pageData, 'You must call SDK#run() first');
48
+ this._pageData.activeData.preSelectedItem = id;
49
+ this._gestureHandler.render();
50
+ });
51
+ this._eventEmitter.on('selectedViewChange', (id) => {
52
+ assertExist(this._pageData, 'You must call SDK#run() first');
53
+ this._pageData.activeData.view = id;
54
+ const targetView = this.getViewProperty(id);
55
+ this._gestureHandler.ignoreInteraction = !!targetView?.ignoreInteraction;
56
+ });
57
+ this._eventEmitter.on('sdkConfigChange', (_, curSDKConfig) => {
58
+ this.setExportConfig(curSDKConfig.exportConfig);
59
+ });
60
+ this._eventEmitter.on('itemCreate', () => {
61
+ this._gestureHandler.closeItemCreateGizmo();
62
+ });
63
+ this._pageDataUtils = new PageDataUtils(this.player, this._playerContainer, this._eventEmitter, this);
64
+ this._backgroundManager.attach(this._playerContainer);
65
+ this._gestureHandler = new GestureHandler(container);
66
+ this._screenShot = new ScreenShot();
67
+ this._sizeAdapt = new SizeAdapt();
68
+ const resizeObserver = new ResizeObserver(() => {
69
+ if (!this._pageData) {
70
+ return;
71
+ }
72
+ const parentSize = [container.offsetWidth, container.offsetHeight];
73
+ const viewProperty = this.getViewProperty(this._pageData.activeData.view ?? 0);
74
+ if (!viewProperty) {
75
+ return;
76
+ }
77
+ if (SDK.config.mode === 'template') {
78
+ const { size } = viewProperty;
79
+ const [width, height] = this._pageDataUtils.getPlayerSizeByParent(parentSize, size);
80
+ this._playerContainer.style.width = `${width}px`;
81
+ this._playerContainer.style.height = `${height}px`;
82
+ this.player.resize();
83
+ }
84
+ this._pageDataUtils.refreshInteractionParam();
85
+ this._gestureHandler.resize();
86
+ this._htmlOverlayManager?.scheduleRender();
87
+ });
88
+ resizeObserver.observe(container);
89
+ this.disposables.push(() => {
90
+ resizeObserver.disconnect();
91
+ });
92
+ this._htmlOverlayManager = new HTMLOverlayManager({
93
+ container,
94
+ emitter: this._eventEmitter,
95
+ getItems: () => this.getSDKItems(),
96
+ getViewBoxById: (id) => this.getViewBoxById(id),
97
+ getViewport: () => {
98
+ const { zoom, translation } = this.getPageConfig();
99
+ return {
100
+ zoom,
101
+ translation: [...translation],
102
+ };
103
+ },
104
+ setViewport: ({ zoom, translation }) => {
105
+ this.setPageZoom(zoom, undefined, true);
106
+ this.setPageMove(new Vector2(...translation));
107
+ },
108
+ viewportFit: (box) => {
109
+ this.viewportFit({
110
+ left: HTML_CARD_EDITING_VIEWPORT_PADDING,
111
+ right: HTML_CARD_EDITING_VIEWPORT_PADDING,
112
+ top: HTML_CARD_EDITING_VIEWPORT_PADDING,
113
+ bottom: HTML_CARD_EDITING_VIEWPORT_PADDING,
114
+ }, box);
115
+ },
116
+ setCardItemHeight: (id, height, options) => {
117
+ const item = this.getSDKItem(id);
118
+ if (!isCardItem(item) || options.anchor === 'center') {
119
+ void this.setItemProperty({
120
+ itemId: id,
121
+ type: SDKItemType.CARD,
122
+ propertyName: 'height',
123
+ propertyValue: height,
124
+ });
125
+ return;
126
+ }
127
+ const [x, y] = item.property.position;
128
+ const deltaY = (height - options.previousHeight) / 2;
129
+ void this.setItemProperty({
130
+ itemId: id,
131
+ type: SDKItemType.CARD,
132
+ property: {
133
+ height,
134
+ position: [x, y + deltaY],
135
+ },
136
+ });
137
+ },
138
+ getSelectedItemIds: () => this._pageData?.activeData.selectedItems ?? [],
139
+ setSelectedItemIds: (ids) => {
140
+ this.setSelectedItems(ids);
141
+ },
142
+ getPreSelectedItemId: () => this._pageData?.activeData.preSelectedItem,
143
+ getSelectionEdgeStyle: () => {
144
+ const { wireframeColor, wireframeAlpha, wireframeWidth, } = SDK.config.gestureHandlerConfig.transformGizmoConfig;
145
+ return {
146
+ color: wireframeColor,
147
+ alpha: wireframeAlpha,
148
+ width: wireframeWidth,
149
+ };
150
+ },
151
+ getPreSelectionEdgeStyle: () => {
152
+ const { preSelectedColor, preSelectedWidth, } = SDK.config.gestureHandlerConfig.selectorGizmoConfig;
153
+ return {
154
+ color: preSelectedColor,
155
+ alpha: 1,
156
+ width: preSelectedWidth,
157
+ };
158
+ },
159
+ getCanvasEventTarget: () => this._gestureHandler?.wireframeApplication.view,
160
+ resolveCardHTML: item => isCardItem(item) ? this.resolveCardHTML(item) : undefined,
161
+ resolveCardTypeConfig: item => isCardItem(item) ? this.resolveCardTypeConfig(item) : undefined,
162
+ });
163
+ this._htmlOverlayManager.attach();
164
+ this.syncCanvasLayerOrder();
165
+ }
166
+ get backgroundManager() {
167
+ return this._backgroundManager;
168
+ }
169
+ get container() {
170
+ return this._container;
171
+ }
172
+ get pageData() {
173
+ return this._pageData;
174
+ }
175
+ get initExporterEnabled() {
176
+ return SDK.config.mode === 'template' && SDK.config.exportConfig.enabled;
177
+ }
178
+ get exportStatus() {
179
+ return this?._exporter?.status;
180
+ }
181
+ get undoRedo() {
182
+ return this._undoRedo;
183
+ }
184
+ get exportOptions() {
185
+ if (!this.pageData) {
186
+ return [];
187
+ }
188
+ const viewProperties = this.pageData.viewProperties.filter((vp) => !vp.ignoreInteraction);
189
+ const folderName = viewProperties[0]?.scene?.compositions?.[0]?.name ?? 'videos';
190
+ const names = [];
191
+ return viewProperties.map((viewProperty, idx) => {
192
+ const { size, scene, export: { name: videoName, ...restViewProperty }, } = viewProperty;
193
+ const sizeInfo = size?.[0] && size?.[1] ? ` (${idx + 1})_${size[0]}×${size[1]}` : ` (${idx + 1})`;
194
+ // 如果用户传视频名称,则使用用户传的名称,否则使用 合成+size 名称
195
+ let newName = '';
196
+ if (videoName) {
197
+ newName = getUniqueName(videoName, names);
198
+ }
199
+ else {
200
+ newName = `${folderName}${sizeInfo}`;
201
+ }
202
+ names.push(newName);
203
+ return {
204
+ folderName,
205
+ name: newName,
206
+ size,
207
+ scene: JSON.parse(JSON.stringify(scene)),
208
+ ...restViewProperty,
209
+ };
210
+ });
211
+ }
212
+ dispose() {
213
+ this._htmlOverlayManager?.dispose();
214
+ this.player?.dispose();
215
+ this._screenShot?.dispose();
216
+ this._pageData = undefined;
217
+ this._playerContainer.remove();
218
+ this?._exporter?.dispose();
219
+ this._screenShot.dispose();
220
+ this._gestureHandler.dispose();
221
+ this.disposables.forEach((dispose) => {
222
+ dispose();
223
+ });
224
+ }
225
+ on = this._eventEmitter.on;
226
+ initPlayer(mode) {
227
+ const playerContainer = document.createElement('div');
228
+ const [width, height] = mode === 'template' ? [this._container.offsetWidth, this._container.offsetHeight] : [document.documentElement.clientWidth, document.documentElement.clientHeight];
229
+ this._playerContainer = playerContainer;
230
+ this._playerContainer.id = 'player-container';
231
+ this._playerContainer.style.position = 'absolute';
232
+ this._playerContainer.style.width = `${width}px`;
233
+ this._playerContainer.style.height = `${height}px`;
234
+ if (mode === 'editor') {
235
+ this._playerContainer.style.left = '0px';
236
+ this._playerContainer.style.top = '0px';
237
+ }
238
+ this._container.appendChild(playerContainer);
239
+ this.player = new Player({
240
+ container: this._playerContainer,
241
+ pixelRatio: 2,
242
+ interactive: true,
243
+ env: 'editor'
244
+ });
245
+ this.player.on('update', () => {
246
+ assertExist(this._pageData, 'You must call SDK#run() first');
247
+ if (this._isSwitchScene) {
248
+ return;
249
+ }
250
+ const time = this.player.getCompositions()[0]?.time;
251
+ if (this._pageData.playing) {
252
+ if (time !== undefined) {
253
+ if (this._pageData.time === time) {
254
+ this.player.pause();
255
+ }
256
+ this._pageData.time = time;
257
+ this._pageDataUtils.refreshPageTime(time);
258
+ }
259
+ else {
260
+ this._pageData.playing = false;
261
+ void this.setPlayProgress(100);
262
+ const scene = this.getViewProperty(this._pageData.activeData.view ?? 0)?.scene;
263
+ const targetComposition = scene?.compositions.find(c => c.id === scene.compositionId);
264
+ this._pageData.time = targetComposition?.duration ?? 2;
265
+ this._pageDataUtils.refreshPageTime(this._pageData.time);
266
+ }
267
+ }
268
+ this._eventEmitter.emit('progress', {
269
+ duration: this.player.getCompositions()[0]?.getDuration() ?? 2,
270
+ time: this._pageData.time,
271
+ end: this.player.getCompositions()[0]?.isDestroyed ?? false,
272
+ paused: !this._pageData.playing,
273
+ });
274
+ });
275
+ this.player.on('rendererror', (error) => {
276
+ console.error('player render error ', error);
277
+ });
278
+ this.player.on('webglcontextlost', () => {
279
+ this._eventEmitter.emit('viewLost');
280
+ const canvas = this.player?.canvas;
281
+ if (canvas) {
282
+ canvas.parentElement?.removeChild(canvas);
283
+ }
284
+ this.player.pause();
285
+ this.player.dispose();
286
+ this._gestureHandler.dispose();
287
+ setTimeout(async () => {
288
+ this.initPlayer(SDK.config.mode);
289
+ this._pageDataUtils = new PageDataUtils(this.player, this._playerContainer, this._eventEmitter, this);
290
+ this._gestureHandler = new GestureHandler(this._container);
291
+ this.syncCanvasLayerOrder();
292
+ const itemExtension = {};
293
+ if (SDK.config.mode === 'template') {
294
+ this.pageData?.items.forEach(item => {
295
+ itemExtension[item.id] = item.getAllExtension();
296
+ });
297
+ await this.runByPageData(this.pageData);
298
+ this.pageData?.items.forEach(item => {
299
+ const extension = itemExtension[item.id];
300
+ if (extension) {
301
+ item.setExtensions(extension);
302
+ }
303
+ });
304
+ }
305
+ else {
306
+ const createInfos = this.getItemCreateInfos();
307
+ await this.runByCreateInfos(createInfos);
308
+ }
309
+ this._eventEmitter.emit('viewRebuildFinish');
310
+ }, 300);
311
+ });
312
+ }
313
+ setSDKMode(mode) {
314
+ if (mode === SDK.config.mode) {
315
+ return;
316
+ }
317
+ SDK.config.mode = mode;
318
+ const [width, height] = mode === 'template' ? [this._container.offsetWidth, this._container.offsetHeight] : [document.documentElement.clientWidth, document.documentElement.clientHeight];
319
+ if (!this._playerContainer) {
320
+ const playerContainer = document.createElement('div');
321
+ this._container.appendChild(playerContainer);
322
+ this._playerContainer = playerContainer;
323
+ this._playerContainer.id = 'player-container';
324
+ this._playerContainer.style.position = 'absolute';
325
+ }
326
+ if (mode === 'editor') {
327
+ this._playerContainer.style.left = '0px';
328
+ this._playerContainer.style.top = '0px';
329
+ }
330
+ this._playerContainer.style.width = `${width}px`;
331
+ this._playerContainer.style.height = `${height}px`;
332
+ this.player ??= new Player({
333
+ container: this._playerContainer,
334
+ interactive: true,
335
+ pixelRatio: 2,
336
+ env: 'editor'
337
+ });
338
+ this.player.resize();
339
+ this.syncCanvasLayerOrder();
340
+ }
341
+ syncCanvasLayerOrder() {
342
+ orderSDKCanvasLayers({
343
+ container: this._container,
344
+ playerContainer: this._playerContainer,
345
+ htmlOverlayLayer: this._htmlOverlayManager?.layerElement,
346
+ gestureCanvas: this._gestureHandler?.wireframeApplication.view,
347
+ });
348
+ }
349
+ async getInitParam(param) {
350
+ const loadParam = JSON.parse(JSON.stringify(param));
351
+ if (loadParam.mode === 'editor') {
352
+ const viewSize = [this._playerContainer.offsetWidth, this._playerContainer.offsetHeight];
353
+ return {
354
+ scene: getBasicScene(viewSize),
355
+ viewParams: [
356
+ {
357
+ size: viewSize,
358
+ export: {
359
+ audioEnable: false,
360
+ },
361
+ },
362
+ ],
363
+ options: {
364
+ asyncMode: false,
365
+ safeAreaPreview: false,
366
+ adsorption: true,
367
+ },
368
+ };
369
+ }
370
+ else {
371
+ if (typeof loadParam.scene === 'string') {
372
+ try {
373
+ const response = await fetch(loadParam.scene, {
374
+ mode: 'cors',
375
+ credentials: 'omit',
376
+ headers: {
377
+ Accept: 'application/json',
378
+ },
379
+ });
380
+ if (!response.ok) {
381
+ throw new Error(`HTTP error! status: ${response.status}, statusText: ${response.statusText}`);
382
+ }
383
+ const scene = (await response.json());
384
+ const mainComposition = scene.compositions.find((c) => c.id === scene.compositionId) ?? scene.compositions[0];
385
+ const viewParams = !loadParam.viewParams?.length
386
+ ? [
387
+ {
388
+ size: mainComposition.previewSize ?? [750, 1624],
389
+ export: {
390
+ audioEnable: false,
391
+ },
392
+ },
393
+ ]
394
+ : loadParam.viewParams;
395
+ return {
396
+ ...loadParam,
397
+ scene,
398
+ viewParams,
399
+ };
400
+ }
401
+ catch (error) {
402
+ // 重新抛出错误,让 sdk#run 方法能够捕获并处理
403
+ throw new Error(`Failed to fetch scene data from ${loadParam.scene}: ${error instanceof Error ? error.message : String(error)}`);
404
+ }
405
+ }
406
+ const mainComposition = loadParam.scene.compositions.find((c) => c.id === loadParam.scene.compositionId) ?? loadParam.scene.compositions[0];
407
+ const viewParams = !loadParam.viewParams?.length
408
+ ? [
409
+ {
410
+ size: mainComposition.previewSize ?? [750, 1624],
411
+ export: {
412
+ audioEnable: false,
413
+ },
414
+ },
415
+ ]
416
+ : loadParam.viewParams;
417
+ return {
418
+ ...loadParam,
419
+ scene: loadParam.scene,
420
+ viewParams,
421
+ };
422
+ }
423
+ }
424
+ initExporter(params) {
425
+ if (!this.initExporterEnabled) {
426
+ return;
427
+ }
428
+ this._exporter = new Exporter(params);
429
+ this._exporter.on('progress', (progress) => {
430
+ this._eventEmitter.emit('exportProgress', progress);
431
+ });
432
+ this._exporter.on('done', (item, success, buffer) => {
433
+ this._eventEmitter.emit('exportDone', item, success, buffer);
434
+ });
435
+ this._exporter.on('complete', (success, taskInfos, buffers, extras) => {
436
+ this._eventEmitter.emit('exportComplete', success, taskInfos, buffers, extras);
437
+ });
438
+ }
439
+ async initSDK(param) {
440
+ const { scene, viewParams, options } = param;
441
+ const result = [];
442
+ // add static scene
443
+ if (SDK.config.pageConfig.staticPreview) {
444
+ const staticScene = JSON.parse(JSON.stringify(scene));
445
+ const mainComposition = staticScene.compositions.find((composition) => composition.id === staticScene.compositionId) ??
446
+ staticScene.compositions[0];
447
+ if (mainComposition) {
448
+ const [width, height] = mainComposition.previewSize ?? [1080, 1920];
449
+ const tick = mainComposition.duration ?? 0;
450
+ result.push({
451
+ size: [width, height],
452
+ safeArea: [0, 0, 0, 0],
453
+ previewSafeAreas: [],
454
+ id: 0,
455
+ scene: staticScene,
456
+ ignoreInteraction: true,
457
+ export: {
458
+ time: tick,
459
+ audioEnable: false,
460
+ },
461
+ });
462
+ }
463
+ }
464
+ for (let i = 0; i < viewParams.length; i++) {
465
+ const viewProperty = viewParams[i];
466
+ if (!viewProperty) {
467
+ continue;
468
+ }
469
+ let resultScene = JSON.parse(JSON.stringify(scene));
470
+ const mainComposition = resultScene.compositions.find((composition) => composition.id === resultScene.compositionId) ??
471
+ resultScene.compositions[0];
472
+ assertExist(mainComposition);
473
+ const previewSize = mainComposition.previewSize ?? [750, 1624];
474
+ const originSize = previewSize;
475
+ const resultSize = viewProperty.size ?? previewSize;
476
+ mainComposition.previewSize = resultSize;
477
+ const tick = mainComposition.duration ?? 0;
478
+ const safeArea = viewProperty.safeArea ?? [0, 0, 0, 0];
479
+ if (SDK.config.sizeAdaptConfig.enabled) {
480
+ resultScene = await this._sizeAdapt.adjustment(resultScene, tick, originSize, resultSize, safeArea, viewProperty.adaptionDirection);
481
+ }
482
+ viewProperty.export.time ??= tick;
483
+ result.push({
484
+ ...viewProperty,
485
+ size: resultSize,
486
+ safeArea,
487
+ previewSafeAreas: [...(viewProperty.previewSafeAreas ?? [])],
488
+ id: i + 1,
489
+ scene: resultScene,
490
+ ignoreInteraction: false,
491
+ });
492
+ }
493
+ const activeScene = result[0]?.scene;
494
+ if (!activeScene) {
495
+ console.warn('SDK need one view property at least.');
496
+ return;
497
+ }
498
+ const mainComposition = activeScene.compositions.find((composition) => composition.id === activeScene.compositionId) ??
499
+ activeScene.compositions[0];
500
+ const property = { ...options, zoom: 1, translation: [0, 0], asyncMode: options.asyncMode ?? false };
501
+ const time = (mainComposition?.duration ?? 0) - 0.1;
502
+ const targetIndex = SDK.config.pageConfig.staticPreview ? 1 : 0;
503
+ this._pageData = {
504
+ scene: JSON.parse(JSON.stringify(scene)),
505
+ time,
506
+ property,
507
+ activeData: {
508
+ view: result[targetIndex].id,
509
+ selectedItems: [],
510
+ },
511
+ items: [],
512
+ viewProperties: result,
513
+ playing: false,
514
+ };
515
+ this._pageDataUtils.init();
516
+ await this._gestureHandler.init(this._pageDataUtils, this._eventEmitter);
517
+ this._gestureHandler.ignoreInteraction = result[1]?.ignoreInteraction ?? false;
518
+ SDK.config.gestureHandlerConfig.preferenceGizmoConfig.safeAreaEnabled = property.safeAreaPreview;
519
+ this._eventEmitter.emit('progress', {
520
+ duration: time,
521
+ time: time,
522
+ end: this.player.getCompositions()[0]?.isDestroyed ?? false,
523
+ paused: !this._pageData.playing,
524
+ });
525
+ await this._pageDataUtils.loadScene(this._pageData.activeData.view);
526
+ this._pageDataUtils.refreshPageTime(time);
527
+ }
528
+ async run(param) {
529
+ this.setSDKMode(param.mode);
530
+ SDK.config.pageConfig.staticPreview = param.mode === 'template' && SDK.config.pageConfig.staticPreview;
531
+ const initPram = await this.getInitParam(param);
532
+ await this.initSDK(initPram);
533
+ this._eventEmitter.emit('pageDataChange', this.pageData);
534
+ this.initExporter(SDK.config.exportConfig);
535
+ }
536
+ getActiveItems() {
537
+ assertExist(this._pageData, 'You must call SDK#run() first');
538
+ return this._pageData.activeData.selectedItems;
539
+ }
540
+ setPreSelectedItem(id) {
541
+ assertExist(this._pageData, 'You must call SDK#run() first');
542
+ this._pageData.activeData.preSelectedItem = id;
543
+ }
544
+ getPreSelectedItem() {
545
+ assertExist(this._pageData, 'You must call SDK#run() first');
546
+ return this._pageData.activeData.preSelectedItem ?? '';
547
+ }
548
+ setSelectedItems(itemIds) {
549
+ this._pageDataUtils.clearPreSelectedItem();
550
+ this._pageDataUtils.clearSelectedItems();
551
+ this._pageDataUtils.addSelectedItems([...itemIds]);
552
+ }
553
+ /**
554
+ * @description 设置元素属性(支持单个元素的单/多属性设置)
555
+ * @param param 设置参数,支持两种场景:
556
+ * 1. 单个元素单个属性: { itemId, type, propertyName, propertyValue }
557
+ * 2. 单个元素多个属性: { itemId, type, property }
558
+ */
559
+ async setItemProperty(param) {
560
+ assertExist(this._pageData, 'You must call SDK#run() first');
561
+ const ignoreInteraction = this.getViewProperty(this._pageData.activeData.view ?? 0)?.ignoreInteraction;
562
+ if (ignoreInteraction) {
563
+ console.warn('Static scene cannot change.');
564
+ return;
565
+ }
566
+ await this._pageDataUtils.setItemProperty(param);
567
+ this._gestureHandler.render();
568
+ this._eventEmitter.emit('pageDataChange', this.pageData);
569
+ }
570
+ async generateScreenShot(id, size = [300, 400], tick, backgroundColor) {
571
+ assertExist(this._pageData, 'You must call SDK#run() first');
572
+ const viewProperty = this.getViewProperty(id);
573
+ if (!viewProperty) {
574
+ return '';
575
+ }
576
+ const { scene, size: [width, height], } = viewProperty;
577
+ const compositionId = scene.compositionId;
578
+ const composition = scene.compositions.find((comp) => comp.id === compositionId);
579
+ tick ??= composition?.duration ?? 0;
580
+ const targetScene = JSON.parse(JSON.stringify(scene));
581
+ const result = await this._screenShot.generate(targetScene, [width, height], size, tick, backgroundColor);
582
+ return result;
583
+ }
584
+ /**
585
+ * @description 切换场景
586
+ * @param index 场景索引
587
+ */
588
+ async switchScene(index) {
589
+ assertExist(this._pageData, 'You must call SDK#run() first');
590
+ // 相同合成不做切换
591
+ if (index === this._pageData.activeData.view) {
592
+ return;
593
+ }
594
+ this._isSwitchScene = true;
595
+ const targetView = this._pageData.viewProperties[index];
596
+ if (!targetView) {
597
+ console.warn('target scene does not exist.');
598
+ }
599
+ else {
600
+ const isPlaying = this._pageData.playing;
601
+ this._pageData.activeData = {
602
+ view: targetView.id,
603
+ selectedItems: [],
604
+ preSelectedItem: undefined,
605
+ };
606
+ await this._pageDataUtils.loadScene(targetView.id);
607
+ if (isPlaying) {
608
+ this._pageData.playing = isPlaying;
609
+ this.player.gotoAndPlay(this._pageData.time);
610
+ }
611
+ }
612
+ this._eventEmitter.emit('selectedViewChange', index);
613
+ this._eventEmitter.emit('pageDataChange', this.pageData);
614
+ this._isSwitchScene = false;
615
+ }
616
+ /**
617
+ * @description 获取页面的 safeAreaPreview、zoom、adsorption、translation 值
618
+ * @returns 页面的 safeAreaPreview、zoom、adsorption、translation 值
619
+ */
620
+ getPageConfig() {
621
+ assertExist(this._pageData, 'You must call SDK#run() first');
622
+ return {
623
+ safeAreaPreview: this._pageData.property.safeAreaPreview,
624
+ zoom: this._pageData.property.zoom,
625
+ adsorption: this._pageData.property.adsorption,
626
+ asyncMode: this._pageData.property.asyncMode,
627
+ translation: this._pageData.property.translation
628
+ };
629
+ }
630
+ /**
631
+ * 设置页面的 safeAreaPreview、zoom、adsorption 值
632
+ * @param pageProperty 设置
633
+ */
634
+ setPageConfig(pageConfig) {
635
+ assertExist(this._pageData, 'You must call SDK#run() first');
636
+ const { adsorption, safeAreaPreview, zoom } = this._pageData.property;
637
+ this._pageData.property = {
638
+ ...this._pageData.property,
639
+ ...pageConfig,
640
+ };
641
+ if (this._pageData.property.zoom !== zoom) {
642
+ this._pageDataUtils.setPageZoom(this._pageData.property.zoom);
643
+ }
644
+ if (adsorption !== pageConfig.adsorption) {
645
+ SDK.config.gestureHandlerConfig.adsorptionGizmoEnabled = pageConfig.adsorption;
646
+ }
647
+ if (safeAreaPreview !== pageConfig.safeAreaPreview) {
648
+ SDK.config.gestureHandlerConfig.preferenceGizmoConfig.safeAreaEnabled = pageConfig.safeAreaPreview;
649
+ }
650
+ this._gestureHandler.render();
651
+ }
652
+ /**
653
+ * @description 设置播放进度
654
+ * @param progress 播放进度 0-100
655
+ */
656
+ async setPlayProgress(progress) {
657
+ assertExist(this._pageData, 'You must call SDK#run() first');
658
+ const duration = this.player.getCompositions()[0]?.getDuration() ?? 2;
659
+ const time = (duration * progress) / 100;
660
+ this._pageData.time = time;
661
+ const hasCleared = !this.player.getCompositions().length;
662
+ if (hasCleared) {
663
+ clearPlayerAssets(this.player);
664
+ await this._pageDataUtils.loadScene(this._pageData.activeData.view ?? 0);
665
+ }
666
+ const playing = this._pageData.playing;
667
+ if (playing) {
668
+ this.player.gotoAndPlay(time);
669
+ }
670
+ else {
671
+ this.player.gotoAndStop(time);
672
+ this._eventEmitter.emit('progress', {
673
+ duration: this.player.getCompositions()[0]?.getDuration() ?? 2,
674
+ time,
675
+ end: this.player.getCompositions()[0]?.isDestroyed ?? false,
676
+ paused: true,
677
+ });
678
+ }
679
+ this._pageDataUtils.refreshPageTime(time);
680
+ }
681
+ /**
682
+ * @description 获取元素
683
+ * @param id 元素ID
684
+ * @returns 元素
685
+ * */
686
+ getSDKItem(id) {
687
+ return this._pageDataUtils.getSDKItem(id);
688
+ }
689
+ /**
690
+ * @description 获取元素数组
691
+ * @param id 元素ID数组
692
+ * @returns 元素数组
693
+ * */
694
+ getSDKItems(ids) {
695
+ if (!ids) {
696
+ return this.pageData?.items ?? [];
697
+ }
698
+ return ids.map(id => this.getSDKItem(id)).filter((v) => !!v);
699
+ }
700
+ async setPlayState(playState) {
701
+ assertExist(this._pageData, 'You must call SDK#run() first');
702
+ const playing = playState === 'play';
703
+ if (this._pageData.playing === playing) {
704
+ return;
705
+ }
706
+ this._pageData.playing = playing;
707
+ this._gestureHandler.ignoreInteraction = playing;
708
+ if (playing) {
709
+ const compositions = this.player.getCompositions();
710
+ const acitveViewProperty = this.getViewProperty(this._pageData.activeData.view ?? 0);
711
+ const playScene = JSON.parse(JSON.stringify(acitveViewProperty.scene));
712
+ await this.player.loadScene(playScene, { autoplay: false });
713
+ this.player.gotoAndPlay(this._pageData.time);
714
+ this.destroyCompositions(compositions);
715
+ }
716
+ else {
717
+ this.player.gotoAndStop(this._pageData.time);
718
+ }
719
+ this._gestureHandler.render();
720
+ }
721
+ /**
722
+ * @description 获取场景预览图
723
+ * @returns 视图预览图
724
+ */
725
+ getViewThumbnail() {
726
+ assertExist(this._pageData, 'You must call SDK#run() first');
727
+ return this._pageData.viewProperties.map(async (property) => {
728
+ return {
729
+ id: property.id,
730
+ thumbnail: await this.generateScreenShot(property.id)
731
+ };
732
+ });
733
+ }
734
+ /**
735
+ * @description 获取视图JSON产物
736
+ * @returns 当前所有视图JSON产物
737
+ */
738
+ getViewScene() {
739
+ assertExist(this._pageData, 'You must call SDK#run() first');
740
+ return this._pageData.viewProperties.map((property) => {
741
+ return {
742
+ id: property.id,
743
+ thumbnail: property.scene,
744
+ };
745
+ });
746
+ }
747
+ destroyCompositions(compositions) {
748
+ compositions.forEach((comp) => {
749
+ comp.dispose();
750
+ const currentCompositions = this.player.getCompositions();
751
+ const index = currentCompositions.indexOf(comp);
752
+ if (index > -1) {
753
+ currentCompositions.splice(index, 1);
754
+ }
755
+ });
756
+ }
757
+ /**
758
+ * @description 以媒体格式 buffer 下载
759
+ */
760
+ downloadByMediaBuffersOfExporter(params, buffers, extras) {
761
+ assertExist(this._exporter, 'You must init exporter first');
762
+ this._exporter.downloadByMediaBuffers(params, buffers, extras);
763
+ }
764
+ /**
765
+ * @description 导出
766
+ * 支持导出媒体或其他,如MP4,未来支持 JSON 等;
767
+ */
768
+ onExport() {
769
+ if (!SDK.config.exportConfig.enabled) {
770
+ return;
771
+ }
772
+ assertExist(this.pageData, 'You must call SDK#run() first');
773
+ assertExist(this._exporter, 'You must init exporter first');
774
+ this._exporter.onExport(this.exportOptions);
775
+ }
776
+ /**
777
+ * @description 取消导出
778
+ */
779
+ cancelExport() {
780
+ assertExist(this._exporter, 'You must init exporter first');
781
+ this._exporter.onCancel();
782
+ }
783
+ async loadPageData(data) {
784
+ assertExist(this._pageData, 'You must call SDK#run() first');
785
+ this._pageData.activeData = {
786
+ view: this._pageData.viewProperties[this._pageData.viewProperties.length - 1].id,
787
+ selectedItems: [],
788
+ preSelectedItem: undefined,
789
+ };
790
+ this._pageData.viewProperties.push(...data.viewProperties);
791
+ this._pageDataUtils.init();
792
+ await this._gestureHandler.init(this._pageDataUtils, this._eventEmitter);
793
+ await this._pageDataUtils.loadScene(this.pageData?.activeData.view ?? 0);
794
+ this._eventEmitter.emit('pageDataChange', this.pageData);
795
+ }
796
+ async runByPageData(data) {
797
+ const loadData = JSON.parse(JSON.stringify(data));
798
+ loadData.property.zoom = 1;
799
+ loadData.property.translation = [0, 0];
800
+ this._pageData = loadData;
801
+ this._pageDataUtils.init();
802
+ await this._gestureHandler.init(this._pageDataUtils, this._eventEmitter);
803
+ await this._pageDataUtils.loadScene(this.pageData?.activeData.view ?? 0);
804
+ this._pageDataUtils.refreshPageTime(this._pageData.time);
805
+ this._eventEmitter.emit('pageDataChange', this.pageData);
806
+ }
807
+ async runByCreateInfos(createInfos) {
808
+ assertExist(this._pageData, 'You must call SDK#run() first');
809
+ this._pageData.property.zoom = 1;
810
+ this._pageData.property.translation = [0, 0];
811
+ this._pageDataUtils.init();
812
+ await this._gestureHandler.init(this._pageDataUtils, this._eventEmitter);
813
+ const viewSize = [this._playerContainer.offsetWidth, this._playerContainer.offsetHeight];
814
+ const scene = getBasicScene(viewSize);
815
+ const targetViewProperty = this.getViewProperty(this._pageData.activeData.view ?? 0);
816
+ if (targetViewProperty) {
817
+ targetViewProperty.scene = scene;
818
+ }
819
+ await this._pageDataUtils.loadScene(this._pageData.activeData.view ?? 0);
820
+ await this.addItemByCreateInfos(createInfos);
821
+ this._pageDataUtils.refreshPageTime(this._pageData.time);
822
+ this._eventEmitter.emit('pageDataChange', this.pageData);
823
+ }
824
+ async reloadPageDataByScene(scene) {
825
+ assertExist(this._pageData, 'You must call SDK#run() first');
826
+ let loadScene = JSON.parse(JSON.stringify(scene));
827
+ if (typeof loadScene === 'string') {
828
+ try {
829
+ const response = await fetch(loadScene, {
830
+ mode: 'cors',
831
+ credentials: 'omit',
832
+ headers: {
833
+ Accept: 'application/json',
834
+ },
835
+ });
836
+ if (!response.ok) {
837
+ throw new Error(`HTTP error! status: ${response.status}, statusText: ${response.statusText}`);
838
+ }
839
+ loadScene = await response.json();
840
+ }
841
+ catch (error) {
842
+ // 重新抛出错误,让 sdk#run 方法能够捕获并处理
843
+ throw new Error(`Failed to fetch scene data from ${loadScene}: ${error instanceof Error ? error.message : String(error)}`);
844
+ }
845
+ }
846
+ this._pageData.time =
847
+ loadScene.compositions.find((composition) => composition.id === loadScene.compositionId)
848
+ ?.duration ?? 2;
849
+ this._pageData.viewProperties.forEach((viewProperty) => {
850
+ viewProperty.scene = JSON.parse(JSON.stringify(loadScene));
851
+ });
852
+ this._pageDataUtils.init();
853
+ await this._gestureHandler.init(this._pageDataUtils, this._eventEmitter);
854
+ await this._pageDataUtils.loadScene(this._pageData.activeData.view ?? 0);
855
+ this._eventEmitter.emit('progress', {
856
+ duration: this.player.getCompositions()[0]?.getDuration() ?? 2,
857
+ time: this._pageData.time,
858
+ end: this.player.getCompositions()[0]?.isDestroyed ?? false,
859
+ paused: !this._pageData.playing,
860
+ });
861
+ }
862
+ /**
863
+ * @description 新增视图数据
864
+ * @param viewParams 视图参数
865
+ * @param scene 场景数据 - 无输入时为默认场景数据
866
+ */
867
+ async addViewParams(viewParams, scene) {
868
+ assertExist(this._pageData);
869
+ const result = [];
870
+ const originLength = this._pageData.viewProperties[this._pageData.viewProperties.length - 1]?.id ??
871
+ this._pageData.viewProperties.length - 1;
872
+ for (let i = 0; i < viewParams.length; i++) {
873
+ const viewProperty = viewParams[i];
874
+ if (!viewProperty) {
875
+ continue;
876
+ }
877
+ let resultScene = JSON.parse(JSON.stringify(scene ?? this._pageData.scene));
878
+ const mainComposition = resultScene.compositions.find((composition) => composition.id === resultScene.compositionId) ??
879
+ resultScene.compositions[0];
880
+ assertExist(mainComposition);
881
+ const { previewSize = [750, 1624] } = mainComposition;
882
+ const originSize = previewSize;
883
+ const resultSize = viewProperty.size ?? previewSize;
884
+ mainComposition.previewSize = resultSize;
885
+ const tick = mainComposition.duration ?? 0;
886
+ const safeArea = viewProperty.safeArea ?? [0, 0, 0, 0];
887
+ if (SDK.config.sizeAdaptConfig.enabled) {
888
+ resultScene = await this._sizeAdapt.adjustment(resultScene, tick, originSize, resultSize, safeArea, viewProperty.adaptionDirection);
889
+ }
890
+ viewProperty.export.time ??= tick;
891
+ result.push({
892
+ ...viewProperty,
893
+ size: resultSize,
894
+ safeArea,
895
+ previewSafeAreas: [...(viewProperty.previewSafeAreas ?? [])],
896
+ id: originLength + 1 + i,
897
+ scene: resultScene,
898
+ ignoreInteraction: false,
899
+ });
900
+ }
901
+ this._pageData.viewProperties.push(...result);
902
+ this._eventEmitter.emit('pageDataChange', this.pageData);
903
+ }
904
+ async deleteViewParams(ids) {
905
+ ids.sort((a, b) => a - b);
906
+ for (let index = 0; index < ids.length; index++) {
907
+ const id = ids[index];
908
+ assertExist(this._pageData);
909
+ const targetId = id - index;
910
+ const targetIndex = this._pageData.viewProperties.findIndex((vp) => vp.id === targetId);
911
+ if (this._pageData.viewProperties[targetIndex]?.ignoreInteraction) {
912
+ console.warn('target view ignore interaction, it can not be deleted.');
913
+ continue;
914
+ }
915
+ if (targetIndex < 0) {
916
+ console.warn('Target view is not existed.');
917
+ continue;
918
+ }
919
+ this._pageData.viewProperties.splice(targetIndex, 1);
920
+ const selectedView = this._pageData.activeData.view ?? 0;
921
+ if (targetId === selectedView) {
922
+ this._pageData.activeData.view = 0;
923
+ await this._pageDataUtils.loadScene(0);
924
+ }
925
+ else if (targetId < selectedView) {
926
+ this._pageData.activeData.view = selectedView - 1;
927
+ }
928
+ this._pageData.viewProperties.forEach((vp) => {
929
+ if (vp.id > targetId) {
930
+ vp.id -= 1;
931
+ }
932
+ });
933
+ }
934
+ this._eventEmitter.emit('selectedViewChange', this._pageData?.activeData?.view ?? 0);
935
+ this._eventEmitter.emit('pageDataChange', this.pageData);
936
+ }
937
+ setExportParam(exportParam, id) {
938
+ assertExist(this._pageData);
939
+ this._pageData.viewProperties.forEach((viewPort) => {
940
+ if (id === undefined || viewPort.id === id) {
941
+ Object.assign(viewPort.export, exportParam);
942
+ }
943
+ });
944
+ }
945
+ /**
946
+ * @description 设置视图缩放
947
+ * @param zoom 缩放值
948
+ * @param center 缩放中心
949
+ * @param ignoreClamp 是否忽视约束
950
+ */
951
+ setPageZoom(zoom, center, ignoreClamp) {
952
+ assertExist(this._pageData);
953
+ this._pageDataUtils.setPageZoom(zoom, center, ignoreClamp);
954
+ this._gestureHandler.render();
955
+ }
956
+ /**
957
+ * @description 设置元素移动
958
+ * @param targetTranslation 目标移动值
959
+ */
960
+ setPageMove(targetTranslation) {
961
+ assertExist(this._pageData);
962
+ this._pageData.property.translation = targetTranslation.toArray();
963
+ this._pageDataUtils.setPageMove(targetTranslation.clone());
964
+ this._gestureHandler.render();
965
+ }
966
+ /**
967
+ * @description 设置静态预览功能开关
968
+ * @param enabled 功能开关
969
+ */
970
+ setStaticPreviewEnabled(enabled) {
971
+ SDK.config.pageConfig.staticPreview = enabled;
972
+ }
973
+ /**
974
+ * @description 设置静态预览视图名称
975
+ * @param name 视图名称
976
+ */
977
+ setStaticPreviewName(name) {
978
+ SDK.config.pageConfig.staticPreviewName = name;
979
+ }
980
+ /**
981
+ * @description 设置同步修改功能开关
982
+ * @param enabled 功能开关
983
+ */
984
+ setAsyncEnabled(enabled) {
985
+ SDK.config.pageConfig.asncMode = enabled;
986
+ }
987
+ /**
988
+ * @description 设置 成组显影 开关
989
+ */
990
+ setGroupVisibleEnabled(enabled) {
991
+ SDK.config.pageConfig.groupVisible = enabled;
992
+ }
993
+ /**
994
+ * @description 新增过滤元素名称
995
+ * @param itemNames 过滤元素名称
996
+ */
997
+ addFilterItemNames(itemNames) {
998
+ if (typeof itemNames === 'string') {
999
+ arrAdd(SDK.config.pageConfig.filterItemNames, itemNames);
1000
+ }
1001
+ else {
1002
+ itemNames.forEach((name) => {
1003
+ arrAdd(SDK.config.pageConfig.filterItemNames, name);
1004
+ });
1005
+ }
1006
+ }
1007
+ /**
1008
+ * @description 设置预览辅助层颜色
1009
+ * @param color 色值
1010
+ */
1011
+ setPreferenceBackgroundColor(color) {
1012
+ SDK.config.gestureHandlerConfig.preferenceGizmoConfig.markColor = (color[0] << 16) | (color[1] << 8) | color[2];
1013
+ SDK.config.gestureHandlerConfig.preferenceGizmoConfig.markAlpha = color[3] ?? 0.3;
1014
+ this._gestureHandler.render();
1015
+ }
1016
+ /**
1017
+ * @description 设置出血区颜色
1018
+ * @param color 色值
1019
+ */
1020
+ setSafeAreaColor(color) {
1021
+ SDK.config.gestureHandlerConfig.preferenceGizmoConfig.safeAreaBoxColor =
1022
+ (color[0] << 16) | (color[1] << 8) | color[2];
1023
+ SDK.config.gestureHandlerConfig.preferenceGizmoConfig.safeAreaBoxAlpha = color[3] ?? 0.3;
1024
+ this._gestureHandler.render();
1025
+ }
1026
+ /**
1027
+ * @description 设置 尺寸自适应拓展 功能开关
1028
+ * @param enabled 功能开关
1029
+ */
1030
+ setSizeAdaptEnabled(enabled) {
1031
+ SDK.config.sizeAdaptConfig.enabled = enabled;
1032
+ }
1033
+ /**
1034
+ * @description 设置 截图 功能开关
1035
+ * @param enabled 功能开关
1036
+ */
1037
+ setScreenShotEnabled(enabled) {
1038
+ SDK.config.screenShotConfig.enabled = enabled;
1039
+ }
1040
+ /**
1041
+ * @description 设置导出功能初始化配置
1042
+ * @param exportConfig
1043
+ */
1044
+ setExportConfig(exportConfig) {
1045
+ const newExportConfig = merge({}, SDK.config.exportConfig, exportConfig);
1046
+ SDK.config.exportConfig = newExportConfig;
1047
+ if (this._exporter) {
1048
+ this._exporter.setOptions(newExportConfig);
1049
+ }
1050
+ else {
1051
+ this.initExporter(newExportConfig);
1052
+ }
1053
+ }
1054
+ /**
1055
+ * @description 设置预选框参数
1056
+ * @param preSelectedColor 预选框颜色
1057
+ * @param preSelectedWidth 预选框线框宽度
1058
+ */
1059
+ setSelectorGizmoPreSelectConfig(preSelectedColor, preSelectedWidth) {
1060
+ if (preSelectedColor !== undefined) {
1061
+ SDK.config.gestureHandlerConfig.selectorGizmoConfig.preSelectedColor = preSelectedColor;
1062
+ }
1063
+ if (preSelectedWidth !== undefined) {
1064
+ SDK.config.gestureHandlerConfig.selectorGizmoConfig.preSelectedWidth = preSelectedWidth;
1065
+ }
1066
+ this._gestureHandler.render();
1067
+ }
1068
+ /**
1069
+ * @description 设置 变换控制器 交互框参数
1070
+ * @param config 参数
1071
+ */
1072
+ setTranformGizmoWireframeConfig(config) {
1073
+ if (config.wireframeAlpha !== undefined) {
1074
+ SDK.config.gestureHandlerConfig.transformGizmoConfig.wireframeAlpha = config.wireframeAlpha;
1075
+ }
1076
+ if (config.wireframeColor !== undefined) {
1077
+ SDK.config.gestureHandlerConfig.transformGizmoConfig.wireframeColor = config.wireframeColor;
1078
+ }
1079
+ if (config.wireframeWidth !== undefined) {
1080
+ SDK.config.gestureHandlerConfig.transformGizmoConfig.wireframeWidth = config.wireframeWidth;
1081
+ }
1082
+ this._gestureHandler.render();
1083
+ }
1084
+ /**
1085
+ * @description 获取 SDK 配置参数
1086
+ * @returns SDK 配置参数
1087
+ */
1088
+ getSDKConfig() {
1089
+ return SDK.config;
1090
+ }
1091
+ /**
1092
+ * @description 设置 SDK 配置参数
1093
+ * @param config SDK 配置参数
1094
+ */
1095
+ setSDKConfig(config) {
1096
+ const sdkConfig = Object.assign({}, SDK.config);
1097
+ this._eventEmitter.emit('sdkConfigChange', sdkConfig, config);
1098
+ SDK.config = config;
1099
+ }
1100
+ /**
1101
+ * @description 设置SDK背景
1102
+ * @param type 背景类型
1103
+ * @param value 值
1104
+ */
1105
+ setSDKBackground(type, value) {
1106
+ switch (type) {
1107
+ case 'color': {
1108
+ this.backgroundManager.setColorBackground(value ?? '');
1109
+ break;
1110
+ }
1111
+ case 'image': {
1112
+ if (value) {
1113
+ this.backgroundManager.setImageBackground(value);
1114
+ }
1115
+ break;
1116
+ }
1117
+ case 'chess-board':
1118
+ case 'dot-board': {
1119
+ this.backgroundManager.applyPreset(type, value);
1120
+ break;
1121
+ }
1122
+ }
1123
+ }
1124
+ /**
1125
+ * @description 创建图层元素
1126
+ * @param spriteInfo 图层元素信息
1127
+ */
1128
+ async addSpriteItem(spriteInfo, scene) {
1129
+ return await this._pageDataUtils.addSpriteItem(spriteInfo, false, scene);
1130
+ }
1131
+ async addVideoItem(videoInfo, scene) {
1132
+ return await this._pageDataUtils.addVideoItem(videoInfo, false, scene);
1133
+ }
1134
+ openPictureCutGizmo() {
1135
+ this._gestureHandler.openPictureCutGizmo();
1136
+ this._gestureHandler.render();
1137
+ }
1138
+ closePictureCutGizmo() {
1139
+ this._gestureHandler.closePictureCutGizmo();
1140
+ }
1141
+ getCutInfo() {
1142
+ return this._gestureHandler.getCutInfo();
1143
+ }
1144
+ setCutBox(min, max) {
1145
+ return this._gestureHandler.setCutBox(min, max);
1146
+ }
1147
+ openPictureExpandGizmo() {
1148
+ this._gestureHandler.openPictureExpandGizmo();
1149
+ this._gestureHandler.render();
1150
+ }
1151
+ closePictureExpandGizmo() {
1152
+ this._gestureHandler.closePictureExpandGizmo();
1153
+ }
1154
+ getExpandInfo() {
1155
+ return this._gestureHandler.getExpandInfo();
1156
+ }
1157
+ setExpandBox(min, max) {
1158
+ return this._gestureHandler.setExpandBox(min, max);
1159
+ }
1160
+ openMaskGizmo(brushSize) {
1161
+ this._gestureHandler.openMaskGizmo(brushSize);
1162
+ this._gestureHandler.render();
1163
+ }
1164
+ clearMaskGizmo() {
1165
+ this._gestureHandler.clearMaskGizmo();
1166
+ }
1167
+ closeMaskGizmo() {
1168
+ this._gestureHandler.closeMaskGizmo();
1169
+ }
1170
+ getMask() {
1171
+ return this._gestureHandler.getMask();
1172
+ }
1173
+ setMaskGizmoConfig(config) {
1174
+ this._gestureHandler.setMaskGizmoConfig(config);
1175
+ }
1176
+ /**
1177
+ * @description 设置蒙版工具模式
1178
+ * @param mode 模式类型:'paint' 笔刷涂抹、'erase' 笔刷逐笔擦除、'box-erase' 框选擦除、'box-paint' 框选涂抹
1179
+ */
1180
+ setMaskGizmoMode(mode) {
1181
+ this._gestureHandler.setMaskGizmoMode(mode);
1182
+ }
1183
+ /**
1184
+ * 撤销蒙版操作
1185
+ * @returns 是否成功撤销
1186
+ */
1187
+ undoMaskGizmo() {
1188
+ return this._gestureHandler.maskGizmoUndo();
1189
+ }
1190
+ /**
1191
+ * 重做蒙版操作
1192
+ * @returns 是否成功重做
1193
+ */
1194
+ redoMaskGizmo() {
1195
+ return this._gestureHandler.maskGizmoRedo();
1196
+ }
1197
+ /**
1198
+ * 检查蒙版是否可以撤销
1199
+ */
1200
+ get canUndoMaskGizmo() {
1201
+ return this._gestureHandler.maskGizmoCanUndo;
1202
+ }
1203
+ /**
1204
+ * 检查蒙版是否可以重做
1205
+ */
1206
+ get canRedoMaskGizmo() {
1207
+ return this._gestureHandler.maskGizmoCanRedo;
1208
+ }
1209
+ /**
1210
+ * 清空蒙版 undoRedo 历史
1211
+ */
1212
+ clearMaskGizmoUndoRedo() {
1213
+ this._gestureHandler.clearMaskGizmoUndoRedo();
1214
+ }
1215
+ /**
1216
+ * 撤销图片裁切操作
1217
+ * @returns 是否成功撤销
1218
+ */
1219
+ undoPictureCutGizmo() {
1220
+ return this._gestureHandler.pictureCutGizmoUndo();
1221
+ }
1222
+ /**
1223
+ * 重做图片裁切操作
1224
+ * @returns 是否成功重做
1225
+ */
1226
+ redoPictureCutGizmo() {
1227
+ return this._gestureHandler.pictureCutGizmoRedo();
1228
+ }
1229
+ /**
1230
+ * 检查图片裁切是否可以撤销
1231
+ */
1232
+ get canUndoPictureCutGizmo() {
1233
+ return this._gestureHandler.pictureCutGizmoCanUndo;
1234
+ }
1235
+ /**
1236
+ * 检查图片裁切是否可以重做
1237
+ */
1238
+ get canRedoPictureCutGizmo() {
1239
+ return this._gestureHandler.pictureCutGizmoCanRedo;
1240
+ }
1241
+ /**
1242
+ * 清空图片裁切 undoRedo 历史
1243
+ */
1244
+ clearPictureCutGizmoUndoRedo() {
1245
+ this._gestureHandler.clearPictureCutGizmoUndoRedo();
1246
+ }
1247
+ openLoadingGizmo(id, options) {
1248
+ this._gestureHandler.openLoadingGizmo(id, options);
1249
+ }
1250
+ updateLoadingGizmo(id, options) {
1251
+ this._gestureHandler.updateLoadingGizmo(id, options);
1252
+ }
1253
+ closeLoadingGizmo(id) {
1254
+ this._gestureHandler.closeLoadingGizmo(id);
1255
+ }
1256
+ /**
1257
+ * @description 元素打组
1258
+ * @param children 子元素ID
1259
+ */
1260
+ groupItems(groupInfo, scene) {
1261
+ return this._pageDataUtils.addGroupItem(groupInfo, scene);
1262
+ }
1263
+ setItemParent(id, parentId) {
1264
+ this._pageDataUtils.setItemParent(id, parentId);
1265
+ }
1266
+ deleteItemParent(id, parentId) {
1267
+ this._pageDataUtils.deleteItemParent(id, parentId);
1268
+ }
1269
+ async addTextItem(textInfo, scene) {
1270
+ return await this._pageDataUtils.addTextItem(textInfo, scene);
1271
+ }
1272
+ async addItemByCreateInfos(createInfos, asyncMode = false) {
1273
+ if (!asyncMode) {
1274
+ const reuslt = await this._pageDataUtils.addItemByCreateInfos(createInfos);
1275
+ return reuslt;
1276
+ }
1277
+ else {
1278
+ const reuslt = await this._pageDataUtils.asyncAddItemByCreateInfos(createInfos);
1279
+ return reuslt;
1280
+ }
1281
+ }
1282
+ deleteItems(idInfo) {
1283
+ assertExist(this._pageData, 'You must call SDK#run() first');
1284
+ if (Array.isArray(idInfo)) {
1285
+ idInfo.forEach((id) => {
1286
+ this._pageDataUtils.deleteItem(id);
1287
+ });
1288
+ const resultSelectedIds = this._pageData.activeData.selectedItems.filter(id => !idInfo.includes(id));
1289
+ this._pageData.activeData.selectedItems = [...resultSelectedIds];
1290
+ this._eventEmitter.emit('selectedItemChange', resultSelectedIds);
1291
+ }
1292
+ else {
1293
+ this._pageDataUtils.deleteItem(idInfo);
1294
+ const resultSelectedIds = this._pageData.activeData.selectedItems.filter(id => id !== idInfo);
1295
+ this._pageData.activeData.selectedItems = [...resultSelectedIds];
1296
+ this._eventEmitter.emit('selectedItemChange', resultSelectedIds);
1297
+ }
1298
+ this._pageDataUtils.interactionUtils.refreshViewParam();
1299
+ this._pageDataUtils.interactionUtils.refreshCameraParam();
1300
+ const composition = this._pageDataUtils.getCurrentComposition();
1301
+ this._pageDataUtils.addSDKItemsByItems(this._pageData.items, composition.items);
1302
+ this._eventEmitter.emit('pageDataChange', this._pageData);
1303
+ }
1304
+ getItemCreateInfo(id) {
1305
+ const createInfo = this._pageDataUtils.getItemCreateInfo(id, false);
1306
+ return createInfo;
1307
+ }
1308
+ getItemCreateInfos(ids) {
1309
+ const createInfos = [];
1310
+ ids ??= this._pageData?.items.map(item => item.id) ?? [];
1311
+ ids.forEach((id) => {
1312
+ const createInfo = this._pageDataUtils.getItemCreateInfo(id, true) ?? this.pageData?.items.find(item => item.id === id)?.toCreateInfo(true);
1313
+ if (createInfo) {
1314
+ createInfos.push(createInfo);
1315
+ }
1316
+ });
1317
+ return createInfos;
1318
+ }
1319
+ async createScreenShotSceneByIds(idInfo, time = 0) {
1320
+ const scene = await this._pageDataUtils.createScreenShotSceneByIds(idInfo, async (cardCreateInfo) => {
1321
+ const id = cardCreateInfo.id;
1322
+ if (!id) {
1323
+ return undefined;
1324
+ }
1325
+ return this._htmlOverlayManager?.rasterizeCard(id, {
1326
+ width: cardCreateInfo.property.width,
1327
+ height: cardCreateInfo.property.height,
1328
+ pixelRatio: 2,
1329
+ });
1330
+ });
1331
+ if (!scene) {
1332
+ return undefined;
1333
+ }
1334
+ const mainCompositionSize = scene?.compositions[0]?.previewSize ?? [750, 1624];
1335
+ const thumbnail = await this._screenShot.generate(scene, mainCompositionSize, mainCompositionSize, time);
1336
+ return thumbnail;
1337
+ }
1338
+ async createScreenShotByFrame(id) {
1339
+ const frameItem = this.getSDKItem(id);
1340
+ if (!isFrameItem(frameItem)) {
1341
+ console.warn(`Item ${id} is not frame item, check your input.`);
1342
+ return;
1343
+ }
1344
+ const itemBox = this.getItemBoxById(frameItem.id);
1345
+ const childrenCreateInfos = this.getItemCreateInfos([...frameItem.children]);
1346
+ const targetScene = this._pageDataUtils.createSceneByCreateInfos(childrenCreateInfos, itemBox.getSize().toArray(), '画板', itemBox.getCenter().toArray());
1347
+ if (!targetScene) {
1348
+ console.warn('Target scene is not existed.');
1349
+ return;
1350
+ }
1351
+ const mainCompositionSize = targetScene?.compositions[0]?.previewSize ?? [750, 1624];
1352
+ const thumbnail = await this._screenShot.generate(targetScene, mainCompositionSize, mainCompositionSize, 0);
1353
+ return thumbnail;
1354
+ }
1355
+ async createScreenShotByEffects(id) {
1356
+ const effectsItem = this.getSDKItem(id);
1357
+ if (!isEffectsItem(effectsItem)) {
1358
+ console.warn(`Item ${id} is not a effects item.`);
1359
+ return;
1360
+ }
1361
+ const targetScene = effectsItem.effects;
1362
+ const playerTime = this._pageDataUtils.getEffectsItemPlayTime(id) ?? 0;
1363
+ const mainCompositionSize = [effectsItem.width, effectsItem.height];
1364
+ const thumbnail = await this._screenShot.generate(targetScene, mainCompositionSize, mainCompositionSize, playerTime);
1365
+ return thumbnail;
1366
+ }
1367
+ getChildrenIds(id) {
1368
+ return this._pageDataUtils.getChildrenIds(id);
1369
+ }
1370
+ /**
1371
+ * @description 更新元素在图层中的顺序
1372
+ * @param id 元素ID
1373
+ * @param action 排序操作:BringToFront(置于顶层)、SendToBack(置于底层)、BringForward(上移一层)、SendBackward(下移一层)
1374
+ */
1375
+ updateItemOrder(id, action) {
1376
+ assertExist(this._pageData, 'You must call SDK#run() first');
1377
+ const ignoreInteraction = this.getViewProperty(this._pageData.activeData.view ?? 0)?.ignoreInteraction;
1378
+ if (ignoreInteraction) {
1379
+ console.warn('Static scene cannot change.');
1380
+ return;
1381
+ }
1382
+ this._pageDataUtils.updateItemOrder(id, action);
1383
+ this._gestureHandler.render();
1384
+ }
1385
+ /**
1386
+ * @description 导出JSON
1387
+ * @param idInfo 视图序号信息
1388
+ * @returns JSON数组
1389
+ */
1390
+ exportJSON(idInfo) {
1391
+ assertExist(this._pageData, 'You must call SDK#run() first');
1392
+ const result = [];
1393
+ if (Array.isArray(idInfo)) {
1394
+ idInfo.forEach(id => {
1395
+ const targetView = this.getViewProperty(id);
1396
+ if (targetView) {
1397
+ result.push(targetView.scene);
1398
+ }
1399
+ else {
1400
+ console.warn(`view id ${id} is not existed.`);
1401
+ }
1402
+ });
1403
+ }
1404
+ else if (idInfo !== undefined) {
1405
+ const targetView = this.getViewProperty(idInfo);
1406
+ if (targetView) {
1407
+ result.push(targetView.scene);
1408
+ }
1409
+ else {
1410
+ console.warn(`view id ${idInfo} is not existed.`);
1411
+ }
1412
+ }
1413
+ else {
1414
+ result.push(...this._pageData.viewProperties.map(viewProperty => viewProperty.scene));
1415
+ }
1416
+ return result;
1417
+ }
1418
+ getViewBoxById(id) {
1419
+ return this._pageDataUtils.getViewBoxById(id);
1420
+ }
1421
+ /**
1422
+ * @description 批量设置元素扩展属性
1423
+ * @param id 元素ID
1424
+ * @param extensions 扩展属性对象(支持同时设置多个)
1425
+ * @returns 是否设置成功
1426
+ */
1427
+ setItemExtension(id, extension) {
1428
+ assertExist(this._pageData, 'You must call SDK#run() first');
1429
+ const item = this._pageDataUtils.getSDKItem(id);
1430
+ if (!item) {
1431
+ console.warn(`Item ${id} not found`);
1432
+ return false;
1433
+ }
1434
+ Object.entries(extension).forEach(([key, value]) => {
1435
+ item.setExtension(key, value);
1436
+ });
1437
+ this._eventEmitter.emit('pageDataChange', this.pageData);
1438
+ return true;
1439
+ }
1440
+ /**
1441
+ * @description 批量获取元素扩展属性
1442
+ * @param id 元素ID
1443
+ * @param keys 扩展属性名称列表(不传则返回所有扩展属性)
1444
+ * @returns 扩展属性对象
1445
+ */
1446
+ getItemExtension(id, keys) {
1447
+ assertExist(this._pageData, 'You must call SDK#run() first');
1448
+ const item = this._pageDataUtils.getSDKItem(id);
1449
+ if (!item) {
1450
+ console.warn(`Item ${id} not found`);
1451
+ return undefined;
1452
+ }
1453
+ if (!keys || keys.length === 0) {
1454
+ return item.getAllExtension();
1455
+ }
1456
+ const result = {};
1457
+ keys.forEach(key => {
1458
+ if (item.hasExtension(key)) {
1459
+ result[key] = item.getExtension(key);
1460
+ }
1461
+ });
1462
+ return result;
1463
+ }
1464
+ /**
1465
+ * @description 删除元素扩展属性(支持批量删除)
1466
+ * @param id 元素ID
1467
+ * @param keys 扩展属性名称列表
1468
+ * @returns 是否删除成功
1469
+ */
1470
+ deleteItemExtensions(id, keys) {
1471
+ assertExist(this._pageData, 'You must call SDK#run() first');
1472
+ const item = this._pageDataUtils.getSDKItem(id);
1473
+ if (!item) {
1474
+ console.warn(`Item ${id} not found`);
1475
+ return false;
1476
+ }
1477
+ keys.forEach(key => {
1478
+ item.deleteExtension(key);
1479
+ });
1480
+ this._eventEmitter.emit('pageDataChange', this.pageData);
1481
+ return true;
1482
+ }
1483
+ /**
1484
+ * @description 检查元素是否有指定扩展属性
1485
+ * @param id 元素ID
1486
+ * @param key 扩展属性名称
1487
+ * @returns 是否存在
1488
+ */
1489
+ hasItemExtension(id, key) {
1490
+ assertExist(this._pageData, 'You must call SDK#run() first');
1491
+ const item = this._pageDataUtils.getSDKItem(id);
1492
+ if (!item) {
1493
+ return false;
1494
+ }
1495
+ return item.hasExtension(key);
1496
+ }
1497
+ /**
1498
+ * @description 获取元素所有扩展属性的键名列表
1499
+ * @param id 元素ID
1500
+ * @returns 键名数组
1501
+ */
1502
+ getItemExtensionKeys(id) {
1503
+ assertExist(this._pageData, 'You must call SDK#run() first');
1504
+ const item = this._pageDataUtils.getSDKItem(id);
1505
+ if (!item) {
1506
+ console.warn(`Item ${id} not found`);
1507
+ return undefined;
1508
+ }
1509
+ return item.getExtensionKeys();
1510
+ }
1511
+ getViewProperty(id) {
1512
+ return this._pageDataUtils.getViewProperty(id);
1513
+ }
1514
+ pageMove(shift) {
1515
+ this._pageDataUtils.pageMove(new Vector2(...shift));
1516
+ }
1517
+ pageZoom(shift, center) {
1518
+ this._pageDataUtils.pageZoom(shift, center ? new Vector2(...center) : undefined);
1519
+ }
1520
+ /**
1521
+ * @description 设置视图缩放工具锁定缩放比例开关
1522
+ * @param state 缩放比例开关
1523
+ */
1524
+ setPictureCutGizmoLockScale(state) {
1525
+ this._gestureHandler.setPictureCutGizmoLockScale(state);
1526
+ }
1527
+ /**
1528
+ * @description 设置视图扩展工具锁定缩放比例开关
1529
+ * @param state 缩放比例开关
1530
+ */
1531
+ setPictureExpandGizmoLockScale(state) {
1532
+ this._gestureHandler.setPictureExpandGizmoLockScale(state);
1533
+ }
1534
+ /**
1535
+ * @description 视图缩放函数
1536
+ * @param shiftParam 视图偏移值
1537
+ */
1538
+ viewportFit(shiftParam, box) {
1539
+ this._pageDataUtils.viewportFit(shiftParam, box);
1540
+ }
1541
+ /**
1542
+ * @description 获取元素包围盒
1543
+ * @param idInfo 元素Id
1544
+ * @returns 元素包围盒
1545
+ */
1546
+ getItemBoxById(idInfo) {
1547
+ return this._pageDataUtils.getItemBoxById(idInfo);
1548
+ }
1549
+ /**
1550
+ * @description 设置元素字体
1551
+ * @param id 元素Id
1552
+ * @param fontFamilyName 字体名称
1553
+ * @param url 字体地址
1554
+ */
1555
+ async setItemFontFamily(id, fontFamilyName, url) {
1556
+ await this._pageDataUtils.setItemFontFamily(id, fontFamilyName, url);
1557
+ this._eventEmitter.emit('itemPropertyChange', { id, propertyKeys: ['fontFamily', 'fontUrl'] });
1558
+ }
1559
+ createSceneByCreateInfos(createInfos, sceneInfo) {
1560
+ return this._pageDataUtils.createSceneByCreateInfos(createInfos, sceneInfo.size, sceneInfo.name);
1561
+ }
1562
+ // 设置图层大小 - 临时方法,用于修改图层元素大小,后续删除 @赤芍
1563
+ setSpriteSize(id, size) {
1564
+ this._pageDataUtils.setSpriteSize(id, size);
1565
+ this._gestureHandler.render();
1566
+ }
1567
+ async setItemPropertyByCreateInfo(createInfo) {
1568
+ await this._pageDataUtils.changeItemPropertyByCreateInfo(createInfo);
1569
+ this._gestureHandler.render();
1570
+ }
1571
+ setTransformGizmoLockScale(state) {
1572
+ this._gestureHandler.setTransformGizmoLockScale(state);
1573
+ }
1574
+ getViewBoxByBox(box) {
1575
+ return this._pageDataUtils.getViewBoxByBox(box);
1576
+ }
1577
+ openSpriteTextEditGizmo(initParam) {
1578
+ this._gestureHandler.openSpriteTextGizmo(initParam);
1579
+ this._gestureHandler.render();
1580
+ }
1581
+ closeSpriteTextEditGizmo() {
1582
+ this._gestureHandler.closeSpriteTextEditGizmo();
1583
+ }
1584
+ setSpriteTextSelectedIndex(id, index) {
1585
+ this._gestureHandler.setSpriteTextSelectedIndex(id, index);
1586
+ }
1587
+ setSpriteTextSelectedText(id, index, text) {
1588
+ this._gestureHandler.setSpriteTextSelectedText(id, index, text);
1589
+ }
1590
+ getBoundingBoxByItemCreateInfo(createInfo) {
1591
+ return this._pageDataUtils.getBoundingBoxByCreateInfo(createInfo);
1592
+ }
1593
+ getBoundingBoxByItemCreateInfos(createInfos) {
1594
+ return this._pageDataUtils.getBoundingBoxByCreateInfos(createInfos);
1595
+ }
1596
+ setSpriteTextChangedState(id, index, hasChanged) {
1597
+ this._gestureHandler.setSpriteTextChangedState(id, index, hasChanged);
1598
+ }
1599
+ setSpriteTextEditState(id, index, isEditing) {
1600
+ this._gestureHandler.setSpriteTextEditState(id, index, isEditing);
1601
+ }
1602
+ getVideoItemPlayTime(id) {
1603
+ return this._pageDataUtils.getVideoItemPlayTime(id);
1604
+ }
1605
+ setVideoItemPlayTime(id, time) {
1606
+ this._pageDataUtils.setVideoItemPlayTime(id, time);
1607
+ }
1608
+ getEffectsItemPlayTime(id) {
1609
+ return this._pageDataUtils.getEffectsItemPlayTime(id);
1610
+ }
1611
+ setEffectsItemPlayTime(id, time) {
1612
+ this._pageDataUtils.setEffectsItemPlayTime(id, time);
1613
+ }
1614
+ setEffectsResource(id, effects) {
1615
+ this._pageDataUtils.setEffectsResource(id, effects);
1616
+ }
1617
+ getPixelPositionByViewPosition(viewPosition) {
1618
+ return this._pageDataUtils.getPixelPositionByViewPosition(viewPosition);
1619
+ }
1620
+ hitTest(x, y) {
1621
+ return this._gestureHandler.selectorGizmo?.hitTest(new Vector2(x, y));
1622
+ }
1623
+ setInteractType(type) {
1624
+ this._gestureHandler.setInteractType(type);
1625
+ this._gestureHandler.render();
1626
+ }
1627
+ getInteractType() {
1628
+ return this._gestureHandler.interactType;
1629
+ }
1630
+ makeItemAlign(type, ids) {
1631
+ this._pageDataUtils.makeItemAlign(type, ids);
1632
+ this._gestureHandler.render();
1633
+ }
1634
+ makeItemDistribute(type, ids) {
1635
+ this._pageDataUtils.makeItemDistribute(type, ids);
1636
+ this._gestureHandler.render();
1637
+ }
1638
+ /**
1639
+ * @description 注册新的卡片类型
1640
+ * @param cardTypeConfig 卡片类型配置(type、label、iconUrl)
1641
+ * @returns 是否注册成功(type 已存在时返回 false)
1642
+ */
1643
+ registerCardType(cardTypeConfig) {
1644
+ const cardTypes = SDK.config.itemConfig.cardConfig.cardTypes;
1645
+ const exists = cardTypes.some(t => t.type === cardTypeConfig.type);
1646
+ if (exists) {
1647
+ console.warn(`CardType "${cardTypeConfig.type}" is already registered.`);
1648
+ return false;
1649
+ }
1650
+ cardTypes.push(cardTypeConfig);
1651
+ return true;
1652
+ }
1653
+ /**
1654
+ * @description 批量注册卡片类型
1655
+ * @param configs 卡片类型配置数组
1656
+ * @returns 成功注册的类型数量
1657
+ */
1658
+ registerCardTypes(configs) {
1659
+ let count = 0;
1660
+ configs.forEach(config => {
1661
+ if (this.registerCardType(config)) {
1662
+ count++;
1663
+ }
1664
+ });
1665
+ return count;
1666
+ }
1667
+ /**
1668
+ * @description 注销卡片类型
1669
+ * @param type 卡片类型标识
1670
+ * @returns 是否注销成功(type 不存在时返回 false)
1671
+ */
1672
+ unregisterCardType(type) {
1673
+ const { cardTypes } = SDK.config.itemConfig.cardConfig;
1674
+ const index = cardTypes.findIndex(t => t.type === type);
1675
+ if (index === -1) {
1676
+ console.warn(`CardType "${type}" is not registered.`);
1677
+ return false;
1678
+ }
1679
+ cardTypes.splice(index, 1);
1680
+ return true;
1681
+ }
1682
+ /**
1683
+ * @description 获取所有已注册的卡片类型
1684
+ * @returns 卡片类型配置数组(只读副本)
1685
+ */
1686
+ getRegisteredCardTypes() {
1687
+ return [...SDK.config.itemConfig.cardConfig.cardTypes];
1688
+ }
1689
+ /**
1690
+ * @description 判断卡片类型是否已注册
1691
+ * @param type 卡片类型标识
1692
+ * @returns 是否已注册
1693
+ */
1694
+ isCardTypeRegistered(type) {
1695
+ return SDK.config.itemConfig.cardConfig.cardTypes.some(t => t.type === type);
1696
+ }
1697
+ /**
1698
+ * @description 按 cardType 从注册表解析卡片的 HTML 渲染配置。
1699
+ * @param item 卡片元素
1700
+ * @returns HTML 渲染配置
1701
+ */
1702
+ resolveCardHTML(item) {
1703
+ const cardTypeConfig = this.resolveCardTypeConfig(item);
1704
+ return cardTypeConfig?.html?.(item);
1705
+ }
1706
+ /**
1707
+ * @description 按 cardType 从注册表解析卡片类型配置。
1708
+ * @param item 卡片元素
1709
+ * @returns 卡片类型配置
1710
+ */
1711
+ resolveCardTypeConfig(item) {
1712
+ return SDK.config.itemConfig.cardConfig.cardTypes.find(t => t.type === item.cardType);
1713
+ }
1714
+ /**
1715
+ * @description 重新解析并挂载指定卡片的 HTML 内容。
1716
+ * @description 当 inline/document 内容依赖 extension 或外部状态变化时,可调用此方法刷新 DOM。
1717
+ * @param id 卡片元素 ID
1718
+ * @returns 是否成功触发刷新
1719
+ */
1720
+ refreshCardHTML(id) {
1721
+ const item = this.getSDKItem(id);
1722
+ if (!isCardItem(item)) {
1723
+ console.warn(`CardItem "${id}" not found.`);
1724
+ return false;
1725
+ }
1726
+ if (!this.resolveCardHTML(item)) {
1727
+ console.warn(`CardItem "${id}" has no registered HTML renderer.`);
1728
+ return false;
1729
+ }
1730
+ this._htmlOverlayManager?.invalidateCardHTML(id);
1731
+ this._htmlOverlayManager?.scheduleRender();
1732
+ return true;
1733
+ }
1734
+ /**
1735
+ * @description 获取指定 HTML 卡片当前 iframe 的 window。
1736
+ * @description 仅 inline/document 或自行渲染 iframe 的 DOM 内容会返回 window。
1737
+ * @param id 卡片元素 ID
1738
+ * @returns HTML iframe window
1739
+ */
1740
+ getHtmlCardWindow(id) {
1741
+ return this._htmlOverlayManager?.getHtmlCardWindow(id);
1742
+ }
1743
+ /**
1744
+ * @description 向指定 HTML 卡片发送增量 patch。
1745
+ * @description 当卡片内容配置了 CardHTMLPatchHandler 时,可用于局部更新 HTML,而不必整卡 refresh。
1746
+ * @param id 卡片元素 ID
1747
+ * @param patch patch 负载,由卡片内容自己的 patch handler 解释
1748
+ * @returns 是否被 patch handler 处理
1749
+ */
1750
+ patchCardHTML(id, patch) {
1751
+ return this._htmlOverlayManager?.patchCardHTML(id, patch) ?? false;
1752
+ }
1753
+ /**
1754
+ * @description 向指定 HTML 卡片 iframe 派发事件。
1755
+ * @description 通过 postMessage 投递事件,跨源/同源行为一致,消息 source 为 vvfx-card-html-event。
1756
+ * @param id 卡片元素 ID
1757
+ * @param type 事件名称
1758
+ * @param detail 事件 detail
1759
+ * @returns 是否成功派发或投递
1760
+ */
1761
+ dispatchHtmlCardEvent(id, type, detail) {
1762
+ return this._htmlOverlayManager?.dispatchHtmlCardEvent(id, type, detail) ?? false;
1763
+ }
1764
+ /**
1765
+ * @description 创建卡片元素
1766
+ * @description 底层以透明 SpriteItem 形式渲染,支持 cardType 属性
1767
+ * @param createInfo 卡片创建信息
1768
+ * @returns 卡片元素ID
1769
+ */
1770
+ addCardItem(createInfo) {
1771
+ return this._pageDataUtils.addCardItem(createInfo);
1772
+ }
1773
+ /**
1774
+ * @description 创建生成器元素
1775
+ * @param createInfo 生成器创建信息
1776
+ * @returns 生成器元素ID
1777
+ */
1778
+ addGeneratorItem(createInfo) {
1779
+ return this._pageDataUtils.addGeneratorItem(createInfo);
1780
+ }
1781
+ /**
1782
+ * @description 创建动效元素
1783
+ * @param effectsInfo 动效创建信息
1784
+ */
1785
+ async addEffectsItem(effectsInfo) {
1786
+ return await this._pageDataUtils.addEffectsItem(effectsInfo);
1787
+ }
1788
+ /**
1789
+ * @description 创建画板元素
1790
+ * @param createInfo 画板创建信息
1791
+ * @returns 画板元素ID
1792
+ */
1793
+ async addFrameItem(createInfo) {
1794
+ return await this._pageDataUtils.addFrameItem(createInfo);
1795
+ }
1796
+ /**
1797
+ * @description 将元素移动到 Frame 中
1798
+ * @param itemIds 要移动的元素ID列表
1799
+ * @param frameId 目标 Frame ID
1800
+ */
1801
+ moveItemsToFrame(itemIds, frameId) {
1802
+ this._pageDataUtils.moveItemsToFrame(itemIds, frameId);
1803
+ }
1804
+ /**
1805
+ * @description 将元素从 Frame 中移出到主场景
1806
+ * @param itemIds 要移动的元素ID列表
1807
+ * @param frameId 源 Frame ID(可选,如果不传则从元素的 parentId 推断)
1808
+ */
1809
+ moveItemsOutOfFrame(itemIds) {
1810
+ this._pageDataUtils.moveItemsOutOfFrame(itemIds);
1811
+ }
1812
+ /**
1813
+ * @description 设置生成器资源,将生成器转换为对应的元素
1814
+ * @param id 生成器元素ID
1815
+ * @param resourceUrl 资源地址
1816
+ * @returns 新的元素ID
1817
+ */
1818
+ async setGeneratorResource(id, resourceUrl) {
1819
+ assertExist(this._pageData, 'You must call SDK#run() first');
1820
+ return this._pageDataUtils.setGeneratorResource(id, resourceUrl);
1821
+ }
1822
+ /**
1823
+ * @description 设置生成器资源(使用 GeneratorResource 对象)
1824
+ * @param resource 生成器资源信息
1825
+ */
1826
+ setGeneratorResourceFromObject(resource) {
1827
+ void this.setGeneratorResource(resource.itemId, resource.url);
1828
+ }
1829
+ /**
1830
+ * @description 设置视频生成器资源
1831
+ * @param resource 视频生成器资源信息
1832
+ */
1833
+ setVideoGeneratorResource(resource) {
1834
+ return this.setGeneratorResource(resource.itemId, resource.url);
1835
+ }
1836
+ /**
1837
+ * @description 设置图层生成器资源
1838
+ * @param resource 图层生成器资源信息
1839
+ */
1840
+ setSpriteGeneratorResource(resource) {
1841
+ return this.setGeneratorResource(resource.itemId, resource.url);
1842
+ }
1843
+ setItemLockState(id, state) {
1844
+ this._pageDataUtils.setItemLockState(id, state);
1845
+ }
1846
+ getItemLockState(id) {
1847
+ return this._pageDataUtils.getItemLockState(id);
1848
+ }
1849
+ openItemCreateGizmo(type) {
1850
+ this._gestureHandler.openItemCreateGizmo(type);
1851
+ this._gestureHandler.render();
1852
+ }
1853
+ closeItemCreateGizmo() {
1854
+ this._gestureHandler.closeItemCreateGizmo();
1855
+ }
1856
+ openTextGizmo(textItemId, mode) {
1857
+ this._gestureHandler.openTextGizmo(textItemId, mode);
1858
+ }
1859
+ closeTextGizmo() {
1860
+ this._gestureHandler.closeTextGizmo();
1861
+ }
1862
+ setItemName(id, name) {
1863
+ this._pageDataUtils.setItemName(id, name);
1864
+ }
1865
+ setSafeAreaPreviewVisible(id, type, visible) {
1866
+ const viewProperty = this.getViewProperty(id);
1867
+ viewProperty?.previewSafeAreas.forEach(safeArea => {
1868
+ if (type in safeArea) {
1869
+ safeArea.visible = visible;
1870
+ }
1871
+ });
1872
+ this._eventEmitter.emit('pageDataChange', this.pageData);
1873
+ }
1874
+ /**
1875
+ * @description 修改画板元素大小
1876
+ * @param id 元素id
1877
+ * @param size 目标大小 [width, height]
1878
+ * @param translation 位置偏移补偿(可选,用于保持拖拽角点固定)
1879
+ */
1880
+ resizeFrameItem(id, size, translation) {
1881
+ const translationVec = translation
1882
+ ? new Vector3(translation[0], translation[1], 0)
1883
+ : undefined;
1884
+ this._pageDataUtils.resizeFrameItem(id, size, translationVec);
1885
+ }
1886
+ /**
1887
+ * @description 对 FrameItem 执行自动布局(当 layoutMode 为 AUTO 时使用)
1888
+ * @param frameId Frame 元素 ID
1889
+ */
1890
+ applyFrameAutoLayout(frameId) {
1891
+ this._pageDataUtils.applyFrameAutoLayout(frameId);
1892
+ void this.setItemProperty({
1893
+ itemId: frameId,
1894
+ type: SDKItemType.FRAME,
1895
+ propertyName: 'layoutMode',
1896
+ propertyValue: FrameLayoutMode.AUTO,
1897
+ });
1898
+ }
1899
+ async autoLayoutPage(param) {
1900
+ await this._pageDataUtils.autoLayoutPage(param);
1901
+ this._gestureHandler.render();
1902
+ }
1903
+ }