@vvfx/sdk 0.2.2-alpha.1 → 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.1
6
+ * Version: v0.2.2-alpha.2
7
7
  */
8
8
 
9
9
  import * as EFFECTS from '@galacean/effects';
@@ -56584,6 +56584,10 @@ var cursorMap = {
56584
56584
  type: 'preset',
56585
56585
  content: 'crosshair'
56586
56586
  },
56587
+ 'box-select': {
56588
+ type: 'preset',
56589
+ content: 'crosshair'
56590
+ },
56587
56591
  'text-rotation': {
56588
56592
  type: 'svg',
56589
56593
  content: 'default',
@@ -60952,7 +60956,7 @@ var PageDataUtils = /*#__PURE__*/ function() {
60952
60956
  * @description 更新 PlayerItem 的 Property 属性
60953
60957
  */ _proto.updatePlayerItemPropertyAttribute = function updatePlayerItemPropertyAttribute(playerItem, targetItem, propertyName, propertyValue) {
60954
60958
  return _async_to_generator(function() {
60955
- 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;
60956
60960
  return _ts_generator(this, function(_state) {
60957
60961
  switch(_state.label){
60958
60962
  case 0:
@@ -61440,7 +61444,10 @@ var PageDataUtils = /*#__PURE__*/ function() {
61440
61444
  compositionItem.parentId = playerItem.getInstanceId();
61441
61445
  component = compositionItem.components[0];
61442
61446
  component == null ? void 0 : component.pause();
61447
+ // 刷新前快照视频播放态,刷新后恢复,避免更换特效导致全量视频被自动播放
61448
+ videoPlayStates = this.snapshotVideoPlayStates();
61443
61449
  this.sdk.player.gotoAndPlay(0);
61450
+ this.restoreVideoPlayStates(videoPlayStates);
61444
61451
  _state.label = 28;
61445
61452
  case 28:
61446
61453
  return [
@@ -61590,11 +61597,14 @@ var PageDataUtils = /*#__PURE__*/ function() {
61590
61597
  'size'
61591
61598
  ].includes(propertyName)) {
61592
61599
  time = this.sdk.pageData.time;
61600
+ // 刷新前快照视频播放态,刷新后恢复,避免设置属性导致全量视频被自动播放
61601
+ videoPlayStates1 = this.snapshotVideoPlayStates();
61593
61602
  if (SDK.config.mode === 'editor') {
61594
61603
  this.player.gotoAndPlay(time);
61595
61604
  } else {
61596
61605
  this.player.gotoAndStop(time);
61597
61606
  }
61607
+ this.restoreVideoPlayStates(videoPlayStates1);
61598
61608
  }
61599
61609
  return [
61600
61610
  2
@@ -65609,6 +65619,51 @@ var PageDataUtils = /*#__PURE__*/ function() {
65609
65619
  var result = box.clone().scale(scale, center).translate(translation);
65610
65620
  return result;
65611
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
+ };
65612
65667
  _proto.playVideoItem = function playVideoItem(id) {
65613
65668
  var playerItem = this.getPlayerItemById(id);
65614
65669
  if ((playerItem == null ? void 0 : playerItem.type) !== spec.ItemType.video) {
@@ -67174,7 +67229,7 @@ var PageDataUtils = /*#__PURE__*/ function() {
67174
67229
  };
67175
67230
  _proto.autoLayoutPage = function autoLayoutPage() {
67176
67231
  return _async_to_generator(function(param) {
67177
- 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;
67178
67233
  return _ts_generator(this, function(_state) {
67179
67234
  switch(_state.label){
67180
67235
  case 0:
@@ -67189,7 +67244,7 @@ var PageDataUtils = /*#__PURE__*/ function() {
67189
67244
  2
67190
67245
  ];
67191
67246
  }
67192
- _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;
67193
67248
  isPartialLayout = !!(ids == null ? void 0 : ids.length);
67194
67249
  // 1. 确定参与排布的顶层元素(过滤子元素)
67195
67250
  targetItems = pageData.items.filter(function(item) {
@@ -67218,7 +67273,7 @@ var PageDataUtils = /*#__PURE__*/ function() {
67218
67273
  // 4. 计算锚点偏移
67219
67274
  // - 选中元素排布:以原始包围盒左上角为锚点
67220
67275
  // - 全量排布:以视口中心为锚点
67221
- anchor = isPartialLayout ? this.getPartialLayoutAnchor(layoutElements, moveInfos.boundingBox) : this.getGlobalLayoutAnchor(moveInfos.boundingBox);
67276
+ anchor = isPartialLayout ? this.getPartialLayoutAnchor(layoutElements, moveInfos.boundingBox) : this.getGlobalLayoutAnchor(moveInfos.boundingBox, shift);
67222
67277
  _iterator = _create_for_of_iterator_helper_loose(moveInfos.items);
67223
67278
  _state.label = 1;
67224
67279
  case 1:
@@ -67261,7 +67316,7 @@ var PageDataUtils = /*#__PURE__*/ function() {
67261
67316
  if (focus) {
67262
67317
  this.setPageZoom(1, undefined, true);
67263
67318
  this.setPageMove(new Vector2());
67264
- this.viewportFit(undefined, moveInfos.boundingBox.translate(anchor));
67319
+ this.viewportFit(shift, moveInfos.boundingBox.translate(anchor));
67265
67320
  }
67266
67321
  return [
67267
67322
  2
@@ -67285,8 +67340,9 @@ var PageDataUtils = /*#__PURE__*/ function() {
67285
67340
  /**
67286
67341
  * @description 计算全量排布的锚点偏移:以视口中心为锚点
67287
67342
  * @param layoutBoundingBox 排布算法输出的包围盒
67288
- */ _proto.getGlobalLayoutAnchor = function getGlobalLayoutAnchor(layoutBoundingBox) {
67289
- 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);
67290
67346
  var boundCenter = layoutBoundingBox.getCenter();
67291
67347
  return new Vector2(viewCenter.x - boundCenter.x, viewCenter.y - boundCenter.y);
67292
67348
  };
@@ -68888,6 +68944,8 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
68888
68944
  */ _this.maskSprite = null, _this._config = {}, _this.boxGraphics = new Graphics(), _this.type = 'mask', _this.mode = 'paint', /**
68889
68945
  * 蒙版工具独立的撤销重做实例
68890
68946
  */ _this._undoRedo = new GizmoUndoRedo(), /**
68947
+ * 框选擦除进行中标记(按下到松开之间),用于实时选框描边的显示控制
68948
+ */ _this._isBoxErasing = false, /**
68891
68949
  * 鼠标状态绘制结果
68892
68950
  */ _this.cursorResult = {
68893
68951
  type: 'normal',
@@ -68904,10 +68962,22 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
68904
68962
  var _proto = MaskGizmo.prototype;
68905
68963
  /**
68906
68964
  * 设置模式
68907
- * @param mode 模式类型:'paint' 表示涂抹,'erase' 表示擦除
68965
+ * @param mode 模式类型:'paint' 笔刷涂抹、'erase' 笔刷逐笔擦除、'box-erase' 框选擦除、'box-paint' 框选涂抹
68908
68966
  */ _proto.setMode = function setMode(mode) {
68909
68967
  this.mode = mode;
68910
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
+ };
68911
68981
  _proto.initialize = function initialize() {};
68912
68982
  _proto.preparationAction = function preparationAction(event) {
68913
68983
  if (!this.interactive) {
@@ -68926,6 +68996,26 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
68926
68996
  };
68927
68997
  // 更新鼠标位置
68928
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
+ }
68929
69019
  // 开启新画笔
68930
69020
  this.result.lines.push({
68931
69021
  type: this.mode,
@@ -68935,32 +69025,61 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
68935
69025
  return this.type;
68936
69026
  };
68937
69027
  _proto.action = function action(event) {
68938
- var // 记录鼠标划线位置
68939
- _this_result_lines_;
68940
69028
  if (!this.interactive || this.result.status === 'init') {
68941
69029
  return;
68942
69030
  }
68943
69031
  // 更新鼠标位置
68944
69032
  var box = this.result.box;
68945
- 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));
68946
- (_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);
68947
69044
  };
68948
69045
  _proto.endAction = function endAction() {
68949
69046
  if (!this.interactive) {
68950
69047
  return undefined;
68951
69048
  }
68952
- // 记录操作到 undoRedo(仅当画线有实际点时才记录)
68953
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(仅当画线有实际点时才记录)
68954
69073
  if (this._oldLines && lastLine && lastLine.points.length > 0) {
68955
- var operation = {
69074
+ var operation1 = {
68956
69075
  type: 'update',
68957
69076
  oldData: this._oldLines,
68958
69077
  newData: {
68959
69078
  lines: JSON.parse(JSON.stringify(this.result.lines))
68960
69079
  }
68961
69080
  };
68962
- this._undoRedo.push(operation);
68963
- this._eventEmitter.emit('maskGizmoUndoRedoChange', operation);
69081
+ this._undoRedo.push(operation1);
69082
+ this._eventEmitter.emit('maskGizmoUndoRedoChange', operation1);
68964
69083
  } else if ((lastLine == null ? void 0 : lastLine.points.length) === 0) {
68965
69084
  // 如果没有实际绘制点,移除空的线条
68966
69085
  this.result.lines.pop();
@@ -69085,6 +69204,17 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
69085
69204
  this.boxGraphics.lineStyle(boxLineWidth, boxLineColor, boxLineAlpha);
69086
69205
  this.boxGraphics.drawBox(box);
69087
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
+ }
69088
69218
  // 1. 画线形(只用于遮罩,不直接显示
69089
69219
  for(var _iterator = _create_for_of_iterator_helper_loose(this.result.lines), _step; !(_step = _iterator()).done;){
69090
69220
  var line = _step.value;
@@ -69092,6 +69222,32 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
69092
69222
  continue;
69093
69223
  }
69094
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
+ }
69095
69251
  lineGraphics.blendMode = line.type === 'paint' ? BLEND_MODES.NORMAL : BLEND_MODES.DST_OUT;
69096
69252
  lineGraphics.lineStyle({
69097
69253
  width: line.brushSize * viewportParam.scale,
@@ -69135,14 +69291,24 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
69135
69291
  if (!point || !box) {
69136
69292
  return;
69137
69293
  }
69138
- if (point.x >= box.min.x && point.x <= box.max.x && point.y >= box.min.y && point.y <= box.max.y) {
69139
- 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') {
69140
69300
  this.cursorResult = {
69141
- type: 'circle',
69142
- angle: 0,
69143
- radius: this.config.brushSize * viewportParam.scale / 2
69301
+ type: 'box-select',
69302
+ angle: 0
69144
69303
  };
69304
+ return;
69145
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
+ };
69146
69312
  };
69147
69313
  _proto.close = function close() {
69148
69314
  this._config.maskImage = undefined;
@@ -69290,6 +69456,21 @@ var MaskGizmo = /*#__PURE__*/ function(Gizmo) {
69290
69456
  if (!line || line.points.length === 0) {
69291
69457
  continue;
69292
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
+ }
69293
69474
  ctx.lineWidth = line.brushSize * scale;
69294
69475
  ctx.lineCap = 'round';
69295
69476
  ctx.lineJoin = 'round';
@@ -71295,7 +71476,8 @@ var GestureHandler = /*#__PURE__*/ function() {
71295
71476
  'active-hand',
71296
71477
  'pointer',
71297
71478
  'text-create',
71298
- 'frame-create'
71479
+ 'frame-create',
71480
+ 'box-select'
71299
71481
  ].includes(result.type)) {
71300
71482
  var cursor = cursorMap[result.type];
71301
71483
  if (cursor.type === 'svg') {
@@ -71467,6 +71649,7 @@ var GestureHandler = /*#__PURE__*/ function() {
71467
71649
  return;
71468
71650
  }
71469
71651
  this.maskGizmo.setMode(mode);
71652
+ this.render();
71470
71653
  };
71471
71654
  _proto.openLoadingGizmo = function openLoadingGizmo(id, options) {
71472
71655
  var _this__emitter;
@@ -94761,7 +94944,7 @@ var SDK = /*#__PURE__*/ function() {
94761
94944
  };
94762
94945
  /**
94763
94946
  * @description 设置蒙版工具模式
94764
- * @param mode 模式类型:'paint' 表示涂抹,'erase' 表示擦除
94947
+ * @param mode 模式类型:'paint' 笔刷涂抹、'erase' 笔刷逐笔擦除、'box-erase' 框选擦除、'box-paint' 框选涂抹
94765
94948
  */ _proto.setMaskGizmoMode = function setMaskGizmoMode(mode) {
94766
94949
  this._gestureHandler.setMaskGizmoMode(mode);
94767
94950
  };