@vvfx/sdk 0.2.2-alpha.0 → 0.2.2-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.
@@ -28,7 +28,7 @@ export declare class MaskGizmo extends Gizmo {
28
28
  private _config;
29
29
  private boxGraphics;
30
30
  type: GizmoType;
31
- mode: 'paint' | 'erase';
31
+ mode: 'paint' | 'erase' | 'box-erase' | 'box-paint';
32
32
  /**
33
33
  * 蒙版工具独立的撤销重做实例
34
34
  */
@@ -37,6 +37,10 @@ export declare class MaskGizmo extends Gizmo {
37
37
  * 存储绘画开始前的数据,用于 undoRedo
38
38
  */
39
39
  private _oldLines;
40
+ /**
41
+ * 框选擦除进行中标记(按下到松开之间),用于实时选框描边的显示控制
42
+ */
43
+ private _isBoxErasing;
40
44
  /**
41
45
  * 鼠标状态绘制结果
42
46
  */
@@ -52,9 +56,17 @@ export declare class MaskGizmo extends Gizmo {
52
56
  set config(config: Partial<MaskGizmoConfig>);
53
57
  /**
54
58
  * 设置模式
55
- * @param mode 模式类型:'paint' 表示涂抹,'erase' 表示擦除
59
+ * @param mode 模式类型:'paint' 笔刷涂抹、'erase' 笔刷逐笔擦除、'box-erase' 框选擦除、'box-paint' 框选涂抹
60
+ */
61
+ setMode(mode: 'paint' | 'erase' | 'box-erase' | 'box-paint'): void;
62
+ /**
63
+ * @description 判断点是否在包围盒内
64
+ */
65
+ private _isPointInBox;
66
+ /**
67
+ * @description 将屏幕坐标转换为包围盒内的归一化坐标 [0,1](钳制在范围内)
56
68
  */
57
- setMode(mode: 'paint' | 'erase'): void;
69
+ private _toNormalized;
58
70
  initialize(): void;
59
71
  preparationAction(event: MouseEvent): GizmoType | undefined;
60
72
  preAction(event: MouseEvent): GizmoType | undefined;
@@ -85,6 +85,10 @@ export type MaskResult = {
85
85
  brushSize: number;
86
86
  points: Vector2[];
87
87
  type?: 'paint' | 'erase';
88
+ /**
89
+ * @description 形状类型:'stroke' 折线(默认),'rect' 矩形框选(points=[起点, 终点])
90
+ */
91
+ shape?: 'stroke' | 'rect';
88
92
  }[];
89
93
  };
90
94
  /**
@@ -396,7 +400,7 @@ export type InsertPosition = {
396
400
  siblingId?: string;
397
401
  };
398
402
  export type GizmoType = 'null' | 'selector' | 'transform' | 'control' | 'adsorption' | 'preference' | 'picture-cut' | 'text' | 'mask' | 'loading' | 'picture-expand' | 'sprite-text-edit' | 'icon' | 'item-create';
399
- export type GestureCursorType = 'normal' | 'rotation' | 'scale' | 'text-rotation' | 'circle' | 'hand' | 'active-hand' | 'pointer' | 'text-create' | 'frame-create';
403
+ export type GestureCursorType = 'normal' | 'rotation' | 'scale' | 'text-rotation' | 'circle' | 'hand' | 'active-hand' | 'pointer' | 'text-create' | 'frame-create' | 'box-select';
400
404
  export type TransformType = 'null' | 'translation' | 'rotation' | 'scale';
401
405
  export type GestureHandlerInteractType = 'select' | 'hand';
402
406
  export type ControlGizmoInteractionType = 'mouse' | 'wheel';
@@ -107,7 +107,7 @@ export declare class GestureHandler {
107
107
  closeMaskGizmo(): void;
108
108
  setMaskGizmoConfig(config: Partial<MaskGizmoConfig>): void;
109
109
  getMask(): string | null | undefined;
110
- setMaskGizmoMode(mode: 'paint' | 'erase'): void;
110
+ setMaskGizmoMode(mode: 'paint' | 'erase' | 'box-erase' | 'box-paint'): void;
111
111
  openLoadingGizmo(id: string, options?: {
112
112
  loadingBox?: Box2;
113
113
  clearSelected?: boolean;
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * Description: TODO
4
4
  * Author: Ant Group CO., Ltd.
5
5
  * Contributors: 赤芍,何即,不择,意绮
6
- * Version: v0.2.2-alpha.0
6
+ * Version: v0.2.2-alpha.2
7
7
  */
8
8
 
9
9
  import * as EFFECTS from '@galacean/effects';
@@ -24013,9 +24013,21 @@ function getUniqueName(name, names) {
24013
24013
  };
24014
24014
  _create_class(TextItem, [
24015
24015
  {
24016
- key: "text",
24016
+ key: "pixelWidth",
24017
24017
  get: // ==================== 便捷访问器 ====================
24018
- /**
24018
+ function get() {
24019
+ return this.width;
24020
+ }
24021
+ },
24022
+ {
24023
+ key: "pixelHeight",
24024
+ get: function get() {
24025
+ return this.height;
24026
+ }
24027
+ },
24028
+ {
24029
+ key: "text",
24030
+ get: /**
24019
24031
  * @description 文本内容
24020
24032
  */ function get() {
24021
24033
  return this.property.text;
@@ -56572,6 +56584,10 @@ var cursorMap = {
56572
56584
  type: 'preset',
56573
56585
  content: 'crosshair'
56574
56586
  },
56587
+ 'box-select': {
56588
+ type: 'preset',
56589
+ content: 'crosshair'
56590
+ },
56575
56591
  'text-rotation': {
56576
56592
  type: 'svg',
56577
56593
  content: 'default',
@@ -60940,7 +60956,7 @@ var PageDataUtils = /*#__PURE__*/ function() {
60940
60956
  * @description 更新 PlayerItem 的 Property 属性
60941
60957
  */ _proto.updatePlayerItemPropertyAttribute = function updatePlayerItemPropertyAttribute(playerItem, targetItem, propertyName, propertyValue) {
60942
60958
  return _async_to_generator(function() {
60943
- var _this, _playerItem_getComponent, _playerItem_getComponent1, color, _array_, array, family, textComponent, textComponent1, lineCount, textHeight, _playerItem_getComponent2, textComponent2, textHeight1, textComponent3, outlineColor, textComponent4, textComponent5, textComponent6, originFontSize, lineCount1, textHeight2, textComponent7, textHeight3, viewSize, worldSizeX, originSize, originChildBoxes, originBox, worldScaleX, originScale, originWidth, currentWidth, ratio, originScale1, textComponent8, originChildBoxes1, originBox1, worldScaleY, originScale2, originHeight, currentHeight, ratio1, originScale3, viewSize1, worldSizeY, originSize1, textComponent9, textHeight4, _playerItem_getComponent3, _, _playerItem_getComponent4, _1, _propertyValue_compositions_find, _ref, subCompositionItem, compositionId, mainComposition, effectsSize, viewSize2, worldSize, compositionItem, component, videoComponent, videoComponent1, videoComponent2, pixelTranslation, viewTranslation, translation, rotation, currentScale, scaleRatio, frameComponent, _SDK_config_itemConfig_frameConfig, freeLayoutBackgroundColor, autoLayoutBackgroundColor, color1, childrenItem, time;
60959
+ var _this, _playerItem_getComponent, _playerItem_getComponent1, color, _array_, array, family, textComponent, textComponent1, lineCount, textHeight, _playerItem_getComponent2, textComponent2, textHeight1, textComponent3, outlineColor, textComponent4, textComponent5, textComponent6, originFontSize, lineCount1, textHeight2, textComponent7, textHeight3, viewSize, worldSizeX, originSize, originChildBoxes, originBox, worldScaleX, originScale, originWidth, currentWidth, ratio, originScale1, textComponent8, originChildBoxes1, originBox1, worldScaleY, originScale2, originHeight, currentHeight, ratio1, originScale3, viewSize1, worldSizeY, originSize1, textComponent9, textHeight4, _playerItem_getComponent3, _, _playerItem_getComponent4, _1, _propertyValue_compositions_find, _ref, subCompositionItem, compositionId, mainComposition, effectsSize, viewSize2, worldSize, compositionItem, component, videoPlayStates, videoComponent, videoComponent1, videoComponent2, pixelTranslation, viewTranslation, translation, rotation, currentScale, scaleRatio, frameComponent, _SDK_config_itemConfig_frameConfig, freeLayoutBackgroundColor, autoLayoutBackgroundColor, color1, childrenItem, time, videoPlayStates1;
60944
60960
  return _ts_generator(this, function(_state) {
60945
60961
  switch(_state.label){
60946
60962
  case 0:
@@ -61428,7 +61444,10 @@ var PageDataUtils = /*#__PURE__*/ function() {
61428
61444
  compositionItem.parentId = playerItem.getInstanceId();
61429
61445
  component = compositionItem.components[0];
61430
61446
  component == null ? void 0 : component.pause();
61447
+ // 刷新前快照视频播放态,刷新后恢复,避免更换特效导致全量视频被自动播放
61448
+ videoPlayStates = this.snapshotVideoPlayStates();
61431
61449
  this.sdk.player.gotoAndPlay(0);
61450
+ this.restoreVideoPlayStates(videoPlayStates);
61432
61451
  _state.label = 28;
61433
61452
  case 28:
61434
61453
  return [
@@ -61578,11 +61597,14 @@ var PageDataUtils = /*#__PURE__*/ function() {
61578
61597
  'size'
61579
61598
  ].includes(propertyName)) {
61580
61599
  time = this.sdk.pageData.time;
61600
+ // 刷新前快照视频播放态,刷新后恢复,避免设置属性导致全量视频被自动播放
61601
+ videoPlayStates1 = this.snapshotVideoPlayStates();
61581
61602
  if (SDK.config.mode === 'editor') {
61582
61603
  this.player.gotoAndPlay(time);
61583
61604
  } else {
61584
61605
  this.player.gotoAndStop(time);
61585
61606
  }
61607
+ this.restoreVideoPlayStates(videoPlayStates1);
61586
61608
  }
61587
61609
  return [
61588
61610
  2
@@ -64560,7 +64582,7 @@ var PageDataUtils = /*#__PURE__*/ function() {
64560
64582
  };
64561
64583
  addTextItemIntoNewScene = function addTextItemIntoNewScene(textCreateInfo, sceneSize, itemViewPosition) {
64562
64584
  var _scene_fonts;
64563
- var _textCreateInfo_id = textCreateInfo.id, id = _textCreateInfo_id === void 0 ? generateGUID() : _textCreateInfo_id, _textCreateInfo_name = textCreateInfo.name, name = _textCreateInfo_name === void 0 ? '文本' : _textCreateInfo_name, _textCreateInfo_property = textCreateInfo.property, lineHeight = _textCreateInfo_property.lineHeight, textWidth = _textCreateInfo_property.width, tmp = _textCreateInfo_property.height, textHeight = tmp === void 0 ? lineHeight : tmp, fontFamily = _textCreateInfo_property.fontFamily, fontSize = _textCreateInfo_property.fontSize, _textCreateInfo_property_fontWeight = _textCreateInfo_property.fontWeight, fontWeight = _textCreateInfo_property_fontWeight === void 0 ? spec.TextWeight.normal : _textCreateInfo_property_fontWeight, _textCreateInfo_property_fontStyle = _textCreateInfo_property.fontStyle, fontStyle = _textCreateInfo_property_fontStyle === void 0 ? spec.FontStyle.normal : _textCreateInfo_property_fontStyle, _textCreateInfo_property_textAlign = _textCreateInfo_property.textAlign, textAlign = _textCreateInfo_property_textAlign === void 0 ? spec.TextAlignment.left : _textCreateInfo_property_textAlign, text = _textCreateInfo_property.text, textColor = _textCreateInfo_property.color, tmp1 = _textCreateInfo_property.rotation, sourceRotation = tmp1 === void 0 ? 0 : tmp1, url = _textCreateInfo_property.fontUrl, outlineColor = _textCreateInfo_property.outlineColor, outlineWidth = _textCreateInfo_property.outlineWidth, outlineEnabled = _textCreateInfo_property.outlineEnabled;
64585
+ var _textCreateInfo_id = textCreateInfo.id, id = _textCreateInfo_id === void 0 ? generateGUID() : _textCreateInfo_id, _textCreateInfo_name = textCreateInfo.name, name = _textCreateInfo_name === void 0 ? '文本' : _textCreateInfo_name, _textCreateInfo_property = textCreateInfo.property, lineHeight = _textCreateInfo_property.lineHeight, textWidth = _textCreateInfo_property.width, tmp = _textCreateInfo_property.height, textHeight = tmp === void 0 ? lineHeight : tmp, fontFamily = _textCreateInfo_property.fontFamily, fontSize = _textCreateInfo_property.fontSize, _textCreateInfo_property_fontWeight = _textCreateInfo_property.fontWeight, fontWeight = _textCreateInfo_property_fontWeight === void 0 ? spec.TextWeight.normal : _textCreateInfo_property_fontWeight, _textCreateInfo_property_fontStyle = _textCreateInfo_property.fontStyle, fontStyle = _textCreateInfo_property_fontStyle === void 0 ? spec.FontStyle.normal : _textCreateInfo_property_fontStyle, _textCreateInfo_property_textAlign = _textCreateInfo_property.textAlign, textAlign = _textCreateInfo_property_textAlign === void 0 ? spec.TextAlignment.left : _textCreateInfo_property_textAlign, text = _textCreateInfo_property.text, textColor = _textCreateInfo_property.color, tmp1 = _textCreateInfo_property.rotation, sourceRotation = tmp1 === void 0 ? 0 : tmp1, url = _textCreateInfo_property.fontUrl, outlineColor = _textCreateInfo_property.outlineColor, outlineWidth = _textCreateInfo_property.outlineWidth, outlineEnabled = _textCreateInfo_property.outlineEnabled, letterSpacing = _textCreateInfo_property.letterSpacing;
64564
64586
  var rotation = Array.isArray(sourceRotation) ? [].concat(sourceRotation) : [
64565
64587
  0,
64566
64588
  0,
@@ -64590,7 +64612,7 @@ var PageDataUtils = /*#__PURE__*/ function() {
64590
64612
  fontSize: fontSize,
64591
64613
  textColor: resutlTextColor,
64592
64614
  fontWeight: fontWeight,
64593
- letterSpace: 0,
64615
+ letterSpace: letterSpacing,
64594
64616
  textAlign: textAlign,
64595
64617
  fontStyle: fontStyle,
64596
64618
  textWidth: textWidth,
@@ -65597,6 +65619,51 @@ var PageDataUtils = /*#__PURE__*/ function() {
65597
65619
  var result = box.clone().scale(scale, center).translate(translation);
65598
65620
  return result;
65599
65621
  };
65622
+ /**
65623
+ * @description 快照当前所有视频元素的播放状态(播放/暂停 + 当前播放进度),用于属性刷新后恢复,
65624
+ * 避免设置属性导致全量视频被自动播放或进度被重置回 0s
65625
+ */ _proto.snapshotVideoPlayStates = function snapshotVideoPlayStates() {
65626
+ var states = new Map();
65627
+ var composition = this.getCurrentComposition();
65628
+ for(var _iterator = _create_for_of_iterator_helper_loose(composition.items), _step; !(_step = _iterator()).done;){
65629
+ var item = _step.value;
65630
+ if (item.type === spec.ItemType.video) {
65631
+ var videoComponent = item.getComponent(VideoComponent);
65632
+ if (!videoComponent) {
65633
+ continue;
65634
+ }
65635
+ //@ts-expect-error @赤芍 played 字段未在类型中声明,参见 rebuildCompositionItems 处用法
65636
+ var played = !!videoComponent.played;
65637
+ var time = videoComponent.getCurrentTime();
65638
+ states.set(item.getInstanceId(), {
65639
+ played: played,
65640
+ time: time
65641
+ });
65642
+ }
65643
+ }
65644
+ return states;
65645
+ };
65646
+ /**
65647
+ * @description 按快照恢复视频元素的播放状态(先 pause 再 seek,最后按原状态 play/pause,避免进度抖动)
65648
+ */ _proto.restoreVideoPlayStates = function restoreVideoPlayStates(states) {
65649
+ for(var _iterator = _create_for_of_iterator_helper_loose(states), _step; !(_step = _iterator()).done;){
65650
+ var _step_value = _step.value, id = _step_value[0], _step_value_ = _step_value[1], played = _step_value_.played, time = _step_value_.time;
65651
+ var playerItem = this.getPlayerItemById(id);
65652
+ if ((playerItem == null ? void 0 : playerItem.type) !== spec.ItemType.video) {
65653
+ continue;
65654
+ }
65655
+ var videoComponent = playerItem.getComponent(VideoComponent);
65656
+ if (!videoComponent) {
65657
+ continue;
65658
+ }
65659
+ // 先暂停再 seek,避免播放状态下 seek 导致画面抖动
65660
+ videoComponent.pauseVideo();
65661
+ videoComponent.setCurrentTime(time);
65662
+ if (played) {
65663
+ videoComponent.playVideo();
65664
+ }
65665
+ }
65666
+ };
65600
65667
  _proto.playVideoItem = function playVideoItem(id) {
65601
65668
  var playerItem = this.getPlayerItemById(id);
65602
65669
  if ((playerItem == null ? void 0 : playerItem.type) !== spec.ItemType.video) {
@@ -67162,7 +67229,7 @@ var PageDataUtils = /*#__PURE__*/ function() {
67162
67229
  };
67163
67230
  _proto.autoLayoutPage = function autoLayoutPage() {
67164
67231
  return _async_to_generator(function(param) {
67165
- var _this, pageData, _param_mode, mode, ids, _param_focus, focus, _param_gap, gap, isPartialLayout, targetItems, layoutElements, moveInfos, anchor, _iterator, _step, moveInfo, sdkItem;
67232
+ var _this, pageData, _param_mode, mode, ids, _param_focus, focus, _param_gap, gap, shift, isPartialLayout, targetItems, layoutElements, moveInfos, anchor, _iterator, _step, moveInfo, sdkItem;
67166
67233
  return _ts_generator(this, function(_state) {
67167
67234
  switch(_state.label){
67168
67235
  case 0:
@@ -67177,7 +67244,7 @@ var PageDataUtils = /*#__PURE__*/ function() {
67177
67244
  2
67178
67245
  ];
67179
67246
  }
67180
- _param_mode = param.mode, mode = _param_mode === void 0 ? SDK.config.pageConfig.autoLayoutDefaultMode : _param_mode, ids = param.ids, _param_focus = param.focus, focus = _param_focus === void 0 ? true : _param_focus, _param_gap = param.gap, gap = _param_gap === void 0 ? SDK.config.pageConfig.autoLayoutDefaultGap : _param_gap;
67247
+ _param_mode = param.mode, mode = _param_mode === void 0 ? SDK.config.pageConfig.autoLayoutDefaultMode : _param_mode, ids = param.ids, _param_focus = param.focus, focus = _param_focus === void 0 ? true : _param_focus, _param_gap = param.gap, gap = _param_gap === void 0 ? SDK.config.pageConfig.autoLayoutDefaultGap : _param_gap, shift = param.shift;
67181
67248
  isPartialLayout = !!(ids == null ? void 0 : ids.length);
67182
67249
  // 1. 确定参与排布的顶层元素(过滤子元素)
67183
67250
  targetItems = pageData.items.filter(function(item) {
@@ -67206,7 +67273,7 @@ var PageDataUtils = /*#__PURE__*/ function() {
67206
67273
  // 4. 计算锚点偏移
67207
67274
  // - 选中元素排布:以原始包围盒左上角为锚点
67208
67275
  // - 全量排布:以视口中心为锚点
67209
- anchor = isPartialLayout ? this.getPartialLayoutAnchor(layoutElements, moveInfos.boundingBox) : this.getGlobalLayoutAnchor(moveInfos.boundingBox);
67276
+ anchor = isPartialLayout ? this.getPartialLayoutAnchor(layoutElements, moveInfos.boundingBox) : this.getGlobalLayoutAnchor(moveInfos.boundingBox, shift);
67210
67277
  _iterator = _create_for_of_iterator_helper_loose(moveInfos.items);
67211
67278
  _state.label = 1;
67212
67279
  case 1:
@@ -67249,7 +67316,7 @@ var PageDataUtils = /*#__PURE__*/ function() {
67249
67316
  if (focus) {
67250
67317
  this.setPageZoom(1, undefined, true);
67251
67318
  this.setPageMove(new Vector2());
67252
- this.viewportFit(undefined, moveInfos.boundingBox.translate(anchor));
67319
+ this.viewportFit(shift, moveInfos.boundingBox.translate(anchor));
67253
67320
  }
67254
67321
  return [
67255
67322
  2
@@ -67273,8 +67340,9 @@ var PageDataUtils = /*#__PURE__*/ function() {
67273
67340
  /**
67274
67341
  * @description 计算全量排布的锚点偏移:以视口中心为锚点
67275
67342
  * @param layoutBoundingBox 排布算法输出的包围盒
67276
- */ _proto.getGlobalLayoutAnchor = function getGlobalLayoutAnchor(layoutBoundingBox) {
67277
- var viewCenter = new Vector2(this.sdk._container.offsetWidth / 2, this.sdk._container.offsetHeight / 2);
67343
+ */ _proto.getGlobalLayoutAnchor = function getGlobalLayoutAnchor(layoutBoundingBox, shift) {
67344
+ var _ref = shift != null ? shift : {}, _ref_top = _ref.top, top = _ref_top === void 0 ? 0 : _ref_top, _ref_bottom = _ref.bottom, bottom = _ref_bottom === void 0 ? 0 : _ref_bottom, _ref_left = _ref.left, left = _ref_left === void 0 ? 0 : _ref_left, _ref_right = _ref.right, right = _ref_right === void 0 ? 0 : _ref_right;
67345
+ var viewCenter = new Vector2(this.sdk._container.offsetWidth / 2 + left - right, this.sdk._container.offsetHeight / 2 + top - bottom);
67278
67346
  var boundCenter = layoutBoundingBox.getCenter();
67279
67347
  return new Vector2(viewCenter.x - boundCenter.x, viewCenter.y - boundCenter.y);
67280
67348
  };
@@ -68876,6 +68944,8 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
68876
68944
  */ _this.maskSprite = null, _this._config = {}, _this.boxGraphics = new Graphics(), _this.type = 'mask', _this.mode = 'paint', /**
68877
68945
  * 蒙版工具独立的撤销重做实例
68878
68946
  */ _this._undoRedo = new GizmoUndoRedo(), /**
68947
+ * 框选擦除进行中标记(按下到松开之间),用于实时选框描边的显示控制
68948
+ */ _this._isBoxErasing = false, /**
68879
68949
  * 鼠标状态绘制结果
68880
68950
  */ _this.cursorResult = {
68881
68951
  type: 'normal',
@@ -68892,10 +68962,22 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
68892
68962
  var _proto = MaskGizmo.prototype;
68893
68963
  /**
68894
68964
  * 设置模式
68895
- * @param mode 模式类型:'paint' 表示涂抹,'erase' 表示擦除
68965
+ * @param mode 模式类型:'paint' 笔刷涂抹、'erase' 笔刷逐笔擦除、'box-erase' 框选擦除、'box-paint' 框选涂抹
68896
68966
  */ _proto.setMode = function setMode(mode) {
68897
68967
  this.mode = mode;
68898
68968
  };
68969
+ /**
68970
+ * @description 判断点是否在包围盒内
68971
+ */ _proto._isPointInBox = function _isPointInBox(p, box) {
68972
+ return p.x >= box.min.x && p.x <= box.max.x && p.y >= box.min.y && p.y <= box.max.y;
68973
+ };
68974
+ /**
68975
+ * @description 将屏幕坐标转换为包围盒内的归一化坐标 [0,1](钳制在范围内)
68976
+ */ _proto._toNormalized = function _toNormalized(p, box) {
68977
+ var x = Math.max(0, Math.min(1, (p.x - box.min.x) / (box.max.x - box.min.x)));
68978
+ var y = Math.max(0, Math.min(1, (p.y - box.min.y) / (box.max.y - box.min.y)));
68979
+ return new Vector2(x, y);
68980
+ };
68899
68981
  _proto.initialize = function initialize() {};
68900
68982
  _proto.preparationAction = function preparationAction(event) {
68901
68983
  if (!this.interactive) {
@@ -68914,6 +68996,26 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
68914
68996
  };
68915
68997
  // 更新鼠标位置
68916
68998
  this.result.point = new Vector2(event.offsetX, event.offsetY);
68999
+ // 框选模式(框选擦除 / 框选涂抹):仅在元素包围盒内按下才触发
69000
+ if (this.mode === 'box-erase' || this.mode === 'box-paint') {
69001
+ var box = this.result.box;
69002
+ if (!box || !this._isPointInBox(this.result.point, box)) {
69003
+ // 包围盒外按下:不触发框选,交由其它 gizmo
69004
+ return undefined;
69005
+ }
69006
+ var start = this._toNormalized(this.result.point, box);
69007
+ this.result.lines.push({
69008
+ type: this.mode === 'box-paint' ? 'paint' : 'erase',
69009
+ shape: 'rect',
69010
+ brushSize: 0,
69011
+ points: [
69012
+ start,
69013
+ start.clone()
69014
+ ]
69015
+ });
69016
+ this._isBoxErasing = true;
69017
+ return this.type;
69018
+ }
68917
69019
  // 开启新画笔
68918
69020
  this.result.lines.push({
68919
69021
  type: this.mode,
@@ -68923,32 +69025,61 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
68923
69025
  return this.type;
68924
69026
  };
68925
69027
  _proto.action = function action(event) {
68926
- var // 记录鼠标划线位置
68927
- _this_result_lines_;
68928
69028
  if (!this.interactive || this.result.status === 'init') {
68929
69029
  return;
68930
69030
  }
68931
69031
  // 更新鼠标位置
68932
69032
  var box = this.result.box;
68933
- var point = new Vector2((event.offsetX - box.min.x) / (box.max.x - box.min.x), (event.offsetY - box.min.y) / (box.max.y - box.min.y));
68934
- (_this_result_lines_ = this.result.lines[this.result.lines.length - 1]) == null ? void 0 : _this_result_lines_.points.push(point);
69033
+ var point = new Vector2(event.offsetX, event.offsetY);
69034
+ this.result.point = point;
69035
+ var lastLine = this.result.lines[this.result.lines.length - 1];
69036
+ // 框选擦除:更新框选终点(钳制到包围盒内)
69037
+ if ((lastLine == null ? void 0 : lastLine.shape) === 'rect') {
69038
+ lastLine.points[1] = this._toNormalized(point, box);
69039
+ return;
69040
+ }
69041
+ // 记录鼠标划线位置(笔刷模式)
69042
+ var np = new Vector2((event.offsetX - box.min.x) / (box.max.x - box.min.x), (event.offsetY - box.min.y) / (box.max.y - box.min.y));
69043
+ lastLine == null ? void 0 : lastLine.points.push(np);
68935
69044
  };
68936
69045
  _proto.endAction = function endAction() {
68937
69046
  if (!this.interactive) {
68938
69047
  return undefined;
68939
69048
  }
68940
- // 记录操作到 undoRedo(仅当画线有实际点时才记录)
68941
69049
  var lastLine = this.result.lines[this.result.lines.length - 1];
69050
+ // 框选擦除:起点==终点视为空框选,移除;否则提交 undoRedo
69051
+ if ((lastLine == null ? void 0 : lastLine.shape) === 'rect') {
69052
+ this._isBoxErasing = false;
69053
+ var _lastLine_points = lastLine.points, a = _lastLine_points[0], b = _lastLine_points[1];
69054
+ var isEmpty = !!a && !!b && a.x === b.x && a.y === b.y;
69055
+ if (this._oldLines && !isEmpty) {
69056
+ var operation = {
69057
+ type: 'update',
69058
+ oldData: this._oldLines,
69059
+ newData: {
69060
+ lines: JSON.parse(JSON.stringify(this.result.lines))
69061
+ }
69062
+ };
69063
+ this._undoRedo.push(operation);
69064
+ this._eventEmitter.emit('maskGizmoUndoRedoChange', operation);
69065
+ } else {
69066
+ // 空框选移除
69067
+ this.result.lines.pop();
69068
+ }
69069
+ this._oldLines = undefined;
69070
+ return this.type;
69071
+ }
69072
+ // 记录操作到 undoRedo(仅当画线有实际点时才记录)
68942
69073
  if (this._oldLines && lastLine && lastLine.points.length > 0) {
68943
- var operation = {
69074
+ var operation1 = {
68944
69075
  type: 'update',
68945
69076
  oldData: this._oldLines,
68946
69077
  newData: {
68947
69078
  lines: JSON.parse(JSON.stringify(this.result.lines))
68948
69079
  }
68949
69080
  };
68950
- this._undoRedo.push(operation);
68951
- this._eventEmitter.emit('maskGizmoUndoRedoChange', operation);
69081
+ this._undoRedo.push(operation1);
69082
+ this._eventEmitter.emit('maskGizmoUndoRedoChange', operation1);
68952
69083
  } else if ((lastLine == null ? void 0 : lastLine.points.length) === 0) {
68953
69084
  // 如果没有实际绘制点,移除空的线条
68954
69085
  this.result.lines.pop();
@@ -69073,6 +69204,17 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
69073
69204
  this.boxGraphics.lineStyle(boxLineWidth, boxLineColor, boxLineAlpha);
69074
69205
  this.boxGraphics.drawBox(box);
69075
69206
  this.boxGraphics.endFill();
69207
+ // 框选擦除进行中:叠加当前拖动矩形的可视描边
69208
+ var lastLine = this.result.lines[this.result.lines.length - 1];
69209
+ if (this._isBoxErasing && (lastLine == null ? void 0 : lastLine.shape) === 'rect' && lastLine.points.length >= 2) {
69210
+ var _lastLine_points = lastLine.points, a = _lastLine_points[0], b = _lastLine_points[1];
69211
+ if (a && b) {
69212
+ var selBox = new Box2(new Vector2(box.min.x + Math.min(a.x, b.x) * (box.max.x - box.min.x), box.min.y + Math.min(a.y, b.y) * (box.max.y - box.min.y)), new Vector2(box.min.x + Math.max(a.x, b.x) * (box.max.x - box.min.x), box.min.y + Math.max(a.y, b.y) * (box.max.y - box.min.y)));
69213
+ this.boxGraphics.lineStyle(boxLineWidth, boxLineColor, boxLineAlpha);
69214
+ this.boxGraphics.drawBox(selBox);
69215
+ this.boxGraphics.endFill();
69216
+ }
69217
+ }
69076
69218
  // 1. 画线形(只用于遮罩,不直接显示
69077
69219
  for(var _iterator = _create_for_of_iterator_helper_loose(this.result.lines), _step; !(_step = _iterator()).done;){
69078
69220
  var line = _step.value;
@@ -69080,6 +69222,32 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
69080
69222
  continue;
69081
69223
  }
69082
69224
  var lineGraphics = new Graphics();
69225
+ // 矩形框选:填充矩形,paint 用 NORMAL 叠加,erase 用 DST_OUT 抠除
69226
+ if (line.shape === 'rect') {
69227
+ var a1 = line.points[0];
69228
+ var b1 = line.points[1];
69229
+ if (a1 && b1) {
69230
+ var w = box.max.x - box.min.x;
69231
+ var h = box.max.y - box.min.y;
69232
+ var x0 = Math.min(a1.x, b1.x) * w;
69233
+ var y0 = Math.min(a1.y, b1.y) * h;
69234
+ var x1 = Math.max(a1.x, b1.x) * w;
69235
+ var y1 = Math.max(a1.y, b1.y) * h;
69236
+ // 太小(纯点击)不渲染,避免 1px 擦除/涂抹点
69237
+ if (x1 - x0 > 0.5 || y1 - y0 > 0.5) {
69238
+ lineGraphics.beginFill(brushColor);
69239
+ lineGraphics.drawRect(x0, y0, x1 - x0, y1 - y0);
69240
+ lineGraphics.endFill();
69241
+ lineGraphics.blendMode = line.type === 'paint' ? BLEND_MODES.NORMAL : BLEND_MODES.DST_OUT;
69242
+ this._app.renderer.render(lineGraphics, {
69243
+ renderTexture: this.maskRenderTexture,
69244
+ clear: false
69245
+ });
69246
+ }
69247
+ }
69248
+ lineGraphics.destroy();
69249
+ continue;
69250
+ }
69083
69251
  lineGraphics.blendMode = line.type === 'paint' ? BLEND_MODES.NORMAL : BLEND_MODES.DST_OUT;
69084
69252
  lineGraphics.lineStyle({
69085
69253
  width: line.brushSize * viewportParam.scale,
@@ -69123,14 +69291,24 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
69123
69291
  if (!point || !box) {
69124
69292
  return;
69125
69293
  }
69126
- if (point.x >= box.min.x && point.x <= box.max.x && point.y >= box.min.y && point.y <= box.max.y) {
69127
- var viewportParam = this._pageDataUtils.interactionUtils.viewportParam;
69294
+ var inside = point.x >= box.min.x && point.x <= box.max.x && point.y >= box.min.y && point.y <= box.max.y;
69295
+ if (!inside) {
69296
+ return;
69297
+ }
69298
+ // 框选模式(框选擦除 / 框选涂抹):crosshair
69299
+ if (this.mode === 'box-erase' || this.mode === 'box-paint') {
69128
69300
  this.cursorResult = {
69129
- type: 'circle',
69130
- angle: 0,
69131
- radius: this.config.brushSize * viewportParam.scale / 2
69301
+ type: 'box-select',
69302
+ angle: 0
69132
69303
  };
69304
+ return;
69133
69305
  }
69306
+ var viewportParam = this._pageDataUtils.interactionUtils.viewportParam;
69307
+ this.cursorResult = {
69308
+ type: 'circle',
69309
+ angle: 0,
69310
+ radius: this.config.brushSize * viewportParam.scale / 2
69311
+ };
69134
69312
  };
69135
69313
  _proto.close = function close() {
69136
69314
  this._config.maskImage = undefined;
@@ -69278,6 +69456,21 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
69278
69456
  if (!line || line.points.length === 0) {
69279
69457
  continue;
69280
69458
  }
69459
+ // 矩形框选:填充矩形
69460
+ if (line.shape === 'rect') {
69461
+ var _line_points = line.points, a = _line_points[0], b1 = _line_points[1];
69462
+ if (!a || !b1) {
69463
+ continue;
69464
+ }
69465
+ var x0 = Math.min(a.x, b1.x) * width;
69466
+ var y0 = Math.min(a.y, b1.y) * height;
69467
+ var x1 = Math.max(a.x, b1.x) * width;
69468
+ var y1 = Math.max(a.y, b1.y) * height;
69469
+ ctx.globalCompositeOperation = 'source-over';
69470
+ ctx.fillStyle = line.type === 'paint' ? maskHexColor : maskBackgroundHexColor;
69471
+ ctx.fillRect(x0, y0, Math.max(1, x1 - x0), Math.max(1, y1 - y0));
69472
+ continue;
69473
+ }
69281
69474
  ctx.lineWidth = line.brushSize * scale;
69282
69475
  ctx.lineCap = 'round';
69283
69476
  ctx.lineJoin = 'round';
@@ -71283,7 +71476,8 @@ var GestureHandler = /*#__PURE__*/ function() {
71283
71476
  'active-hand',
71284
71477
  'pointer',
71285
71478
  'text-create',
71286
- 'frame-create'
71479
+ 'frame-create',
71480
+ 'box-select'
71287
71481
  ].includes(result.type)) {
71288
71482
  var cursor = cursorMap[result.type];
71289
71483
  if (cursor.type === 'svg') {
@@ -71455,6 +71649,7 @@ var GestureHandler = /*#__PURE__*/ function() {
71455
71649
  return;
71456
71650
  }
71457
71651
  this.maskGizmo.setMode(mode);
71652
+ this.render();
71458
71653
  };
71459
71654
  _proto.openLoadingGizmo = function openLoadingGizmo(id, options) {
71460
71655
  var _this__emitter;
@@ -94749,7 +94944,7 @@ var SDK = /*#__PURE__*/ function() {
94749
94944
  };
94750
94945
  /**
94751
94946
  * @description 设置蒙版工具模式
94752
- * @param mode 模式类型:'paint' 表示涂抹,'erase' 表示擦除
94947
+ * @param mode 模式类型:'paint' 笔刷涂抹、'erase' 笔刷逐笔擦除、'box-erase' 框选擦除、'box-paint' 框选涂抹
94753
94948
  */ _proto.setMaskGizmoMode = function setMaskGizmoMode(mode) {
94754
94949
  this._gestureHandler.setMaskGizmoMode(mode);
94755
94950
  };