245 lines
7.3 KiB
JavaScript
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,
|
|
};
|
|
}
|
|
}
|