Files
aida_front/src/component/Canvas/CanvasEditor/commands/UpdateGroupMaskPositionCommand.js
2025-07-14 01:00:23 +08:00

245 lines
7.3 KiB
JavaScript

import { findLayerRecursively } from "../utils/layerHelper";
import { restoreFabricObject } from "../utils/objectHelper";
import { Command } from "./Command";
/**
* 更新组图层遮罩位置命令
* 当组图层的对象移动时,同步更新遮罩的位置
*/
export class UpdateGroupMaskPositionCommand extends Command {
constructor(options) {
super({
name: "更新组图层遮罩位置",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerManager = options.layerManager;
this.layerId = options.layerId;
this.deltaX = options.deltaX || 0;
this.deltaY = options.deltaY || 0;
this.maskInitialLeft = options.maskInitialLeft || 0;
this.maskInitialTop = options.maskInitialTop || 0;
this.isExecuteRealtime = options.isExecuteRealtime || false;
this.activeSelection = this.canvas.getActiveObject() || {};
this.isFristExecute = true;
// 查找目标图层
this.layer = findLayerRecursively(this.layers.value, this.layerId)?.layer;
if (!this.layer || !this.layer.clippingMask) {
console.warn(`图层 ${this.layerId} 不存在或没有遮罩`);
return false;
}
// 保存原始遮罩位置(用于撤销)
// 保存原始位置
this.originalMaskPosition = {
left: this.maskInitialLeft || 0,
top: this.maskInitialTop || 0,
};
// 收集当前选择的所有对象位置
this.originalObjectsPostion = this.activeSelection.getObjects().map((obj) => {
return {
left: obj.left || 0,
top: obj.top || 0,
id: obj.id,
};
});
this.originalSelectionPosition = {
left: this.activeSelection.left || 0,
top: this.activeSelection.top || 0,
};
console.log(
`🛠️ 初始化更新组图层遮罩位置命令: ${this.name}, 图层ID: ${this.layerId}, 初始位置: (${this.originalMaskPosition.left}, ${this.originalMaskPosition.top})`
);
this.newMaskPosition = null;
}
async execute() {
try {
// 计算新位置
const newLeft = this.maskInitialLeft + this.deltaX;
const newTop = this.maskInitialTop + this.deltaY;
// 更新遮罩位置
this.layer.clippingMask.left = newLeft;
this.layer.clippingMask.top = newTop;
this.newMaskPosition = {
left: newLeft,
top: newTop,
};
// 更新所有使用此遮罩的子图层对象
await this._updateChildObjectsClipPath(this.layer, false, true);
this.isFristExecute = false;
console.log(`✅ 组图层遮罩位置已更新: (${newLeft}, ${newTop})`);
return true;
} catch (error) {
console.error("更新组图层遮罩位置失败:", error);
return false;
}
}
async undo() {
try {
if (!this.originalMaskPosition) {
console.warn("没有原始遮罩位置数据,无法撤销");
return false;
}
// 查找目标图层
const layer = this.layers.value.find((l) => l.id === this.layerId);
if (!layer || !layer.clippingMask) {
console.warn(`图层 ${this.layerId} 不存在或没有遮罩`);
return false;
}
console.log(
`↶ 撤销更新组图层遮罩位置: ${this.originalMaskPosition.left}, 图层ID: ${this.originalMaskPosition.top}`
);
// 恢复原始位置
layer.clippingMask.left = this.originalMaskPosition.left;
layer.clippingMask.top = this.originalMaskPosition.top;
// 更新所有使用此遮罩的子图层对象
await this._updateChildObjectsClipPath(layer, true);
// await this.layerManager.updateLayersObjectsInteractivity();
// this.canvas.renderAll();
console.log(
`↶ 组图层遮罩位置已恢复: (${this.originalMaskPosition.left}, ${this.originalMaskPosition.top})`
);
return true;
} catch (error) {
console.error("撤销组图层遮罩位置更新失败:", error);
return false;
}
}
/**
* 实时执行(不记录到历史记录)
* 用于拖拽过程中的实时更新
*/
executeRealtime() {
try {
// 查找目标图层
const layer = this.layers.value.find((l) => l.id === this.layerId);
if (!layer || !layer.clippingMask) {
return false;
}
// 计算新位置
const newLeft = this.maskInitialLeft + this.deltaX;
const newTop = this.maskInitialTop + this.deltaY;
// 更新遮罩位置
layer.clippingMask.left = newLeft;
layer.clippingMask.top = newTop;
// 更新所有使用此遮罩的子图层对象(不需要等待)
this._updateChildObjectsClipPath(layer);
return true;
} catch (error) {
console.error("实时更新组图层遮罩位置失败:", error);
return false;
}
}
/**
* 更新子图层对象的裁剪路径
* @param {Object} layer 组图层对象
* @private
*/
async _updateChildObjectsClipPath(layer, isUndo = false, isExecute = false) {
if (!layer.children || layer.children.length === 0) {
return;
}
try {
// 重新创建遮罩对象
const clippingMaskFabricObject = await restoreFabricObject(layer.clippingMask, this.canvas);
if (!clippingMaskFabricObject) {
console.warn("无法恢复遮罩对象");
return;
}
clippingMaskFabricObject.clipPath = null;
clippingMaskFabricObject.set({
absolutePositioned: true,
});
clippingMaskFabricObject.dirty = true;
clippingMaskFabricObject.setCoords();
// 更新所有子图层对象的裁剪路径
layer.children.forEach((childLayer) => {
// 更新 fabricObjects 中的对象
childLayer.fabricObjects?.forEach((obj) => {
const fabricObject = this.canvas.getObjects().find((o) => o.id === obj.id);
if (fabricObject) {
fabricObject.clipPath = clippingMaskFabricObject;
fabricObject.dirty = true;
fabricObject.setCoords();
}
});
// 更新单个 fabricObject
if (childLayer.fabricObject) {
const fabricObject = this.canvas
.getObjects()
.find((o) => o.id === childLayer.fabricObject.id);
if (fabricObject) {
fabricObject.clipPath = clippingMaskFabricObject;
fabricObject.dirty = true;
fabricObject.setCoords();
}
}
});
if (isUndo) {
this.activeSelection.set({
left: this.originalSelectionPosition.left - this.deltaX,
top: this.originalSelectionPosition.top - this.deltaY,
});
this.activeSelection.dirty = true;
this.activeSelection.setCoords();
}
if (isExecute && !this.isFristExecute) {
this.activeSelection.set({
left: this.activeSelection.left + this.deltaX,
top: this.activeSelection.top + this.deltaY,
});
this.activeSelection.dirty = true;
this.activeSelection.setCoords();
}
// 触发画布重新渲染
this.canvas.renderAll();
} catch (error) {
console.error("更新子图层对象裁剪路径失败:", error);
}
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
deltaX: this.deltaX,
deltaY: this.deltaY,
originalPosition: this.originalMaskPosition,
newPosition: this.newMaskPosition,
};
}
}