@vvfx/artis 0.0.1-alpha.1 → 0.0.1-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/artis/operations/operations.d.ts +15 -10
- package/dist/artis/types.d.ts +2 -2
- package/dist/core/command/commands/{picture-cut-commit-command.d.ts → image-cut-commit-command.d.ts} +4 -4
- package/dist/core/command/commands/{picture-expand-commit-command.d.ts → image-expand-commit-command.d.ts} +5 -5
- package/dist/core/command/commands/index.d.ts +4 -4
- package/dist/core/command/commands/item-replace-source-command.d.ts +5 -0
- package/dist/core/command/commands/item-set-font-family-command.d.ts +1 -0
- package/dist/core/command/commands/item-transform-command.d.ts +1 -0
- package/dist/core/command/commands/item-update-property-by-schema-command.d.ts +1 -0
- package/dist/core/gizmo/gizmo-command-binder.d.ts +3 -3
- package/dist/core/gizmo/gizmo-registry.d.ts +2 -2
- package/dist/index.cjs +1599 -1495
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +1596 -1492
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Description: 智能画布
|
|
4
4
|
* Author: Ant Group CO., Ltd.
|
|
5
5
|
* Contributors: 赤芍,何即,不择,意绮
|
|
6
|
-
* Version: v0.0.1-alpha.
|
|
6
|
+
* Version: v0.0.1-alpha.2
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
function _define_property$1(obj, key, value) {
|
|
@@ -71092,6 +71092,29 @@ const textareaDefaultCssClass = `
|
|
|
71092
71092
|
return this._editingItem !== undefined;
|
|
71093
71093
|
}
|
|
71094
71094
|
/**
|
|
71095
|
+
* 选中当前编辑文本的全部内容,并将焦点交给输入框。
|
|
71096
|
+
*
|
|
71097
|
+
* 输入框尚未完成首次画布投影时会先保存全文选区,待投影打开后恢复。
|
|
71098
|
+
* @returns 当前存在可编辑文本时返回 true
|
|
71099
|
+
*/ selectAllText() {
|
|
71100
|
+
if (this._disposed) {
|
|
71101
|
+
return false;
|
|
71102
|
+
}
|
|
71103
|
+
const textComponent = this._editingItem?.getComponent(TextComponent);
|
|
71104
|
+
if (!textComponent) {
|
|
71105
|
+
return false;
|
|
71106
|
+
}
|
|
71107
|
+
const textLength = this.textAreaElement.style.display === 'block' ? this.textAreaElement.value.length : (textComponent.text ?? '').length;
|
|
71108
|
+
this._selectionStart = 0;
|
|
71109
|
+
this._selectionEnd = textLength;
|
|
71110
|
+
if (this.textAreaElement.style.display === 'block') {
|
|
71111
|
+
this.textAreaElement.focus();
|
|
71112
|
+
this.textAreaElement.select();
|
|
71113
|
+
this.textAreaElement.scrollTop = 0;
|
|
71114
|
+
}
|
|
71115
|
+
return true;
|
|
71116
|
+
}
|
|
71117
|
+
/**
|
|
71095
71118
|
* 使用当前单选文本元素开始编辑。
|
|
71096
71119
|
* @param textareaType 文本框激活方式
|
|
71097
71120
|
* @returns 是否成功开始编辑
|
|
@@ -71530,11 +71553,11 @@ const textareaDefaultCssClass = `
|
|
|
71530
71553
|
/** 角点旋转工具。 */ GizmoType["CORNER_ROTATION"] = "corner-rotation";
|
|
71531
71554
|
/** 选区缩放工具。 */ GizmoType["RESIZE_SELECTION"] = "resize-selection";
|
|
71532
71555
|
/** 视口覆盖层。 */ GizmoType["VIEWPORT_OVERLAY"] = "viewport-overlay";
|
|
71533
|
-
/** 图片裁切工具。 */ GizmoType["
|
|
71556
|
+
/** 图片裁切工具。 */ GizmoType["IMAGE_CUT"] = "image-cut";
|
|
71534
71557
|
/** 文本编辑工具。 */ GizmoType["TEXT"] = "text";
|
|
71535
71558
|
/** 蒙版编辑工具。 */ GizmoType["MASK"] = "mask";
|
|
71536
71559
|
/** 加载状态工具。 */ GizmoType["LOADING"] = "loading";
|
|
71537
|
-
/** 图片扩边工具。 */ GizmoType["
|
|
71560
|
+
/** 图片扩边工具。 */ GizmoType["IMAGE_EXPAND"] = "image-expand";
|
|
71538
71561
|
/** 精准文字编辑工具。 */ GizmoType["SPRITE_TEXT_EDIT"] = "sprite-text-edit";
|
|
71539
71562
|
/** 媒体图标工具。 */ GizmoType["ICON"] = "icon";
|
|
71540
71563
|
/** 元素创建工具。 */ GizmoType["ITEM_CREATE"] = "item-create";
|
|
@@ -71678,95 +71701,311 @@ class GizmoViewportUtils {
|
|
|
71678
71701
|
defaults: freezeConfigValue(cloneConfigValue(definition.defaults))
|
|
71679
71702
|
});
|
|
71680
71703
|
}
|
|
71681
|
-
|
|
71682
|
-
|
|
71683
|
-
|
|
71684
|
-
|
|
71685
|
-
|
|
71686
|
-
|
|
71687
|
-
|
|
71688
|
-
|
|
71689
|
-
|
|
71690
|
-
|
|
71691
|
-
|
|
71692
|
-
|
|
71693
|
-
|
|
71694
|
-
|
|
71695
|
-
|
|
71696
|
-
|
|
71697
|
-
|
|
71698
|
-
|
|
71699
|
-
|
|
71700
|
-
|
|
71701
|
-
|
|
71704
|
+
const DEFAULT_LOADING_FRAGMENT = `
|
|
71705
|
+
// Shadertoy Fragment Shader
|
|
71706
|
+
// Diagonal background gradient + wider colorful transparent shimmer
|
|
71707
|
+
|
|
71708
|
+
precision highp float;
|
|
71709
|
+
|
|
71710
|
+
varying vec2 vUV;
|
|
71711
|
+
|
|
71712
|
+
uniform vec4 _Time;
|
|
71713
|
+
|
|
71714
|
+
// ------------------------------------------------------------
|
|
71715
|
+
// Background
|
|
71716
|
+
// ------------------------------------------------------------
|
|
71717
|
+
vec3 background(vec2 uv) {
|
|
71718
|
+
vec3 topLeft = vec3(0.88, 0.85, 1.00);
|
|
71719
|
+
vec3 bottomRight = vec3(0.98, 0.98, 0.98);
|
|
71720
|
+
|
|
71721
|
+
float d = (uv.x + (1.0 - uv.y)) * 0.5;
|
|
71722
|
+
d = smoothstep(0.0, 1.0, d);
|
|
71723
|
+
|
|
71724
|
+
vec3 col = mix(topLeft, bottomRight, d);
|
|
71725
|
+
|
|
71726
|
+
vec2 p1 = uv - vec2(1.13, 1.40);
|
|
71727
|
+
float r1 = length(p1 / vec2(0.85, 0.85));
|
|
71728
|
+
float g1 = 1.0 - smoothstep(0.0, 0.96, r1);
|
|
71729
|
+
col += vec3(172.0/255.0, 183.0/255.0, 1.0) * g1 * 0.28;
|
|
71730
|
+
|
|
71731
|
+
vec2 p2 = uv - vec2(0.25, 0.23);
|
|
71732
|
+
float r2 = length(p2 / vec2(0.74, 0.64));
|
|
71733
|
+
float g2 = 1.0 - smoothstep(0.0, 1.0, r2);
|
|
71734
|
+
col += vec3(147.0/255.0, 108.0/255.0, 1.0) * g2 * 0.10;
|
|
71735
|
+
|
|
71736
|
+
return col;
|
|
71737
|
+
}
|
|
71738
|
+
|
|
71739
|
+
// ------------------------------------------------------------
|
|
71740
|
+
// Easing: slow at start, fast at end
|
|
71741
|
+
// ------------------------------------------------------------
|
|
71742
|
+
float easeInQuad(float x) {
|
|
71743
|
+
return x * x;
|
|
71744
|
+
}
|
|
71745
|
+
|
|
71746
|
+
// ------------------------------------------------------------
|
|
71747
|
+
// Color palette helper
|
|
71748
|
+
// ------------------------------------------------------------
|
|
71749
|
+
vec3 palette(float t) {
|
|
71750
|
+
// 柔和的彩色条:蓝 -> 青 -> 紫 -> 粉 -> 蓝
|
|
71751
|
+
vec3 a = vec3(0.62, 0.82, 1.00);
|
|
71752
|
+
vec3 b = vec3(0.72, 0.95, 1.00);
|
|
71753
|
+
vec3 c = vec3(0.83, 0.76, 1.00);
|
|
71754
|
+
vec3 d = vec3(1.00, 0.82, 0.95);
|
|
71755
|
+
|
|
71756
|
+
t = fract(t);
|
|
71757
|
+
|
|
71758
|
+
if (t < 0.33) {
|
|
71759
|
+
float k = smoothstep(0.0, 0.33, t);
|
|
71760
|
+
return mix(a, b, k);
|
|
71761
|
+
} else if (t < 0.66) {
|
|
71762
|
+
float k = smoothstep(0.33, 0.66, t);
|
|
71763
|
+
return mix(b, c, k);
|
|
71764
|
+
} else {
|
|
71765
|
+
float k = smoothstep(0.66, 1.0, t);
|
|
71766
|
+
return mix(c, d, k);
|
|
71702
71767
|
}
|
|
71703
71768
|
}
|
|
71704
|
-
|
|
71705
|
-
|
|
71706
|
-
|
|
71707
|
-
|
|
71708
|
-
|
|
71709
|
-
|
|
71710
|
-
|
|
71711
|
-
|
|
71712
|
-
|
|
71713
|
-
|
|
71714
|
-
|
|
71769
|
+
|
|
71770
|
+
// ------------------------------------------------------------
|
|
71771
|
+
// Wider colorful transparent left-to-right shimmer
|
|
71772
|
+
// ------------------------------------------------------------
|
|
71773
|
+
vec4 shimmerBand(vec2 uv, float t) {
|
|
71774
|
+
float cycle = fract(t * 0.70);
|
|
71775
|
+
cycle = easeInQuad(cycle);
|
|
71776
|
+
|
|
71777
|
+
float x = cycle * 1.55 - 0.25; // sweep from left to right
|
|
71778
|
+
|
|
71779
|
+
float d = abs(uv.x - x);
|
|
71780
|
+
float band = 1.0 - smoothstep(0.0, 0.30, d);
|
|
71781
|
+
float core = 1.0 - smoothstep(0.0, 0.10, d);
|
|
71782
|
+
|
|
71783
|
+
float x2 = x + (uv.y - 0.5) * 0.18;
|
|
71784
|
+
float d2 = abs(uv.x - x2);
|
|
71785
|
+
float band2 = 1.0 - smoothstep(0.0, 0.20, d2);
|
|
71786
|
+
|
|
71787
|
+
float s = max(band * 0.85, band2 * 0.60);
|
|
71788
|
+
s = max(s, core * 0.95);
|
|
71789
|
+
s = clamp(s, 0.0, 1.0);
|
|
71790
|
+
|
|
71791
|
+
// 颜色沿条带变化,模拟彩色渐变
|
|
71792
|
+
float hueT = uv.y * 0.25 + uv.x * 0.60 + t * 0.10;
|
|
71793
|
+
vec3 color1 = palette(hueT);
|
|
71794
|
+
|
|
71795
|
+
// 中间更亮一点,边缘更淡
|
|
71796
|
+
vec3 color2 = mix(color1, vec3(1.0), core * 0.35);
|
|
71797
|
+
|
|
71798
|
+
return vec4(color2, s);
|
|
71799
|
+
}
|
|
71800
|
+
|
|
71801
|
+
// ------------------------------------------------------------
|
|
71802
|
+
// Main
|
|
71803
|
+
// ------------------------------------------------------------
|
|
71804
|
+
void main() {
|
|
71805
|
+
vec2 uv = vUV;
|
|
71806
|
+
|
|
71807
|
+
vec3 col = background(uv);
|
|
71808
|
+
|
|
71809
|
+
vec4 sh = shimmerBand(uv, _Time.y);
|
|
71810
|
+
|
|
71811
|
+
// 可选:增加一点柔光感
|
|
71812
|
+
col += sh.rgb * sh.a * 0.06;
|
|
71813
|
+
|
|
71814
|
+
gl_FragColor = vec4(col, 1.0);
|
|
71815
|
+
}`;
|
|
71816
|
+
const loadingConfig = defineConfig({
|
|
71817
|
+
id: 'feedback.loading',
|
|
71818
|
+
defaults: {
|
|
71819
|
+
loadingFragment: DEFAULT_LOADING_FRAGMENT
|
|
71715
71820
|
}
|
|
71716
|
-
|
|
71717
|
-
|
|
71718
|
-
|
|
71719
|
-
|
|
71720
|
-
|
|
71721
|
-
|
|
71722
|
-
|
|
71723
|
-
const vfxItem = VFXItemFactory.createVFXItem(composition, parent, name, SpriteComponent);
|
|
71724
|
-
vfxItem.type = index$1.ItemType.sprite;
|
|
71725
|
-
return vfxItem;
|
|
71821
|
+
});
|
|
71822
|
+
const viewportNavigationConfig = defineConfig({
|
|
71823
|
+
id: 'viewport.navigation',
|
|
71824
|
+
defaults: {
|
|
71825
|
+
scrollWheelZoom: false,
|
|
71826
|
+
invertZoom: false,
|
|
71827
|
+
zoomStep: 0.1
|
|
71726
71828
|
}
|
|
71727
|
-
|
|
71728
|
-
|
|
71729
|
-
|
|
71730
|
-
|
|
71731
|
-
|
|
71732
|
-
|
|
71733
|
-
|
|
71734
|
-
|
|
71735
|
-
|
|
71736
|
-
|
|
71829
|
+
});
|
|
71830
|
+
const viewportOverlayConfig = defineConfig({
|
|
71831
|
+
id: 'viewport.overlay',
|
|
71832
|
+
defaults: {
|
|
71833
|
+
boxColor: 0xFF0000,
|
|
71834
|
+
boxWidth: 1,
|
|
71835
|
+
outerMaskEnabled: true,
|
|
71836
|
+
markColor: 0x000000,
|
|
71837
|
+
markAlpha: 0.17,
|
|
71838
|
+
safeAreaEnabled: true,
|
|
71839
|
+
safeAreaBoxColor: 0x00FF00,
|
|
71840
|
+
safeAreaBoxAlpha: 0.3
|
|
71737
71841
|
}
|
|
71738
|
-
|
|
71739
|
-
|
|
71740
|
-
|
|
71741
|
-
|
|
71742
|
-
|
|
71743
|
-
|
|
71744
|
-
|
|
71745
|
-
|
|
71746
|
-
|
|
71747
|
-
|
|
71842
|
+
});
|
|
71843
|
+
const selectionPreviewConfig = defineConfig({
|
|
71844
|
+
id: 'selection.preview',
|
|
71845
|
+
defaults: {
|
|
71846
|
+
videoPreSelectedPlay: true,
|
|
71847
|
+
preSelectedColor: 0x3b82f6,
|
|
71848
|
+
preSelectedWidth: 2,
|
|
71849
|
+
regionBoxColor: 0x3b82f6,
|
|
71850
|
+
regionBoxAlpha: 0.17,
|
|
71851
|
+
regionWireframeColor: 0x3b82f6,
|
|
71852
|
+
regionWireframeAlpha: 0.78,
|
|
71853
|
+
regionWireframeWidth: 1
|
|
71748
71854
|
}
|
|
71749
|
-
|
|
71750
|
-
|
|
71751
|
-
|
|
71752
|
-
|
|
71753
|
-
|
|
71754
|
-
|
|
71755
|
-
|
|
71756
|
-
|
|
71757
|
-
const preComposition = await AssetManager$1.loadPrecomposition(effects, {
|
|
71758
|
-
autoplay: false
|
|
71759
|
-
});
|
|
71760
|
-
const vfxItem = PrecompositionManager.instantiate(preComposition, composition);
|
|
71761
|
-
vfxItem.name = urlname;
|
|
71762
|
-
vfxItem.type = index$1.ItemType.composition;
|
|
71763
|
-
vfxItem.getComponent(CompositionComponent).endBehavior = vfxItem.endBehavior;
|
|
71764
|
-
if (parent) {
|
|
71765
|
-
vfxItem.setParent(parent);
|
|
71766
|
-
}
|
|
71767
|
-
return vfxItem;
|
|
71855
|
+
});
|
|
71856
|
+
const selectionSnapConfig = defineConfig({
|
|
71857
|
+
id: 'selection.snap',
|
|
71858
|
+
defaults: {
|
|
71859
|
+
enabled: true,
|
|
71860
|
+
lineWidth: 0.8,
|
|
71861
|
+
lineColor: 0x0BD6FF,
|
|
71862
|
+
distance: 6
|
|
71768
71863
|
}
|
|
71769
|
-
}
|
|
71864
|
+
});
|
|
71865
|
+
const resizeSelectionConfig = defineConfig({
|
|
71866
|
+
id: 'resize-selection',
|
|
71867
|
+
defaults: {
|
|
71868
|
+
pixelRatio: 1,
|
|
71869
|
+
contentRatio: 1,
|
|
71870
|
+
wireframeColor: 0x3b82f6,
|
|
71871
|
+
wireframeAlpha: 1,
|
|
71872
|
+
wireframeWidth: 1.5,
|
|
71873
|
+
cornerFillColor: 0xFFFFFF,
|
|
71874
|
+
cornerLineColor: 0x3b82f6,
|
|
71875
|
+
cornerLineWidth: 1.5,
|
|
71876
|
+
cornerLineAlpha: 1,
|
|
71877
|
+
scaleCircleSize: 4,
|
|
71878
|
+
rotationCircleSize: 7,
|
|
71879
|
+
infoShowEnabled: true,
|
|
71880
|
+
sizeTextColor: 0x666666,
|
|
71881
|
+
nameTextColor: 0x666666,
|
|
71882
|
+
frameMoveLineColor: 0x3b82f6,
|
|
71883
|
+
frameMoveLineWidth: 2,
|
|
71884
|
+
imageLogoUrl: 'https://mdn.alipayobjects.com/huamei_ixsp8m/afts/img/A*F2wVS7x0MfIAAAAAQBAAAAgAev-aAQ/original',
|
|
71885
|
+
groupLogoUrl: 'https://mdn.alipayobjects.com/huamei_ppzin5/afts/img/Yo69Sr7boqYAAAAAH3AAAAgADjdkAQFr/original',
|
|
71886
|
+
textLogoUrl: 'https://mdn.alipayobjects.com/huamei_ppzin5/afts/img/Yo69Sr7boqYAAAAAH3AAAAgADjdkAQFr/original',
|
|
71887
|
+
videoLogoUrl: 'https://mdn.alipayobjects.com/huamei_ixsp8m/afts/img/A*w1fnS4mq0VgAAAAAQCAAAAgAev-aAQ/original',
|
|
71888
|
+
frameLogoUrl: 'https://mdn.alipayobjects.com/huamei_ixsp8m/afts/img/A*DRF_RpndkjUAAAAAQDAAAAgAev-aAQ/original',
|
|
71889
|
+
effectsLogoUrl: 'https://mdn.alipayobjects.com/huamei_ixsp8m/afts/img/A*RMewR4ruUnYAAAAAQGAAAAgAev-aAQ/original'
|
|
71890
|
+
}
|
|
71891
|
+
});
|
|
71892
|
+
const imageCutConfig = defineConfig({
|
|
71893
|
+
id: 'tool.image-cut',
|
|
71894
|
+
defaults: {
|
|
71895
|
+
maskColor: 0xFFFFFF,
|
|
71896
|
+
maskAlpha: 0.5,
|
|
71897
|
+
cutBoxLineWidth: 2,
|
|
71898
|
+
cutBoxLineColor: 0x6A34FF,
|
|
71899
|
+
cutBoxLineAlpha: 1,
|
|
71900
|
+
itemBoxLineWidth: 1,
|
|
71901
|
+
itemBoxLineColor: 0x6A34FF,
|
|
71902
|
+
itemBoxLineAlpha: 1,
|
|
71903
|
+
cutBoxCornerRadius: 5,
|
|
71904
|
+
cutBoxCornerFillColor: 0xFFFFFF,
|
|
71905
|
+
cutBoxCornerLineWidth: 2,
|
|
71906
|
+
cutBoxCornerLineColor: 0x6A34FF,
|
|
71907
|
+
cutBoxCornerLineAlpha: 1,
|
|
71908
|
+
scaleInteractionDistance: 8,
|
|
71909
|
+
directionScaleInteractionDistance: 5,
|
|
71910
|
+
gridLineWidth: 1,
|
|
71911
|
+
gridLineColor: 0xFFFFFF,
|
|
71912
|
+
gridLineAlpha: 1,
|
|
71913
|
+
gridCount: 2
|
|
71914
|
+
}
|
|
71915
|
+
});
|
|
71916
|
+
const imageExpandConfig = defineConfig({
|
|
71917
|
+
id: 'tool.image-expand',
|
|
71918
|
+
defaults: {
|
|
71919
|
+
maskColor: 0x6A34FF,
|
|
71920
|
+
maskAlpha: 0.2,
|
|
71921
|
+
expandBoxLineWidth: 2,
|
|
71922
|
+
expandBoxLineColor: 0x6A34FF,
|
|
71923
|
+
expandBoxLineAlpha: 1,
|
|
71924
|
+
expandBoxCornerRadius: 5,
|
|
71925
|
+
expandBoxCornerLineWidth: 2,
|
|
71926
|
+
expandBoxCornerLineColor: 0x6A34FF,
|
|
71927
|
+
expandBoxCornerLineAlpha: 1,
|
|
71928
|
+
expandBoxCornerFillColor: 0xFFFFFF,
|
|
71929
|
+
scaleInteractionDistance: 8,
|
|
71930
|
+
directionScaleInteractionDistance: 5,
|
|
71931
|
+
gridLineWidth: 1,
|
|
71932
|
+
gridLineColor: 0xFFFFFF,
|
|
71933
|
+
gridLineAlpha: 1,
|
|
71934
|
+
gridCount: 2
|
|
71935
|
+
}
|
|
71936
|
+
});
|
|
71937
|
+
const maskConfig = defineConfig({
|
|
71938
|
+
id: 'tool.mask',
|
|
71939
|
+
defaults: {
|
|
71940
|
+
maskImage: '',
|
|
71941
|
+
brushSize: 20,
|
|
71942
|
+
brushColor: 0x6A34FF,
|
|
71943
|
+
brushAlpha: 0.5,
|
|
71944
|
+
maskColor: 0x00FF00,
|
|
71945
|
+
maskBackgroundColor: 0xFFFFFF,
|
|
71946
|
+
maskAlpha: 1,
|
|
71947
|
+
boxLineWidth: 1,
|
|
71948
|
+
boxLineColor: 0x6A34FF,
|
|
71949
|
+
boxLineAlpha: 1
|
|
71950
|
+
}
|
|
71951
|
+
});
|
|
71952
|
+
const spriteTextEditConfig = defineConfig({
|
|
71953
|
+
id: 'tool.sprite-text-edit',
|
|
71954
|
+
defaults: {
|
|
71955
|
+
textColor: 0xFFFFFF,
|
|
71956
|
+
preSelectedTextColor: 0xFFFFFF,
|
|
71957
|
+
boxLineWidth: 3,
|
|
71958
|
+
dashLineDash: 8,
|
|
71959
|
+
dashLineGap: 8,
|
|
71960
|
+
editBoxAlpha: 0.15,
|
|
71961
|
+
editBoxColor: 0x3B82F6,
|
|
71962
|
+
editBoxLineAlpha: 1,
|
|
71963
|
+
editBoxLineColor: 0x3B82F6,
|
|
71964
|
+
editBoxPreSelectedAlpha: 0.25,
|
|
71965
|
+
editBoxPreSelectedColor: 0x3B82F6,
|
|
71966
|
+
editBoxLinePreSelectedAlpha: 1,
|
|
71967
|
+
editBoxLinePreSelectedColor: 0x3B82F6,
|
|
71968
|
+
hasChangedEditBoxAlpha: 0.2,
|
|
71969
|
+
hasChangedEditBoxColor: 0x22C55E,
|
|
71970
|
+
hasChangedEditBoxLineAlpha: 1,
|
|
71971
|
+
hasChangedEditBoxLineColor: 0x22C55E,
|
|
71972
|
+
hasChangedEditBoxPreSelectedAlpha: 0.3,
|
|
71973
|
+
hasChangedEditBoxPreSelectedColor: 0x22C55E,
|
|
71974
|
+
hasChangedEditBoxLinePreSelectedAlpha: 1,
|
|
71975
|
+
hasChangedEditBoxLinePreSelectedColor: 0x22C55E,
|
|
71976
|
+
editBoxSelectedAlpha: 0.6,
|
|
71977
|
+
editBoxSelectedColor: 0xFFFF00
|
|
71978
|
+
}
|
|
71979
|
+
});
|
|
71980
|
+
const iconConfig = defineConfig({
|
|
71981
|
+
id: 'feedback.icon',
|
|
71982
|
+
defaults: {
|
|
71983
|
+
autoShow: true,
|
|
71984
|
+
videoPlayUrl: 'https://mdn.alipayobjects.com/huamei_ixsp8m/afts/img/A*ORMmSYYHIHUAAAAAJbAAAAgAev-aAQ/original',
|
|
71985
|
+
videoPlayShift: [
|
|
71986
|
+
20,
|
|
71987
|
+
20
|
|
71988
|
+
],
|
|
71989
|
+
videoPlayWidth: 20,
|
|
71990
|
+
videoPlayHeight: 20,
|
|
71991
|
+
imageGeneratorUrl: 'https://mdn.alipayobjects.com/huamei_ixsp8m/afts/img/A*bYB-TIEWLBkAAAAAQGAAAAgAev-aAQ/original',
|
|
71992
|
+
videoGeneratorUrl: 'https://mdn.alipayobjects.com/huamei_ixsp8m/afts/img/A*6cTFT44CuKEAAAAAQCAAAAgAev-aAQ/original',
|
|
71993
|
+
generatorWidth: 200,
|
|
71994
|
+
generatorHeight: 200
|
|
71995
|
+
}
|
|
71996
|
+
});
|
|
71997
|
+
const itemCreateConfig = defineConfig({
|
|
71998
|
+
id: 'tool.item-create',
|
|
71999
|
+
defaults: {
|
|
72000
|
+
frameBorderColor: 0x2178FF,
|
|
72001
|
+
frameBorderWidth: 1,
|
|
72002
|
+
frameBorderAlpha: 0.8,
|
|
72003
|
+
frameFillColor: 0x2178FF,
|
|
72004
|
+
frameFillAlpha: 0.15,
|
|
72005
|
+
frameChildBoxAlpha: 0.35,
|
|
72006
|
+
frameChildBoxColor: 0x2178FF
|
|
72007
|
+
}
|
|
72008
|
+
});
|
|
71770
72009
|
/**
|
|
71771
72010
|
* 获取元素所在合成的相机视图投影矩阵。
|
|
71772
72011
|
* @param item 播放器元素
|
|
@@ -71886,23 +72125,244 @@ class GizmoViewportUtils {
|
|
|
71886
72125
|
return plane;
|
|
71887
72126
|
}
|
|
71888
72127
|
/**
|
|
71889
|
-
*
|
|
71890
|
-
* @param
|
|
71891
|
-
* @
|
|
72128
|
+
* 缩放视图。
|
|
72129
|
+
* @param engine 引擎
|
|
72130
|
+
* @param zoom 缩放值
|
|
72131
|
+
* @param center 缩放中心
|
|
72132
|
+
*/ function zoomView(engine, zoom, center = new Vector2()) {
|
|
72133
|
+
const composition = engine.compositions[0];
|
|
72134
|
+
if (!composition) {
|
|
72135
|
+
return;
|
|
72136
|
+
}
|
|
72137
|
+
const { camera } = composition;
|
|
72138
|
+
const scale = camera.getViewportMatrix().elements[0];
|
|
72139
|
+
const translation = new Vector2(camera.getViewportMatrix().elements[12], camera.getViewportMatrix().elements[13]);
|
|
72140
|
+
const result = scale + zoom;
|
|
72141
|
+
// 1. 反算缩放中心对应的世界坐标。
|
|
72142
|
+
const worldX = (center.x - translation.x) / scale;
|
|
72143
|
+
const worldY = (center.y - translation.y) / scale;
|
|
72144
|
+
// 2. 调整平移,使缩放中心在屏幕上的位置保持不变。
|
|
72145
|
+
const newNDCTranslation = new Vector2(center.x - worldX * result, center.y - worldY * result);
|
|
72146
|
+
const viewportMatrix = new Matrix4().compose(new Vector3(newNDCTranslation.x, newNDCTranslation.y, 0), new Quaternion(), new Vector3(result, result, 1));
|
|
72147
|
+
composition.camera.setViewportMatrix(viewportMatrix);
|
|
72148
|
+
}
|
|
72149
|
+
/**
|
|
72150
|
+
* 平移视图。
|
|
72151
|
+
* @param engine 引擎
|
|
72152
|
+
* @param translation 位移值
|
|
72153
|
+
*/ function panView(engine, translation) {
|
|
72154
|
+
const composition = engine.compositions[0];
|
|
72155
|
+
if (!composition) {
|
|
72156
|
+
return;
|
|
72157
|
+
}
|
|
72158
|
+
const { camera } = composition;
|
|
72159
|
+
const scale = camera.getViewportMatrix().elements[0];
|
|
72160
|
+
const resultTranslation = new Vector2(camera.getViewportMatrix().elements[12], camera.getViewportMatrix().elements[13]).add(translation);
|
|
72161
|
+
const viewportMatrix = new Matrix4().compose(new Vector3(resultTranslation.x, resultTranslation.y, 0), new Quaternion(), new Vector3(scale, scale, 1));
|
|
72162
|
+
camera.setViewportMatrix(viewportMatrix);
|
|
72163
|
+
}
|
|
72164
|
+
/** 统一处理手形工具和滚轮触发的视口平移与缩放。 */ class ViewportNavigationController extends EventEmitter {
|
|
72165
|
+
/** 当前视口导航配置。 */ get config() {
|
|
72166
|
+
return this._owner.getConfigManager().get(viewportNavigationConfig);
|
|
72167
|
+
}
|
|
72168
|
+
/** 当前 Effects 引擎。 */ get _engine() {
|
|
72169
|
+
return this._owner.getEngine();
|
|
72170
|
+
}
|
|
72171
|
+
/**
|
|
72172
|
+
* 设置允许的视口缩放范围。
|
|
72173
|
+
* @param minScale 最小缩放
|
|
72174
|
+
* @param maxScale 最大缩放
|
|
72175
|
+
*/ setScaleRange(minScale, maxScale) {
|
|
72176
|
+
if (!Number.isFinite(minScale) || !Number.isFinite(maxScale) || minScale <= 0 || maxScale <= 0 || minScale > maxScale) {
|
|
72177
|
+
throw new RangeError('Viewport scale range must be finite, positive, and ordered.');
|
|
72178
|
+
}
|
|
72179
|
+
this._minScale = minScale;
|
|
72180
|
+
this._maxScale = maxScale;
|
|
72181
|
+
}
|
|
72182
|
+
/**
|
|
72183
|
+
* 根据滚轮来源和修饰键执行平移或缩放。
|
|
72184
|
+
* @param event 滚轮事件
|
|
72185
|
+
* @param _pointerCaptured 指针是否已被捕获
|
|
72186
|
+
* @returns 视口是否发生变化
|
|
72187
|
+
*/ handleWheel(event, _pointerCaptured) {
|
|
72188
|
+
if (!this._hasViewport()) {
|
|
72189
|
+
return false;
|
|
72190
|
+
}
|
|
72191
|
+
event.accept();
|
|
72192
|
+
if (event.buttonMask !== MouseButtonMask.None) {
|
|
72193
|
+
return false;
|
|
72194
|
+
}
|
|
72195
|
+
const { delta, source } = this._normalizeWheel(event);
|
|
72196
|
+
const mode = this._classifyWheel(event, source);
|
|
72197
|
+
const center = new Vector2(event.position.x, event.position.y);
|
|
72198
|
+
if (mode === 'zoom') {
|
|
72199
|
+
if (delta.y === 0) {
|
|
72200
|
+
return false;
|
|
72201
|
+
}
|
|
72202
|
+
const direction = this.config.invertZoom ? -delta.y : delta.y;
|
|
72203
|
+
const zoomStep = this.config.zoomStep;
|
|
72204
|
+
const zoomShift = clamp(direction * 0.01, -zoomStep, zoomStep);
|
|
72205
|
+
return this._zoomByShift(zoomShift, center, event.ctrlPressed && source === 'trackpad' ? 'pinch-zoom' : 'wheel-zoom');
|
|
72206
|
+
}
|
|
72207
|
+
if (delta.x === 0 && delta.y === 0) {
|
|
72208
|
+
return false;
|
|
72209
|
+
}
|
|
72210
|
+
return this.panByViewDelta(delta, center, 'wheel-pan');
|
|
72211
|
+
}
|
|
72212
|
+
/**
|
|
72213
|
+
* 按视图像素增量平移视口。
|
|
72214
|
+
* @param delta 视图像素位移
|
|
72215
|
+
* @param center 操作中心
|
|
72216
|
+
* @param source 操作来源
|
|
72217
|
+
* @returns 视口是否发生变化
|
|
72218
|
+
*/ panByViewDelta(delta, center, source) {
|
|
72219
|
+
if (!this._hasViewport() || delta.x === 0 && delta.y === 0) {
|
|
72220
|
+
return false;
|
|
72221
|
+
}
|
|
72222
|
+
const containerSize = this._containerSize();
|
|
72223
|
+
if (containerSize.x <= 0 || containerSize.y <= 0) {
|
|
72224
|
+
return false;
|
|
72225
|
+
}
|
|
72226
|
+
panView(this._engine, viewSizeToNDC(delta, containerSize));
|
|
72227
|
+
this._emitChange(center, source);
|
|
72228
|
+
return true;
|
|
72229
|
+
}
|
|
72230
|
+
/**
|
|
72231
|
+
* 按倍率缩放视口。
|
|
72232
|
+
* @param factor 缩放倍率
|
|
72233
|
+
* @param center 缩放中心
|
|
72234
|
+
* @param source 操作来源
|
|
72235
|
+
* @returns 视口是否发生变化
|
|
72236
|
+
*/ zoomByFactor(factor, center, source) {
|
|
72237
|
+
if (!this._hasViewport() || !Number.isFinite(factor) || factor <= 0) {
|
|
72238
|
+
return false;
|
|
72239
|
+
}
|
|
72240
|
+
const currentScale = GizmoViewportUtils.getViewScale(this._engine);
|
|
72241
|
+
const nextScale = clamp(currentScale * factor, this._minScale, this._maxScale);
|
|
72242
|
+
if (nextScale === currentScale) {
|
|
72243
|
+
return false;
|
|
72244
|
+
}
|
|
72245
|
+
const containerSize = this._containerSize();
|
|
72246
|
+
if (containerSize.x <= 0 || containerSize.y <= 0) {
|
|
72247
|
+
return false;
|
|
72248
|
+
}
|
|
72249
|
+
zoomView(this._engine, nextScale - currentScale, viewPositionToNDC(center, containerSize));
|
|
72250
|
+
this._emitChange(center, source);
|
|
72251
|
+
return true;
|
|
72252
|
+
}
|
|
72253
|
+
/** 释放配置订阅和事件监听器。 */ dispose() {
|
|
72254
|
+
this._configOff?.();
|
|
72255
|
+
this._configOff = undefined;
|
|
72256
|
+
for (const listener of this.getListeners('change').slice()){
|
|
72257
|
+
this.off('change', listener);
|
|
72258
|
+
}
|
|
72259
|
+
}
|
|
72260
|
+
/**
|
|
72261
|
+
* 根据滚轮来源和修饰键确定导航模式。
|
|
72262
|
+
* @param event 滚轮事件
|
|
72263
|
+
* @param source 输入设备类型
|
|
72264
|
+
* @returns 滚轮导航模式
|
|
72265
|
+
*/ _classifyWheel(event, source) {
|
|
72266
|
+
const signature = `${source}:${Number(event.ctrlPressed)}:${Number(event.metaPressed)}`;
|
|
72267
|
+
if (signature !== this._wheelSignature) {
|
|
72268
|
+
this._wheelSignature = signature;
|
|
72269
|
+
this._wheelMode = event.ctrlPressed || event.metaPressed || source === 'mouse' && this.config.scrollWheelZoom ? 'zoom' : 'pan';
|
|
72270
|
+
}
|
|
72271
|
+
return this._wheelMode;
|
|
72272
|
+
}
|
|
72273
|
+
/**
|
|
72274
|
+
* 将方向型滚轮事件转换为视图位移。
|
|
72275
|
+
* @param event 滚轮事件
|
|
72276
|
+
* @returns 视图位移和输入设备类型
|
|
72277
|
+
*/ _normalizeWheel(event) {
|
|
72278
|
+
const delta = new Vector2();
|
|
72279
|
+
switch(event.buttonIndex){
|
|
72280
|
+
case MouseButton.WheelUp:
|
|
72281
|
+
delta.y = event.factor;
|
|
72282
|
+
break;
|
|
72283
|
+
case MouseButton.WheelDown:
|
|
72284
|
+
delta.y = -event.factor;
|
|
72285
|
+
break;
|
|
72286
|
+
case MouseButton.WheelLeft:
|
|
72287
|
+
delta.x = event.factor;
|
|
72288
|
+
break;
|
|
72289
|
+
case MouseButton.WheelRight:
|
|
72290
|
+
delta.x = -event.factor;
|
|
72291
|
+
break;
|
|
72292
|
+
}
|
|
72293
|
+
// Windows 下 Shift + 滚轮映射为水平平移。
|
|
72294
|
+
const isApplePlatform = typeof navigator !== 'undefined' && /Mac|iPhone|iPad|iPod/.test(navigator.platform);
|
|
72295
|
+
if (!isApplePlatform && event.shiftPressed && delta.x === 0) {
|
|
72296
|
+
delta.x = delta.y;
|
|
72297
|
+
delta.y = 0;
|
|
72298
|
+
}
|
|
72299
|
+
const source = event.ctrlPressed || event.metaPressed || !Number.isInteger(event.factor) || delta.x !== 0 ? 'trackpad' : 'mouse';
|
|
72300
|
+
return {
|
|
72301
|
+
delta,
|
|
72302
|
+
source
|
|
72303
|
+
};
|
|
72304
|
+
}
|
|
72305
|
+
/**
|
|
72306
|
+
* 按绝对缩放增量更新视口。
|
|
72307
|
+
* @param shift 缩放增量
|
|
72308
|
+
* @param center 缩放中心
|
|
72309
|
+
* @param source 操作来源
|
|
72310
|
+
* @returns 视口是否发生变化
|
|
72311
|
+
*/ _zoomByShift(shift, center, source) {
|
|
72312
|
+
const currentScale = GizmoViewportUtils.getViewScale(this._engine);
|
|
72313
|
+
const nextScale = roundNumber(clamp(currentScale + shift, this._minScale, this._maxScale), 2);
|
|
72314
|
+
if (nextScale === currentScale) {
|
|
72315
|
+
return false;
|
|
72316
|
+
}
|
|
72317
|
+
return this.zoomByFactor(nextScale / currentScale, center, source);
|
|
72318
|
+
}
|
|
72319
|
+
/**
|
|
72320
|
+
* 发出当前视口快照。
|
|
72321
|
+
* @param center 操作中心
|
|
72322
|
+
* @param source 操作来源
|
|
72323
|
+
*/ _emitChange(center, source) {
|
|
72324
|
+
const containerSize = this._containerSize();
|
|
72325
|
+
this.emit('change', {
|
|
72326
|
+
source,
|
|
72327
|
+
scale: GizmoViewportUtils.getViewScale(this._engine),
|
|
72328
|
+
translation: ndcSizeToViewSize(GizmoViewportUtils.getViewportTranslation(this._engine), containerSize),
|
|
72329
|
+
center: center.clone()
|
|
72330
|
+
});
|
|
72331
|
+
}
|
|
72332
|
+
/** @returns 当前画布容器尺寸。 */ _containerSize() {
|
|
72333
|
+
return GizmoViewportUtils.getContainerSize(this._engine.canvas.parentElement);
|
|
72334
|
+
}
|
|
72335
|
+
/** @returns 是否存在可操作的画布容器和相机。 */ _hasViewport() {
|
|
72336
|
+
return Boolean(this._engine.canvas.parentElement && this._engine.compositions[0]?.camera);
|
|
72337
|
+
}
|
|
72338
|
+
/**
|
|
72339
|
+
* @param owner Gizmo 宿主
|
|
72340
|
+
*/ constructor(owner){
|
|
72341
|
+
super(), _define_property(this, "_owner", void 0), _define_property(this, "_minScale", 0.01), _define_property(this, "_maxScale", 20), _define_property(this, "_configOff", void 0), _define_property(this, "_wheelSignature", ''), _define_property(this, "_wheelMode", 'pan');
|
|
72342
|
+
this._owner = owner;
|
|
72343
|
+
this._configOff = owner.getConfigManager().onChange(viewportNavigationConfig, ()=>{
|
|
72344
|
+
this._wheelSignature = '';
|
|
72345
|
+
});
|
|
72346
|
+
}
|
|
72347
|
+
}
|
|
72348
|
+
/**
|
|
72349
|
+
* 判断播放器元素是否为画板元素。
|
|
72350
|
+
* @param item 播放器元素
|
|
72351
|
+
* @returns 是否为画板元素
|
|
71892
72352
|
*/ function isFramePlayerItem(item) {
|
|
71893
72353
|
return item.type === index$1.ItemType.null && item.getComponent(FrameComponent) !== undefined && item.name === '画板';
|
|
71894
72354
|
}
|
|
71895
|
-
/**
|
|
71896
|
-
* 判断播放器元素是否为特效元素。
|
|
71897
|
-
* @param item 播放器元素
|
|
71898
|
-
* @returns 是否为特效元素
|
|
72355
|
+
/**
|
|
72356
|
+
* 判断播放器元素是否为特效元素。
|
|
72357
|
+
* @param item 播放器元素
|
|
72358
|
+
* @returns 是否为特效元素
|
|
71899
72359
|
*/ function isEffectsPlayerItem(item) {
|
|
71900
72360
|
return item.type === index$1.ItemType.null && item.getComponent(FrameComponent) !== undefined && item.name === '特效';
|
|
71901
72361
|
}
|
|
71902
|
-
/**
|
|
71903
|
-
* 判断播放器元素是否为生成器元素。
|
|
71904
|
-
* @param item 播放器元素
|
|
71905
|
-
* @returns 是否为生成器元素
|
|
72362
|
+
/**
|
|
72363
|
+
* 判断播放器元素是否为生成器元素。
|
|
72364
|
+
* @param item 播放器元素
|
|
72365
|
+
* @returns 是否为生成器元素
|
|
71906
72366
|
*/ function isGeneratorPlayerItem(item) {
|
|
71907
72367
|
if (item.type !== index$1.ItemType.sprite) {
|
|
71908
72368
|
return false;
|
|
@@ -71921,18 +72381,95 @@ class GizmoViewportUtils {
|
|
|
71921
72381
|
const content = item.definition?.content;
|
|
71922
72382
|
return content?.generatorType === 'video' || content?.isVideoGenerator === true || item.name.includes('视频');
|
|
71923
72383
|
}
|
|
71924
|
-
/**
|
|
71925
|
-
* 判断播放器元素是否为组元素。
|
|
71926
|
-
* @param item 播放器元素
|
|
71927
|
-
* @returns 是否为组元素
|
|
72384
|
+
/**
|
|
72385
|
+
* 判断播放器元素是否为组元素。
|
|
72386
|
+
* @param item 播放器元素
|
|
72387
|
+
* @returns 是否为组元素
|
|
71928
72388
|
*/ function isGroupPlayerItem(item) {
|
|
71929
72389
|
return item.type === index$1.ItemType.null && !item.getComponent(FrameComponent);
|
|
71930
72390
|
}
|
|
71931
|
-
/**
|
|
71932
|
-
*
|
|
71933
|
-
* @param item 播放器元素
|
|
71934
|
-
* @
|
|
71935
|
-
|
|
72391
|
+
/**
|
|
72392
|
+
* 获取播放器元素的所有子元素。
|
|
72393
|
+
* @param item 播放器元素
|
|
72394
|
+
* @returns 子元素数组
|
|
72395
|
+
*/ function getItemChildren(item) {
|
|
72396
|
+
const children = [];
|
|
72397
|
+
const isFrameItem = isFramePlayerItem(item);
|
|
72398
|
+
const isEffectItem = isEffectsPlayerItem(item);
|
|
72399
|
+
if (isEffectItem) {
|
|
72400
|
+
return children;
|
|
72401
|
+
}
|
|
72402
|
+
/**
|
|
72403
|
+
* 递归展开子元素。
|
|
72404
|
+
* @param items 当前层子元素
|
|
72405
|
+
* @returns 当前层及其全部后代
|
|
72406
|
+
*/ function getAllChildren(items) {
|
|
72407
|
+
const result = [];
|
|
72408
|
+
for (const child of items){
|
|
72409
|
+
result.push(child);
|
|
72410
|
+
if (child.children && child.children.length > 0) {
|
|
72411
|
+
result.push(...getAllChildren(child.children));
|
|
72412
|
+
}
|
|
72413
|
+
}
|
|
72414
|
+
return result;
|
|
72415
|
+
}
|
|
72416
|
+
if (isFrameItem) {
|
|
72417
|
+
return getAllChildren(item.children);
|
|
72418
|
+
} else if (item.children && item.children.length > 0) {
|
|
72419
|
+
return getAllChildren(item.children);
|
|
72420
|
+
}
|
|
72421
|
+
return children;
|
|
72422
|
+
}
|
|
72423
|
+
/**
|
|
72424
|
+
* 在合成元素树内按实例 ID 查找元素。
|
|
72425
|
+
* @param composition 合成(无合成返回 undefined)
|
|
72426
|
+
* @param id 元素 instanceId
|
|
72427
|
+
* @returns 命中元素;未命中或无合成返回 undefined
|
|
72428
|
+
*/ function getPlayerItemById(composition, id) {
|
|
72429
|
+
if (!composition) {
|
|
72430
|
+
return undefined;
|
|
72431
|
+
}
|
|
72432
|
+
/**
|
|
72433
|
+
* 在当前元素子树中递归查找实例。
|
|
72434
|
+
* @param items 当前层元素。
|
|
72435
|
+
* @param targetId 目标实例 ID。
|
|
72436
|
+
* @returns 命中的元素。
|
|
72437
|
+
*/ const dfs = (items, targetId)=>{
|
|
72438
|
+
for (const item of items){
|
|
72439
|
+
if (item.getInstanceId() === targetId) {
|
|
72440
|
+
return item;
|
|
72441
|
+
}
|
|
72442
|
+
const found = dfs(item.children, targetId);
|
|
72443
|
+
if (found) {
|
|
72444
|
+
return found;
|
|
72445
|
+
}
|
|
72446
|
+
}
|
|
72447
|
+
return undefined;
|
|
72448
|
+
};
|
|
72449
|
+
return dfs(composition.items, id);
|
|
72450
|
+
}
|
|
72451
|
+
/**
|
|
72452
|
+
* 过滤掉祖先也在列表中的元素,仅保留顶层元素。
|
|
72453
|
+
* @param items 待过滤元素
|
|
72454
|
+
* @returns 保持原顺序的顶层元素
|
|
72455
|
+
*/ function filterTopLevelPlayerItems(items) {
|
|
72456
|
+
const selectedItems = new Set(items);
|
|
72457
|
+
return items.filter((item)=>{
|
|
72458
|
+
let parent = item.parent;
|
|
72459
|
+
while(parent){
|
|
72460
|
+
if (selectedItems.has(parent)) {
|
|
72461
|
+
return false;
|
|
72462
|
+
}
|
|
72463
|
+
parent = parent.parent;
|
|
72464
|
+
}
|
|
72465
|
+
return true;
|
|
72466
|
+
});
|
|
72467
|
+
}
|
|
72468
|
+
/**
|
|
72469
|
+
* 获取播放器元素的视图包围盒。
|
|
72470
|
+
* @param item 播放器元素
|
|
72471
|
+
* @param containerSize 视图大小
|
|
72472
|
+
* @returns 视图包围盒
|
|
71936
72473
|
*/ function getItemViewBox(item, containerSize) {
|
|
71937
72474
|
// 1. 跳过不可见元素并收集子元素。
|
|
71938
72475
|
const box = new Box2();
|
|
@@ -71985,21 +72522,21 @@ class GizmoViewportUtils {
|
|
|
71985
72522
|
}
|
|
71986
72523
|
return box;
|
|
71987
72524
|
}
|
|
71988
|
-
/**
|
|
71989
|
-
* 获取播放器元素在视图中的锚点坐标。
|
|
71990
|
-
* @param item 播放器元素
|
|
71991
|
-
* @param containerSize 视图容器大小
|
|
71992
|
-
* @returns 视图锚点坐标
|
|
72525
|
+
/**
|
|
72526
|
+
* 获取播放器元素在视图中的锚点坐标。
|
|
72527
|
+
* @param item 播放器元素
|
|
72528
|
+
* @param containerSize 视图容器大小
|
|
72529
|
+
* @returns 视图锚点坐标
|
|
71993
72530
|
*/ function getItemViewAnchor(item, containerSize) {
|
|
71994
72531
|
const anchor = item.transform.anchor ?? item.transform.position;
|
|
71995
72532
|
const worldAnchor = new Vector3().copyFrom(anchor).applyMatrix(new Matrix4().copyFrom(item.transform.getWorldMatrix()));
|
|
71996
72533
|
const viewAnchor = projectPoint(worldAnchor, item, containerSize).multiply(100).round().divide(100);
|
|
71997
72534
|
return viewAnchor;
|
|
71998
72535
|
}
|
|
71999
|
-
/**
|
|
72000
|
-
* 获取元素的变换矩阵和父级变换矩阵。
|
|
72001
|
-
* @param item 播放器元素
|
|
72002
|
-
* @returns 元素的变换矩阵和父级变换矩阵
|
|
72536
|
+
/**
|
|
72537
|
+
* 获取元素的变换矩阵和父级变换矩阵。
|
|
72538
|
+
* @param item 播放器元素
|
|
72539
|
+
* @returns 元素的变换矩阵和父级变换矩阵
|
|
72003
72540
|
*/ function getItemTransform(item) {
|
|
72004
72541
|
const transform = {
|
|
72005
72542
|
matrix: new Matrix4(),
|
|
@@ -72013,43 +72550,11 @@ class GizmoViewportUtils {
|
|
|
72013
72550
|
}
|
|
72014
72551
|
return transform;
|
|
72015
72552
|
}
|
|
72016
|
-
/**
|
|
72017
|
-
*
|
|
72018
|
-
*
|
|
72019
|
-
*
|
|
72020
|
-
|
|
72021
|
-
const children = [];
|
|
72022
|
-
const isFrameItem = isFramePlayerItem(item);
|
|
72023
|
-
const isEffectItem = isEffectsPlayerItem(item);
|
|
72024
|
-
if (isEffectItem) {
|
|
72025
|
-
return children;
|
|
72026
|
-
}
|
|
72027
|
-
/**
|
|
72028
|
-
* 递归展开子元素。
|
|
72029
|
-
* @param items 当前层子元素
|
|
72030
|
-
* @returns 当前层及其全部后代
|
|
72031
|
-
*/ function getAllChildren(items) {
|
|
72032
|
-
const result = [];
|
|
72033
|
-
for (const child of items){
|
|
72034
|
-
result.push(child);
|
|
72035
|
-
if (child.children && child.children.length > 0) {
|
|
72036
|
-
result.push(...getAllChildren(child.children));
|
|
72037
|
-
}
|
|
72038
|
-
}
|
|
72039
|
-
return result;
|
|
72040
|
-
}
|
|
72041
|
-
if (isFrameItem) {
|
|
72042
|
-
return getAllChildren(item.children);
|
|
72043
|
-
} else if (item.children && item.children.length > 0) {
|
|
72044
|
-
return getAllChildren(item.children);
|
|
72045
|
-
}
|
|
72046
|
-
return children;
|
|
72047
|
-
}
|
|
72048
|
-
/**
|
|
72049
|
-
* 获取元素在所属合成坐标系中的实际世界尺寸。
|
|
72050
|
-
*
|
|
72051
|
-
* `transform.size` 是元素本地尺寸;这里叠加元素到合成根之间的缩放,
|
|
72052
|
-
* 但排除合成本身的世界变换,与 Frame 尺寸写回使用的坐标系保持一致。
|
|
72553
|
+
/**
|
|
72554
|
+
* 获取元素在所属合成坐标系中的实际世界尺寸。
|
|
72555
|
+
*
|
|
72556
|
+
* `transform.size` 是元素本地尺寸;这里叠加元素到合成根之间的缩放,
|
|
72557
|
+
* 但排除合成本身的世界变换,与 Frame 尺寸写回使用的坐标系保持一致。
|
|
72053
72558
|
* @param item 播放器元素
|
|
72054
72559
|
* @returns 元素在所属合成坐标系中的尺寸
|
|
72055
72560
|
*/ function getItemWorldSize(item) {
|
|
@@ -72061,1256 +72566,432 @@ class GizmoViewportUtils {
|
|
|
72061
72566
|
itemToComposition.decompose(new Vector3(), new Quaternion(), worldScale);
|
|
72062
72567
|
return new Vector2(Math.abs(transform.size.x * worldScale.x), Math.abs(transform.size.y * worldScale.y));
|
|
72063
72568
|
}
|
|
72064
|
-
/**
|
|
72065
|
-
* 在合成元素树内按实例 ID 查找元素。
|
|
72066
|
-
* @param composition 合成(无合成返回 undefined)
|
|
72067
|
-
* @param id 元素 instanceId
|
|
72068
|
-
* @returns 命中元素;未命中或无合成返回 undefined
|
|
72069
|
-
*/ function getPlayerItemById(composition, id) {
|
|
72070
|
-
if (!composition) {
|
|
72071
|
-
return undefined;
|
|
72072
|
-
}
|
|
72073
|
-
/**
|
|
72074
|
-
* 在当前元素子树中递归查找实例。
|
|
72075
|
-
* @param items 当前层元素。
|
|
72076
|
-
* @param targetId 目标实例 ID。
|
|
72077
|
-
* @returns 命中的元素。
|
|
72078
|
-
*/ const dfs = (items, targetId)=>{
|
|
72079
|
-
for (const item of items){
|
|
72080
|
-
if (item.getInstanceId() === targetId) {
|
|
72081
|
-
return item;
|
|
72082
|
-
}
|
|
72083
|
-
const found = dfs(item.children, targetId);
|
|
72084
|
-
if (found) {
|
|
72085
|
-
return found;
|
|
72086
|
-
}
|
|
72087
|
-
}
|
|
72088
|
-
return undefined;
|
|
72089
|
-
};
|
|
72090
|
-
return dfs(composition.items, id);
|
|
72091
|
-
}
|
|
72092
72569
|
/**
|
|
72093
|
-
*
|
|
72094
|
-
* @param
|
|
72095
|
-
* @
|
|
72096
|
-
|
|
72097
|
-
|
|
72098
|
-
|
|
72099
|
-
|
|
72100
|
-
|
|
72101
|
-
if (selectedItems.has(parent)) {
|
|
72102
|
-
return false;
|
|
72103
|
-
}
|
|
72104
|
-
parent = parent.parent;
|
|
72105
|
-
}
|
|
72106
|
-
return true;
|
|
72107
|
-
});
|
|
72108
|
-
}
|
|
72109
|
-
/**
|
|
72110
|
-
* 播放视频元素。
|
|
72111
|
-
* @param engine 引擎
|
|
72112
|
-
* @param id 视频元素 id
|
|
72113
|
-
*/ function playVideoItem(engine, id) {
|
|
72114
|
-
const playerItem = getPlayerItemById(engine.compositions[0], id);
|
|
72115
|
-
if (playerItem?.type !== index$1.ItemType.video) {
|
|
72570
|
+
* 调整画板元素(Frame)的尺寸与位置,并同步其子合成 Item 的位移。
|
|
72571
|
+
* @param frameItem 画板元素(Frame 空节点控制器)
|
|
72572
|
+
* @param worldSize 目标世界尺寸(所属合成坐标系,不受 viewport zoom 影响)
|
|
72573
|
+
* @param translation 位移
|
|
72574
|
+
* @param initialSize pointer down 时冻结的本地 / 世界尺寸;传入后允许尺寸连续经过 0 并变为负值
|
|
72575
|
+
*/ function resizeFrameItem(frameItem, worldSize, translation, initialSize) {
|
|
72576
|
+
if (!isFramePlayerItem(frameItem)) {
|
|
72577
|
+
console.warn(`Item ${frameItem.getInstanceId()} is not a frame item.`);
|
|
72116
72578
|
return;
|
|
72117
72579
|
}
|
|
72118
|
-
|
|
72119
|
-
|
|
72120
|
-
|
|
72121
|
-
|
|
72122
|
-
*
|
|
72123
|
-
|
|
72124
|
-
|
|
72125
|
-
|
|
72126
|
-
|
|
72127
|
-
|
|
72128
|
-
return;
|
|
72580
|
+
// 1. 根据本地尺寸与世界尺寸的比例写回画板尺寸。
|
|
72581
|
+
const currentWorldSize = initialSize?.worldSize ?? getItemWorldSize(frameItem);
|
|
72582
|
+
const currentLocalSize = initialSize?.localSize ?? frameItem.transform.size;
|
|
72583
|
+
const localWidth = currentWorldSize.x === 0 ? worldSize.x : currentLocalSize.x * worldSize.x / currentWorldSize.x;
|
|
72584
|
+
const localHeight = currentWorldSize.y === 0 ? worldSize.y : currentLocalSize.y * worldSize.y / currentWorldSize.y;
|
|
72585
|
+
frameItem.transform.setSize(localWidth, localHeight);
|
|
72586
|
+
// 2. 将交互位移应用到画板。
|
|
72587
|
+
if (translation && (translation.x !== 0 || translation.y !== 0)) {
|
|
72588
|
+
const currentPosition = frameItem.transform.position;
|
|
72589
|
+
frameItem.setPosition(currentPosition.x + translation.x, currentPosition.y + translation.y, currentPosition.z);
|
|
72129
72590
|
}
|
|
72130
|
-
|
|
72131
|
-
|
|
72132
|
-
|
|
72133
|
-
|
|
72134
|
-
|
|
72135
|
-
|
|
72136
|
-
|
|
72137
|
-
|
|
72138
|
-
|
|
72139
|
-
|
|
72140
|
-
if (compositionItem?.type !== index$1.ItemType.composition) {
|
|
72141
|
-
return;
|
|
72591
|
+
// 3. 反向补偿子合成元素,保持其世界位置不变。
|
|
72592
|
+
const subCompositionItem = frameItem?.children?.[0];
|
|
72593
|
+
if (subCompositionItem && translation) {
|
|
72594
|
+
subCompositionItem.children.forEach((item)=>{
|
|
72595
|
+
const parentMatrix = new Matrix4().copyFrom(item.transform.getParentMatrix() ?? new Matrix4());
|
|
72596
|
+
parentMatrix.setPosition(new Vector3());
|
|
72597
|
+
const result = translation.clone().applyMatrix(parentMatrix.invert()).negate();
|
|
72598
|
+
item.translate(...result.toArray());
|
|
72599
|
+
item.transform.updateLocalMatrix();
|
|
72600
|
+
});
|
|
72142
72601
|
}
|
|
72143
|
-
compositionItem.getComponent(CompositionComponent).play();
|
|
72144
72602
|
}
|
|
72145
|
-
/**
|
|
72146
|
-
|
|
72147
|
-
|
|
72148
|
-
|
|
72149
|
-
|
|
72150
|
-
|
|
72151
|
-
|
|
72152
|
-
|
|
72153
|
-
|
|
72603
|
+
/** 创建 VFXItem、挂载组件并加入合成的底层工厂。 */ class VFXItemFactory {
|
|
72604
|
+
/**
|
|
72605
|
+
* 创建并挂载 VFXItem。
|
|
72606
|
+
* @param composition 目标合成
|
|
72607
|
+
* @param parent 父元素
|
|
72608
|
+
* @param name 元素名称
|
|
72609
|
+
* @param types 待挂载的组件类型
|
|
72610
|
+
* @returns 新建的 VFXItem
|
|
72611
|
+
*/ static createVFXItem(composition, parent = null, name = 'NewVFXItem', ...types) {
|
|
72612
|
+
const vfxItem = new VFXItem(composition.engine);
|
|
72613
|
+
vfxItem.name = name;
|
|
72614
|
+
for (const type of types){
|
|
72615
|
+
vfxItem.addComponent(type);
|
|
72616
|
+
}
|
|
72617
|
+
composition.addItem(vfxItem);
|
|
72618
|
+
// @ts-expect-error rootComposition.items 的类型未公开受支持的写入操作。
|
|
72619
|
+
composition.rootComposition.items.push(vfxItem);
|
|
72620
|
+
if (parent) {
|
|
72621
|
+
vfxItem.setParent(parent);
|
|
72622
|
+
}
|
|
72623
|
+
return vfxItem;
|
|
72154
72624
|
}
|
|
72155
|
-
compositionItem.getComponent(CompositionComponent).pause();
|
|
72156
72625
|
}
|
|
72157
|
-
/**
|
|
72158
|
-
/**
|
|
72159
|
-
|
|
72160
|
-
|
|
72161
|
-
|
|
72162
|
-
|
|
72163
|
-
|
|
72164
|
-
|
|
72165
|
-
|
|
72166
|
-
|
|
72167
|
-
|
|
72168
|
-
* @param alpha 透明度 0..1
|
|
72169
|
-
* @returns effects Color
|
|
72170
|
-
*/ function toColor(hex, alpha = 1) {
|
|
72171
|
-
const key = `${hex}_${alpha}`;
|
|
72172
|
-
const cached = colorCache.get(key);
|
|
72173
|
-
if (cached) {
|
|
72174
|
-
return cached;
|
|
72175
|
-
}
|
|
72176
|
-
const color = new Color((hex >> 16 & 0xff) / 255, (hex >> 8 & 0xff) / 255, (hex & 0xff) / 255, alpha);
|
|
72177
|
-
colorCache.set(key, color);
|
|
72178
|
-
return color;
|
|
72179
|
-
}
|
|
72180
|
-
/**
|
|
72181
|
-
* 离屏文本测量上下文,懒加载并复用。
|
|
72182
|
-
*/ let _measureCtx = null;
|
|
72183
|
-
/**
|
|
72184
|
-
* 测量文本的宽度与可见字形边界。
|
|
72185
|
-
* @param text 文本内容
|
|
72186
|
-
* @param fontSize 字号
|
|
72187
|
-
* @param fontFamily 字体
|
|
72188
|
-
* @param fontWeight 字重
|
|
72189
|
-
* @param fontStyle 字体样式
|
|
72190
|
-
* @returns 文本测量结果
|
|
72191
|
-
*/ function measureTextMetrics(text, fontSize = INFO_TEXT_FONT_SIZE, fontFamily = INFO_TEXT_FONT_FAMILY, fontWeight, fontStyle) {
|
|
72192
|
-
_measureCtx ?? (_measureCtx = document.createElement('canvas').getContext('2d'));
|
|
72193
|
-
if (!_measureCtx) {
|
|
72194
|
-
return {
|
|
72195
|
-
width: 0,
|
|
72196
|
-
actualBoundingBoxAscent: 0,
|
|
72197
|
-
actualBoundingBoxDescent: 0
|
|
72198
|
-
};
|
|
72199
|
-
}
|
|
72200
|
-
_measureCtx.font = `${''}${fontWeight ? `${fontWeight} ` : ''}${fontSize}px ${fontFamily}`;
|
|
72201
|
-
const metrics = _measureCtx.measureText(text);
|
|
72202
|
-
return {
|
|
72203
|
-
width: metrics.width,
|
|
72204
|
-
actualBoundingBoxAscent: metrics.actualBoundingBoxAscent ?? 0,
|
|
72205
|
-
actualBoundingBoxDescent: metrics.actualBoundingBoxDescent ?? 0
|
|
72206
|
-
};
|
|
72207
|
-
}
|
|
72208
|
-
/**
|
|
72209
|
-
* 计算 effects Control.drawText 实际使用的 atlas cell 高度。
|
|
72210
|
-
* @param fontSize 字号
|
|
72211
|
-
* @param fontFamily 字体
|
|
72212
|
-
* @param fontWeight 字重
|
|
72213
|
-
* @param fontStyle 字体样式
|
|
72214
|
-
* @param resolution 渲染分辨率
|
|
72215
|
-
* @returns 字符图集单元格高度
|
|
72216
|
-
*/ function measureControlTextCellHeight(fontSize = INFO_TEXT_FONT_SIZE, fontFamily = INFO_TEXT_FONT_FAMILY, fontWeight, fontStyle, resolution = 1) {
|
|
72217
|
-
const safeResolution = Number.isFinite(resolution) && resolution > 0 ? resolution : 1;
|
|
72218
|
-
const scaledFontSize = fontSize * safeResolution;
|
|
72219
|
-
const metrics = measureTextMetrics(METRICS_STRING + BASELINE_SYMBOL, scaledFontSize, fontFamily, fontWeight);
|
|
72220
|
-
const ascent = metrics.actualBoundingBoxAscent || scaledFontSize * 0.8;
|
|
72221
|
-
const descent = metrics.actualBoundingBoxDescent || scaledFontSize * 0.2;
|
|
72222
|
-
return Math.ceil(ascent + descent + CONTROL_TEXT_GLYPH_PADDING * 2 * safeResolution) / safeResolution;
|
|
72223
|
-
}
|
|
72224
|
-
/**
|
|
72225
|
-
* 测量文本宽度(逻辑像素),用于信息标签的溢出判断与右对齐定位。
|
|
72226
|
-
* @param text 文本内容
|
|
72227
|
-
* @param fontSize 字号
|
|
72228
|
-
* @param fontFamily 字体
|
|
72229
|
-
* @param fontWeight 字重
|
|
72230
|
-
* @returns 文本宽度
|
|
72231
|
-
*/ function measureTextWidth(text, fontSize = INFO_TEXT_FONT_SIZE, fontFamily = INFO_TEXT_FONT_FAMILY, fontWeight) {
|
|
72232
|
-
return measureTextMetrics(text, fontSize, fontFamily, fontWeight).width;
|
|
72233
|
-
}
|
|
72234
|
-
/**
|
|
72235
|
-
* 单行文本截断:逐字符累加,超出可用宽度时把最后两个字符替换为省略号。
|
|
72236
|
-
* @param text 文本内容
|
|
72237
|
-
* @param maxWidth 可用宽度
|
|
72238
|
-
* @param fontSize 字号
|
|
72239
|
-
* @param fontFamily 字体
|
|
72240
|
-
* @returns 截断后的文本
|
|
72241
|
-
*/ function truncateText(text, maxWidth, fontSize = INFO_TEXT_FONT_SIZE, fontFamily = INFO_TEXT_FONT_FAMILY) {
|
|
72242
|
-
if (measureTextWidth(text, fontSize, fontFamily) <= maxWidth) {
|
|
72243
|
-
return text;
|
|
72244
|
-
}
|
|
72245
|
-
let current = '';
|
|
72246
|
-
for (const char of text){
|
|
72247
|
-
if (measureTextWidth(current + char, fontSize, fontFamily) > maxWidth) {
|
|
72248
|
-
return current.length > 2 ? current.slice(0, -2) + '...' : '...';
|
|
72249
|
-
}
|
|
72250
|
-
current += char;
|
|
72251
|
-
}
|
|
72252
|
-
return current;
|
|
72253
|
-
}
|
|
72254
|
-
/**
|
|
72255
|
-
* 多行逐字符折行:行宽超出 maxWidth 时换行;行数达到 maxLines 时末行用省略号收尾。
|
|
72256
|
-
* @param text 文本内容
|
|
72257
|
-
* @param maxWidth 单行可用宽度
|
|
72258
|
-
* @param maxLines 最大行数
|
|
72259
|
-
* @param fontSize 字号
|
|
72260
|
-
* @param fontFamily 字体
|
|
72261
|
-
* @returns 折行后的文本行数组
|
|
72262
|
-
*/ function wrapText(text, maxWidth, maxLines, fontSize = INFO_TEXT_FONT_SIZE, fontFamily = INFO_TEXT_FONT_FAMILY) {
|
|
72263
|
-
const lines = [];
|
|
72264
|
-
let currentLine = '';
|
|
72265
|
-
const chars = text.split('');
|
|
72266
|
-
for(let i = 0; i < chars.length; i++){
|
|
72267
|
-
const char = chars[i];
|
|
72268
|
-
const testLine = currentLine + char;
|
|
72269
|
-
if (measureTextWidth(testLine, fontSize, fontFamily) > maxWidth) {
|
|
72270
|
-
lines.push(currentLine);
|
|
72271
|
-
if (lines.length >= maxLines) {
|
|
72272
|
-
const lastLine = lines[maxLines - 1];
|
|
72273
|
-
lines[maxLines - 1] = lastLine.length > 2 ? lastLine.slice(0, -2) + '...' : '...';
|
|
72274
|
-
break;
|
|
72275
|
-
}
|
|
72276
|
-
currentLine = char;
|
|
72277
|
-
} else {
|
|
72278
|
-
currentLine = testLine;
|
|
72279
|
-
}
|
|
72280
|
-
if (i === chars.length - 1 && currentLine) {
|
|
72281
|
-
lines.push(currentLine);
|
|
72282
|
-
}
|
|
72283
|
-
}
|
|
72284
|
-
return lines.slice(0, maxLines);
|
|
72285
|
-
}
|
|
72286
|
-
/**
|
|
72287
|
-
* 绘制由 4 个角点构成的(可能非正交的)包围盒边框。
|
|
72288
|
-
* @param control 绘制控制器
|
|
72289
|
-
* @param corners 4 个角点(视图坐标,Y 向下)
|
|
72290
|
-
* @param color 边框颜色
|
|
72291
|
-
* @param width 线宽
|
|
72292
|
-
*/ function drawCorners(control, corners, color, width) {
|
|
72293
|
-
if (corners.length < 4) {
|
|
72294
|
-
return;
|
|
72295
|
-
}
|
|
72296
|
-
for(let i = 0; i < 4; i++){
|
|
72297
|
-
const start = corners[i];
|
|
72298
|
-
const end = corners[(i + 1) % 4];
|
|
72299
|
-
control.drawLine(start.x, start.y, end.x, end.y, color, width);
|
|
72300
|
-
}
|
|
72301
|
-
}
|
|
72302
|
-
/**
|
|
72303
|
-
* 绘制虚线包围盒,并在相邻边之间保持连续虚线相位。
|
|
72304
|
-
* @param control 绘制控制器
|
|
72305
|
-
* @param corners 四个视图角点
|
|
72306
|
-
* @param color 虚线颜色
|
|
72307
|
-
* @param width 线宽
|
|
72308
|
-
* @param dashLength 实线段长度
|
|
72309
|
-
* @param gapLength 间隔长度
|
|
72310
|
-
*/ function drawDashedCorners(control, corners, color, width, dashLength, gapLength) {
|
|
72311
|
-
// 1. 校验角点和虚线参数。
|
|
72312
|
-
if (corners.length < 4 || dashLength <= 0 || gapLength < 0) {
|
|
72313
|
-
return;
|
|
72314
|
-
}
|
|
72315
|
-
const patternLength = dashLength + gapLength;
|
|
72316
|
-
let perimeterOffset = 0;
|
|
72317
|
-
// 2. 逐边计算虚线相位,并继承上一条边的周长偏移。
|
|
72318
|
-
for(let i = 0; i < 4; i++){
|
|
72319
|
-
const start = corners[i];
|
|
72320
|
-
const end = corners[(i + 1) % 4];
|
|
72321
|
-
const dx = end.x - start.x;
|
|
72322
|
-
const dy = end.y - start.y;
|
|
72323
|
-
const edgeLength = Math.hypot(dx, dy);
|
|
72324
|
-
if (edgeLength <= Number.EPSILON) {
|
|
72325
|
-
continue;
|
|
72326
|
-
}
|
|
72327
|
-
let edgeOffset = 0;
|
|
72328
|
-
while(edgeOffset < edgeLength){
|
|
72329
|
-
const patternOffset = perimeterOffset % patternLength;
|
|
72330
|
-
const drawingDash = gapLength === 0 || patternOffset < dashLength;
|
|
72331
|
-
const phaseRemaining = drawingDash ? dashLength - patternOffset : patternLength - patternOffset;
|
|
72332
|
-
const segmentLength = Math.min(phaseRemaining, edgeLength - edgeOffset);
|
|
72333
|
-
// 3. 仅绘制当前相位中的实线段。
|
|
72334
|
-
if (drawingDash && segmentLength > Number.EPSILON) {
|
|
72335
|
-
const startRatio = edgeOffset / edgeLength;
|
|
72336
|
-
const endRatio = (edgeOffset + segmentLength) / edgeLength;
|
|
72337
|
-
control.drawLine(start.x + dx * startRatio, start.y + dy * startRatio, start.x + dx * endRatio, start.y + dy * endRatio, color, width);
|
|
72338
|
-
}
|
|
72339
|
-
edgeOffset += segmentLength;
|
|
72340
|
-
perimeterOffset += segmentLength;
|
|
72341
|
-
}
|
|
72342
|
-
}
|
|
72343
|
-
}
|
|
72344
|
-
/**
|
|
72345
|
-
* 绘制包围盒边框(沿 4 个角点连边)。
|
|
72346
|
-
* @param control 绘制控制器
|
|
72347
|
-
* @param box 包围盒(视图坐标,Y 向下)
|
|
72348
|
-
* @param color 边框颜色
|
|
72349
|
-
* @param width 线宽
|
|
72350
|
-
*/ function drawBox(control, box, color, width) {
|
|
72351
|
-
drawCorners(control, box.corners, color, width);
|
|
72352
|
-
}
|
|
72353
|
-
/**
|
|
72354
|
-
* 填充轴对齐包围盒(实心矩形)。
|
|
72355
|
-
* @param control 绘制控制器
|
|
72356
|
-
* @param box 包围盒(视图坐标,Y 向下)
|
|
72357
|
-
* @param color 填充颜色
|
|
72358
|
-
*/ function fillBox(control, box, color) {
|
|
72359
|
-
const size = box.getSize();
|
|
72360
|
-
control.fillRect(box.min.x, box.min.y, size.x, size.y, color);
|
|
72361
|
-
}
|
|
72362
|
-
/**
|
|
72363
|
-
* 构造沿局部轴展开的旋转矩形角点。
|
|
72364
|
-
* @param center 矩形中心(视图坐标)
|
|
72365
|
-
* @param xAxis 局部 X 轴单位向量(视图坐标,宽方向)
|
|
72366
|
-
* @param yAxis 局部 Y 轴单位向量(视图坐标,高方向)
|
|
72367
|
-
* @param halfWidth 半宽(沿 xAxis,视图像素)
|
|
72368
|
-
* @param halfHeight 半高(沿 yAxis,视图像素)
|
|
72369
|
-
* @returns 4 个角点(视图坐标,环绕顺序)
|
|
72370
|
-
*/ function rotatedRectCorners(center, xAxis, yAxis, halfWidth, halfHeight) {
|
|
72371
|
-
const halfW = xAxis.clone().multiply(halfWidth);
|
|
72372
|
-
const halfH = yAxis.clone().multiply(halfHeight);
|
|
72373
|
-
return [
|
|
72374
|
-
center.clone().subtract(halfW).subtract(halfH),
|
|
72375
|
-
center.clone().add(halfW).subtract(halfH),
|
|
72376
|
-
center.clone().add(halfW).add(halfH),
|
|
72377
|
-
center.clone().subtract(halfW).add(halfH)
|
|
72378
|
-
];
|
|
72379
|
-
}
|
|
72380
|
-
/**
|
|
72381
|
-
* 填充沿局部轴展开的旋转矩形。
|
|
72382
|
-
* @param control 绘制控制器
|
|
72383
|
-
* @param center 矩形中心(视图坐标)
|
|
72384
|
-
* @param xAxis 局部 X 轴单位向量(视图坐标,宽方向)
|
|
72385
|
-
* @param yAxis 局部 Y 轴单位向量(视图坐标,高方向)
|
|
72386
|
-
* @param width 宽(沿 xAxis,视图像素)
|
|
72387
|
-
* @param height 高(沿 yAxis,视图像素)
|
|
72388
|
-
* @param color 填充颜色
|
|
72389
|
-
*/ function fillRotatedRect(control, center, xAxis, yAxis, width, height, color) {
|
|
72390
|
-
const ex = xAxis.clone();
|
|
72391
|
-
const ey = yAxis.clone();
|
|
72392
|
-
const anchor = center.clone();
|
|
72393
|
-
drawRotatedQuad(control, anchor, ex, ey, ()=>{
|
|
72394
|
-
control.fillRect(-width / 2, -height / 2, width, height, color);
|
|
72395
|
-
});
|
|
72396
|
-
}
|
|
72397
|
-
/**
|
|
72398
|
-
* 在由锚点和两个基向量定义的局部坐标系内执行绘制。
|
|
72399
|
-
* @param control 绘制控制器
|
|
72400
|
-
* @param anchor Control 绘制空间锚点(局部原点)
|
|
72401
|
-
* @param ex 局部 X 轴基向量(单位向量)
|
|
72402
|
-
* @param ey 局部 Y 轴基向量(单位向量)
|
|
72403
|
-
* @param drawFn 在局部坐标系内执行的绘制
|
|
72404
|
-
*/ function drawRotatedQuad(control, anchor, ex, ey, drawFn) {
|
|
72405
|
-
const graphics = control.engine.graphics;
|
|
72406
|
-
// 列优先:第一列 = ex,第二列 = ey,第三列 = anchor(平移)
|
|
72407
|
-
const matrix = Matrix3.fromColumnVectors(new Vector3(ex.x, ex.y, 0), new Vector3(ey.x, ey.y, 0), new Vector3(anchor.x, anchor.y, 1));
|
|
72408
|
-
graphics.pushTransform(matrix);
|
|
72409
|
-
drawFn();
|
|
72410
|
-
graphics.popTransform();
|
|
72411
|
-
}
|
|
72412
|
-
const DEFAULT_LOADING_FRAGMENT = `
|
|
72413
|
-
// Shadertoy Fragment Shader
|
|
72414
|
-
// Diagonal background gradient + wider colorful transparent shimmer
|
|
72415
|
-
|
|
72416
|
-
precision highp float;
|
|
72417
|
-
|
|
72418
|
-
varying vec2 vUV;
|
|
72419
|
-
|
|
72420
|
-
uniform vec4 _Time;
|
|
72421
|
-
|
|
72422
|
-
// ------------------------------------------------------------
|
|
72423
|
-
// Background
|
|
72424
|
-
// ------------------------------------------------------------
|
|
72425
|
-
vec3 background(vec2 uv) {
|
|
72426
|
-
vec3 topLeft = vec3(0.88, 0.85, 1.00);
|
|
72427
|
-
vec3 bottomRight = vec3(0.98, 0.98, 0.98);
|
|
72428
|
-
|
|
72429
|
-
float d = (uv.x + (1.0 - uv.y)) * 0.5;
|
|
72430
|
-
d = smoothstep(0.0, 1.0, d);
|
|
72431
|
-
|
|
72432
|
-
vec3 col = mix(topLeft, bottomRight, d);
|
|
72433
|
-
|
|
72434
|
-
vec2 p1 = uv - vec2(1.13, 1.40);
|
|
72435
|
-
float r1 = length(p1 / vec2(0.85, 0.85));
|
|
72436
|
-
float g1 = 1.0 - smoothstep(0.0, 0.96, r1);
|
|
72437
|
-
col += vec3(172.0/255.0, 183.0/255.0, 1.0) * g1 * 0.28;
|
|
72438
|
-
|
|
72439
|
-
vec2 p2 = uv - vec2(0.25, 0.23);
|
|
72440
|
-
float r2 = length(p2 / vec2(0.74, 0.64));
|
|
72441
|
-
float g2 = 1.0 - smoothstep(0.0, 1.0, r2);
|
|
72442
|
-
col += vec3(147.0/255.0, 108.0/255.0, 1.0) * g2 * 0.10;
|
|
72443
|
-
|
|
72444
|
-
return col;
|
|
72445
|
-
}
|
|
72446
|
-
|
|
72447
|
-
// ------------------------------------------------------------
|
|
72448
|
-
// Easing: slow at start, fast at end
|
|
72449
|
-
// ------------------------------------------------------------
|
|
72450
|
-
float easeInQuad(float x) {
|
|
72451
|
-
return x * x;
|
|
72452
|
-
}
|
|
72453
|
-
|
|
72454
|
-
// ------------------------------------------------------------
|
|
72455
|
-
// Color palette helper
|
|
72456
|
-
// ------------------------------------------------------------
|
|
72457
|
-
vec3 palette(float t) {
|
|
72458
|
-
// 柔和的彩色条:蓝 -> 青 -> 紫 -> 粉 -> 蓝
|
|
72459
|
-
vec3 a = vec3(0.62, 0.82, 1.00);
|
|
72460
|
-
vec3 b = vec3(0.72, 0.95, 1.00);
|
|
72461
|
-
vec3 c = vec3(0.83, 0.76, 1.00);
|
|
72462
|
-
vec3 d = vec3(1.00, 0.82, 0.95);
|
|
72463
|
-
|
|
72464
|
-
t = fract(t);
|
|
72465
|
-
|
|
72466
|
-
if (t < 0.33) {
|
|
72467
|
-
float k = smoothstep(0.0, 0.33, t);
|
|
72468
|
-
return mix(a, b, k);
|
|
72469
|
-
} else if (t < 0.66) {
|
|
72470
|
-
float k = smoothstep(0.33, 0.66, t);
|
|
72471
|
-
return mix(b, c, k);
|
|
72472
|
-
} else {
|
|
72473
|
-
float k = smoothstep(0.66, 1.0, t);
|
|
72474
|
-
return mix(c, d, k);
|
|
72475
|
-
}
|
|
72476
|
-
}
|
|
72477
|
-
|
|
72478
|
-
// ------------------------------------------------------------
|
|
72479
|
-
// Wider colorful transparent left-to-right shimmer
|
|
72480
|
-
// ------------------------------------------------------------
|
|
72481
|
-
vec4 shimmerBand(vec2 uv, float t) {
|
|
72482
|
-
float cycle = fract(t * 0.70);
|
|
72483
|
-
cycle = easeInQuad(cycle);
|
|
72484
|
-
|
|
72485
|
-
float x = cycle * 1.55 - 0.25; // sweep from left to right
|
|
72486
|
-
|
|
72487
|
-
float d = abs(uv.x - x);
|
|
72488
|
-
float band = 1.0 - smoothstep(0.0, 0.30, d);
|
|
72489
|
-
float core = 1.0 - smoothstep(0.0, 0.10, d);
|
|
72490
|
-
|
|
72491
|
-
float x2 = x + (uv.y - 0.5) * 0.18;
|
|
72492
|
-
float d2 = abs(uv.x - x2);
|
|
72493
|
-
float band2 = 1.0 - smoothstep(0.0, 0.20, d2);
|
|
72494
|
-
|
|
72495
|
-
float s = max(band * 0.85, band2 * 0.60);
|
|
72496
|
-
s = max(s, core * 0.95);
|
|
72497
|
-
s = clamp(s, 0.0, 1.0);
|
|
72498
|
-
|
|
72499
|
-
// 颜色沿条带变化,模拟彩色渐变
|
|
72500
|
-
float hueT = uv.y * 0.25 + uv.x * 0.60 + t * 0.10;
|
|
72501
|
-
vec3 color1 = palette(hueT);
|
|
72502
|
-
|
|
72503
|
-
// 中间更亮一点,边缘更淡
|
|
72504
|
-
vec3 color2 = mix(color1, vec3(1.0), core * 0.35);
|
|
72505
|
-
|
|
72506
|
-
return vec4(color2, s);
|
|
72507
|
-
}
|
|
72508
|
-
|
|
72509
|
-
// ------------------------------------------------------------
|
|
72510
|
-
// Main
|
|
72511
|
-
// ------------------------------------------------------------
|
|
72512
|
-
void main() {
|
|
72513
|
-
vec2 uv = vUV;
|
|
72514
|
-
|
|
72515
|
-
vec3 col = background(uv);
|
|
72516
|
-
|
|
72517
|
-
vec4 sh = shimmerBand(uv, _Time.y);
|
|
72518
|
-
|
|
72519
|
-
// 可选:增加一点柔光感
|
|
72520
|
-
col += sh.rgb * sh.a * 0.06;
|
|
72521
|
-
|
|
72522
|
-
gl_FragColor = vec4(col, 1.0);
|
|
72523
|
-
}`;
|
|
72524
|
-
const loadingConfig = defineConfig({
|
|
72525
|
-
id: 'feedback.loading',
|
|
72526
|
-
defaults: {
|
|
72527
|
-
loadingFragment: DEFAULT_LOADING_FRAGMENT
|
|
72528
|
-
}
|
|
72529
|
-
});
|
|
72530
|
-
const LOADING_TIP_FONT_SIZE = 16;
|
|
72531
|
-
const LOADING_TIP_FONT_FAMILY = 'sans-serif';
|
|
72532
|
-
const LOADING_TIP_COLOR = 0x000000;
|
|
72533
|
-
/** 为目标元素叠加加载动画与提示文案。 */ class LoadingGizmo extends Gizmo {
|
|
72534
|
-
/** 当前加载覆盖层配置。 */ get config() {
|
|
72535
|
-
return this._owner.getConfigManager().get(loadingConfig);
|
|
72536
|
-
}
|
|
72537
|
-
/** 当前 Gizmo 实例持有的可销毁渲染投影。 */ get idMap() {
|
|
72538
|
-
return this._idMap;
|
|
72539
|
-
}
|
|
72540
|
-
/** 当前 loading 元素 id 列表(由稳定 manager 派生)。 */ get loadingIds() {
|
|
72541
|
-
return this._manager.ids;
|
|
72542
|
-
}
|
|
72543
|
-
/**
|
|
72544
|
-
* 在片元着色器变化时重建加载动画对象。
|
|
72545
|
-
* @param change 加载配置变更。
|
|
72546
|
-
*/ _onConfigChange(change) {
|
|
72547
|
-
if (change.previous.loadingFragment === change.current.loadingFragment) {
|
|
72548
|
-
return;
|
|
72549
|
-
}
|
|
72550
|
-
for (const [id, loadingItem] of this._idMap){
|
|
72551
|
-
this._disposeLoadingVFXItem(loadingItem.loadingVFXItem);
|
|
72552
|
-
loadingItem.loadingVFXItem = this.createLoadingVFXItem();
|
|
72553
|
-
this.updateLoadingVFXItemTransform(id, loadingItem);
|
|
72554
|
-
}
|
|
72555
|
-
}
|
|
72556
|
-
/**
|
|
72557
|
-
* 订阅 loading 集合变化:add/delete 后回调当前全量 id 列表。
|
|
72558
|
-
* @param cb 收到当前全量 loading id 列表的回调
|
|
72559
|
-
* @returns 退订函数,调用后取消对应监听
|
|
72560
|
-
*/ onLoadingChange(cb) {
|
|
72561
|
-
return this._manager.on('change', (change)=>{
|
|
72562
|
-
if (change.addedIds.length > 0 || change.removedIds.length > 0) {
|
|
72563
|
-
cb(change.ids);
|
|
72564
|
-
}
|
|
72565
|
-
});
|
|
72566
|
-
}
|
|
72567
|
-
/**
|
|
72568
|
-
* 为指定元素添加 loading 覆盖层;同一元素不可重复添加。
|
|
72569
|
-
* @param id 目标元素 ID
|
|
72570
|
-
* @param options loading 配置(文案、位置、自定义区域、是否清空选中)
|
|
72571
|
-
*/ add(id, options) {
|
|
72572
|
-
this._manager.add(id, options);
|
|
72626
|
+
/** 创建内置类型 VFXItem 的便捷工厂。 */ class DefaultVFXItems {
|
|
72627
|
+
/**
|
|
72628
|
+
* 创建空元素。
|
|
72629
|
+
* @param composition 目标合成
|
|
72630
|
+
* @param parent 父元素
|
|
72631
|
+
* @param name 元素名称
|
|
72632
|
+
* @returns 新建的空元素
|
|
72633
|
+
*/ static createEmpty(composition, parent = null, name = 'NewVFXItem') {
|
|
72634
|
+
const vfxItem = VFXItemFactory.createVFXItem(composition, parent, name);
|
|
72635
|
+
vfxItem.type = index$1.ItemType.null;
|
|
72636
|
+
return vfxItem;
|
|
72573
72637
|
}
|
|
72574
72638
|
/**
|
|
72575
|
-
*
|
|
72576
|
-
* @param
|
|
72577
|
-
|
|
72578
|
-
|
|
72579
|
-
|
|
72580
|
-
|
|
72581
|
-
|
|
72582
|
-
|
|
72583
|
-
|
|
72584
|
-
*/ updateItem(id, options) {
|
|
72585
|
-
this._manager.update(id, options);
|
|
72586
|
-
}
|
|
72587
|
-
/** 根据目标元素的实时包围盒刷新加载动画。 */ onPreRender() {
|
|
72588
|
-
if (this._idMap.size === 0) {
|
|
72589
|
-
return;
|
|
72590
|
-
}
|
|
72591
|
-
for (const [id, loadingItem] of this._idMap){
|
|
72592
|
-
this.updateLoadingVFXItemTransform(id, loadingItem);
|
|
72593
|
-
}
|
|
72594
|
-
}
|
|
72595
|
-
/**
|
|
72596
|
-
* 绘制所有加载提示文案。
|
|
72597
|
-
* @param control 绘制控制器。
|
|
72598
|
-
*/ draw(control) {
|
|
72599
|
-
if (this._idMap.size === 0) {
|
|
72600
|
-
return;
|
|
72601
|
-
}
|
|
72602
|
-
for (const [id, loadingItem] of this._idMap){
|
|
72603
|
-
if (!loadingItem.tip?.text) {
|
|
72604
|
-
continue;
|
|
72605
|
-
}
|
|
72606
|
-
const item = getPlayerItemById(this._owner.getEngine().compositions[0], id);
|
|
72607
|
-
const itemBox = item ? getItemViewBox(item, GizmoViewportUtils.getContainerSize(this._owner.getEngine().canvas.parentElement)) : new Box2();
|
|
72608
|
-
const loadingBox = getBoxByNormalizeBox(itemBox, loadingItem.loadingBox);
|
|
72609
|
-
this.drawLoadingTip(control, loadingBox, itemBox, loadingItem.tip);
|
|
72610
|
-
}
|
|
72611
|
-
}
|
|
72612
|
-
/**
|
|
72613
|
-
* 绘制单条加载提示,并将文本限制在加载区域内。
|
|
72614
|
-
* @param control 绘制控制器。
|
|
72615
|
-
* @param loadingBox 加载区域。
|
|
72616
|
-
* @param itemBox 目标元素包围盒。
|
|
72617
|
-
* @param tip 加载提示配置。
|
|
72618
|
-
*/ drawLoadingTip(control, loadingBox, itemBox, tip) {
|
|
72619
|
-
// 步骤 1:计算提示位置与可用宽度。
|
|
72620
|
-
const { x: width, y: height } = loadingBox.getSize(this._loadingBoxSize);
|
|
72621
|
-
if (!tip.text || !Number.isFinite(width) || width <= 0) {
|
|
72622
|
-
return;
|
|
72623
|
-
}
|
|
72624
|
-
const positionedLeft = tip.position ? itemBox.min.x + (Number.isFinite(tip.position.x) ? tip.position.x : 0) : loadingBox.min.x;
|
|
72625
|
-
const left = tip.position ? Math.min(Math.max(positionedLeft, loadingBox.min.x), loadingBox.max.x) : loadingBox.min.x;
|
|
72626
|
-
const availableWidth = tip.position ? loadingBox.max.x - left : width;
|
|
72627
|
-
if (availableWidth <= 0) {
|
|
72628
|
-
return;
|
|
72629
|
-
}
|
|
72630
|
-
/**
|
|
72631
|
-
* 测量加载提示的粗体字形。
|
|
72632
|
-
* @param text 提示文本。
|
|
72633
|
-
* @param fontSize 字号。
|
|
72634
|
-
* @returns 文本字形尺寸。
|
|
72635
|
-
*/ const measureTipText = (text, fontSize)=>{
|
|
72636
|
-
const metrics = measureTextMetrics(text, fontSize, LOADING_TIP_FONT_FAMILY, 'bold');
|
|
72637
|
-
return {
|
|
72638
|
-
width: metrics.width || Array.from(text).length * fontSize,
|
|
72639
|
-
actualBoundingBoxAscent: metrics.actualBoundingBoxAscent || fontSize * 0.8,
|
|
72640
|
-
actualBoundingBoxDescent: metrics.actualBoundingBoxDescent || fontSize * 0.2
|
|
72641
|
-
};
|
|
72642
|
-
};
|
|
72643
|
-
// 步骤 2:测量文本并缩小字号以适应可用宽度。
|
|
72644
|
-
const measuredAtBaseSize = measureTipText(tip.text, LOADING_TIP_FONT_SIZE);
|
|
72645
|
-
let fontSize = measuredAtBaseSize.width > availableWidth ? LOADING_TIP_FONT_SIZE * availableWidth / measuredAtBaseSize.width : LOADING_TIP_FONT_SIZE;
|
|
72646
|
-
let textMetrics = measureTipText(tip.text, fontSize);
|
|
72647
|
-
if (textMetrics.width > availableWidth) {
|
|
72648
|
-
fontSize *= availableWidth / textMetrics.width;
|
|
72649
|
-
textMetrics = measureTipText(tip.text, fontSize);
|
|
72650
|
-
}
|
|
72651
|
-
// 步骤 3:按字形基线计算最终绘制位置。
|
|
72652
|
-
const textLeft = tip.position ? left : loadingBox.min.x + (width - textMetrics.width) / 2;
|
|
72653
|
-
const inkHeight = textMetrics.actualBoundingBoxAscent + textMetrics.actualBoundingBoxDescent;
|
|
72654
|
-
const top = tip.position ? itemBox.min.y + (Number.isFinite(tip.position.y) ? tip.position.y : 0) : loadingBox.min.y + (height - inkHeight) / 2;
|
|
72655
|
-
const probeMetrics = measureTipText(METRICS_STRING + BASELINE_SYMBOL, fontSize);
|
|
72656
|
-
const inkTopFromCellTop = CONTROL_TEXT_GLYPH_PADDING + probeMetrics.actualBoundingBoxAscent - textMetrics.actualBoundingBoxAscent;
|
|
72657
|
-
control.drawText(textLeft, top - inkTopFromCellTop, tip.text, fontSize, toColor(LOADING_TIP_COLOR, 1), LOADING_TIP_FONT_FAMILY, 'bold');
|
|
72658
|
-
}
|
|
72659
|
-
/** 释放当前实例的渲染投影;稳定 LoadingManager 不随 Gizmo 重建清空。 */ dispose() {
|
|
72660
|
-
this._configOff?.();
|
|
72661
|
-
this._configOff = undefined;
|
|
72662
|
-
this._managerOff?.();
|
|
72663
|
-
this._managerOff = undefined;
|
|
72664
|
-
this._idMap.forEach((loadingItem)=>{
|
|
72665
|
-
this._disposeLoadingVFXItem(loadingItem.loadingVFXItem);
|
|
72666
|
-
});
|
|
72667
|
-
this._idMap.clear();
|
|
72668
|
-
super.dispose();
|
|
72669
|
-
}
|
|
72670
|
-
/** 将可销毁的渲染投影同步到当前加载状态。 */ _syncManager() {
|
|
72671
|
-
const activeIds = new Set(this._manager.ids);
|
|
72672
|
-
for (const [id, loadingItem] of this._idMap){
|
|
72673
|
-
if (!activeIds.has(id)) {
|
|
72674
|
-
this._disposeLoadingVFXItem(loadingItem.loadingVFXItem);
|
|
72675
|
-
this._idMap.delete(id);
|
|
72676
|
-
}
|
|
72677
|
-
}
|
|
72678
|
-
for (const id of activeIds){
|
|
72679
|
-
const state = this._manager.get(id);
|
|
72680
|
-
if (!state) {
|
|
72681
|
-
continue;
|
|
72682
|
-
}
|
|
72683
|
-
const existing = this._idMap.get(id);
|
|
72684
|
-
if (existing) {
|
|
72685
|
-
existing.tip = {
|
|
72686
|
-
...state.tip,
|
|
72687
|
-
position: state.tip.position ? state.tip.position.clone() : undefined
|
|
72688
|
-
};
|
|
72689
|
-
} else {
|
|
72690
|
-
this._createProjection(id, state);
|
|
72691
|
-
}
|
|
72692
|
-
}
|
|
72693
|
-
}
|
|
72694
|
-
/**
|
|
72695
|
-
* 为加载状态创建渲染投影。
|
|
72696
|
-
* @param id 目标元素 ID。
|
|
72697
|
-
* @param state 加载状态。
|
|
72698
|
-
*/ _createProjection(id, state) {
|
|
72699
|
-
const item = getPlayerItemById(this._owner.getEngine().compositions[0], id);
|
|
72700
|
-
const itemViewBox = item ? getItemViewBox(item, GizmoViewportUtils.getContainerSize(this._owner.getEngine().canvas.parentElement)) : new Box2();
|
|
72701
|
-
const currentBox = state.loadingBox ? this.getViewBoxByBox(state.loadingBox) : itemViewBox;
|
|
72702
|
-
this._idMap.set(id, {
|
|
72703
|
-
loadingBox: getNormalizeBoxByBoxes(itemViewBox, currentBox),
|
|
72704
|
-
loadingVFXItem: this.createLoadingVFXItem(),
|
|
72705
|
-
tip: {
|
|
72706
|
-
...state.tip,
|
|
72707
|
-
position: state.tip.position ? state.tip.position.clone() : undefined
|
|
72708
|
-
}
|
|
72709
|
-
});
|
|
72710
|
-
this.updateLoadingVFXItemTransform(id, this._idMap.get(id));
|
|
72711
|
-
}
|
|
72712
|
-
/** @returns 当前相机信息。 */ getCameraInfo() {
|
|
72713
|
-
return GizmoViewportUtils.getCameraInfo(this._owner.getEngine());
|
|
72714
|
-
}
|
|
72715
|
-
/** @returns 当前视口的缩放、平移与尺寸。 */ getViewportParams() {
|
|
72716
|
-
const composition = this._owner.getEngine().compositions[0];
|
|
72717
|
-
const camera = composition?.camera;
|
|
72718
|
-
if (camera) {
|
|
72719
|
-
const viewportMatrix = camera.getViewportMatrix();
|
|
72720
|
-
const scale = viewportMatrix.elements[0];
|
|
72721
|
-
const translation = new Vector2(viewportMatrix.elements[12], viewportMatrix.elements[13]);
|
|
72722
|
-
const width = GizmoViewportUtils.getContainerSize(this._owner.getEngine().canvas.parentElement).x;
|
|
72723
|
-
const height = GizmoViewportUtils.getContainerSize(this._owner.getEngine().canvas.parentElement).y;
|
|
72724
|
-
return {
|
|
72725
|
-
scale,
|
|
72726
|
-
translation,
|
|
72727
|
-
width,
|
|
72728
|
-
height
|
|
72729
|
-
};
|
|
72730
|
-
}
|
|
72731
|
-
return {
|
|
72732
|
-
scale: 1,
|
|
72733
|
-
translation: new Vector2(),
|
|
72734
|
-
width: GizmoViewportUtils.getContainerSize(this._owner.getEngine().canvas.parentElement).x,
|
|
72735
|
-
height: GizmoViewportUtils.getContainerSize(this._owner.getEngine().canvas.parentElement).y
|
|
72736
|
-
};
|
|
72737
|
-
}
|
|
72738
|
-
/**
|
|
72739
|
-
* 将视图坐标下的包围盒按当前视口缩放与平移变换为实际渲染包围盒。
|
|
72740
|
-
* @param box 视图坐标下的包围盒
|
|
72741
|
-
* @returns 经视口缩放与平移后的实际渲染包围盒
|
|
72742
|
-
*/ getViewBoxByBox(box) {
|
|
72743
|
-
const { scale, translation, width, height } = this.getViewportParams();
|
|
72744
|
-
const center = new Vector2(width / 2, height / 2);
|
|
72745
|
-
const result = scaleBox(box.clone(), scale, center).translate(translation);
|
|
72746
|
-
return result;
|
|
72639
|
+
* 创建图片元素。
|
|
72640
|
+
* @param composition 目标合成
|
|
72641
|
+
* @param parent 父元素
|
|
72642
|
+
* @param name 元素名称
|
|
72643
|
+
* @returns 新建的图片元素
|
|
72644
|
+
*/ static createSprite(composition, parent = null, name = 'NewSprite') {
|
|
72645
|
+
const vfxItem = VFXItemFactory.createVFXItem(composition, parent, name, SpriteComponent);
|
|
72646
|
+
vfxItem.type = index$1.ItemType.sprite;
|
|
72647
|
+
return vfxItem;
|
|
72747
72648
|
}
|
|
72748
72649
|
/**
|
|
72749
|
-
*
|
|
72750
|
-
* @
|
|
72751
|
-
|
|
72752
|
-
|
|
72753
|
-
|
|
72754
|
-
|
|
72755
|
-
|
|
72756
|
-
|
|
72757
|
-
|
|
72758
|
-
loadingVFXItem.type = index$1.ItemType.effect;
|
|
72759
|
-
const effects = loadingVFXItem.getComponent(EffectComponent);
|
|
72760
|
-
const engine = this._owner.getEngine();
|
|
72761
|
-
const geometry = Geometry.create(engine, {
|
|
72762
|
-
attributes: {
|
|
72763
|
-
aPos: {
|
|
72764
|
-
size: 3,
|
|
72765
|
-
data: new Float32Array([
|
|
72766
|
-
-0.5,
|
|
72767
|
-
-0.5,
|
|
72768
|
-
0,
|
|
72769
|
-
0.5,
|
|
72770
|
-
-0.5,
|
|
72771
|
-
0,
|
|
72772
|
-
0.5,
|
|
72773
|
-
0.5,
|
|
72774
|
-
0,
|
|
72775
|
-
-0.5,
|
|
72776
|
-
0.5,
|
|
72777
|
-
0
|
|
72778
|
-
])
|
|
72779
|
-
},
|
|
72780
|
-
aUV: {
|
|
72781
|
-
size: 2,
|
|
72782
|
-
data: new Float32Array([
|
|
72783
|
-
0,
|
|
72784
|
-
0,
|
|
72785
|
-
1,
|
|
72786
|
-
0,
|
|
72787
|
-
1,
|
|
72788
|
-
1,
|
|
72789
|
-
0,
|
|
72790
|
-
1
|
|
72791
|
-
])
|
|
72792
|
-
}
|
|
72793
|
-
},
|
|
72794
|
-
indices: {
|
|
72795
|
-
data: new Uint16Array([
|
|
72796
|
-
0,
|
|
72797
|
-
1,
|
|
72798
|
-
2,
|
|
72799
|
-
0,
|
|
72800
|
-
2,
|
|
72801
|
-
3
|
|
72802
|
-
])
|
|
72803
|
-
},
|
|
72804
|
-
mode: glContext.TRIANGLES,
|
|
72805
|
-
drawCount: 6
|
|
72806
|
-
});
|
|
72807
|
-
// 步骤 2:使用当前配置创建动画材质。
|
|
72808
|
-
const material = Material.create(engine, {
|
|
72809
|
-
shader: {
|
|
72810
|
-
vertex: `
|
|
72811
|
-
precision highp float;
|
|
72812
|
-
attribute vec3 aPos;
|
|
72813
|
-
attribute vec2 aUV;
|
|
72814
|
-
uniform mat4 effects_MatrixVP;
|
|
72815
|
-
uniform mat4 effects_ObjectToWorld;
|
|
72816
|
-
varying vec2 vUV;
|
|
72817
|
-
void main() {
|
|
72818
|
-
vUV = aUV;
|
|
72819
|
-
gl_Position = effects_MatrixVP * effects_ObjectToWorld * vec4(aPos, 1.0);
|
|
72820
|
-
}`,
|
|
72821
|
-
fragment: this.config.loadingFragment
|
|
72822
|
-
}
|
|
72823
|
-
});
|
|
72824
|
-
// 步骤 3:绑定运行时几何与材质。
|
|
72825
|
-
// @ts-expect-error Effects 类型未暴露可写 geometry。
|
|
72826
|
-
effects.geometry = geometry;
|
|
72827
|
-
effects.material = material;
|
|
72828
|
-
return loadingVFXItem;
|
|
72829
|
-
}
|
|
72830
|
-
/** 释放 loading 渲染对象,并同步恢复 Selection 的命中过滤。 */ _disposeLoadingVFXItem(item) {
|
|
72831
|
-
this._owner.getSelection().deleteIgnoreIds([
|
|
72832
|
-
item.getInstanceId()
|
|
72833
|
-
]);
|
|
72834
|
-
item.dispose();
|
|
72650
|
+
* 创建文本元素。
|
|
72651
|
+
* @param composition 目标合成
|
|
72652
|
+
* @param parent 父元素
|
|
72653
|
+
* @param name 元素名称
|
|
72654
|
+
* @returns 新建的文本元素
|
|
72655
|
+
*/ static createText(composition, parent = null, name = 'NewText') {
|
|
72656
|
+
const vfxItem = VFXItemFactory.createVFXItem(composition, parent, name, TextComponent);
|
|
72657
|
+
vfxItem.type = index$1.ItemType.text;
|
|
72658
|
+
return vfxItem;
|
|
72835
72659
|
}
|
|
72836
72660
|
/**
|
|
72837
|
-
*
|
|
72838
|
-
* @param
|
|
72839
|
-
* @param
|
|
72840
|
-
|
|
72841
|
-
|
|
72842
|
-
|
|
72843
|
-
const
|
|
72844
|
-
|
|
72845
|
-
|
|
72846
|
-
const cameraInfo = this.getCameraInfo();
|
|
72847
|
-
const interactionPlane = new Plane(0, new Vector3(0, 0, 1));
|
|
72848
|
-
const worldPosition = viewPositionToWorld(viewPosition, cameraInfo, interactionPlane, containerSize);
|
|
72849
|
-
const viewSize = new Vector2(currentBox.max.x - currentBox.min.x, currentBox.max.y - currentBox.min.y);
|
|
72850
|
-
const worldSize = viewSizeToWorld(viewSize, containerSize, loadingItem.loadingVFXItem, cameraInfo, interactionPlane);
|
|
72851
|
-
if (worldPosition) {
|
|
72852
|
-
loadingItem.loadingVFXItem.transform.setPosition(worldPosition.x, worldPosition.y, 0);
|
|
72853
|
-
}
|
|
72854
|
-
loadingItem.loadingVFXItem.transform.setScale(worldSize.x, worldSize.y, 1);
|
|
72661
|
+
* 创建视频元素。
|
|
72662
|
+
* @param composition 目标合成
|
|
72663
|
+
* @param parent 父元素
|
|
72664
|
+
* @param name 元素名称
|
|
72665
|
+
* @returns 新建的视频元素
|
|
72666
|
+
*/ static createVideo(composition, parent = null, name = 'NewVideo') {
|
|
72667
|
+
const vfxItem = VFXItemFactory.createVFXItem(composition, parent, name, VideoComponent);
|
|
72668
|
+
vfxItem.type = index$1.ItemType.video;
|
|
72669
|
+
return vfxItem;
|
|
72855
72670
|
}
|
|
72856
72671
|
/**
|
|
72857
|
-
*
|
|
72858
|
-
* @param
|
|
72859
|
-
* @param
|
|
72860
|
-
|
|
72861
|
-
|
|
72862
|
-
|
|
72863
|
-
|
|
72864
|
-
|
|
72865
|
-
|
|
72866
|
-
|
|
72867
|
-
|
|
72868
|
-
|
|
72869
|
-
|
|
72870
|
-
|
|
72871
|
-
|
|
72872
|
-
|
|
72873
|
-
|
|
72874
|
-
|
|
72875
|
-
scrollWheelZoom: false,
|
|
72876
|
-
invertZoom: false,
|
|
72877
|
-
zoomStep: 0.1
|
|
72878
|
-
}
|
|
72879
|
-
});
|
|
72880
|
-
const viewportOverlayConfig = defineConfig({
|
|
72881
|
-
id: 'viewport.overlay',
|
|
72882
|
-
defaults: {
|
|
72883
|
-
boxColor: 0xFF0000,
|
|
72884
|
-
boxWidth: 1,
|
|
72885
|
-
outerMaskEnabled: true,
|
|
72886
|
-
markColor: 0x000000,
|
|
72887
|
-
markAlpha: 0.17,
|
|
72888
|
-
safeAreaEnabled: true,
|
|
72889
|
-
safeAreaBoxColor: 0x00FF00,
|
|
72890
|
-
safeAreaBoxAlpha: 0.3
|
|
72891
|
-
}
|
|
72892
|
-
});
|
|
72893
|
-
const selectionPreviewConfig = defineConfig({
|
|
72894
|
-
id: 'selection.preview',
|
|
72895
|
-
defaults: {
|
|
72896
|
-
videoPreSelectedPlay: true,
|
|
72897
|
-
preSelectedColor: 0x3b82f6,
|
|
72898
|
-
preSelectedWidth: 2,
|
|
72899
|
-
regionBoxColor: 0x3b82f6,
|
|
72900
|
-
regionBoxAlpha: 0.17,
|
|
72901
|
-
regionWireframeColor: 0x3b82f6,
|
|
72902
|
-
regionWireframeAlpha: 0.78,
|
|
72903
|
-
regionWireframeWidth: 1
|
|
72904
|
-
}
|
|
72905
|
-
});
|
|
72906
|
-
const selectionSnapConfig = defineConfig({
|
|
72907
|
-
id: 'selection.snap',
|
|
72908
|
-
defaults: {
|
|
72909
|
-
enabled: true,
|
|
72910
|
-
lineWidth: 0.8,
|
|
72911
|
-
lineColor: 0x0BD6FF,
|
|
72912
|
-
distance: 6
|
|
72913
|
-
}
|
|
72914
|
-
});
|
|
72915
|
-
const resizeSelectionConfig = defineConfig({
|
|
72916
|
-
id: 'resize-selection',
|
|
72917
|
-
defaults: {
|
|
72918
|
-
pixelRatio: 1,
|
|
72919
|
-
contentRatio: 1,
|
|
72920
|
-
wireframeColor: 0x3b82f6,
|
|
72921
|
-
wireframeAlpha: 1,
|
|
72922
|
-
wireframeWidth: 1.5,
|
|
72923
|
-
cornerFillColor: 0xFFFFFF,
|
|
72924
|
-
cornerLineColor: 0x3b82f6,
|
|
72925
|
-
cornerLineWidth: 1.5,
|
|
72926
|
-
cornerLineAlpha: 1,
|
|
72927
|
-
scaleCircleSize: 4,
|
|
72928
|
-
rotationCircleSize: 7,
|
|
72929
|
-
infoShowEnabled: true,
|
|
72930
|
-
sizeTextColor: 0x666666,
|
|
72931
|
-
nameTextColor: 0x666666,
|
|
72932
|
-
frameMoveLineColor: 0x3b82f6,
|
|
72933
|
-
frameMoveLineWidth: 2,
|
|
72934
|
-
pictureLogoUrl: 'https://mdn.alipayobjects.com/huamei_ixsp8m/afts/img/A*F2wVS7x0MfIAAAAAQBAAAAgAev-aAQ/original',
|
|
72935
|
-
groupLogoUrl: 'https://mdn.alipayobjects.com/huamei_ppzin5/afts/img/Yo69Sr7boqYAAAAAH3AAAAgADjdkAQFr/original',
|
|
72936
|
-
textLogoUrl: 'https://mdn.alipayobjects.com/huamei_ppzin5/afts/img/Yo69Sr7boqYAAAAAH3AAAAgADjdkAQFr/original',
|
|
72937
|
-
videoLogoUrl: 'https://mdn.alipayobjects.com/huamei_ixsp8m/afts/img/A*w1fnS4mq0VgAAAAAQCAAAAgAev-aAQ/original',
|
|
72938
|
-
frameLogoUrl: 'https://mdn.alipayobjects.com/huamei_ixsp8m/afts/img/A*DRF_RpndkjUAAAAAQDAAAAgAev-aAQ/original',
|
|
72939
|
-
effectsLogoUrl: 'https://mdn.alipayobjects.com/huamei_ixsp8m/afts/img/A*RMewR4ruUnYAAAAAQGAAAAgAev-aAQ/original'
|
|
72940
|
-
}
|
|
72941
|
-
});
|
|
72942
|
-
const pictureCutConfig = defineConfig({
|
|
72943
|
-
id: 'tool.picture-cut',
|
|
72944
|
-
defaults: {
|
|
72945
|
-
maskColor: 0xFFFFFF,
|
|
72946
|
-
maskAlpha: 0.5,
|
|
72947
|
-
cutBoxLineWidth: 2,
|
|
72948
|
-
cutBoxLineColor: 0x6A34FF,
|
|
72949
|
-
cutBoxLineAlpha: 1,
|
|
72950
|
-
itemBoxLineWidth: 1,
|
|
72951
|
-
itemBoxLineColor: 0x6A34FF,
|
|
72952
|
-
itemBoxLineAlpha: 1,
|
|
72953
|
-
cutBoxCornerRadius: 5,
|
|
72954
|
-
cutBoxCornerFillColor: 0xFFFFFF,
|
|
72955
|
-
cutBoxCornerLineWidth: 2,
|
|
72956
|
-
cutBoxCornerLineColor: 0x6A34FF,
|
|
72957
|
-
cutBoxCornerLineAlpha: 1,
|
|
72958
|
-
scaleInteractionDistance: 8,
|
|
72959
|
-
directionScaleInteractionDistance: 5,
|
|
72960
|
-
gridLineWidth: 1,
|
|
72961
|
-
gridLineColor: 0xFFFFFF,
|
|
72962
|
-
gridLineAlpha: 1,
|
|
72963
|
-
gridCount: 2
|
|
72964
|
-
}
|
|
72965
|
-
});
|
|
72966
|
-
const pictureExpandConfig = defineConfig({
|
|
72967
|
-
id: 'tool.picture-expand',
|
|
72968
|
-
defaults: {
|
|
72969
|
-
maskColor: 0x6A34FF,
|
|
72970
|
-
maskAlpha: 0.2,
|
|
72971
|
-
expandBoxLineWidth: 2,
|
|
72972
|
-
expandBoxLineColor: 0x6A34FF,
|
|
72973
|
-
expandBoxLineAlpha: 1,
|
|
72974
|
-
expandBoxCornerRadius: 5,
|
|
72975
|
-
expandBoxCornerLineWidth: 2,
|
|
72976
|
-
expandBoxCornerLineColor: 0x6A34FF,
|
|
72977
|
-
expandBoxCornerLineAlpha: 1,
|
|
72978
|
-
expandBoxCornerFillColor: 0xFFFFFF,
|
|
72979
|
-
scaleInteractionDistance: 8,
|
|
72980
|
-
directionScaleInteractionDistance: 5,
|
|
72981
|
-
gridLineWidth: 1,
|
|
72982
|
-
gridLineColor: 0xFFFFFF,
|
|
72983
|
-
gridLineAlpha: 1,
|
|
72984
|
-
gridCount: 2
|
|
72985
|
-
}
|
|
72986
|
-
});
|
|
72987
|
-
const maskConfig = defineConfig({
|
|
72988
|
-
id: 'tool.mask',
|
|
72989
|
-
defaults: {
|
|
72990
|
-
maskImage: '',
|
|
72991
|
-
brushSize: 20,
|
|
72992
|
-
brushColor: 0x6A34FF,
|
|
72993
|
-
brushAlpha: 0.5,
|
|
72994
|
-
maskColor: 0x00FF00,
|
|
72995
|
-
maskBackgroundColor: 0xFFFFFF,
|
|
72996
|
-
maskAlpha: 1,
|
|
72997
|
-
boxLineWidth: 1,
|
|
72998
|
-
boxLineColor: 0x6A34FF,
|
|
72999
|
-
boxLineAlpha: 1
|
|
73000
|
-
}
|
|
73001
|
-
});
|
|
73002
|
-
const spriteTextEditConfig = defineConfig({
|
|
73003
|
-
id: 'tool.sprite-text-edit',
|
|
73004
|
-
defaults: {
|
|
73005
|
-
textColor: 0xFFFFFF,
|
|
73006
|
-
preSelectedTextColor: 0xFFFFFF,
|
|
73007
|
-
boxLineWidth: 3,
|
|
73008
|
-
dashLineDash: 8,
|
|
73009
|
-
dashLineGap: 8,
|
|
73010
|
-
editBoxAlpha: 0.15,
|
|
73011
|
-
editBoxColor: 0x3B82F6,
|
|
73012
|
-
editBoxLineAlpha: 1,
|
|
73013
|
-
editBoxLineColor: 0x3B82F6,
|
|
73014
|
-
editBoxPreSelectedAlpha: 0.25,
|
|
73015
|
-
editBoxPreSelectedColor: 0x3B82F6,
|
|
73016
|
-
editBoxLinePreSelectedAlpha: 1,
|
|
73017
|
-
editBoxLinePreSelectedColor: 0x3B82F6,
|
|
73018
|
-
hasChangedEditBoxAlpha: 0.2,
|
|
73019
|
-
hasChangedEditBoxColor: 0x22C55E,
|
|
73020
|
-
hasChangedEditBoxLineAlpha: 1,
|
|
73021
|
-
hasChangedEditBoxLineColor: 0x22C55E,
|
|
73022
|
-
hasChangedEditBoxPreSelectedAlpha: 0.3,
|
|
73023
|
-
hasChangedEditBoxPreSelectedColor: 0x22C55E,
|
|
73024
|
-
hasChangedEditBoxLinePreSelectedAlpha: 1,
|
|
73025
|
-
hasChangedEditBoxLinePreSelectedColor: 0x22C55E,
|
|
73026
|
-
editBoxSelectedAlpha: 0.6,
|
|
73027
|
-
editBoxSelectedColor: 0xFFFF00
|
|
73028
|
-
}
|
|
73029
|
-
});
|
|
73030
|
-
const iconConfig = defineConfig({
|
|
73031
|
-
id: 'feedback.icon',
|
|
73032
|
-
defaults: {
|
|
73033
|
-
autoShow: true,
|
|
73034
|
-
videoPlayUrl: 'https://mdn.alipayobjects.com/huamei_ixsp8m/afts/img/A*ORMmSYYHIHUAAAAAJbAAAAgAev-aAQ/original',
|
|
73035
|
-
videoPlayShift: [
|
|
73036
|
-
20,
|
|
73037
|
-
20
|
|
73038
|
-
],
|
|
73039
|
-
videoPlayWidth: 20,
|
|
73040
|
-
videoPlayHeight: 20,
|
|
73041
|
-
imageGeneratorUrl: 'https://mdn.alipayobjects.com/huamei_ixsp8m/afts/img/A*bYB-TIEWLBkAAAAAQGAAAAgAev-aAQ/original',
|
|
73042
|
-
videoGeneratorUrl: 'https://mdn.alipayobjects.com/huamei_ixsp8m/afts/img/A*6cTFT44CuKEAAAAAQCAAAAgAev-aAQ/original',
|
|
73043
|
-
generatorWidth: 200,
|
|
73044
|
-
generatorHeight: 200
|
|
73045
|
-
}
|
|
73046
|
-
});
|
|
73047
|
-
const itemCreateConfig = defineConfig({
|
|
73048
|
-
id: 'tool.item-create',
|
|
73049
|
-
defaults: {
|
|
73050
|
-
frameBorderColor: 0x2178FF,
|
|
73051
|
-
frameBorderWidth: 1,
|
|
73052
|
-
frameBorderAlpha: 0.8,
|
|
73053
|
-
frameFillColor: 0x2178FF,
|
|
73054
|
-
frameFillAlpha: 0.15,
|
|
73055
|
-
frameChildBoxAlpha: 0.35,
|
|
73056
|
-
frameChildBoxColor: 0x2178FF
|
|
72672
|
+
* 加载并创建特效合成元素。
|
|
72673
|
+
* @param composition 目标合成
|
|
72674
|
+
* @param effects 特效地址或场景数据
|
|
72675
|
+
* @param parent 父元素
|
|
72676
|
+
* @param urlname 元素名称
|
|
72677
|
+
* @returns 新建的特效元素
|
|
72678
|
+
*/ static async createEffects(composition, effects, parent = null, urlname = 'NewEffects') {
|
|
72679
|
+
const preComposition = await AssetManager$1.loadPrecomposition(effects, {
|
|
72680
|
+
autoplay: false
|
|
72681
|
+
});
|
|
72682
|
+
const vfxItem = PrecompositionManager.instantiate(preComposition, composition);
|
|
72683
|
+
vfxItem.name = urlname;
|
|
72684
|
+
vfxItem.type = index$1.ItemType.composition;
|
|
72685
|
+
vfxItem.getComponent(CompositionComponent).endBehavior = vfxItem.endBehavior;
|
|
72686
|
+
if (parent) {
|
|
72687
|
+
vfxItem.setParent(parent);
|
|
72688
|
+
}
|
|
72689
|
+
return vfxItem;
|
|
73057
72690
|
}
|
|
73058
|
-
}
|
|
72691
|
+
}
|
|
73059
72692
|
/**
|
|
73060
|
-
*
|
|
72693
|
+
* 播放视频元素。
|
|
73061
72694
|
* @param engine 引擎
|
|
73062
|
-
* @param
|
|
73063
|
-
|
|
73064
|
-
|
|
73065
|
-
|
|
73066
|
-
if (!composition) {
|
|
72695
|
+
* @param id 视频元素 id
|
|
72696
|
+
*/ function playVideoItem(engine, id) {
|
|
72697
|
+
const playerItem = getPlayerItemById(engine.compositions[0], id);
|
|
72698
|
+
if (playerItem?.type !== index$1.ItemType.video) {
|
|
73067
72699
|
return;
|
|
73068
72700
|
}
|
|
73069
|
-
const
|
|
73070
|
-
|
|
73071
|
-
const translation = new Vector2(camera.getViewportMatrix().elements[12], camera.getViewportMatrix().elements[13]);
|
|
73072
|
-
const result = scale + zoom;
|
|
73073
|
-
// 1. 反算缩放中心对应的世界坐标。
|
|
73074
|
-
const worldX = (center.x - translation.x) / scale;
|
|
73075
|
-
const worldY = (center.y - translation.y) / scale;
|
|
73076
|
-
// 2. 调整平移,使缩放中心在屏幕上的位置保持不变。
|
|
73077
|
-
const newNDCTranslation = new Vector2(center.x - worldX * result, center.y - worldY * result);
|
|
73078
|
-
const viewportMatrix = new Matrix4().compose(new Vector3(newNDCTranslation.x, newNDCTranslation.y, 0), new Quaternion(), new Vector3(result, result, 1));
|
|
73079
|
-
composition.camera.setViewportMatrix(viewportMatrix);
|
|
72701
|
+
const videoComponent = playerItem.getComponent(VideoComponent);
|
|
72702
|
+
videoComponent?.playVideo();
|
|
73080
72703
|
}
|
|
73081
72704
|
/**
|
|
73082
|
-
*
|
|
72705
|
+
* 暂停视频元素。
|
|
73083
72706
|
* @param engine 引擎
|
|
73084
|
-
* @param
|
|
73085
|
-
*/ function
|
|
73086
|
-
const
|
|
73087
|
-
if (
|
|
72707
|
+
* @param id 视频元素 id
|
|
72708
|
+
*/ function pauseVideoItem(engine, id) {
|
|
72709
|
+
const playerItem = getPlayerItemById(engine.compositions[0], id);
|
|
72710
|
+
if (playerItem?.type !== index$1.ItemType.video) {
|
|
73088
72711
|
return;
|
|
73089
72712
|
}
|
|
73090
|
-
const
|
|
73091
|
-
|
|
73092
|
-
const resultTranslation = new Vector2(camera.getViewportMatrix().elements[12], camera.getViewportMatrix().elements[13]).add(translation);
|
|
73093
|
-
const viewportMatrix = new Matrix4().compose(new Vector3(resultTranslation.x, resultTranslation.y, 0), new Quaternion(), new Vector3(scale, scale, 1));
|
|
73094
|
-
camera.setViewportMatrix(viewportMatrix);
|
|
72713
|
+
const videoComponent = playerItem.getComponent(VideoComponent);
|
|
72714
|
+
videoComponent?.pauseVideo();
|
|
73095
72715
|
}
|
|
73096
72716
|
/**
|
|
73097
|
-
*
|
|
73098
|
-
* @param
|
|
73099
|
-
* @param
|
|
73100
|
-
|
|
73101
|
-
|
|
73102
|
-
|
|
73103
|
-
if (
|
|
73104
|
-
console.warn(`Item ${frameItem.getInstanceId()} is not a frame item.`);
|
|
72717
|
+
* 播放特效元素。
|
|
72718
|
+
* @param engine 引擎
|
|
72719
|
+
* @param id 特效元素 id
|
|
72720
|
+
*/ function playEffectsItem(engine, id) {
|
|
72721
|
+
const controlItem = getPlayerItemById(engine.compositions[0], id);
|
|
72722
|
+
const compositionItem = controlItem?.children?.[0];
|
|
72723
|
+
if (compositionItem?.type !== index$1.ItemType.composition) {
|
|
73105
72724
|
return;
|
|
73106
72725
|
}
|
|
73107
|
-
|
|
73108
|
-
|
|
73109
|
-
|
|
73110
|
-
|
|
73111
|
-
|
|
73112
|
-
|
|
73113
|
-
|
|
73114
|
-
|
|
73115
|
-
|
|
73116
|
-
|
|
72726
|
+
compositionItem.getComponent(CompositionComponent).play();
|
|
72727
|
+
}
|
|
72728
|
+
/**
|
|
72729
|
+
* 暂停特效元素。
|
|
72730
|
+
* @param engine 引擎
|
|
72731
|
+
* @param id 特效元素 id
|
|
72732
|
+
*/ function pauseEffectsItem(engine, id) {
|
|
72733
|
+
const controlItem = getPlayerItemById(engine.compositions[0], id);
|
|
72734
|
+
const compositionItem = controlItem?.children?.[0];
|
|
72735
|
+
if (compositionItem?.type !== index$1.ItemType.composition) {
|
|
72736
|
+
return;
|
|
73117
72737
|
}
|
|
73118
|
-
|
|
73119
|
-
|
|
73120
|
-
|
|
73121
|
-
|
|
73122
|
-
|
|
73123
|
-
|
|
73124
|
-
|
|
73125
|
-
|
|
73126
|
-
|
|
73127
|
-
|
|
72738
|
+
compositionItem.getComponent(CompositionComponent).pause();
|
|
72739
|
+
}
|
|
72740
|
+
/** 信息标签默认字号。 */ const INFO_TEXT_FONT_SIZE = 14;
|
|
72741
|
+
/** 信息标签默认字体。 */ const INFO_TEXT_FONT_FAMILY = 'sans-serif';
|
|
72742
|
+
/** effects Control 字符 atlas 的固定单边留白。 */ const CONTROL_TEXT_GLYPH_PADDING = 4;
|
|
72743
|
+
/** 用于测量字体高度的代表字符。 */ const METRICS_STRING = '|ÉqÅ';
|
|
72744
|
+
/** 用于测量字体基线的字符。 */ const BASELINE_SYMBOL = 'M';
|
|
72745
|
+
/**
|
|
72746
|
+
* 颜色缓存:`hex_alpha` → effects Color。键到颜色映射不可变,全局缓存无需清理。
|
|
72747
|
+
*/ const colorCache = new Map();
|
|
72748
|
+
/**
|
|
72749
|
+
* 将十六进制色值 + alpha 转为 effects Color(带全局缓存)。
|
|
72750
|
+
* @param hex 0xRRGGBB 颜色
|
|
72751
|
+
* @param alpha 透明度 0..1
|
|
72752
|
+
* @returns effects Color
|
|
72753
|
+
*/ function toColor(hex, alpha = 1) {
|
|
72754
|
+
const key = `${hex}_${alpha}`;
|
|
72755
|
+
const cached = colorCache.get(key);
|
|
72756
|
+
if (cached) {
|
|
72757
|
+
return cached;
|
|
73128
72758
|
}
|
|
72759
|
+
const color = new Color((hex >> 16 & 0xff) / 255, (hex >> 8 & 0xff) / 255, (hex & 0xff) / 255, alpha);
|
|
72760
|
+
colorCache.set(key, color);
|
|
72761
|
+
return color;
|
|
73129
72762
|
}
|
|
73130
|
-
/**
|
|
73131
|
-
|
|
73132
|
-
|
|
72763
|
+
/**
|
|
72764
|
+
* 离屏文本测量上下文,懒加载并复用。
|
|
72765
|
+
*/ let _measureCtx = null;
|
|
72766
|
+
/**
|
|
72767
|
+
* 测量文本的宽度与可见字形边界。
|
|
72768
|
+
* @param text 文本内容
|
|
72769
|
+
* @param fontSize 字号
|
|
72770
|
+
* @param fontFamily 字体
|
|
72771
|
+
* @param fontWeight 字重
|
|
72772
|
+
* @param fontStyle 字体样式
|
|
72773
|
+
* @returns 文本测量结果
|
|
72774
|
+
*/ function measureTextMetrics(text, fontSize = INFO_TEXT_FONT_SIZE, fontFamily = INFO_TEXT_FONT_FAMILY, fontWeight, fontStyle) {
|
|
72775
|
+
_measureCtx ?? (_measureCtx = document.createElement('canvas').getContext('2d'));
|
|
72776
|
+
if (!_measureCtx) {
|
|
72777
|
+
return {
|
|
72778
|
+
width: 0,
|
|
72779
|
+
actualBoundingBoxAscent: 0,
|
|
72780
|
+
actualBoundingBoxDescent: 0
|
|
72781
|
+
};
|
|
73133
72782
|
}
|
|
73134
|
-
|
|
73135
|
-
|
|
72783
|
+
_measureCtx.font = `${''}${fontWeight ? `${fontWeight} ` : ''}${fontSize}px ${fontFamily}`;
|
|
72784
|
+
const metrics = _measureCtx.measureText(text);
|
|
72785
|
+
return {
|
|
72786
|
+
width: metrics.width,
|
|
72787
|
+
actualBoundingBoxAscent: metrics.actualBoundingBoxAscent ?? 0,
|
|
72788
|
+
actualBoundingBoxDescent: metrics.actualBoundingBoxDescent ?? 0
|
|
72789
|
+
};
|
|
72790
|
+
}
|
|
72791
|
+
/**
|
|
72792
|
+
* 计算 effects Control.drawText 实际使用的 atlas cell 高度。
|
|
72793
|
+
* @param fontSize 字号
|
|
72794
|
+
* @param fontFamily 字体
|
|
72795
|
+
* @param fontWeight 字重
|
|
72796
|
+
* @param fontStyle 字体样式
|
|
72797
|
+
* @param resolution 渲染分辨率
|
|
72798
|
+
* @returns 字符图集单元格高度
|
|
72799
|
+
*/ function measureControlTextCellHeight(fontSize = INFO_TEXT_FONT_SIZE, fontFamily = INFO_TEXT_FONT_FAMILY, fontWeight, fontStyle, resolution = 1) {
|
|
72800
|
+
const safeResolution = Number.isFinite(resolution) && resolution > 0 ? resolution : 1;
|
|
72801
|
+
const scaledFontSize = fontSize * safeResolution;
|
|
72802
|
+
const metrics = measureTextMetrics(METRICS_STRING + BASELINE_SYMBOL, scaledFontSize, fontFamily, fontWeight);
|
|
72803
|
+
const ascent = metrics.actualBoundingBoxAscent || scaledFontSize * 0.8;
|
|
72804
|
+
const descent = metrics.actualBoundingBoxDescent || scaledFontSize * 0.2;
|
|
72805
|
+
return Math.ceil(ascent + descent + CONTROL_TEXT_GLYPH_PADDING * 2 * safeResolution) / safeResolution;
|
|
72806
|
+
}
|
|
72807
|
+
/**
|
|
72808
|
+
* 测量文本宽度(逻辑像素),用于信息标签的溢出判断与右对齐定位。
|
|
72809
|
+
* @param text 文本内容
|
|
72810
|
+
* @param fontSize 字号
|
|
72811
|
+
* @param fontFamily 字体
|
|
72812
|
+
* @param fontWeight 字重
|
|
72813
|
+
* @returns 文本宽度
|
|
72814
|
+
*/ function measureTextWidth(text, fontSize = INFO_TEXT_FONT_SIZE, fontFamily = INFO_TEXT_FONT_FAMILY, fontWeight) {
|
|
72815
|
+
return measureTextMetrics(text, fontSize, fontFamily, fontWeight).width;
|
|
72816
|
+
}
|
|
72817
|
+
/**
|
|
72818
|
+
* 单行文本截断:逐字符累加,超出可用宽度时把最后两个字符替换为省略号。
|
|
72819
|
+
* @param text 文本内容
|
|
72820
|
+
* @param maxWidth 可用宽度
|
|
72821
|
+
* @param fontSize 字号
|
|
72822
|
+
* @param fontFamily 字体
|
|
72823
|
+
* @returns 截断后的文本
|
|
72824
|
+
*/ function truncateText(text, maxWidth, fontSize = INFO_TEXT_FONT_SIZE, fontFamily = INFO_TEXT_FONT_FAMILY) {
|
|
72825
|
+
if (measureTextWidth(text, fontSize, fontFamily) <= maxWidth) {
|
|
72826
|
+
return text;
|
|
73136
72827
|
}
|
|
73137
|
-
|
|
73138
|
-
|
|
73139
|
-
|
|
73140
|
-
|
|
73141
|
-
*/ setScaleRange(minScale, maxScale) {
|
|
73142
|
-
if (!Number.isFinite(minScale) || !Number.isFinite(maxScale) || minScale <= 0 || maxScale <= 0 || minScale > maxScale) {
|
|
73143
|
-
throw new RangeError('Viewport scale range must be finite, positive, and ordered.');
|
|
72828
|
+
let current = '';
|
|
72829
|
+
for (const char of text){
|
|
72830
|
+
if (measureTextWidth(current + char, fontSize, fontFamily) > maxWidth) {
|
|
72831
|
+
return current.length > 2 ? current.slice(0, -2) + '...' : '...';
|
|
73144
72832
|
}
|
|
73145
|
-
|
|
73146
|
-
this._maxScale = maxScale;
|
|
72833
|
+
current += char;
|
|
73147
72834
|
}
|
|
73148
|
-
|
|
73149
|
-
|
|
73150
|
-
|
|
73151
|
-
|
|
73152
|
-
|
|
73153
|
-
|
|
73154
|
-
|
|
73155
|
-
|
|
73156
|
-
|
|
73157
|
-
|
|
73158
|
-
|
|
73159
|
-
|
|
73160
|
-
|
|
73161
|
-
|
|
73162
|
-
|
|
73163
|
-
const
|
|
73164
|
-
|
|
73165
|
-
|
|
73166
|
-
|
|
72835
|
+
return current;
|
|
72836
|
+
}
|
|
72837
|
+
/**
|
|
72838
|
+
* 多行逐字符折行:行宽超出 maxWidth 时换行;行数达到 maxLines 时末行用省略号收尾。
|
|
72839
|
+
* @param text 文本内容
|
|
72840
|
+
* @param maxWidth 单行可用宽度
|
|
72841
|
+
* @param maxLines 最大行数
|
|
72842
|
+
* @param fontSize 字号
|
|
72843
|
+
* @param fontFamily 字体
|
|
72844
|
+
* @returns 折行后的文本行数组
|
|
72845
|
+
*/ function wrapText(text, maxWidth, maxLines, fontSize = INFO_TEXT_FONT_SIZE, fontFamily = INFO_TEXT_FONT_FAMILY) {
|
|
72846
|
+
const lines = [];
|
|
72847
|
+
let currentLine = '';
|
|
72848
|
+
const chars = text.split('');
|
|
72849
|
+
for(let i = 0; i < chars.length; i++){
|
|
72850
|
+
const char = chars[i];
|
|
72851
|
+
const testLine = currentLine + char;
|
|
72852
|
+
if (measureTextWidth(testLine, fontSize, fontFamily) > maxWidth) {
|
|
72853
|
+
lines.push(currentLine);
|
|
72854
|
+
if (lines.length >= maxLines) {
|
|
72855
|
+
const lastLine = lines[maxLines - 1];
|
|
72856
|
+
lines[maxLines - 1] = lastLine.length > 2 ? lastLine.slice(0, -2) + '...' : '...';
|
|
72857
|
+
break;
|
|
73167
72858
|
}
|
|
73168
|
-
|
|
73169
|
-
|
|
73170
|
-
|
|
73171
|
-
return this._zoomByShift(zoomShift, center, event.ctrlPressed && source === 'trackpad' ? 'pinch-zoom' : 'wheel-zoom');
|
|
73172
|
-
}
|
|
73173
|
-
if (delta.x === 0 && delta.y === 0) {
|
|
73174
|
-
return false;
|
|
73175
|
-
}
|
|
73176
|
-
return this.panByViewDelta(delta, center, 'wheel-pan');
|
|
73177
|
-
}
|
|
73178
|
-
/**
|
|
73179
|
-
* 按视图像素增量平移视口。
|
|
73180
|
-
* @param delta 视图像素位移
|
|
73181
|
-
* @param center 操作中心
|
|
73182
|
-
* @param source 操作来源
|
|
73183
|
-
* @returns 视口是否发生变化
|
|
73184
|
-
*/ panByViewDelta(delta, center, source) {
|
|
73185
|
-
if (!this._hasViewport() || delta.x === 0 && delta.y === 0) {
|
|
73186
|
-
return false;
|
|
72859
|
+
currentLine = char;
|
|
72860
|
+
} else {
|
|
72861
|
+
currentLine = testLine;
|
|
73187
72862
|
}
|
|
73188
|
-
|
|
73189
|
-
|
|
73190
|
-
return false;
|
|
72863
|
+
if (i === chars.length - 1 && currentLine) {
|
|
72864
|
+
lines.push(currentLine);
|
|
73191
72865
|
}
|
|
73192
|
-
panView(this._engine, viewSizeToNDC(delta, containerSize));
|
|
73193
|
-
this._emitChange(center, source);
|
|
73194
|
-
return true;
|
|
73195
72866
|
}
|
|
73196
|
-
|
|
73197
|
-
|
|
73198
|
-
|
|
73199
|
-
|
|
73200
|
-
|
|
73201
|
-
|
|
73202
|
-
|
|
73203
|
-
|
|
73204
|
-
|
|
73205
|
-
|
|
73206
|
-
|
|
73207
|
-
const nextScale = clamp(currentScale * factor, this._minScale, this._maxScale);
|
|
73208
|
-
if (nextScale === currentScale) {
|
|
73209
|
-
return false;
|
|
73210
|
-
}
|
|
73211
|
-
const containerSize = this._containerSize();
|
|
73212
|
-
if (containerSize.x <= 0 || containerSize.y <= 0) {
|
|
73213
|
-
return false;
|
|
73214
|
-
}
|
|
73215
|
-
zoomView(this._engine, nextScale - currentScale, viewPositionToNDC(center, containerSize));
|
|
73216
|
-
this._emitChange(center, source);
|
|
73217
|
-
return true;
|
|
72867
|
+
return lines.slice(0, maxLines);
|
|
72868
|
+
}
|
|
72869
|
+
/**
|
|
72870
|
+
* 绘制由 4 个角点构成的(可能非正交的)包围盒边框。
|
|
72871
|
+
* @param control 绘制控制器
|
|
72872
|
+
* @param corners 4 个角点(视图坐标,Y 向下)
|
|
72873
|
+
* @param color 边框颜色
|
|
72874
|
+
* @param width 线宽
|
|
72875
|
+
*/ function drawCorners(control, corners, color, width) {
|
|
72876
|
+
if (corners.length < 4) {
|
|
72877
|
+
return;
|
|
73218
72878
|
}
|
|
73219
|
-
|
|
73220
|
-
|
|
73221
|
-
|
|
73222
|
-
|
|
73223
|
-
this.off('change', listener);
|
|
73224
|
-
}
|
|
72879
|
+
for(let i = 0; i < 4; i++){
|
|
72880
|
+
const start = corners[i];
|
|
72881
|
+
const end = corners[(i + 1) % 4];
|
|
72882
|
+
control.drawLine(start.x, start.y, end.x, end.y, color, width);
|
|
73225
72883
|
}
|
|
73226
|
-
|
|
73227
|
-
|
|
73228
|
-
|
|
73229
|
-
|
|
73230
|
-
|
|
73231
|
-
|
|
73232
|
-
|
|
73233
|
-
|
|
73234
|
-
|
|
73235
|
-
|
|
73236
|
-
|
|
73237
|
-
|
|
72884
|
+
}
|
|
72885
|
+
/**
|
|
72886
|
+
* 绘制虚线包围盒,并在相邻边之间保持连续虚线相位。
|
|
72887
|
+
* @param control 绘制控制器
|
|
72888
|
+
* @param corners 四个视图角点
|
|
72889
|
+
* @param color 虚线颜色
|
|
72890
|
+
* @param width 线宽
|
|
72891
|
+
* @param dashLength 实线段长度
|
|
72892
|
+
* @param gapLength 间隔长度
|
|
72893
|
+
*/ function drawDashedCorners(control, corners, color, width, dashLength, gapLength) {
|
|
72894
|
+
// 1. 校验角点和虚线参数。
|
|
72895
|
+
if (corners.length < 4 || dashLength <= 0 || gapLength < 0) {
|
|
72896
|
+
return;
|
|
73238
72897
|
}
|
|
73239
|
-
|
|
73240
|
-
|
|
73241
|
-
|
|
73242
|
-
|
|
73243
|
-
|
|
73244
|
-
const
|
|
73245
|
-
|
|
73246
|
-
|
|
73247
|
-
|
|
73248
|
-
|
|
73249
|
-
|
|
73250
|
-
delta.y = -event.factor;
|
|
73251
|
-
break;
|
|
73252
|
-
case MouseButton.WheelLeft:
|
|
73253
|
-
delta.x = event.factor;
|
|
73254
|
-
break;
|
|
73255
|
-
case MouseButton.WheelRight:
|
|
73256
|
-
delta.x = -event.factor;
|
|
73257
|
-
break;
|
|
73258
|
-
}
|
|
73259
|
-
// Windows 下 Shift + 滚轮映射为水平平移。
|
|
73260
|
-
const isApplePlatform = typeof navigator !== 'undefined' && /Mac|iPhone|iPad|iPod/.test(navigator.platform);
|
|
73261
|
-
if (!isApplePlatform && event.shiftPressed && delta.x === 0) {
|
|
73262
|
-
delta.x = delta.y;
|
|
73263
|
-
delta.y = 0;
|
|
72898
|
+
const patternLength = dashLength + gapLength;
|
|
72899
|
+
let perimeterOffset = 0;
|
|
72900
|
+
// 2. 逐边计算虚线相位,并继承上一条边的周长偏移。
|
|
72901
|
+
for(let i = 0; i < 4; i++){
|
|
72902
|
+
const start = corners[i];
|
|
72903
|
+
const end = corners[(i + 1) % 4];
|
|
72904
|
+
const dx = end.x - start.x;
|
|
72905
|
+
const dy = end.y - start.y;
|
|
72906
|
+
const edgeLength = Math.hypot(dx, dy);
|
|
72907
|
+
if (edgeLength <= Number.EPSILON) {
|
|
72908
|
+
continue;
|
|
73264
72909
|
}
|
|
73265
|
-
|
|
73266
|
-
|
|
73267
|
-
|
|
73268
|
-
|
|
73269
|
-
|
|
73270
|
-
|
|
73271
|
-
|
|
73272
|
-
|
|
73273
|
-
|
|
73274
|
-
|
|
73275
|
-
|
|
73276
|
-
|
|
73277
|
-
|
|
73278
|
-
|
|
73279
|
-
const nextScale = roundNumber(clamp(currentScale + shift, this._minScale, this._maxScale), 2);
|
|
73280
|
-
if (nextScale === currentScale) {
|
|
73281
|
-
return false;
|
|
72910
|
+
let edgeOffset = 0;
|
|
72911
|
+
while(edgeOffset < edgeLength){
|
|
72912
|
+
const patternOffset = perimeterOffset % patternLength;
|
|
72913
|
+
const drawingDash = gapLength === 0 || patternOffset < dashLength;
|
|
72914
|
+
const phaseRemaining = drawingDash ? dashLength - patternOffset : patternLength - patternOffset;
|
|
72915
|
+
const segmentLength = Math.min(phaseRemaining, edgeLength - edgeOffset);
|
|
72916
|
+
// 3. 仅绘制当前相位中的实线段。
|
|
72917
|
+
if (drawingDash && segmentLength > Number.EPSILON) {
|
|
72918
|
+
const startRatio = edgeOffset / edgeLength;
|
|
72919
|
+
const endRatio = (edgeOffset + segmentLength) / edgeLength;
|
|
72920
|
+
control.drawLine(start.x + dx * startRatio, start.y + dy * startRatio, start.x + dx * endRatio, start.y + dy * endRatio, color, width);
|
|
72921
|
+
}
|
|
72922
|
+
edgeOffset += segmentLength;
|
|
72923
|
+
perimeterOffset += segmentLength;
|
|
73282
72924
|
}
|
|
73283
|
-
return this.zoomByFactor(nextScale / currentScale, center, source);
|
|
73284
|
-
}
|
|
73285
|
-
/**
|
|
73286
|
-
* 发出当前视口快照。
|
|
73287
|
-
* @param center 操作中心
|
|
73288
|
-
* @param source 操作来源
|
|
73289
|
-
*/ _emitChange(center, source) {
|
|
73290
|
-
const containerSize = this._containerSize();
|
|
73291
|
-
this.emit('change', {
|
|
73292
|
-
source,
|
|
73293
|
-
scale: GizmoViewportUtils.getViewScale(this._engine),
|
|
73294
|
-
translation: ndcSizeToViewSize(GizmoViewportUtils.getViewportTranslation(this._engine), containerSize),
|
|
73295
|
-
center: center.clone()
|
|
73296
|
-
});
|
|
73297
|
-
}
|
|
73298
|
-
/** @returns 当前画布容器尺寸。 */ _containerSize() {
|
|
73299
|
-
return GizmoViewportUtils.getContainerSize(this._engine.canvas.parentElement);
|
|
73300
|
-
}
|
|
73301
|
-
/** @returns 是否存在可操作的画布容器和相机。 */ _hasViewport() {
|
|
73302
|
-
return Boolean(this._engine.canvas.parentElement && this._engine.compositions[0]?.camera);
|
|
73303
|
-
}
|
|
73304
|
-
/**
|
|
73305
|
-
* @param owner Gizmo 宿主
|
|
73306
|
-
*/ constructor(owner){
|
|
73307
|
-
super(), _define_property(this, "_owner", void 0), _define_property(this, "_minScale", 0.01), _define_property(this, "_maxScale", 20), _define_property(this, "_configOff", void 0), _define_property(this, "_wheelSignature", ''), _define_property(this, "_wheelMode", 'pan');
|
|
73308
|
-
this._owner = owner;
|
|
73309
|
-
this._configOff = owner.getConfigManager().onChange(viewportNavigationConfig, ()=>{
|
|
73310
|
-
this._wheelSignature = '';
|
|
73311
|
-
});
|
|
73312
72925
|
}
|
|
73313
72926
|
}
|
|
72927
|
+
/**
|
|
72928
|
+
* 绘制包围盒边框(沿 4 个角点连边)。
|
|
72929
|
+
* @param control 绘制控制器
|
|
72930
|
+
* @param box 包围盒(视图坐标,Y 向下)
|
|
72931
|
+
* @param color 边框颜色
|
|
72932
|
+
* @param width 线宽
|
|
72933
|
+
*/ function drawBox(control, box, color, width) {
|
|
72934
|
+
drawCorners(control, box.corners, color, width);
|
|
72935
|
+
}
|
|
72936
|
+
/**
|
|
72937
|
+
* 填充轴对齐包围盒(实心矩形)。
|
|
72938
|
+
* @param control 绘制控制器
|
|
72939
|
+
* @param box 包围盒(视图坐标,Y 向下)
|
|
72940
|
+
* @param color 填充颜色
|
|
72941
|
+
*/ function fillBox(control, box, color) {
|
|
72942
|
+
const size = box.getSize();
|
|
72943
|
+
control.fillRect(box.min.x, box.min.y, size.x, size.y, color);
|
|
72944
|
+
}
|
|
72945
|
+
/**
|
|
72946
|
+
* 构造沿局部轴展开的旋转矩形角点。
|
|
72947
|
+
* @param center 矩形中心(视图坐标)
|
|
72948
|
+
* @param xAxis 局部 X 轴单位向量(视图坐标,宽方向)
|
|
72949
|
+
* @param yAxis 局部 Y 轴单位向量(视图坐标,高方向)
|
|
72950
|
+
* @param halfWidth 半宽(沿 xAxis,视图像素)
|
|
72951
|
+
* @param halfHeight 半高(沿 yAxis,视图像素)
|
|
72952
|
+
* @returns 4 个角点(视图坐标,环绕顺序)
|
|
72953
|
+
*/ function rotatedRectCorners(center, xAxis, yAxis, halfWidth, halfHeight) {
|
|
72954
|
+
const halfW = xAxis.clone().multiply(halfWidth);
|
|
72955
|
+
const halfH = yAxis.clone().multiply(halfHeight);
|
|
72956
|
+
return [
|
|
72957
|
+
center.clone().subtract(halfW).subtract(halfH),
|
|
72958
|
+
center.clone().add(halfW).subtract(halfH),
|
|
72959
|
+
center.clone().add(halfW).add(halfH),
|
|
72960
|
+
center.clone().subtract(halfW).add(halfH)
|
|
72961
|
+
];
|
|
72962
|
+
}
|
|
72963
|
+
/**
|
|
72964
|
+
* 填充沿局部轴展开的旋转矩形。
|
|
72965
|
+
* @param control 绘制控制器
|
|
72966
|
+
* @param center 矩形中心(视图坐标)
|
|
72967
|
+
* @param xAxis 局部 X 轴单位向量(视图坐标,宽方向)
|
|
72968
|
+
* @param yAxis 局部 Y 轴单位向量(视图坐标,高方向)
|
|
72969
|
+
* @param width 宽(沿 xAxis,视图像素)
|
|
72970
|
+
* @param height 高(沿 yAxis,视图像素)
|
|
72971
|
+
* @param color 填充颜色
|
|
72972
|
+
*/ function fillRotatedRect(control, center, xAxis, yAxis, width, height, color) {
|
|
72973
|
+
const ex = xAxis.clone();
|
|
72974
|
+
const ey = yAxis.clone();
|
|
72975
|
+
const anchor = center.clone();
|
|
72976
|
+
drawRotatedQuad(control, anchor, ex, ey, ()=>{
|
|
72977
|
+
control.fillRect(-width / 2, -height / 2, width, height, color);
|
|
72978
|
+
});
|
|
72979
|
+
}
|
|
72980
|
+
/**
|
|
72981
|
+
* 在由锚点和两个基向量定义的局部坐标系内执行绘制。
|
|
72982
|
+
* @param control 绘制控制器
|
|
72983
|
+
* @param anchor Control 绘制空间锚点(局部原点)
|
|
72984
|
+
* @param ex 局部 X 轴基向量(单位向量)
|
|
72985
|
+
* @param ey 局部 Y 轴基向量(单位向量)
|
|
72986
|
+
* @param drawFn 在局部坐标系内执行的绘制
|
|
72987
|
+
*/ function drawRotatedQuad(control, anchor, ex, ey, drawFn) {
|
|
72988
|
+
const graphics = control.engine.graphics;
|
|
72989
|
+
// 列优先:第一列 = ex,第二列 = ey,第三列 = anchor(平移)
|
|
72990
|
+
const matrix = Matrix3.fromColumnVectors(new Vector3(ex.x, ex.y, 0), new Vector3(ey.x, ey.y, 0), new Vector3(anchor.x, anchor.y, 1));
|
|
72991
|
+
graphics.pushTransform(matrix);
|
|
72992
|
+
drawFn();
|
|
72993
|
+
graphics.popTransform();
|
|
72994
|
+
}
|
|
73314
72995
|
/** 缩放角点的桌面端命中区域边长;视觉手柄仍由 scaleCircleSize 控制。 */ const SCALE_CORNER_HIT_SIZE = 14;
|
|
73315
72996
|
/** 单选信息标签中的类型图标尺寸。 */ const INFO_ICON_SIZE = 15;
|
|
73316
72997
|
/** 图标相对选框顶边的底部偏移。 */ const INFO_ICON_BOTTOM = 5.5;
|
|
@@ -74018,7 +73699,7 @@ const itemCreateConfig = defineConfig({
|
|
|
74018
73699
|
*/ _getIconUrl(type) {
|
|
74019
73700
|
const urlMap = {
|
|
74020
73701
|
'null': '',
|
|
74021
|
-
'image': this.config.
|
|
73702
|
+
'image': this.config.imageLogoUrl,
|
|
74022
73703
|
'group': this.config.groupLogoUrl,
|
|
74023
73704
|
'text': this.config.textLogoUrl,
|
|
74024
73705
|
'video': this.config.videoLogoUrl,
|
|
@@ -74036,7 +73717,7 @@ const itemCreateConfig = defineConfig({
|
|
|
74036
73717
|
const logoKeys = [
|
|
74037
73718
|
{
|
|
74038
73719
|
type: "image",
|
|
74039
|
-
key: '
|
|
73720
|
+
key: 'imageLogoUrl'
|
|
74040
73721
|
},
|
|
74041
73722
|
{
|
|
74042
73723
|
type: "group",
|
|
@@ -76202,6 +75883,12 @@ const itemCreateConfig = defineConfig({
|
|
|
76202
75883
|
this._session.syncTextArea(this.result, this.viewScale);
|
|
76203
75884
|
}
|
|
76204
75885
|
/**
|
|
75886
|
+
* 选中当前编辑文本的全部内容,并将焦点交给输入框。
|
|
75887
|
+
* @returns 当前存在可编辑文本时返回 true
|
|
75888
|
+
*/ selectAllText() {
|
|
75889
|
+
return this._session.selectAllText();
|
|
75890
|
+
}
|
|
75891
|
+
/**
|
|
76205
75892
|
* 绘制文本编辑包围盒。
|
|
76206
75893
|
* @param control 绘制控制器
|
|
76207
75894
|
*/ _drawEditBox(control) {
|
|
@@ -76485,16 +76172,16 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76485
76172
|
this._session = new TextEditSession(_owner);
|
|
76486
76173
|
}
|
|
76487
76174
|
}
|
|
76488
|
-
/** 图片裁切和扩边的交互类型。 */ var
|
|
76489
|
-
/** 无交互。 */
|
|
76490
|
-
/** 角点双轴缩放。 */
|
|
76491
|
-
/** 边中点单轴缩放。 */
|
|
76492
|
-
/** 移动交互框。 */
|
|
76493
|
-
return
|
|
76175
|
+
/** 图片裁切和扩边的交互类型。 */ var ImageInteractionType = /*#__PURE__*/ function(ImageInteractionType) {
|
|
76176
|
+
/** 无交互。 */ ImageInteractionType["NONE"] = "none";
|
|
76177
|
+
/** 角点双轴缩放。 */ ImageInteractionType["SCALE"] = "scale";
|
|
76178
|
+
/** 边中点单轴缩放。 */ ImageInteractionType["DIRECTION_SCALE"] = "direction-scale";
|
|
76179
|
+
/** 移动交互框。 */ ImageInteractionType["MOVE"] = "move";
|
|
76180
|
+
return ImageInteractionType;
|
|
76494
76181
|
}({});
|
|
76495
|
-
/** 在图片元素范围内移动或缩放归一化裁剪框。 */ class
|
|
76182
|
+
/** 在图片元素范围内移动或缩放归一化裁剪框。 */ class ImageCutGizmo extends Gizmo {
|
|
76496
76183
|
/** 当前图片裁剪配置。 */ get config() {
|
|
76497
|
-
return this._owner.getConfigManager().get(
|
|
76184
|
+
return this._owner.getConfigManager().get(imageCutConfig);
|
|
76498
76185
|
}
|
|
76499
76186
|
/** 当前选中的元素(直读 selection.getSelectedPlayerItems:id→VFXItem 已解析)。 */ get selectedItems() {
|
|
76500
76187
|
return this._owner.getSelection().getSelectedPlayerItems();
|
|
@@ -76530,7 +76217,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76530
76217
|
const inputPosition = new Vector2(event.position.x, event.position.y);
|
|
76531
76218
|
this.refreshInteractionType(hover, inputPosition);
|
|
76532
76219
|
this._owner.setCursor(this.cursorResult);
|
|
76533
|
-
if (event.buttonMask === MouseButtonMask.None && (this.interactionParam.type ===
|
|
76220
|
+
if (event.buttonMask === MouseButtonMask.None && (this.interactionParam.type === ImageInteractionType.SCALE || this.interactionParam.type === ImageInteractionType.DIRECTION_SCALE)) {
|
|
76534
76221
|
event.accept();
|
|
76535
76222
|
}
|
|
76536
76223
|
}
|
|
@@ -76559,9 +76246,9 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76559
76246
|
return;
|
|
76560
76247
|
}
|
|
76561
76248
|
this.interactionParam = {
|
|
76562
|
-
type:
|
|
76249
|
+
type: ImageInteractionType.NONE
|
|
76563
76250
|
};
|
|
76564
|
-
this.refreshCursorResult(
|
|
76251
|
+
this.refreshCursorResult(ImageInteractionType.NONE);
|
|
76565
76252
|
this._owner.setCursor(this.cursorResult);
|
|
76566
76253
|
}
|
|
76567
76254
|
/** @returns 是否仅选中了一个可裁剪元素。 */ _isApplicableSelection() {
|
|
@@ -76576,7 +76263,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76576
76263
|
if (!this._mouseGrabbed) {
|
|
76577
76264
|
return false;
|
|
76578
76265
|
}
|
|
76579
|
-
if (this.interactionParam.type ===
|
|
76266
|
+
if (this.interactionParam.type === ImageInteractionType.NONE) {
|
|
76580
76267
|
return true;
|
|
76581
76268
|
}
|
|
76582
76269
|
// 步骤 2:获取实时投影并计算指针位移。
|
|
@@ -76591,7 +76278,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76591
76278
|
const { min: itemBoxMin, max: itemBoxMax } = itemBox;
|
|
76592
76279
|
// 步骤 3:按移动、角点缩放或边缩放更新归一化裁剪框。
|
|
76593
76280
|
switch(this.interactionParam.type){
|
|
76594
|
-
case
|
|
76281
|
+
case ImageInteractionType.MOVE:
|
|
76595
76282
|
{
|
|
76596
76283
|
const { min: originMin, max: originMax } = box;
|
|
76597
76284
|
const xMinShift = itemBoxMin.x - originMin.x;
|
|
@@ -76604,7 +76291,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76604
76291
|
this.result.normalizeCutBox = getNormalizeBoxByBoxes(itemBox, resultBox);
|
|
76605
76292
|
break;
|
|
76606
76293
|
}
|
|
76607
|
-
case
|
|
76294
|
+
case ImageInteractionType.SCALE:
|
|
76608
76295
|
{
|
|
76609
76296
|
const { startCorner, anchor } = this.interactionParam;
|
|
76610
76297
|
const resultCorner = new Vector2();
|
|
@@ -76669,7 +76356,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76669
76356
|
}
|
|
76670
76357
|
break;
|
|
76671
76358
|
}
|
|
76672
|
-
case
|
|
76359
|
+
case ImageInteractionType.DIRECTION_SCALE:
|
|
76673
76360
|
{
|
|
76674
76361
|
var _this_interactionParam1;
|
|
76675
76362
|
const { index } = this.interactionParam;
|
|
@@ -76744,7 +76431,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76744
76431
|
const inputPosition = new Vector2(event.position.x, event.position.y);
|
|
76745
76432
|
this.refreshInteractionType(mouse, inputPosition);
|
|
76746
76433
|
this._owner.setCursor(this.cursorResult);
|
|
76747
|
-
if (this.interactionParam.type ===
|
|
76434
|
+
if (this.interactionParam.type === ImageInteractionType.NONE) {
|
|
76748
76435
|
return;
|
|
76749
76436
|
}
|
|
76750
76437
|
this._mouseGrabbed = true;
|
|
@@ -76841,7 +76528,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76841
76528
|
* @param angle 指针方向
|
|
76842
76529
|
*/ refreshCursorResult(activeType, angle = 0) {
|
|
76843
76530
|
switch(activeType){
|
|
76844
|
-
case
|
|
76531
|
+
case ImageInteractionType.SCALE:
|
|
76845
76532
|
{
|
|
76846
76533
|
this.cursorResult = {
|
|
76847
76534
|
type: GestureCursorType.SCALE,
|
|
@@ -76849,7 +76536,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76849
76536
|
};
|
|
76850
76537
|
break;
|
|
76851
76538
|
}
|
|
76852
|
-
case
|
|
76539
|
+
case ImageInteractionType.DIRECTION_SCALE:
|
|
76853
76540
|
{
|
|
76854
76541
|
this.cursorResult = {
|
|
76855
76542
|
type: GestureCursorType.SCALE,
|
|
@@ -76857,8 +76544,8 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76857
76544
|
};
|
|
76858
76545
|
break;
|
|
76859
76546
|
}
|
|
76860
|
-
case
|
|
76861
|
-
case
|
|
76547
|
+
case ImageInteractionType.MOVE:
|
|
76548
|
+
case ImageInteractionType.NONE:
|
|
76862
76549
|
{
|
|
76863
76550
|
this.cursorResult = {
|
|
76864
76551
|
type: GestureCursorType.NORMAL,
|
|
@@ -76908,7 +76595,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76908
76595
|
*/ refreshInteractionType(point, inputPosition) {
|
|
76909
76596
|
// 步骤 1:重置交互状态并获取实时裁剪投影。
|
|
76910
76597
|
this.interactionParam = {
|
|
76911
|
-
type:
|
|
76598
|
+
type: ImageInteractionType.NONE
|
|
76912
76599
|
};
|
|
76913
76600
|
const projection = this._projectSelection();
|
|
76914
76601
|
if (!projection) {
|
|
@@ -76925,7 +76612,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76925
76612
|
if (corner.distance(point) < this.config.scaleInteractionDistance) {
|
|
76926
76613
|
hasInteractionType = true;
|
|
76927
76614
|
this.interactionParam = {
|
|
76928
|
-
type:
|
|
76615
|
+
type: ImageInteractionType.SCALE,
|
|
76929
76616
|
box: cutBox.clone(),
|
|
76930
76617
|
startMouse: inputPosition,
|
|
76931
76618
|
startCorner: corner.clone(),
|
|
@@ -76950,7 +76637,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76950
76637
|
if (state) {
|
|
76951
76638
|
hasInteractionType = true;
|
|
76952
76639
|
this.interactionParam = {
|
|
76953
|
-
type:
|
|
76640
|
+
type: ImageInteractionType.DIRECTION_SCALE,
|
|
76954
76641
|
index,
|
|
76955
76642
|
box: cutBox.clone(),
|
|
76956
76643
|
startMouse: inputPosition
|
|
@@ -76961,7 +76648,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76961
76648
|
// 步骤 4:最后检测裁剪区域整体移动并刷新光标。
|
|
76962
76649
|
if (cutBox.containsPoint(point) && !hasInteractionType) {
|
|
76963
76650
|
this.interactionParam = {
|
|
76964
|
-
type:
|
|
76651
|
+
type: ImageInteractionType.MOVE,
|
|
76965
76652
|
box: cutBox.clone(),
|
|
76966
76653
|
startMouse: inputPosition
|
|
76967
76654
|
};
|
|
@@ -76973,8 +76660,8 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76973
76660
|
super(...args), _define_property(this, "result", {
|
|
76974
76661
|
normalizeCutBox: new Box2(new Vector2(), new Vector2(1, 1))
|
|
76975
76662
|
}), /** 仅供当前渲染帧使用的投影快照;输入不读取它。 */ _define_property(this, "_renderProjection", void 0), _define_property(this, "interactionParam", {
|
|
76976
|
-
type:
|
|
76977
|
-
}), _define_property(this, "type", GizmoType.
|
|
76663
|
+
type: ImageInteractionType.NONE
|
|
76664
|
+
}), _define_property(this, "type", GizmoType.IMAGE_CUT), /** 光标结果。 */ _define_property(this, "cursorResult", {
|
|
76978
76665
|
type: GestureCursorType.NORMAL,
|
|
76979
76666
|
angle: 0
|
|
76980
76667
|
}), _define_property(this, "_isLockScale", false), _define_property(this, "_mouseGrabbed", false);
|
|
@@ -76983,13 +76670,13 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
76983
76670
|
/** 图片裁切工具。 */ class ImageCutGizmoTool extends GizmoTool {
|
|
76984
76671
|
/** @returns 图片裁切 Gizmo 图。 */ createGizmos() {
|
|
76985
76672
|
return [
|
|
76986
|
-
new
|
|
76673
|
+
new ImageCutGizmo(this.owner)
|
|
76987
76674
|
];
|
|
76988
76675
|
}
|
|
76989
76676
|
}
|
|
76990
|
-
/** 在图片范围外移动或缩放归一化扩边框。 */ class
|
|
76677
|
+
/** 在图片范围外移动或缩放归一化扩边框。 */ class ImageExpandGizmo extends Gizmo {
|
|
76991
76678
|
/** 当前图片扩边配置。 */ get config() {
|
|
76992
|
-
return this._owner.getConfigManager().get(
|
|
76679
|
+
return this._owner.getConfigManager().get(imageExpandConfig);
|
|
76993
76680
|
}
|
|
76994
76681
|
/** 当前选中的元素(直读 selection.getSelectedPlayerItems:id→VFXItem 已解析)。 */ get selectedItems() {
|
|
76995
76682
|
return this._owner.getSelection().getSelectedPlayerItems();
|
|
@@ -77025,7 +76712,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77025
76712
|
const inputPosition = new Vector2(event.position.x, event.position.y);
|
|
77026
76713
|
this.refreshInteractionType(hover, inputPosition);
|
|
77027
76714
|
this._owner.setCursor(this.cursorResult);
|
|
77028
|
-
if (event.buttonMask === MouseButtonMask.None && (this.interactionParam.type ===
|
|
76715
|
+
if (event.buttonMask === MouseButtonMask.None && (this.interactionParam.type === ImageInteractionType.SCALE || this.interactionParam.type === ImageInteractionType.DIRECTION_SCALE)) {
|
|
77029
76716
|
event.accept();
|
|
77030
76717
|
}
|
|
77031
76718
|
}
|
|
@@ -77054,9 +76741,9 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77054
76741
|
return;
|
|
77055
76742
|
}
|
|
77056
76743
|
this.interactionParam = {
|
|
77057
|
-
type:
|
|
76744
|
+
type: ImageInteractionType.NONE
|
|
77058
76745
|
};
|
|
77059
|
-
this.refreshCursorResult(
|
|
76746
|
+
this.refreshCursorResult(ImageInteractionType.NONE);
|
|
77060
76747
|
this._owner.setCursor(this.cursorResult);
|
|
77061
76748
|
}
|
|
77062
76749
|
/** @returns 是否仅选中了一个可扩边元素。 */ _isApplicableSelection() {
|
|
@@ -77071,7 +76758,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77071
76758
|
if (!this._mouseGrabbed) {
|
|
77072
76759
|
return false;
|
|
77073
76760
|
}
|
|
77074
|
-
if (this.interactionParam.type ===
|
|
76761
|
+
if (this.interactionParam.type === ImageInteractionType.NONE) {
|
|
77075
76762
|
return true;
|
|
77076
76763
|
}
|
|
77077
76764
|
// 步骤 2:获取实时投影并计算指针位移。
|
|
@@ -77086,7 +76773,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77086
76773
|
const { min: itemBoxMin, max: itemBoxMax } = itemBox;
|
|
77087
76774
|
// 步骤 3:按移动、角点缩放或边缩放更新归一化扩边框。
|
|
77088
76775
|
switch(this.interactionParam.type){
|
|
77089
|
-
case
|
|
76776
|
+
case ImageInteractionType.MOVE:
|
|
77090
76777
|
{
|
|
77091
76778
|
const { min: originMin, max: originMax } = box;
|
|
77092
76779
|
const xMinShift = itemBoxMax.x - originMax.x;
|
|
@@ -77099,7 +76786,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77099
76786
|
this.result.normalizeExpandBox = getNormalizeBoxByBoxes(itemBox, resultBox);
|
|
77100
76787
|
break;
|
|
77101
76788
|
}
|
|
77102
|
-
case
|
|
76789
|
+
case ImageInteractionType.SCALE:
|
|
77103
76790
|
{
|
|
77104
76791
|
const { index } = this.interactionParam;
|
|
77105
76792
|
const { min, max } = box;
|
|
@@ -77158,7 +76845,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77158
76845
|
]));
|
|
77159
76846
|
break;
|
|
77160
76847
|
}
|
|
77161
|
-
case
|
|
76848
|
+
case ImageInteractionType.DIRECTION_SCALE:
|
|
77162
76849
|
{
|
|
77163
76850
|
var _this_interactionParam1;
|
|
77164
76851
|
const { index } = this.interactionParam;
|
|
@@ -77276,7 +76963,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77276
76963
|
const inputPosition = new Vector2(event.position.x, event.position.y);
|
|
77277
76964
|
this.refreshInteractionType(mouse, inputPosition);
|
|
77278
76965
|
this._owner.setCursor(this.cursorResult);
|
|
77279
|
-
if (this.interactionParam.type ===
|
|
76966
|
+
if (this.interactionParam.type === ImageInteractionType.NONE) {
|
|
77280
76967
|
return;
|
|
77281
76968
|
}
|
|
77282
76969
|
this._mouseGrabbed = true;
|
|
@@ -77363,7 +77050,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77363
77050
|
* @param angle 指针方向角度。
|
|
77364
77051
|
*/ refreshCursorResult(activeType, angle = 0) {
|
|
77365
77052
|
switch(activeType){
|
|
77366
|
-
case
|
|
77053
|
+
case ImageInteractionType.SCALE:
|
|
77367
77054
|
{
|
|
77368
77055
|
this.cursorResult = {
|
|
77369
77056
|
type: GestureCursorType.SCALE,
|
|
@@ -77371,7 +77058,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77371
77058
|
};
|
|
77372
77059
|
break;
|
|
77373
77060
|
}
|
|
77374
|
-
case
|
|
77061
|
+
case ImageInteractionType.DIRECTION_SCALE:
|
|
77375
77062
|
{
|
|
77376
77063
|
this.cursorResult = {
|
|
77377
77064
|
type: GestureCursorType.SCALE,
|
|
@@ -77379,8 +77066,8 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77379
77066
|
};
|
|
77380
77067
|
break;
|
|
77381
77068
|
}
|
|
77382
|
-
case
|
|
77383
|
-
case
|
|
77069
|
+
case ImageInteractionType.MOVE:
|
|
77070
|
+
case ImageInteractionType.NONE:
|
|
77384
77071
|
{
|
|
77385
77072
|
this.cursorResult = {
|
|
77386
77073
|
type: GestureCursorType.NORMAL,
|
|
@@ -77429,7 +77116,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77429
77116
|
* @param inputPosition Control 本地坐标鼠标位置
|
|
77430
77117
|
*/ refreshInteractionType(point, inputPosition) {
|
|
77431
77118
|
// 步骤 1:重置交互状态并获取实时扩边投影。
|
|
77432
|
-
this.interactionParam.type =
|
|
77119
|
+
this.interactionParam.type = ImageInteractionType.NONE;
|
|
77433
77120
|
const projection = this._projectSelection();
|
|
77434
77121
|
if (!projection) {
|
|
77435
77122
|
return;
|
|
@@ -77445,7 +77132,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77445
77132
|
if (corner.distance(point) < 20) {
|
|
77446
77133
|
hasInteractionType = true;
|
|
77447
77134
|
this.interactionParam = {
|
|
77448
|
-
type:
|
|
77135
|
+
type: ImageInteractionType.SCALE,
|
|
77449
77136
|
index,
|
|
77450
77137
|
box: expandBox.clone(),
|
|
77451
77138
|
startMouse: inputPosition
|
|
@@ -77469,7 +77156,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77469
77156
|
if (state) {
|
|
77470
77157
|
hasInteractionType = true;
|
|
77471
77158
|
this.interactionParam = {
|
|
77472
|
-
type:
|
|
77159
|
+
type: ImageInteractionType.DIRECTION_SCALE,
|
|
77473
77160
|
index,
|
|
77474
77161
|
box: expandBox.clone(),
|
|
77475
77162
|
startMouse: inputPosition
|
|
@@ -77480,7 +77167,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77480
77167
|
// 步骤 4:最后检测扩边区域整体移动并刷新光标。
|
|
77481
77168
|
if (expandBox.containsPoint(point) && !hasInteractionType) {
|
|
77482
77169
|
this.interactionParam = {
|
|
77483
|
-
type:
|
|
77170
|
+
type: ImageInteractionType.MOVE,
|
|
77484
77171
|
box: expandBox.clone(),
|
|
77485
77172
|
startMouse: inputPosition
|
|
77486
77173
|
};
|
|
@@ -77492,8 +77179,8 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77492
77179
|
super(...args), _define_property(this, "result", {
|
|
77493
77180
|
normalizeExpandBox: new Box2(new Vector2(), new Vector2(1, 1))
|
|
77494
77181
|
}), _define_property(this, "_renderProjection", void 0), _define_property(this, "interactionParam", {
|
|
77495
|
-
type:
|
|
77496
|
-
}), _define_property(this, "type", GizmoType.
|
|
77182
|
+
type: ImageInteractionType.NONE
|
|
77183
|
+
}), _define_property(this, "type", GizmoType.IMAGE_EXPAND), /** 光标结果。 */ _define_property(this, "cursorResult", {
|
|
77497
77184
|
type: GestureCursorType.NORMAL,
|
|
77498
77185
|
angle: 0
|
|
77499
77186
|
}), _define_property(this, "_isLockScale", false), _define_property(this, "_mouseGrabbed", false);
|
|
@@ -77502,7 +77189,7 @@ _define_property(SelectTextGizmo, "HOVER_GAP_LENGTH", 4);
|
|
|
77502
77189
|
/** 图片扩边工具。 */ class ImageExpandGizmoTool extends GizmoTool {
|
|
77503
77190
|
/** @returns 图片扩边 Gizmo 图。 */ createGizmos() {
|
|
77504
77191
|
return [
|
|
77505
|
-
new
|
|
77192
|
+
new ImageExpandGizmo(this.owner)
|
|
77506
77193
|
];
|
|
77507
77194
|
}
|
|
77508
77195
|
}
|
|
@@ -77746,7 +77433,7 @@ const EDIT_TEXT_FONT_FAMILY = 'sans-serif';
|
|
|
77746
77433
|
}), /** onMouseMove 命中缓存(坐标未变则跳过 _computePreSelected,避免每帧全 result 命中扫描)。 */ _define_property(this, "_cachedCoords", null);
|
|
77747
77434
|
}
|
|
77748
77435
|
}
|
|
77749
|
-
/**
|
|
77436
|
+
/** Sprite 精准文字编辑工具。 */ class SpriteTextEditGizmoTool extends GizmoTool {
|
|
77750
77437
|
/** @returns 精准文字编辑 Gizmo 图。 */ createGizmos() {
|
|
77751
77438
|
return [
|
|
77752
77439
|
new SpriteTextEditGizmo(this.owner)
|
|
@@ -78317,8 +78004,8 @@ const EDIT_TEXT_FONT_FAMILY = 'sans-serif';
|
|
|
78317
78004
|
void this._refreshMaskImage(this.config.maskImage);
|
|
78318
78005
|
}
|
|
78319
78006
|
}
|
|
78320
|
-
/**
|
|
78321
|
-
/** @returns
|
|
78007
|
+
/** 蒙版编辑工具。 */ class MaskGizmoTool extends GizmoTool {
|
|
78008
|
+
/** @returns 蒙版 Gizmo 图。 */ createGizmos() {
|
|
78322
78009
|
return [
|
|
78323
78010
|
new MaskGizmo(this.owner)
|
|
78324
78011
|
];
|
|
@@ -80464,6 +80151,348 @@ const cursorMap = {
|
|
|
80464
80151
|
console.error(e);
|
|
80465
80152
|
});
|
|
80466
80153
|
}
|
|
80154
|
+
const LOADING_TIP_FONT_SIZE = 16;
|
|
80155
|
+
const LOADING_TIP_FONT_FAMILY = 'sans-serif';
|
|
80156
|
+
const LOADING_TIP_COLOR = 0x000000;
|
|
80157
|
+
/** 为目标元素叠加加载动画与提示文案。 */ class LoadingGizmo extends Gizmo {
|
|
80158
|
+
/** 当前加载覆盖层配置。 */ get config() {
|
|
80159
|
+
return this._owner.getConfigManager().get(loadingConfig);
|
|
80160
|
+
}
|
|
80161
|
+
/** 当前 Gizmo 实例持有的可销毁渲染投影。 */ get idMap() {
|
|
80162
|
+
return this._idMap;
|
|
80163
|
+
}
|
|
80164
|
+
/** 当前 loading 元素 id 列表(由稳定 manager 派生)。 */ get loadingIds() {
|
|
80165
|
+
return this._manager.ids;
|
|
80166
|
+
}
|
|
80167
|
+
/**
|
|
80168
|
+
* 在片元着色器变化时重建加载动画对象。
|
|
80169
|
+
* @param change 加载配置变更。
|
|
80170
|
+
*/ _onConfigChange(change) {
|
|
80171
|
+
if (change.previous.loadingFragment === change.current.loadingFragment) {
|
|
80172
|
+
return;
|
|
80173
|
+
}
|
|
80174
|
+
for (const [id, loadingItem] of this._idMap){
|
|
80175
|
+
this._disposeLoadingVFXItem(loadingItem.loadingVFXItem);
|
|
80176
|
+
loadingItem.loadingVFXItem = this.createLoadingVFXItem();
|
|
80177
|
+
this.updateLoadingVFXItemTransform(id, loadingItem);
|
|
80178
|
+
}
|
|
80179
|
+
}
|
|
80180
|
+
/**
|
|
80181
|
+
* 订阅 loading 集合变化:add/delete 后回调当前全量 id 列表。
|
|
80182
|
+
* @param cb 收到当前全量 loading id 列表的回调
|
|
80183
|
+
* @returns 退订函数,调用后取消对应监听
|
|
80184
|
+
*/ onLoadingChange(cb) {
|
|
80185
|
+
return this._manager.on('change', (change)=>{
|
|
80186
|
+
if (change.addedIds.length > 0 || change.removedIds.length > 0) {
|
|
80187
|
+
cb(change.ids);
|
|
80188
|
+
}
|
|
80189
|
+
});
|
|
80190
|
+
}
|
|
80191
|
+
/**
|
|
80192
|
+
* 为指定元素添加 loading 覆盖层;同一元素不可重复添加。
|
|
80193
|
+
* @param id 目标元素 ID
|
|
80194
|
+
* @param options loading 配置(文案、位置、自定义区域、是否清空选中)
|
|
80195
|
+
*/ add(id, options) {
|
|
80196
|
+
this._manager.add(id, options);
|
|
80197
|
+
}
|
|
80198
|
+
/**
|
|
80199
|
+
* 移除指定元素的 loading 覆盖层并释放对应 VFXItem。
|
|
80200
|
+
* @param id 目标元素 ID
|
|
80201
|
+
*/ delete(id) {
|
|
80202
|
+
this._manager.delete(id);
|
|
80203
|
+
}
|
|
80204
|
+
/**
|
|
80205
|
+
* 更新指定 loading 元素的提示文案。
|
|
80206
|
+
* @param id 目标元素 ID
|
|
80207
|
+
* @param options 待合并更新的 LoadingTip 属性
|
|
80208
|
+
*/ updateItem(id, options) {
|
|
80209
|
+
this._manager.update(id, options);
|
|
80210
|
+
}
|
|
80211
|
+
/** 根据目标元素的实时包围盒刷新加载动画。 */ onPreRender() {
|
|
80212
|
+
if (this._idMap.size === 0) {
|
|
80213
|
+
return;
|
|
80214
|
+
}
|
|
80215
|
+
for (const [id, loadingItem] of this._idMap){
|
|
80216
|
+
this.updateLoadingVFXItemTransform(id, loadingItem);
|
|
80217
|
+
}
|
|
80218
|
+
}
|
|
80219
|
+
/**
|
|
80220
|
+
* 绘制所有加载提示文案。
|
|
80221
|
+
* @param control 绘制控制器。
|
|
80222
|
+
*/ draw(control) {
|
|
80223
|
+
if (this._idMap.size === 0) {
|
|
80224
|
+
return;
|
|
80225
|
+
}
|
|
80226
|
+
for (const [id, loadingItem] of this._idMap){
|
|
80227
|
+
if (!loadingItem.tip?.text) {
|
|
80228
|
+
continue;
|
|
80229
|
+
}
|
|
80230
|
+
const item = getPlayerItemById(this._owner.getEngine().compositions[0], id);
|
|
80231
|
+
const itemBox = item ? getItemViewBox(item, GizmoViewportUtils.getContainerSize(this._owner.getEngine().canvas.parentElement)) : new Box2();
|
|
80232
|
+
const loadingBox = getBoxByNormalizeBox(itemBox, loadingItem.loadingBox);
|
|
80233
|
+
this.drawLoadingTip(control, loadingBox, itemBox, loadingItem.tip);
|
|
80234
|
+
}
|
|
80235
|
+
}
|
|
80236
|
+
/**
|
|
80237
|
+
* 绘制单条加载提示,并将文本限制在加载区域内。
|
|
80238
|
+
* @param control 绘制控制器。
|
|
80239
|
+
* @param loadingBox 加载区域。
|
|
80240
|
+
* @param itemBox 目标元素包围盒。
|
|
80241
|
+
* @param tip 加载提示配置。
|
|
80242
|
+
*/ drawLoadingTip(control, loadingBox, itemBox, tip) {
|
|
80243
|
+
// 步骤 1:计算提示位置与可用宽度。
|
|
80244
|
+
const { x: width, y: height } = loadingBox.getSize(this._loadingBoxSize);
|
|
80245
|
+
if (!tip.text || !Number.isFinite(width) || width <= 0) {
|
|
80246
|
+
return;
|
|
80247
|
+
}
|
|
80248
|
+
const positionedLeft = tip.position ? itemBox.min.x + (Number.isFinite(tip.position.x) ? tip.position.x : 0) : loadingBox.min.x;
|
|
80249
|
+
const left = tip.position ? Math.min(Math.max(positionedLeft, loadingBox.min.x), loadingBox.max.x) : loadingBox.min.x;
|
|
80250
|
+
const availableWidth = tip.position ? loadingBox.max.x - left : width;
|
|
80251
|
+
if (availableWidth <= 0) {
|
|
80252
|
+
return;
|
|
80253
|
+
}
|
|
80254
|
+
/**
|
|
80255
|
+
* 测量加载提示的粗体字形。
|
|
80256
|
+
* @param text 提示文本。
|
|
80257
|
+
* @param fontSize 字号。
|
|
80258
|
+
* @returns 文本字形尺寸。
|
|
80259
|
+
*/ const measureTipText = (text, fontSize)=>{
|
|
80260
|
+
const metrics = measureTextMetrics(text, fontSize, LOADING_TIP_FONT_FAMILY, 'bold');
|
|
80261
|
+
return {
|
|
80262
|
+
width: metrics.width || Array.from(text).length * fontSize,
|
|
80263
|
+
actualBoundingBoxAscent: metrics.actualBoundingBoxAscent || fontSize * 0.8,
|
|
80264
|
+
actualBoundingBoxDescent: metrics.actualBoundingBoxDescent || fontSize * 0.2
|
|
80265
|
+
};
|
|
80266
|
+
};
|
|
80267
|
+
// 步骤 2:测量文本并缩小字号以适应可用宽度。
|
|
80268
|
+
const measuredAtBaseSize = measureTipText(tip.text, LOADING_TIP_FONT_SIZE);
|
|
80269
|
+
let fontSize = measuredAtBaseSize.width > availableWidth ? LOADING_TIP_FONT_SIZE * availableWidth / measuredAtBaseSize.width : LOADING_TIP_FONT_SIZE;
|
|
80270
|
+
let textMetrics = measureTipText(tip.text, fontSize);
|
|
80271
|
+
if (textMetrics.width > availableWidth) {
|
|
80272
|
+
fontSize *= availableWidth / textMetrics.width;
|
|
80273
|
+
textMetrics = measureTipText(tip.text, fontSize);
|
|
80274
|
+
}
|
|
80275
|
+
// 步骤 3:按字形基线计算最终绘制位置。
|
|
80276
|
+
const textLeft = tip.position ? left : loadingBox.min.x + (width - textMetrics.width) / 2;
|
|
80277
|
+
const inkHeight = textMetrics.actualBoundingBoxAscent + textMetrics.actualBoundingBoxDescent;
|
|
80278
|
+
const top = tip.position ? itemBox.min.y + (Number.isFinite(tip.position.y) ? tip.position.y : 0) : loadingBox.min.y + (height - inkHeight) / 2;
|
|
80279
|
+
const probeMetrics = measureTipText(METRICS_STRING + BASELINE_SYMBOL, fontSize);
|
|
80280
|
+
const inkTopFromCellTop = CONTROL_TEXT_GLYPH_PADDING + probeMetrics.actualBoundingBoxAscent - textMetrics.actualBoundingBoxAscent;
|
|
80281
|
+
control.drawText(textLeft, top - inkTopFromCellTop, tip.text, fontSize, toColor(LOADING_TIP_COLOR, 1), LOADING_TIP_FONT_FAMILY, 'bold');
|
|
80282
|
+
}
|
|
80283
|
+
/** 释放当前实例的渲染投影;稳定 LoadingManager 不随 Gizmo 重建清空。 */ dispose() {
|
|
80284
|
+
this._configOff?.();
|
|
80285
|
+
this._configOff = undefined;
|
|
80286
|
+
this._managerOff?.();
|
|
80287
|
+
this._managerOff = undefined;
|
|
80288
|
+
this._idMap.forEach((loadingItem)=>{
|
|
80289
|
+
this._disposeLoadingVFXItem(loadingItem.loadingVFXItem);
|
|
80290
|
+
});
|
|
80291
|
+
this._idMap.clear();
|
|
80292
|
+
super.dispose();
|
|
80293
|
+
}
|
|
80294
|
+
/** 将可销毁的渲染投影同步到当前加载状态。 */ _syncManager() {
|
|
80295
|
+
const activeIds = new Set(this._manager.ids);
|
|
80296
|
+
for (const [id, loadingItem] of this._idMap){
|
|
80297
|
+
if (!activeIds.has(id)) {
|
|
80298
|
+
this._disposeLoadingVFXItem(loadingItem.loadingVFXItem);
|
|
80299
|
+
this._idMap.delete(id);
|
|
80300
|
+
}
|
|
80301
|
+
}
|
|
80302
|
+
for (const id of activeIds){
|
|
80303
|
+
const state = this._manager.get(id);
|
|
80304
|
+
if (!state) {
|
|
80305
|
+
continue;
|
|
80306
|
+
}
|
|
80307
|
+
const existing = this._idMap.get(id);
|
|
80308
|
+
if (existing) {
|
|
80309
|
+
existing.tip = {
|
|
80310
|
+
...state.tip,
|
|
80311
|
+
position: state.tip.position ? state.tip.position.clone() : undefined
|
|
80312
|
+
};
|
|
80313
|
+
} else {
|
|
80314
|
+
this._createProjection(id, state);
|
|
80315
|
+
}
|
|
80316
|
+
}
|
|
80317
|
+
}
|
|
80318
|
+
/**
|
|
80319
|
+
* 为加载状态创建渲染投影。
|
|
80320
|
+
* @param id 目标元素 ID。
|
|
80321
|
+
* @param state 加载状态。
|
|
80322
|
+
*/ _createProjection(id, state) {
|
|
80323
|
+
const item = getPlayerItemById(this._owner.getEngine().compositions[0], id);
|
|
80324
|
+
const itemViewBox = item ? getItemViewBox(item, GizmoViewportUtils.getContainerSize(this._owner.getEngine().canvas.parentElement)) : new Box2();
|
|
80325
|
+
const currentBox = state.loadingBox ? this.getViewBoxByBox(state.loadingBox) : itemViewBox;
|
|
80326
|
+
this._idMap.set(id, {
|
|
80327
|
+
loadingBox: getNormalizeBoxByBoxes(itemViewBox, currentBox),
|
|
80328
|
+
loadingVFXItem: this.createLoadingVFXItem(),
|
|
80329
|
+
tip: {
|
|
80330
|
+
...state.tip,
|
|
80331
|
+
position: state.tip.position ? state.tip.position.clone() : undefined
|
|
80332
|
+
}
|
|
80333
|
+
});
|
|
80334
|
+
this.updateLoadingVFXItemTransform(id, this._idMap.get(id));
|
|
80335
|
+
}
|
|
80336
|
+
/** @returns 当前相机信息。 */ getCameraInfo() {
|
|
80337
|
+
return GizmoViewportUtils.getCameraInfo(this._owner.getEngine());
|
|
80338
|
+
}
|
|
80339
|
+
/** @returns 当前视口的缩放、平移与尺寸。 */ getViewportParams() {
|
|
80340
|
+
const composition = this._owner.getEngine().compositions[0];
|
|
80341
|
+
const camera = composition?.camera;
|
|
80342
|
+
if (camera) {
|
|
80343
|
+
const viewportMatrix = camera.getViewportMatrix();
|
|
80344
|
+
const scale = viewportMatrix.elements[0];
|
|
80345
|
+
const translation = new Vector2(viewportMatrix.elements[12], viewportMatrix.elements[13]);
|
|
80346
|
+
const width = GizmoViewportUtils.getContainerSize(this._owner.getEngine().canvas.parentElement).x;
|
|
80347
|
+
const height = GizmoViewportUtils.getContainerSize(this._owner.getEngine().canvas.parentElement).y;
|
|
80348
|
+
return {
|
|
80349
|
+
scale,
|
|
80350
|
+
translation,
|
|
80351
|
+
width,
|
|
80352
|
+
height
|
|
80353
|
+
};
|
|
80354
|
+
}
|
|
80355
|
+
return {
|
|
80356
|
+
scale: 1,
|
|
80357
|
+
translation: new Vector2(),
|
|
80358
|
+
width: GizmoViewportUtils.getContainerSize(this._owner.getEngine().canvas.parentElement).x,
|
|
80359
|
+
height: GizmoViewportUtils.getContainerSize(this._owner.getEngine().canvas.parentElement).y
|
|
80360
|
+
};
|
|
80361
|
+
}
|
|
80362
|
+
/**
|
|
80363
|
+
* 将视图坐标下的包围盒按当前视口缩放与平移变换为实际渲染包围盒。
|
|
80364
|
+
* @param box 视图坐标下的包围盒
|
|
80365
|
+
* @returns 经视口缩放与平移后的实际渲染包围盒
|
|
80366
|
+
*/ getViewBoxByBox(box) {
|
|
80367
|
+
const { scale, translation, width, height } = this.getViewportParams();
|
|
80368
|
+
const center = new Vector2(width / 2, height / 2);
|
|
80369
|
+
const result = scaleBox(box.clone(), scale, center).translate(translation);
|
|
80370
|
+
return result;
|
|
80371
|
+
}
|
|
80372
|
+
/**
|
|
80373
|
+
* 创建承载加载动画的 VFXItem。
|
|
80374
|
+
* @returns 已绑定几何与材质的加载动画对象。
|
|
80375
|
+
*/ createLoadingVFXItem() {
|
|
80376
|
+
// 步骤 1:创建加载动画对象与平面几何。
|
|
80377
|
+
const composition = this._owner.getEngine().compositions[0];
|
|
80378
|
+
const loadingVFXItem = VFXItemFactory.createVFXItem(composition, null, 'LoadingVFXItem', EffectComponent);
|
|
80379
|
+
this._owner.getSelection().addIgnoreIds([
|
|
80380
|
+
loadingVFXItem.getInstanceId()
|
|
80381
|
+
]);
|
|
80382
|
+
loadingVFXItem.type = index$1.ItemType.effect;
|
|
80383
|
+
const effects = loadingVFXItem.getComponent(EffectComponent);
|
|
80384
|
+
const engine = this._owner.getEngine();
|
|
80385
|
+
const geometry = Geometry.create(engine, {
|
|
80386
|
+
attributes: {
|
|
80387
|
+
aPos: {
|
|
80388
|
+
size: 3,
|
|
80389
|
+
data: new Float32Array([
|
|
80390
|
+
-0.5,
|
|
80391
|
+
-0.5,
|
|
80392
|
+
0,
|
|
80393
|
+
0.5,
|
|
80394
|
+
-0.5,
|
|
80395
|
+
0,
|
|
80396
|
+
0.5,
|
|
80397
|
+
0.5,
|
|
80398
|
+
0,
|
|
80399
|
+
-0.5,
|
|
80400
|
+
0.5,
|
|
80401
|
+
0
|
|
80402
|
+
])
|
|
80403
|
+
},
|
|
80404
|
+
aUV: {
|
|
80405
|
+
size: 2,
|
|
80406
|
+
data: new Float32Array([
|
|
80407
|
+
0,
|
|
80408
|
+
0,
|
|
80409
|
+
1,
|
|
80410
|
+
0,
|
|
80411
|
+
1,
|
|
80412
|
+
1,
|
|
80413
|
+
0,
|
|
80414
|
+
1
|
|
80415
|
+
])
|
|
80416
|
+
}
|
|
80417
|
+
},
|
|
80418
|
+
indices: {
|
|
80419
|
+
data: new Uint16Array([
|
|
80420
|
+
0,
|
|
80421
|
+
1,
|
|
80422
|
+
2,
|
|
80423
|
+
0,
|
|
80424
|
+
2,
|
|
80425
|
+
3
|
|
80426
|
+
])
|
|
80427
|
+
},
|
|
80428
|
+
mode: glContext.TRIANGLES,
|
|
80429
|
+
drawCount: 6
|
|
80430
|
+
});
|
|
80431
|
+
// 步骤 2:使用当前配置创建动画材质。
|
|
80432
|
+
const material = Material.create(engine, {
|
|
80433
|
+
shader: {
|
|
80434
|
+
vertex: `
|
|
80435
|
+
precision highp float;
|
|
80436
|
+
attribute vec3 aPos;
|
|
80437
|
+
attribute vec2 aUV;
|
|
80438
|
+
uniform mat4 effects_MatrixVP;
|
|
80439
|
+
uniform mat4 effects_ObjectToWorld;
|
|
80440
|
+
varying vec2 vUV;
|
|
80441
|
+
void main() {
|
|
80442
|
+
vUV = aUV;
|
|
80443
|
+
gl_Position = effects_MatrixVP * effects_ObjectToWorld * vec4(aPos, 1.0);
|
|
80444
|
+
}`,
|
|
80445
|
+
fragment: this.config.loadingFragment
|
|
80446
|
+
}
|
|
80447
|
+
});
|
|
80448
|
+
// 步骤 3:绑定运行时几何与材质。
|
|
80449
|
+
// @ts-expect-error Effects 类型未暴露可写 geometry。
|
|
80450
|
+
effects.geometry = geometry;
|
|
80451
|
+
effects.material = material;
|
|
80452
|
+
return loadingVFXItem;
|
|
80453
|
+
}
|
|
80454
|
+
/** 释放 loading 渲染对象,并同步恢复 Selection 的命中过滤。 */ _disposeLoadingVFXItem(item) {
|
|
80455
|
+
this._owner.getSelection().deleteIgnoreIds([
|
|
80456
|
+
item.getInstanceId()
|
|
80457
|
+
]);
|
|
80458
|
+
item.dispose();
|
|
80459
|
+
}
|
|
80460
|
+
/**
|
|
80461
|
+
* 按目标元素的实时包围盒更新加载动画变换。
|
|
80462
|
+
* @param id 目标元素 ID。
|
|
80463
|
+
* @param loadingItem 对应的加载渲染投影。
|
|
80464
|
+
*/ updateLoadingVFXItemTransform(id, loadingItem) {
|
|
80465
|
+
const item = getPlayerItemById(this._owner.getEngine().compositions[0], id);
|
|
80466
|
+
const containerSize = GizmoViewportUtils.getContainerSize(this._owner.getEngine().canvas.parentElement);
|
|
80467
|
+
const itemViewBox = item ? getItemViewBox(item, containerSize) : new Box2();
|
|
80468
|
+
const currentBox = getBoxByNormalizeBox(itemViewBox, loadingItem.loadingBox);
|
|
80469
|
+
const viewPosition = new Vector2((currentBox.max.x + currentBox.min.x) / 2, (currentBox.max.y + currentBox.min.y) / 2);
|
|
80470
|
+
const cameraInfo = this.getCameraInfo();
|
|
80471
|
+
const interactionPlane = new Plane(0, new Vector3(0, 0, 1));
|
|
80472
|
+
const worldPosition = viewPositionToWorld(viewPosition, cameraInfo, interactionPlane, containerSize);
|
|
80473
|
+
const viewSize = new Vector2(currentBox.max.x - currentBox.min.x, currentBox.max.y - currentBox.min.y);
|
|
80474
|
+
const worldSize = viewSizeToWorld(viewSize, containerSize, loadingItem.loadingVFXItem, cameraInfo, interactionPlane);
|
|
80475
|
+
if (worldPosition) {
|
|
80476
|
+
loadingItem.loadingVFXItem.transform.setPosition(worldPosition.x, worldPosition.y, 0);
|
|
80477
|
+
}
|
|
80478
|
+
loadingItem.loadingVFXItem.transform.setScale(worldSize.x, worldSize.y, 1);
|
|
80479
|
+
}
|
|
80480
|
+
/**
|
|
80481
|
+
* 创建加载覆盖层。
|
|
80482
|
+
* @param owner Gizmo 宿主。
|
|
80483
|
+
* @param manager 加载状态管理器。
|
|
80484
|
+
*/ constructor(owner, manager){
|
|
80485
|
+
super(owner), _define_property(this, "type", 'loading'), _define_property(this, "_configOff", void 0), _define_property(this, "_managerOff", void 0), _define_property(this, "_manager", void 0), _define_property(this, "_loadingBoxSize", new Vector2()), _define_property(this, "_idMap", new Map());
|
|
80486
|
+
this._manager = manager;
|
|
80487
|
+
this._configOff = owner.getConfigManager().onChange(loadingConfig, (change)=>{
|
|
80488
|
+
this._onConfigChange(change);
|
|
80489
|
+
});
|
|
80490
|
+
this._managerOff = this._manager.on('change', ()=>{
|
|
80491
|
+
this._syncManager();
|
|
80492
|
+
});
|
|
80493
|
+
this._syncManager();
|
|
80494
|
+
}
|
|
80495
|
+
}
|
|
80467
80496
|
/** 通过中键或抓手模式拖拽平移视口。 */ class HandGizmo extends Gizmo {
|
|
80468
80497
|
/** @returns 是否正在平移或等待空格拖拽。 */ isPanning() {
|
|
80469
80498
|
return this._dragType === "pan" || this._panKeyPressed;
|
|
@@ -83964,7 +83993,6 @@ const identityFrameItemIdAdapter = {
|
|
|
83964
83993
|
},
|
|
83965
83994
|
sceneBindings: []
|
|
83966
83995
|
};
|
|
83967
|
-
const [width, height] = size;
|
|
83968
83996
|
const composition = {
|
|
83969
83997
|
id: resolvedCompositionId,
|
|
83970
83998
|
name: name + '_inner',
|
|
@@ -83988,9 +84016,7 @@ const identityFrameItemIdAdapter = {
|
|
|
83988
84016
|
0,
|
|
83989
84017
|
0,
|
|
83990
84018
|
0
|
|
83991
|
-
]
|
|
83992
|
-
// @ts-expect-error: aspect 属性在 CameraOptions 上有定义但类型声明不完善
|
|
83993
|
-
aspect: width / height
|
|
84019
|
+
]
|
|
83994
84020
|
},
|
|
83995
84021
|
components: [
|
|
83996
84022
|
{
|
|
@@ -86944,8 +86970,9 @@ const identityFrameItemIdAdapter = {
|
|
|
86944
86970
|
if (width === undefined || height === undefined) {
|
|
86945
86971
|
return box;
|
|
86946
86972
|
}
|
|
86947
|
-
|
|
86948
|
-
const
|
|
86973
|
+
// 文本元素的scale不作为计算包围盒尺寸运算
|
|
86974
|
+
const sx = schema.type === ArtisItemType.TEXT ? 1 : scale?.[0] ?? 1;
|
|
86975
|
+
const sy = schema.type === ArtisItemType.TEXT ? 1 : scale?.[1] ?? 1;
|
|
86949
86976
|
const rot = Array.isArray(rotation) ? rotation[2] : rotation ?? 0;
|
|
86950
86977
|
rotateBox(box.setFromCenterAndSize(new Vector2(...position ?? [
|
|
86951
86978
|
0,
|
|
@@ -88434,6 +88461,7 @@ const identityFrameItemIdAdapter = {
|
|
|
88434
88461
|
...this._newTransform,
|
|
88435
88462
|
...other._newTransform
|
|
88436
88463
|
};
|
|
88464
|
+
this.eventPayload.propertyKeys = Object.keys(this._newTransform);
|
|
88437
88465
|
return true;
|
|
88438
88466
|
}
|
|
88439
88467
|
/**
|
|
@@ -88442,6 +88470,7 @@ const identityFrameItemIdAdapter = {
|
|
|
88442
88470
|
*/ constructor(args){
|
|
88443
88471
|
_define_property$1(this, "id", void 0);
|
|
88444
88472
|
_define_property$1(this, "commandId", 'item.transform');
|
|
88473
|
+
_define_property$1(this, "eventPayload", void 0);
|
|
88445
88474
|
_define_property$1(this, "_itemId", void 0);
|
|
88446
88475
|
_define_property$1(this, "_newTransform", void 0);
|
|
88447
88476
|
_define_property$1(this, "_oldTransform", void 0);
|
|
@@ -88452,6 +88481,10 @@ const identityFrameItemIdAdapter = {
|
|
|
88452
88481
|
this._newTransform = args.newTransform;
|
|
88453
88482
|
this._itemService = args.itemService;
|
|
88454
88483
|
this._store = args.store;
|
|
88484
|
+
this.eventPayload = {
|
|
88485
|
+
itemId: args.itemId,
|
|
88486
|
+
propertyKeys: Object.keys(args.newTransform)
|
|
88487
|
+
};
|
|
88455
88488
|
}
|
|
88456
88489
|
}
|
|
88457
88490
|
|
|
@@ -89346,6 +89379,7 @@ const DEFAULT_GROUP_POSITION = [
|
|
|
89346
89379
|
*/ constructor(args){
|
|
89347
89380
|
_define_property$1(this, "id", void 0);
|
|
89348
89381
|
_define_property$1(this, "commandId", 'item.updatePropertyBySchema');
|
|
89382
|
+
_define_property$1(this, "eventPayload", void 0);
|
|
89349
89383
|
_define_property$1(this, "completion", Promise.resolve());
|
|
89350
89384
|
_define_property$1(this, "_schemas", void 0);
|
|
89351
89385
|
_define_property$1(this, "_itemService", void 0);
|
|
@@ -89355,6 +89389,14 @@ const DEFAULT_GROUP_POSITION = [
|
|
|
89355
89389
|
args.schema
|
|
89356
89390
|
];
|
|
89357
89391
|
this._itemService = args.itemService;
|
|
89392
|
+
this.eventPayload = {
|
|
89393
|
+
propertyChanges: this._schemas.flatMap((schema)=>schema.id ? [
|
|
89394
|
+
{
|
|
89395
|
+
itemId: schema.id,
|
|
89396
|
+
propertyKeys: Object.keys(schema.property)
|
|
89397
|
+
}
|
|
89398
|
+
] : [])
|
|
89399
|
+
};
|
|
89358
89400
|
}
|
|
89359
89401
|
}
|
|
89360
89402
|
|
|
@@ -89401,6 +89443,7 @@ const DEFAULT_GROUP_POSITION = [
|
|
|
89401
89443
|
*/ constructor(args){
|
|
89402
89444
|
_define_property$1(this, "id", void 0);
|
|
89403
89445
|
_define_property$1(this, "commandId", 'item.setFontFamily');
|
|
89446
|
+
_define_property$1(this, "eventPayload", void 0);
|
|
89404
89447
|
_define_property$1(this, "completion", Promise.resolve());
|
|
89405
89448
|
_define_property$1(this, "_itemId", void 0);
|
|
89406
89449
|
_define_property$1(this, "_fontFamily", void 0);
|
|
@@ -89414,6 +89457,13 @@ const DEFAULT_GROUP_POSITION = [
|
|
|
89414
89457
|
this._fontFamily = args.fontFamily;
|
|
89415
89458
|
this._fontUrl = args.fontUrl;
|
|
89416
89459
|
this._itemService = args.itemService;
|
|
89460
|
+
this.eventPayload = {
|
|
89461
|
+
itemId: args.itemId,
|
|
89462
|
+
propertyKeys: [
|
|
89463
|
+
'fontFamily',
|
|
89464
|
+
'fontUrl'
|
|
89465
|
+
]
|
|
89466
|
+
};
|
|
89417
89467
|
}
|
|
89418
89468
|
}
|
|
89419
89469
|
|
|
@@ -90767,7 +90817,7 @@ const DEFAULT_GROUP_POSITION = [
|
|
|
90767
90817
|
}
|
|
90768
90818
|
}
|
|
90769
90819
|
|
|
90770
|
-
/** 提交图片裁切区域变化的可撤销命令。 */ class
|
|
90820
|
+
/** 提交图片裁切区域变化的可撤销命令。 */ class ImageCutCommitCommand {
|
|
90771
90821
|
/** 应用新的裁切包围盒 */ execute() {
|
|
90772
90822
|
this._applyBox(this._newBox);
|
|
90773
90823
|
}
|
|
@@ -90782,18 +90832,18 @@ const DEFAULT_GROUP_POSITION = [
|
|
|
90782
90832
|
* @param args 命令参数(含新旧裁切包围盒与 applyBox 回调)
|
|
90783
90833
|
*/ constructor(args){
|
|
90784
90834
|
_define_property$1(this, "id", void 0);
|
|
90785
|
-
_define_property$1(this, "commandId", '
|
|
90835
|
+
_define_property$1(this, "commandId", 'imageCut.commit');
|
|
90786
90836
|
_define_property$1(this, "_newBox", void 0);
|
|
90787
90837
|
_define_property$1(this, "_oldBox", void 0);
|
|
90788
90838
|
_define_property$1(this, "_applyBox", void 0);
|
|
90789
|
-
this.id = `
|
|
90839
|
+
this.id = `imageCut.commit_${Date.now()}`;
|
|
90790
90840
|
this._newBox = args.newBox;
|
|
90791
90841
|
this._oldBox = args.oldBox;
|
|
90792
90842
|
this._applyBox = args.applyBox;
|
|
90793
90843
|
}
|
|
90794
90844
|
}
|
|
90795
90845
|
|
|
90796
|
-
/** 提交图片扩边区域变化的可撤销命令。 */ class
|
|
90846
|
+
/** 提交图片扩边区域变化的可撤销命令。 */ class ImageExpandCommitCommand {
|
|
90797
90847
|
/** 应用新的扩图包围盒 */ execute() {
|
|
90798
90848
|
this._applyBox(this._newBox);
|
|
90799
90849
|
}
|
|
@@ -90808,11 +90858,11 @@ const DEFAULT_GROUP_POSITION = [
|
|
|
90808
90858
|
* @param args 命令参数(含新旧扩图包围盒与 applyBox 回调)
|
|
90809
90859
|
*/ constructor(args){
|
|
90810
90860
|
_define_property$1(this, "id", void 0);
|
|
90811
|
-
_define_property$1(this, "commandId", '
|
|
90861
|
+
_define_property$1(this, "commandId", 'imageExpand.commit');
|
|
90812
90862
|
_define_property$1(this, "_newBox", void 0);
|
|
90813
90863
|
_define_property$1(this, "_oldBox", void 0);
|
|
90814
90864
|
_define_property$1(this, "_applyBox", void 0);
|
|
90815
|
-
this.id = `
|
|
90865
|
+
this.id = `imageExpand.commit_${Date.now()}`;
|
|
90816
90866
|
this._newBox = args.newBox;
|
|
90817
90867
|
this._oldBox = args.oldBox;
|
|
90818
90868
|
this._applyBox = args.applyBox;
|
|
@@ -91040,13 +91090,29 @@ const DEFAULT_GROUP_POSITION = [
|
|
|
91040
91090
|
|
|
91041
91091
|
/** 按元素类型静默替换在线资源且不写入历史的命令。 */ class ItemReplaceSourceCommand {
|
|
91042
91092
|
/** 替换为新资源(async,execute 契约为 void,故 fire-and-forget) */ execute() {
|
|
91043
|
-
|
|
91093
|
+
this.completion = this._replaceSource(this._newUrl);
|
|
91044
91094
|
}
|
|
91045
91095
|
/** 回退为旧资源 */ undo() {
|
|
91046
|
-
|
|
91096
|
+
this.completion = this._replaceSource(this._oldUrl);
|
|
91047
91097
|
}
|
|
91048
91098
|
/** 重新应用新资源 */ redo() {
|
|
91049
|
-
|
|
91099
|
+
this.completion = this._replaceSource(this._newUrl);
|
|
91100
|
+
}
|
|
91101
|
+
/** 仅在资源实际替换成功时保留属性变化载荷。 */ async _replaceSource(url) {
|
|
91102
|
+
if (this._propertyKey) {
|
|
91103
|
+
this.eventPayload = {
|
|
91104
|
+
itemId: this._itemId,
|
|
91105
|
+
propertyKeys: [
|
|
91106
|
+
this._propertyKey
|
|
91107
|
+
]
|
|
91108
|
+
};
|
|
91109
|
+
}
|
|
91110
|
+
const changed = await this._itemService.replaceSourceSilent(this._itemId, url);
|
|
91111
|
+
if (!changed) {
|
|
91112
|
+
this.eventPayload = {
|
|
91113
|
+
propertyChanges: []
|
|
91114
|
+
};
|
|
91115
|
+
}
|
|
91050
91116
|
}
|
|
91051
91117
|
/** 将在线换源标记为不可重放,避免复现流程依赖外部资源时序。 */ serializeReplay() {
|
|
91052
91118
|
return {
|
|
@@ -91065,9 +91131,12 @@ const DEFAULT_GROUP_POSITION = [
|
|
|
91065
91131
|
_define_property$1(this, "commandId", 'item.replaceSource');
|
|
91066
91132
|
_define_property$1(this, "isHistorical", false);
|
|
91067
91133
|
_define_property$1(this, "params", void 0);
|
|
91134
|
+
_define_property$1(this, "eventPayload", void 0);
|
|
91135
|
+
_define_property$1(this, "completion", Promise.resolve());
|
|
91068
91136
|
_define_property$1(this, "_itemId", void 0);
|
|
91069
91137
|
_define_property$1(this, "_newUrl", void 0);
|
|
91070
91138
|
_define_property$1(this, "_oldUrl", void 0);
|
|
91139
|
+
_define_property$1(this, "_propertyKey", void 0);
|
|
91071
91140
|
_define_property$1(this, "_itemService", void 0);
|
|
91072
91141
|
_define_property$1(this, "_store", void 0);
|
|
91073
91142
|
this.id = `item.replaceSource_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
@@ -91082,12 +91151,15 @@ const DEFAULT_GROUP_POSITION = [
|
|
|
91082
91151
|
switch(item.type){
|
|
91083
91152
|
case ArtisItemType.SPRITE:
|
|
91084
91153
|
this._oldUrl = typeof prop?.image === 'string' ? prop.image : '';
|
|
91154
|
+
this._propertyKey = 'image';
|
|
91085
91155
|
break;
|
|
91086
91156
|
case ArtisItemType.VIDEO:
|
|
91087
91157
|
this._oldUrl = typeof prop?.video === 'string' ? prop.video : '';
|
|
91158
|
+
this._propertyKey = 'video';
|
|
91088
91159
|
break;
|
|
91089
91160
|
case ArtisItemType.EFFECTS:
|
|
91090
91161
|
this._oldUrl = typeof prop?.effects === 'string' ? prop.effects : '';
|
|
91162
|
+
this._propertyKey = 'effects';
|
|
91091
91163
|
break;
|
|
91092
91164
|
default:
|
|
91093
91165
|
this._oldUrl = '';
|
|
@@ -91095,6 +91167,14 @@ const DEFAULT_GROUP_POSITION = [
|
|
|
91095
91167
|
} else {
|
|
91096
91168
|
this._oldUrl = '';
|
|
91097
91169
|
}
|
|
91170
|
+
if (this._propertyKey) {
|
|
91171
|
+
this.eventPayload = {
|
|
91172
|
+
itemId: this._itemId,
|
|
91173
|
+
propertyKeys: [
|
|
91174
|
+
this._propertyKey
|
|
91175
|
+
]
|
|
91176
|
+
};
|
|
91177
|
+
}
|
|
91098
91178
|
this.params = {
|
|
91099
91179
|
itemId: this._itemId,
|
|
91100
91180
|
newUrl: this._newUrl,
|
|
@@ -91989,7 +92069,7 @@ function hasTransformItemIds(event) {
|
|
|
91989
92069
|
* @param context 提供当前 Selection、ID 翻译与像素框查询
|
|
91990
92070
|
* @param normalizeBox Gizmo 维护的归一化编辑框
|
|
91991
92071
|
* @returns 图片像素坐标系下的包围盒;输入无效时返回空盒
|
|
91992
|
-
*/ const
|
|
92072
|
+
*/ const getSelectedImagePixelBox = (context, normalizeBox)=>{
|
|
91993
92073
|
const selectedId = context.selection.getSelectedIds()[0];
|
|
91994
92074
|
if (!normalizeBox || selectedId === undefined) {
|
|
91995
92075
|
return new Box2();
|
|
@@ -92001,14 +92081,14 @@ function hasTransformItemIds(event) {
|
|
|
92001
92081
|
* 创建图片裁剪事件绑定,以每个 Gizmo 实例的旧框快照生成可撤销命令。
|
|
92002
92082
|
* @param context Command 绑定所需的 Artis 服务上下文
|
|
92003
92083
|
* @returns 图片裁剪生命周期事件处理器
|
|
92004
|
-
*/ const
|
|
92084
|
+
*/ const createImageCutCommandBinding = (context)=>{
|
|
92005
92085
|
const oldBoxBySource = new WeakMap();
|
|
92006
92086
|
/**
|
|
92007
92087
|
* 读取当前裁剪框并转换为可序列化快照。
|
|
92008
|
-
* @param
|
|
92088
|
+
* @param imageCutGizmo 要读取的裁剪 Gizmo
|
|
92009
92089
|
* @returns 归一化裁剪框;Gizmo 尚无框时返回 undefined
|
|
92010
|
-
*/ const snapshot = (
|
|
92011
|
-
const box =
|
|
92090
|
+
*/ const snapshot = (imageCutGizmo)=>{
|
|
92091
|
+
const box = imageCutGizmo.getCutBox();
|
|
92012
92092
|
if (!box) {
|
|
92013
92093
|
return undefined;
|
|
92014
92094
|
}
|
|
@@ -92021,10 +92101,10 @@ function hasTransformItemIds(event) {
|
|
|
92021
92101
|
};
|
|
92022
92102
|
/**
|
|
92023
92103
|
* 将归一化快照恢复为 Gizmo 使用的 Box2。
|
|
92024
|
-
* @param
|
|
92104
|
+
* @param imageCutGizmo 要恢复的裁剪 Gizmo
|
|
92025
92105
|
* @param box 命令保存的归一化裁剪框
|
|
92026
|
-
*/ const apply = (
|
|
92027
|
-
|
|
92106
|
+
*/ const apply = (imageCutGizmo, box)=>{
|
|
92107
|
+
imageCutGizmo.setCutBox(new Box2(new Vector2(box.x, box.y), new Vector2(box.x + box.width, box.y + box.height)));
|
|
92028
92108
|
};
|
|
92029
92109
|
return {
|
|
92030
92110
|
/**
|
|
@@ -92042,8 +92122,8 @@ function hasTransformItemIds(event) {
|
|
|
92042
92122
|
* @param event 图片裁剪 actionupdate 事件
|
|
92043
92123
|
*/ actionupdate: (event)=>{
|
|
92044
92124
|
const normalizeBox = event.source.getCutBox();
|
|
92045
|
-
context.emit('
|
|
92046
|
-
box:
|
|
92125
|
+
context.emit('image-cut.change', {
|
|
92126
|
+
box: getSelectedImagePixelBox(context, normalizeBox)
|
|
92047
92127
|
});
|
|
92048
92128
|
},
|
|
92049
92129
|
/**
|
|
@@ -92057,7 +92137,7 @@ function hasTransformItemIds(event) {
|
|
|
92057
92137
|
if (!oldBox || !newBox) {
|
|
92058
92138
|
return;
|
|
92059
92139
|
}
|
|
92060
|
-
context.commandService.record(new
|
|
92140
|
+
context.commandService.record(new ImageCutCommitCommand({
|
|
92061
92141
|
newBox,
|
|
92062
92142
|
oldBox,
|
|
92063
92143
|
/**
|
|
@@ -92074,14 +92154,14 @@ function hasTransformItemIds(event) {
|
|
|
92074
92154
|
* 创建图片扩边事件绑定,以每个 Gizmo 实例的旧框快照生成可撤销命令。
|
|
92075
92155
|
* @param context Command 绑定所需的 Artis 服务上下文
|
|
92076
92156
|
* @returns 图片扩边生命周期事件处理器
|
|
92077
|
-
*/ const
|
|
92157
|
+
*/ const createImageExpandCommandBinding = (context)=>{
|
|
92078
92158
|
const oldBoxBySource = new WeakMap();
|
|
92079
92159
|
/**
|
|
92080
92160
|
* 读取当前扩边框并转换为可序列化快照。
|
|
92081
|
-
* @param
|
|
92161
|
+
* @param imageExpandGizmo 要读取的扩边 Gizmo
|
|
92082
92162
|
* @returns 归一化扩边框;Gizmo 尚无框时返回 undefined
|
|
92083
|
-
*/ const snapshot = (
|
|
92084
|
-
const box =
|
|
92163
|
+
*/ const snapshot = (imageExpandGizmo)=>{
|
|
92164
|
+
const box = imageExpandGizmo.getExpandBox();
|
|
92085
92165
|
if (!box) {
|
|
92086
92166
|
return undefined;
|
|
92087
92167
|
}
|
|
@@ -92115,8 +92195,8 @@ function hasTransformItemIds(event) {
|
|
|
92115
92195
|
* @param event 图片扩边 actionupdate 事件
|
|
92116
92196
|
*/ actionupdate: (event)=>{
|
|
92117
92197
|
const normalizeBox = event.source.getExpandBox();
|
|
92118
|
-
context.emit('
|
|
92119
|
-
box:
|
|
92198
|
+
context.emit('image-expand.change', {
|
|
92199
|
+
box: getSelectedImagePixelBox(context, normalizeBox)
|
|
92120
92200
|
});
|
|
92121
92201
|
},
|
|
92122
92202
|
/**
|
|
@@ -92130,7 +92210,7 @@ function hasTransformItemIds(event) {
|
|
|
92130
92210
|
if (!oldBox || !newBox) {
|
|
92131
92211
|
return;
|
|
92132
92212
|
}
|
|
92133
|
-
context.commandService.record(new
|
|
92213
|
+
context.commandService.record(new ImageExpandCommitCommand({
|
|
92134
92214
|
newBox,
|
|
92135
92215
|
oldBox,
|
|
92136
92216
|
/**
|
|
@@ -92191,8 +92271,8 @@ const builtinCommandBindingFactories = {
|
|
|
92191
92271
|
[GizmoType.BOX_SELECTION]: registerSelectionGizmoCommandBinding,
|
|
92192
92272
|
'item-create': createItemCreateCommandBinding,
|
|
92193
92273
|
mask: createMaskCommandBinding,
|
|
92194
|
-
'
|
|
92195
|
-
'
|
|
92274
|
+
'image-cut': createImageCutCommandBinding,
|
|
92275
|
+
'image-expand': createImageExpandCommandBinding
|
|
92196
92276
|
};
|
|
92197
92277
|
/**
|
|
92198
92278
|
* 将全部内置 Gizmo 类型与对应的 Command 绑定工厂注册到 Binder。
|
|
@@ -92401,8 +92481,8 @@ var BuiltinGizmoId = /*#__PURE__*/ function(BuiltinGizmoId) {
|
|
|
92401
92481
|
BuiltinGizmoId["LOADING"] = "loading";
|
|
92402
92482
|
BuiltinGizmoId["VIEWPORT_OVERLAY"] = "viewport-overlay";
|
|
92403
92483
|
BuiltinGizmoId["READONLY_SELECTION"] = "readonly-selection";
|
|
92404
|
-
BuiltinGizmoId["
|
|
92405
|
-
BuiltinGizmoId["
|
|
92484
|
+
BuiltinGizmoId["IMAGE_CUT"] = "image-cut";
|
|
92485
|
+
BuiltinGizmoId["IMAGE_EXPAND"] = "image-expand";
|
|
92406
92486
|
BuiltinGizmoId["SPRITE_TEXT_EDIT"] = "sprite-text-edit";
|
|
92407
92487
|
BuiltinGizmoId["MASK"] = "mask";
|
|
92408
92488
|
BuiltinGizmoId["ITEM_CREATE"] = "item-create";
|
|
@@ -101936,13 +102016,13 @@ var OfficialStateId = /*#__PURE__*/ function(OfficialStateId) {
|
|
|
101936
102016
|
}
|
|
101937
102017
|
/** 表示编辑图片文字内容的状态。 */ class ImageTextEditState extends BaseState {
|
|
101938
102018
|
/** 创建隔离其他交互的图片文字编辑状态。 */ constructor(){
|
|
101939
|
-
super(OfficialStateId.IMAGE_TEXT_EDIT, '精准改字',
|
|
102019
|
+
super(OfficialStateId.IMAGE_TEXT_EDIT, '精准改字', SpriteTextEditGizmoTool);
|
|
101940
102020
|
this.isolated = true;
|
|
101941
102021
|
}
|
|
101942
102022
|
}
|
|
101943
102023
|
/** 表示编辑图片蒙版的状态。 */ class ImageMaskState extends BaseState {
|
|
101944
102024
|
/** 创建隔离其他交互的图片蒙版状态。 */ constructor(){
|
|
101945
|
-
super(OfficialStateId.IMAGE_MASK, '图片蒙版',
|
|
102025
|
+
super(OfficialStateId.IMAGE_MASK, '图片蒙版', MaskGizmoTool);
|
|
101946
102026
|
this.isolated = true;
|
|
101947
102027
|
}
|
|
101948
102028
|
}
|
|
@@ -123704,6 +123784,12 @@ const CARD_HTML_EVENT_MESSAGE_SOURCE = 'vvfx-card-html-event';
|
|
|
123704
123784
|
this.artis.leaveTextEditing();
|
|
123705
123785
|
}
|
|
123706
123786
|
/**
|
|
123787
|
+
* 选中当前 TextGizmo 正在编辑的全部文字,并聚焦文本输入框。
|
|
123788
|
+
* @returns TextGizmo 已就绪且存在正在编辑的文本时返回 true
|
|
123789
|
+
*/ selectAllText() {
|
|
123790
|
+
return this.artis.gizmoManager.get('text')?.selectAllText() ?? false;
|
|
123791
|
+
}
|
|
123792
|
+
/**
|
|
123707
123793
|
* 应用笔刷大小后开启蒙版 Gizmo;非法尺寸回退为 1。
|
|
123708
123794
|
* @param brushSize 初始笔刷像素大小
|
|
123709
123795
|
*/ openMaskGizmo(brushSize) {
|
|
@@ -123751,69 +123837,69 @@ const CARD_HTML_EVENT_MESSAGE_SOURCE = 'vvfx-card-html-event';
|
|
|
123751
123837
|
*/ closeLoadingGizmo(id) {
|
|
123752
123838
|
this.artis.gestureHandler.getLoadingManager().delete(this.artis.item.toVfxItemId(id));
|
|
123753
123839
|
}
|
|
123754
|
-
/** 开启图片裁切 Gizmo。 */
|
|
123840
|
+
/** 开启图片裁切 Gizmo。 */ openImageCutGizmo() {
|
|
123755
123841
|
this.artis.states.activate('imageCut');
|
|
123756
123842
|
}
|
|
123757
123843
|
/**
|
|
123758
123844
|
* 设置图片裁切 Gizmo 是否锁定裁切框比例。
|
|
123759
123845
|
* @param lock 是否锁定比例
|
|
123760
|
-
*/
|
|
123761
|
-
const
|
|
123762
|
-
if (!
|
|
123763
|
-
console.warn('[Artis.operations]
|
|
123846
|
+
*/ setImageCutGizmoLockScale(lock) {
|
|
123847
|
+
const imageCutGizmo = this.artis.gizmoManager.get('image-cut');
|
|
123848
|
+
if (!imageCutGizmo) {
|
|
123849
|
+
console.warn('[Artis.operations] setImageCutGizmoLockScale:image-cut Gizmo 未注册或未启用。');
|
|
123764
123850
|
return;
|
|
123765
123851
|
}
|
|
123766
|
-
|
|
123852
|
+
imageCutGizmo.isLockScale = lock;
|
|
123767
123853
|
}
|
|
123768
123854
|
/**
|
|
123769
|
-
* 获取当前裁切信息(归一化裁切框 + 元素视图框),委托
|
|
123855
|
+
* 获取当前裁切信息(归一化裁切框 + 元素视图框),委托 ImageCutGizmo.getCutInfo。
|
|
123770
123856
|
* @returns 裁切信息;Gizmo 未就绪 / 未选中单个元素 / 结果无效时返回 undefined
|
|
123771
123857
|
*/ getCutInfo() {
|
|
123772
|
-
return this.artis.gizmoManager.get('
|
|
123858
|
+
return this.artis.gizmoManager.get('image-cut')?.getCutInfo();
|
|
123773
123859
|
}
|
|
123774
123860
|
/**
|
|
123775
|
-
* 获取归一化裁切包围盒(min/max ∈ [0,1],相对元素包围盒),委托
|
|
123861
|
+
* 获取归一化裁切包围盒(min/max ∈ [0,1],相对元素包围盒),委托 ImageCutGizmo.getCutBox。
|
|
123776
123862
|
* @returns 归一化裁切框;Gizmo 未就绪时返回 undefined
|
|
123777
123863
|
*/ getCutBox() {
|
|
123778
|
-
return this.artis.gizmoManager.get('
|
|
123864
|
+
return this.artis.gizmoManager.get('image-cut')?.getCutBox();
|
|
123779
123865
|
}
|
|
123780
123866
|
/**
|
|
123781
|
-
* 设置归一化裁切包围盒(入参为归一化坐标),委托
|
|
123867
|
+
* 设置归一化裁切包围盒(入参为归一化坐标),委托 ImageCutGizmo.setCutBox。
|
|
123782
123868
|
* @param normalizeBox 归一化裁切框
|
|
123783
123869
|
*/ setCutBox(normalizeBox) {
|
|
123784
|
-
this.artis.gizmoManager.get('
|
|
123870
|
+
this.artis.gizmoManager.get('image-cut')?.setCutBox(normalizeBox);
|
|
123785
123871
|
}
|
|
123786
|
-
/** 关闭图片裁切 Gizmo。 */
|
|
123872
|
+
/** 关闭图片裁切 Gizmo。 */ closeImageCutGizmo() {
|
|
123787
123873
|
this.artis.states.activate('move');
|
|
123788
123874
|
}
|
|
123789
123875
|
/**
|
|
123790
123876
|
* 设置图片扩边 Gizmo 是否锁定扩边框比例。
|
|
123791
123877
|
* @param lock 是否锁定比例
|
|
123792
|
-
*/
|
|
123793
|
-
const
|
|
123794
|
-
if (!
|
|
123795
|
-
console.warn('[Artis.operations]
|
|
123878
|
+
*/ setImageExpandGizmoLockScale(lock) {
|
|
123879
|
+
const imageExpandGizmo = this.artis.gizmoManager.get('image-expand');
|
|
123880
|
+
if (!imageExpandGizmo) {
|
|
123881
|
+
console.warn('[Artis.operations] setImageExpandGizmoLockScale:image-expand Gizmo 未注册或未启用。');
|
|
123796
123882
|
return;
|
|
123797
123883
|
}
|
|
123798
|
-
|
|
123884
|
+
imageExpandGizmo.isLockScale = lock;
|
|
123799
123885
|
}
|
|
123800
123886
|
/**
|
|
123801
|
-
* 获取当前扩边信息(归一化扩边框 + 元素视图框),委托
|
|
123887
|
+
* 获取当前扩边信息(归一化扩边框 + 元素视图框),委托 ImageExpandGizmo.getExpandInfo。
|
|
123802
123888
|
* @returns 扩边信息;Gizmo 未就绪 / 未选中单个元素 / 结果无效时返回 undefined
|
|
123803
123889
|
*/ getExpandInfo() {
|
|
123804
|
-
return this.artis.gizmoManager.get('
|
|
123890
|
+
return this.artis.gizmoManager.get('image-expand')?.getExpandInfo();
|
|
123805
123891
|
}
|
|
123806
123892
|
/**
|
|
123807
|
-
* 获取归一化扩边包围盒(相对元素包围盒,可超出 [0,1]),委托
|
|
123893
|
+
* 获取归一化扩边包围盒(相对元素包围盒,可超出 [0,1]),委托 ImageExpandGizmo.getExpandBox。
|
|
123808
123894
|
* @returns 归一化扩边框;Gizmo 未就绪时返回 undefined
|
|
123809
123895
|
*/ getExpandBox() {
|
|
123810
|
-
return this.artis.gizmoManager.get('
|
|
123896
|
+
return this.artis.gizmoManager.get('image-expand')?.getExpandBox();
|
|
123811
123897
|
}
|
|
123812
123898
|
/**
|
|
123813
|
-
* 设置归一化扩边包围盒(入参为归一化坐标),委托
|
|
123899
|
+
* 设置归一化扩边包围盒(入参为归一化坐标),委托 ImageExpandGizmo.setExpandBox。
|
|
123814
123900
|
* @param normalizeBox 归一化扩边框
|
|
123815
123901
|
*/ setExpandBox(normalizeBox) {
|
|
123816
|
-
this.artis.gizmoManager.get('
|
|
123902
|
+
this.artis.gizmoManager.get('image-expand')?.setExpandBox(normalizeBox);
|
|
123817
123903
|
}
|
|
123818
123904
|
/**
|
|
123819
123905
|
* 绑定操作门面所属的 Artis 实例。
|
|
@@ -123898,8 +123984,8 @@ const CARD_HTML_EVENT_MESSAGE_SOURCE = 'vvfx-card-html-event';
|
|
|
123898
123984
|
createSelectionInteractionGizmo(owner)
|
|
123899
123985
|
];
|
|
123900
123986
|
});
|
|
123901
|
-
this.registry.register(BuiltinGizmoId.
|
|
123902
|
-
this.registry.register(BuiltinGizmoId.
|
|
123987
|
+
this.registry.register(BuiltinGizmoId.IMAGE_CUT, ({ owner })=>new ImageCutGizmo(owner));
|
|
123988
|
+
this.registry.register(BuiltinGizmoId.IMAGE_EXPAND, ({ owner })=>new ImageExpandGizmo(owner));
|
|
123903
123989
|
this.registry.register(BuiltinGizmoId.SPRITE_TEXT_EDIT, ({ owner })=>new SpriteTextEditGizmo(owner));
|
|
123904
123990
|
this.registry.register(BuiltinGizmoId.MASK, ({ owner })=>new MaskGizmo(owner));
|
|
123905
123991
|
this.registry.register(BuiltinGizmoId.ITEM_CREATE, ({ owner })=>{
|
|
@@ -124427,6 +124513,26 @@ const CARD_HTML_EVENT_MESSAGE_SOURCE = 'vvfx-card-html-event';
|
|
|
124427
124513
|
});
|
|
124428
124514
|
}
|
|
124429
124515
|
|
|
124516
|
+
/** 从 Command 的标准载荷中提取单个或批量属性变化。 */ function getItemPropertyChanges(payload) {
|
|
124517
|
+
const changes = Array.isArray(payload?.propertyChanges) ? payload.propertyChanges : [
|
|
124518
|
+
payload
|
|
124519
|
+
];
|
|
124520
|
+
return changes.flatMap((change)=>{
|
|
124521
|
+
if (!change || typeof change !== 'object') {
|
|
124522
|
+
return [];
|
|
124523
|
+
}
|
|
124524
|
+
const { itemId, propertyKeys, propertyKey } = change;
|
|
124525
|
+
const keys = Array.isArray(propertyKeys) ? propertyKeys.filter((key)=>typeof key === 'string') : typeof propertyKey === 'string' ? [
|
|
124526
|
+
propertyKey
|
|
124527
|
+
] : [];
|
|
124528
|
+
return typeof itemId === 'string' && keys.length > 0 ? [
|
|
124529
|
+
{
|
|
124530
|
+
itemId,
|
|
124531
|
+
propertyKeys: keys
|
|
124532
|
+
}
|
|
124533
|
+
] : [];
|
|
124534
|
+
});
|
|
124535
|
+
}
|
|
124430
124536
|
/**
|
|
124431
124537
|
* 注册内置 Command,并配置命令执行后、历史变化后的同步与事件转发。
|
|
124432
124538
|
* @param ctx 已完成核心服务装配的 wiring 上下文
|
|
@@ -124462,22 +124568,20 @@ const CARD_HTML_EVENT_MESSAGE_SOURCE = 'vvfx-card-html-event';
|
|
|
124462
124568
|
}
|
|
124463
124569
|
ctx.emit('history.change', operation);
|
|
124464
124570
|
});
|
|
124465
|
-
//
|
|
124571
|
+
// 任何提供标准属性载荷的命令,在实际投影完成后共用同一事件出口。
|
|
124466
124572
|
ctx.commandService.onCommandLifecycle(({ command, payload })=>{
|
|
124467
|
-
if (
|
|
124468
|
-
return;
|
|
124469
|
-
}
|
|
124470
|
-
const id = payload?.itemId;
|
|
124471
|
-
const propertyKeys = Array.isArray(payload?.propertyKeys) ? payload.propertyKeys.filter((key)=>typeof key === 'string') : typeof payload?.propertyKey === 'string' ? [
|
|
124472
|
-
payload.propertyKey
|
|
124473
|
-
] : [];
|
|
124474
|
-
if (typeof id !== 'string' || propertyKeys.length === 0) {
|
|
124573
|
+
if (getItemPropertyChanges(payload).length === 0) {
|
|
124475
124574
|
return;
|
|
124476
124575
|
}
|
|
124477
|
-
|
|
124478
|
-
|
|
124479
|
-
propertyKeys
|
|
124480
|
-
|
|
124576
|
+
void (command.completion ?? Promise.resolve()).then(()=>{
|
|
124577
|
+
const changes = getItemPropertyChanges(command.eventPayload ?? payload);
|
|
124578
|
+
for (const { itemId, propertyKeys } of changes){
|
|
124579
|
+
ctx.emit('item.propertychange', {
|
|
124580
|
+
id: itemId,
|
|
124581
|
+
propertyKeys
|
|
124582
|
+
});
|
|
124583
|
+
}
|
|
124584
|
+
}).catch(()=>undefined);
|
|
124481
124585
|
});
|
|
124482
124586
|
}
|
|
124483
124587
|
|
|
@@ -125695,8 +125799,8 @@ const BUILTIN_DEFS = [
|
|
|
125695
125799
|
this._emitBase('item.dragend', type);
|
|
125696
125800
|
break;
|
|
125697
125801
|
}
|
|
125698
|
-
case '
|
|
125699
|
-
case '
|
|
125802
|
+
case 'image-cut.change':
|
|
125803
|
+
case 'image-expand.change':
|
|
125700
125804
|
this._handleVariantGizmoEvent(event, args);
|
|
125701
125805
|
break;
|
|
125702
125806
|
default:
|
|
@@ -125983,9 +126087,9 @@ const BUILTIN_DEFS = [
|
|
|
125983
126087
|
* @param args 事件携带的参数列表
|
|
125984
126088
|
* @internal
|
|
125985
126089
|
*/ _handleVariantGizmoEvent(event, args) {
|
|
125986
|
-
if (event === '
|
|
126090
|
+
if (event === 'image-cut.change') {
|
|
125987
126091
|
this.emit(event, ...args);
|
|
125988
|
-
} else if (event === '
|
|
126092
|
+
} else if (event === 'image-expand.change') {
|
|
125989
126093
|
this.emit(event, ...args);
|
|
125990
126094
|
}
|
|
125991
126095
|
}
|
|
@@ -125995,11 +126099,11 @@ const BUILTIN_DEFS = [
|
|
|
125995
126099
|
* @internal
|
|
125996
126100
|
*/ _handleStateChange(event) {
|
|
125997
126101
|
const { previousState, currentState, source } = event;
|
|
125998
|
-
const
|
|
125999
|
-
const
|
|
126102
|
+
const isImageCut = currentState.id === OfficialStateId.IMAGE_CUT;
|
|
126103
|
+
const isImageExpand = currentState.id === OfficialStateId.IMAGE_EXPAND;
|
|
126000
126104
|
const isItemCreate = currentState.id === OfficialStateId.ITEM_CREATE;
|
|
126001
126105
|
let eventSource = source;
|
|
126002
|
-
if (
|
|
126106
|
+
if (isImageCut || isImageExpand) {
|
|
126003
126107
|
const selectedId = this.selection.getSelectedIds()[0];
|
|
126004
126108
|
eventSource = {
|
|
126005
126109
|
...source,
|
|
@@ -126821,5 +126925,5 @@ const BUILTIN_DEFS = [
|
|
|
126821
126925
|
'sprite.image'
|
|
126822
126926
|
]));
|
|
126823
126927
|
|
|
126824
|
-
export { Artis, ArtisItemType, AssetLoadState, AssetManager, AssetType, BackgroundController, BackgroundManager, BaseArtis, BaseItem, BaseState, Box2, BuiltinGizmoId, CardItem, Circle, CommandService, CompositeCommand, DEG2RAD, DuplicateComboError, DuplicateElementIdError, EffectsItem, ElementFacade, ElementRegistry, ElementRegistryErrorCode, ErrorMonitor, ErrorMonitorFacade, Euler, EulerOrder, FrameItem, FrameLayoutCommand, FrameLayoutMode, FrameLayoutModeCommand, FrameMoveInCommand, FrameMoveOutCommand, GeneratorItem, GeneratorType, GizmoBootstrap, GizmoCommandBinder, GizmoManager, GizmoRegistry, GlobalLayoutMode, GroupChildrenDetachCommand, GroupItem, HTMLCardService, HandState, HistoryManager, IOPlugin, IdentityStrategy, IgnoredInteractionError, ImageCutState, ImageExpandState, ImageMaskState, ImageTextEditState, InteractionService, ItemAlignCommand, ItemCreateCommand, ItemCreateState, ItemCreateType, ItemDeleteCommand, ItemDistributeCommand, ItemGroupCommand, ItemOrderAction, ItemReorderCommand, ItemReplaceSourceCommand, ItemService, ItemSetFontFamilyCommand, ItemSetGeneratorResourceCommand, ItemTransformCommand, ItemUngroupCommand, ItemUpdatePropertyBySchemaCommand, ItemUpdatePropertyCommand, JsonSceneSyncService, KeyBindingController, Line2, Line3, LocalStorageKeyBindingStore, MaskCommitCommand, Matrix4, MissingKeyBindingError, MoveState, OfficialStateId, Operations, PageAutoLayoutCommand, PerfMonitor, PerfMonitorFacade, PerfPhase,
|
|
126928
|
+
export { Artis, ArtisItemType, AssetLoadState, AssetManager, AssetType, BackgroundController, BackgroundManager, BaseArtis, BaseItem, BaseState, Box2, BuiltinGizmoId, CardItem, Circle, CommandService, CompositeCommand, DEG2RAD, DuplicateComboError, DuplicateElementIdError, EffectsItem, ElementFacade, ElementRegistry, ElementRegistryErrorCode, ErrorMonitor, ErrorMonitorFacade, Euler, EulerOrder, FrameItem, FrameLayoutCommand, FrameLayoutMode, FrameLayoutModeCommand, FrameMoveInCommand, FrameMoveOutCommand, GeneratorItem, GeneratorType, GizmoBootstrap, GizmoCommandBinder, GizmoManager, GizmoRegistry, GlobalLayoutMode, GroupChildrenDetachCommand, GroupItem, HTMLCardService, HandState, HistoryManager, IOPlugin, IdentityStrategy, IgnoredInteractionError, ImageCutCommitCommand, ImageCutState, ImageExpandCommitCommand, ImageExpandState, ImageMaskState, ImageTextEditState, InteractionService, ItemAlignCommand, ItemCreateCommand, ItemCreateState, ItemCreateType, ItemDeleteCommand, ItemDistributeCommand, ItemGroupCommand, ItemOrderAction, ItemReorderCommand, ItemReplaceSourceCommand, ItemService, ItemSetFontFamilyCommand, ItemSetGeneratorResourceCommand, ItemTransformCommand, ItemUngroupCommand, ItemUpdatePropertyBySchemaCommand, ItemUpdatePropertyCommand, JsonSceneSyncService, KeyBindingController, Line2, Line3, LocalStorageKeyBindingStore, MaskCommitCommand, Matrix4, MissingKeyBindingError, MoveState, OfficialStateId, Operations, PageAutoLayoutCommand, PerfMonitor, PerfMonitorFacade, PerfPhase, Plane, PlayerAdapter, PluginSystem, Quaternion, RAD2DEG, Ray, RayCaster, RegistryIdentityStrategy, Renderer, ReorderType, SafeConstraint, SceneArtis, SceneDataAssembler, SceneOperations, SceneStore, SceneSwitchCommand, ScreenShot, ScreenshotService, SelectionSetCommand, SpriteImageCommand, SpriteItem, SpriteTextEditCommitCommand, StabilityMonitor, StabilityMonitorFacade, StabilitySignal, StateHandCommand, StateImageCutCommand, StateImageExpandCommand, StateImageMaskCommand, StateImageTextEditCommand, StateItemCreateCommand, StateManager, StateMoveCommand, StateSwitchCommandBase, Store, TextItem, TextMoveCommand, TextRotateCommand, TextScaleCommand, TextUpdateContentCommand, TransformMoveCommand, TransformMoveWithFrameChangeCommand, TransformMoveWithLayoutCommand, TransformRotateCommand, TransformScaleCommand, UserPreferencesManager, Vector2, Vector3, VideoItem, VideoPlayCommand, VideoSourceCommand, ViewService, ViewportFitToBoxCommand, ViewportFitToItemsCommand, ViewportMoveCommand, ViewportZoomCommand, addCompositionItemByComposition, addItemInfoToScene, adjustOtherElementsLayoutInfo, applyGizmoConfigs, arrAdd, assertExist, asserts, autoLayout, boxCenter, boxSize, buildFrameLayoutInput, buildItemSchemaByCreateType, calculateDisplacement, calculateLayoutDisplacements, clamp, clearItemParentInfo, comboToString, computeAlignedPositions, computeDistributedPositions, createCameraProvider, createCompositionItemJSON, createDefaultStates, createExportableScene, createFrameCompositionScene, createItemTransformProvider, createKeyComboFromEvent, createMaskScene, createNullItemJSON, createSpriteItemJSON, createStatesByIds, createTextItemJSON, createVideoGeneratorItemJSON, createVideoItemJSON, createViewportProvider, deepClone, deepEquals, deleteCompositionFromScene, deleteCompositionItemFromScene, deleteItemInfoFromScene, downloadBlob, extractSubCompositionToScene, findPlayerItemByInstanceId, fixStandardJSON, generateGUID, getAbsMaxIndex, getAngleByVectors, getBasicScene, getBoxByNormalizeBox, getColorByNormalizeColor, getCompositionDataByRefCompositionItemId, getCompositionIdByRefCompositionItemId, getContainerSize, getItemTransformUnderParent, getNormalizeBoxByBoxes, getNormalizeColorByColor, getPixelBoxBySchema, getPixelBoxBySchemas, getTextureUrlById, getUniqueName, getVector2Angle, gizmoConfig, globalAutoLayout, imageCutConfig, imageExpandConfig, isBaseItem, isCardItem, isEffectsItem, isEqual, isEqual$1 as isEqualNumber, isFrameItem, isGeneratorItem, isGroupItem, isObj, isSpriteItem, isTextItem, isVideoItem, loadScriptAsync, localToWorldBox, logger, maskConfig, matchCombo, moveItemBetweenCompositions, moveItemOutOfFrame, moveItemToFrame, moveItemToRoot, parseCombo, registerCommands, removeItemInfoFromScene, resetSubCompositionItemId, resizeSelectionConfig, roundNumber, schemaToBoxMap, selectionPreviewConfig, serializeArtisItemToJSON, serializeReplayArgs, setItemJSONParentId, setJSONItemName, setupCommands, setupCoreEventBindings, setupKeyBindings, setupPlugins, setupSelectionBindings, index$1 as spec, transformBox, unionBoxes, updateItemLayoutInfo, viewportNavigationConfig, viewportOverlayConfig, worldToLocalBox };
|
|
126825
126929
|
//# sourceMappingURL=index.mjs.map
|