Files
aida_front/src/component/Canvas/CanvasEditor/commands/LayerCommands.js
2026-01-19 16:57:11 +08:00

4542 lines
123 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Command } from "./Command";
import {
createLayer,
findLayerRecursively,
LayerType,
OperationType,
} from "../utils/layerHelper";
import { createStaticCanvas } from "../utils/canvasFactory";
import { AddObjectToLayerCommand } from "./ObjectLayerCommands";
import { ToolCommand } from "./ToolCommands";
import {
findObjectById,
findObjectByLayerId,
generateId,
getObjectZIndex,
insertObjectAtZIndex,
objectIsInCanvas,
optimizeCanvasRendering,
removeCanvasObjectByObject,
} from "../utils/helper";
import { fabric } from "fabric-with-all";
import { restoreFabricObject } from "../utils/objectHelper";
import EventManager from "../utils/event.js";
/**
* 添加图层命令
*/
export class AddLayerCommand extends Command {
constructor(options) {
super({
name: "添加图层",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.newLayer = options.newLayer;
this.activeLayerId = options.activeLayerId;
this.insertIndex = options.insertIndex;
this.oldActiveLayerId = null;
this.beforeLayers = JSON.stringify(this.layers.value); // 备份原图层列表
this.options = options.options || {};
}
execute() {
// 保存当前活动图层ID
this.oldActiveLayerId = this.activeLayerId.value;
// 执行添加顶级图层操作
if (this.options?.insertTop) {
this.layers.value.splice(0, 0, this.newLayer);
this.activeLayerId.value = this.newLayer.id;
return this.newLayer.id;
}
// 智能插入图层到合适位置
this._insertLayerAtCorrectPosition(this.newLayer);
// if (this.insertIndex !== undefined && this.insertIndex !== null) {
// this.layers.value.splice(this.insertIndex, 0, this.newLayer);
// } else {
// this.layers.value.push(this.newLayer);
// }
// // 更新活动图层
if (!this.newLayer.isBackground) {
this.activeLayerId.value = this.newLayer.id;
}
return this.newLayer.id;
}
undo() {
// 从图层列表删除该图层
this.layers.value = JSON.parse(this.beforeLayers);
// 恢复原活动图层
this.activeLayerId.value = this.oldActiveLayerId;
}
/**
* 智能插入图层到正确位置
* 根据当前激活图层位置确定新图层插入位置
* @param {Object} newLayer 要插入的新图层
* @private
*/
_insertLayerAtCorrectPosition(newLayer) {
const layers = this.layers.value;
const currentActiveLayerId = this.activeLayerId?.value;
// 如果没有当前激活图层插入到顶部索引0
if (!currentActiveLayerId) {
layers.splice(0, 0, newLayer);
return;
}
// 查找当前激活图层的位置
const {
layer: activeLayer,
parent: parentLayer,
index: activeIndex,
} = this._findLayerPosition(currentActiveLayerId);
if (!activeLayer) {
// 没找到激活图层,插入到顶部
layers.splice(0, 0, newLayer);
return;
}
// 确定插入位置
let insertIndex = 0;
if (parentLayer) {
// 当前激活图层是子图层
// 在同一父图层内,插入到激活子图层之上
insertIndex = Math.max(0, activeIndex);
parentLayer.children = parentLayer.children || [];
parentLayer.children.splice(insertIndex, 0, newLayer);
console.log(
`新图层已插入到子图层位置: ${insertIndex} (父图层: ${parentLayer.name})`
);
} else {
// 当前激活图层是一级图层
// 在一级图层中,插入到激活图层之上
const activeLayerIndex = layers.findIndex(
(layer) => layer.id === currentActiveLayerId
);
insertIndex = Math.max(0, activeLayerIndex);
layers.splice(insertIndex, 0, newLayer);
console.log(`新图层已插入到一级图层位置: ${insertIndex}`);
}
}
/**
* 查找图层位置信息
* @param {String} layerId 图层ID
* @returns {Object} 包含图层、父图层和索引的对象
* @private
*/
_findLayerPosition(layerId) {
const layers = this.layers.value;
// 先在一级图层中查找
for (let i = 0; i < layers.length; i++) {
const layer = layers[i];
if (layer.isPrintTrimsGroup) continue;
if (layer.id === layerId) {
return {
layer: layer,
parent: null,
index: i,
};
}
// 在子图层中查找
if (layer.children && Array.isArray(layer.children)) {
for (let j = 0; j < layer.children.length; j++) {
const childLayer = layer.children[j];
if (childLayer.id === layerId) {
return {
layer: childLayer,
parent: layer,
index: j,
};
}
}
}
}
return {
layer: null,
parent: null,
index: -1,
};
}
getInfo() {
return {
name: this.name,
layerName: this.newLayer.name,
layerId: this.newLayer.id,
};
}
}
/**
* 粘贴并创建图层命令 - 更新为支持异步操作
*/
export class PasteLayerCommand extends Command {
constructor(options) {
super({
name: "粘贴图层",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.activeLayerId = options.activeLayerId;
this.clipboardData = options.clipboardData;
this.layerManager = options.layerManager;
this.newLayer = null;
this.newLayerId = generateId("layer_");
this.insertIndex = null;
this.oldActiveLayerId = null;
this.createdObjects = [];
this.isGroupLayer = false;
this.childLayerIdMap = new Map();
}
async execute() {
if (!this.clipboardData) {
console.error("剪贴板中没有图层数据");
return null;
}
const data = JSON.parse(JSON.stringify(this.clipboardData));
// 判断是否为组图层
this.isGroupLayer = data.type === "group" || !!data?.children?.length;
// 保存当前活动图层ID
this.oldActiveLayerId = this.activeLayerId.value;
// 计算插入位置
this.insertIndex = this.layerManager._getInsertIndexAboveActiveLayer();
if (this.isGroupLayer) {
// 粘贴为新的组图层递归生成子图层ID
const { groupLayer, allObjects } =
await this._createGroupLayerFromClipboard(data);
if (groupLayer?.clippingMask) {
// 给遮罩蒙层也添加上偏移
groupLayer.clippingMask.left += 30;
groupLayer.clippingMask.top += 30;
if (groupLayer.selectObject) {
// 如果有选区 则选区位置也要更新
groupLayer.selectObject.left = groupLayer.clippingMask.left;
groupLayer.selectObject.top = groupLayer.clippingMask.top;
}
}
this.newLayer = groupLayer;
this.newLayer.id = this.newLayerId;
// 插入组图层
if (this.insertIndex !== undefined && this.insertIndex !== null) {
this.layers.value.splice(this.insertIndex, 0, this.newLayer);
} else {
this.layers.value.push(this.newLayer);
}
// 重新创建遮罩对象
const clippingMaskFabricObject =
(await restoreFabricObject(groupLayer?.clippingMask, this.canvas)) ||
null;
// clippingMaskFabricObject.clipPath = null;
clippingMaskFabricObject.set({
absolutePositioned: true,
});
// clippingMaskFabricObject.dirty = true;
clippingMaskFabricObject.setCoords();
// 添加所有对象到画布
allObjects.forEach((obj) => {
obj.clipPath = clippingMaskFabricObject;
obj.dirty = true;
obj.setCoords();
this.canvas.add(obj);
});
this.createdObjects = allObjects;
// 设置活动图层为新组图层
this.activeLayerId.value = this.newLayer.id;
} else {
// 普通图层粘贴逻辑
this.newLayer = {
...data,
id: this.newLayerId,
name: `${data.name} 副本`,
fabricObjects: [],
isCut: undefined,
serializedObjects: undefined,
};
if (this.insertIndex !== undefined && this.insertIndex !== null) {
this.layers.value.splice(this.insertIndex, 0, this.newLayer);
} else {
this.layers.value.push(this.newLayer);
}
if (!this.newLayer.isBackground) {
this.activeLayerId.value = this.newLayer.id;
}
if (
data.serializedObjects &&
Array.isArray(data.serializedObjects) &&
data.serializedObjects.length > 0
) {
await this._restoreObjectsAsync(data);
} else {
this._onObjectsRestored(data);
}
}
// 取消画布激活对象
this.canvas.discardActiveObject(); // 取消当前活动对象
// 重新排序
await this.layerManager?.sortLayersWithTool?.();
// 更新画布上对象的可选择状态
await this.layerManager?.updateLayersObjectsInteractivity?.();
return this.newLayerId;
}
/**
* 递归创建组图层及其所有子图层和对象
*/
async _createGroupLayerFromClipboard(data) {
const groupId = generateId("group_layer_");
const childLayerIdMap = new Map();
const allObjects = [];
// 递归处理子图层
const processChildren = async (children) => {
const result = [];
for (const child of children) {
const newChildId = generateId("layer_");
childLayerIdMap.set(child.id, newChildId);
// 递归处理子组
let childLayer;
if (child.type === "group" && Array.isArray(child.children)) {
const { groupLayer, allObjects: childObjs } =
await this._createGroupLayerFromClipboard(child);
childLayer = groupLayer;
allObjects.push(...childObjs);
} else {
// 普通子图层
childLayer = {
...child,
id: newChildId,
name: `${child.name} 副本`,
fabricObjects: [],
isCut: undefined,
serializedObjects: undefined,
};
// 恢复对象
if (
child.serializedObjects &&
Array.isArray(child.serializedObjects) &&
child.serializedObjects.length > 0
) {
const objs = await this._enlivenObjects(
child.serializedObjects,
newChildId,
`${child.name} 副本`
);
childLayer.fabricObjects = objs.map((obj) =>
obj.toObject(["id", "layerId", "layerName"])
);
allObjects.push(...objs);
}
}
result.push(childLayer);
}
return result;
};
// 处理当前组的子图层
const children = await processChildren(data.children);
// 创建组图层对象
const groupLayer = {
...data,
id: groupId,
name: `${data.name} 副本`,
type: "group",
children,
fabricObjects: [],
isCut: undefined,
serializedObjects: undefined,
};
this.childLayerIdMap = childLayerIdMap;
// 取消画布激活对象
this.canvas.discardActiveObject(); // 取消当前活动对象
return { groupLayer, allObjects };
}
/**
* 恢复对象(用于普通图层和组图层的子图层)
*/
async _enlivenObjects(serializedObjects, layerId, layerName) {
return new Promise((resolve, reject) => {
fabric.util.enlivenObjects(serializedObjects, (objects) => {
try {
objects.forEach((obj) => {
obj.id = generateId("obj_");
obj.layerId = layerId;
obj.layerName = layerName;
// 添加偏移
const offset = 30;
if (obj.left !== undefined) obj.left += offset;
if (obj.top !== undefined) obj.top += offset;
});
resolve(objects);
} catch (error) {
reject(error);
}
});
});
}
async _restoreObjectsAsync(data) {
return new Promise((resolve, reject) => {
fabric.util.enlivenObjects(data.serializedObjects, (objects) => {
try {
objects.forEach((obj) => {
const newObjId = generateId("obj_");
obj.id = newObjId;
obj.layerId = this.newLayerId;
obj.layerName = this.newLayer.name;
if (!data.isCut) {
const offset = 30;
if (obj.left !== undefined) obj.left += offset;
if (obj.top !== undefined) obj.top += offset;
}
this.canvas.add(obj);
this.newLayer.fabricObjects.push(
obj.toObject(["id", "layerId", "layerName"])
);
this.createdObjects.push(obj);
});
this._onObjectsRestored(data);
resolve();
} catch (error) {
reject(error);
}
});
});
}
_onObjectsRestored(data) {
this.layerManager?.updateLayersObjectsInteractivity?.();
this.layerManager?._rearrangeObjects?.();
if (data.isCut && this.layerManager) {
this.layerManager.clipboardData = null;
}
if (this.canvas) {
this.canvas.renderAll();
}
}
async undo() {
if (!this.newLayer || !this.newLayerId) return;
const { layer, parent } = findLayerRecursively(
this.layers.value,
this.newLayerId
);
if (!layer) {
console.error(`图层 ${this.newLayerId} 不存在, 无法撤销`);
return false;
}
if (parent) {
// 如果是子图层,直接从父图层中删除
const index = parent.children.findIndex(
(child) => child.id === this.newLayerId
);
if (index !== -1) {
parent.children.splice(index, 1);
}
} else {
// 如果是顶级图层,直接从图层列表中删除
const index = this.layers.value.findIndex(
(l) => l.id === this.newLayerId
);
if (index !== -1) {
this.layers.value.splice(index, 1);
}
}
this.createdObjects?.forEach((obj) => {
removeCanvasObjectByObject(this.canvas, obj);
});
this.activeLayerId.value = this.oldActiveLayerId;
// 取消激活对象
this.canvas.discardActiveObject(); // 取消当前活动对象
// 重新排序
await this.layerManager?.sortLayersWithTool?.();
// 更新画布上对象的可选择状态
await this.layerManager?.updateLayersObjectsInteractivity?.();
return true;
}
getInfo() {
return {
name: this.name,
layerName: this.newLayer?.name || "未知图层",
layerId: this.newLayerId,
objectCount: this.createdObjects.length,
isGroupLayer: this.isGroupLayer,
};
}
}
/**
* 移除图层命令
*/
export class RemoveLayerCommand extends Command {
constructor(options) {
super({
name: "移除图层",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.activeLayerId = options.activeLayerId;
this.layerManager = options.layerManager || null;
this.IsOnlyLayer = this.layers.value.filter((v => !v.isFixed && !v.isFixedOther && !v.isBackground)).length <= 1
// 查找要删除的图层
this.layerIndex = this.layers.value.findIndex(
(layer) => layer.id === this.layerId
);
this.removedLayer = this.layers.value[this.layerIndex];
this.isActiveLayer = this.layerId === this.activeLayerId.value;
// 从Canvas中找到真实对象并备份包括当前图层及其所有子图层的对象
this.originalObjects = [];
if (this.removedLayer) {
this.originalObjects = this._collectAllLayerObjects(this.removedLayer);
}
// 备份原活动图层ID
this.originalActiveLayerId = this.activeLayerId.value;
}
/**
* 收集图层及其所有子图层的画布对象
* @param {Object} layer 要收集对象的图层
* @returns {Array} 所有相关的画布对象
* @private
*/
_collectAllLayerObjects(layer) {
const allObjects = [];
// 收集当前图层的对象
const layerObjects = this.canvas.getObjects().filter((obj) => {
return obj.layerId === layer.id;
});
allObjects.push(...layerObjects);
// 如果图层有特殊的fabricObject属性如背景图层
if (layer.fabricObject) {
const { object } = findObjectById(this.canvas, layer.fabricObject.id);
if (object && !allObjects.includes(object)) {
allObjects.push(object);
}
}
layer.fabricObjects?.forEach((fabric) => {
const { object } = findObjectById(this.canvas, fabric.id);
if (object && !allObjects.includes(object)) {
allObjects.push(object);
}
});
// 递归收集子图层的对象
if (layer.children && Array.isArray(layer.children)) {
layer.children.forEach((childLayer) => {
const childObjects = this._collectAllLayerObjects(childLayer);
allObjects.push(...childObjects);
});
}
return allObjects;
}
async execute() {
if (this.layerIndex === -1 || !this.removedLayer) {
console.error(`图层 ${this.layerId} 不存在`);
return false;
}
// 从画布中移除图层及其所有子图层中的真实对象
this.originalObjects.forEach((obj) => {
if (this.canvas.getObjects().includes(obj)) {
this.canvas.remove(obj);
}
});
this.layerIndex = this.layers.value.findIndex(
(layer) => layer.id === this.layerId
);
// 从图层列表中删除
this.layers.value.splice(this.layerIndex, 1);
if(this.IsOnlyLayer){
this.addCmd = await this.layerManager?.createLayer?.(null, LayerType.EMPTY, {}, false);
}
// 如果删除的是当前活动图层,需要更新活动图层
if (this.isActiveLayer) {
// 查找最近的非背景层作为新的活动图层
const newActiveLayer = this.layers.value.find(
(layer) => !layer.isBackground
);
if (newActiveLayer) {
this.activeLayerId.value = newActiveLayer.id;
if(this.canvas.toolId === OperationType.SELECT){
this.layerManager.selectLayerObjects(newActiveLayer.id);
}
} else {
this.activeLayerId.value = null;
}
}
// 重新渲染画布
// if (this.canvas) {
// this.canvas.renderAll();
// }
await this.layerManager?.updateLayersObjectsInteractivity?.();
this.canvas.renderAll();
console.log(
`✅ 已移除图层: ${this.removedLayer.name} (ID: ${this.layerId}),包含 ${this.originalObjects.length} 个对象`
);
return true;
}
async undo() {
// 恢复图层到原位置
if (this.layerIndex !== -1 && this.removedLayer) {
if(this.IsOnlyLayer && this.addCmd){
this.addCmd?.undo?.();
}
this.layers.value.splice(this.layerIndex, 0, this.removedLayer);
// 使用优化渲染批处理恢复真实对象到画布
await optimizeCanvasRendering(this.canvas, () => {
// 倒序添加对象,确保下标越小的子图层在画布中越靠前
this.originalObjects
.slice()
.reverse()
.forEach((obj) => {
// 确保对象不在画布中才添加,避免重复添加
if (!this.canvas.getObjects().includes(obj)) {
this.canvas.add(obj);
// 确保对象的坐标正确
obj.setCoords();
}
});
});
await this.layerManager?.updateLayersObjectsInteractivity?.();
this.canvas.renderAll();
// 如果删除的是当前活动图层,恢复活动图层
if (this.isActiveLayer) {
this.activeLayerId.value = this.layerId;
}
console.log(
`↩️ 已恢复图层: ${this.removedLayer.name} (ID: ${this.layerId}),包含 ${this.originalObjects.length} 个对象`
);
}
}
getInfo() {
return {
name: this.name,
layerName: this.removedLayer?.name || "未知图层",
layerId: this.layerId,
objectCount: this.originalObjects.length,
};
}
}
/**
* 移动图层命令
*/
export class MoveLayerCommand extends Command {
constructor(options) {
super({
name: `移动图层 ${options.direction === "up" ? "上移" : "下移"}`,
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.direction = options.direction; // "up" or "down"
this.layerSort = options.layerSort;
this.parentLayer = null; // 父图层
const { layer, parent } = findLayerRecursively(
this.layers.value,
this.layerId
);
// 如果parent 有值 或者 layer 上有parentId 则视为子图层的置顶
if (parent?.id) {
// 查找子图层索引
this.layerIndex = parent?.children?.findIndex(
(layer) => layer.id === this.layerId
);
this.parentLayer = parent;
} else {
// 查找图层索引
this.layerIndex = this.layers.value.findIndex(
(layer) => layer.id === this.layerId
);
}
this.layer = layer;
this.originalIndex = this.layerIndex;
// 目标位置
this.targetIndex =
options.direction === "up" ? this.layerIndex - 1 : this.layerIndex + 1;
}
async execute() {
if (this.layerIndex === -1 || !this.layer) {
console.error(`图层 ${this.layerId} 不存在`);
return false;
}
// 检查是否是背景层或固定层(不允许移动)
if (this.layer.isBackground || this.layer.isFixed) {
console.warn("背景层和固定层不能移动");
return false;
}
// 如果已经在顶部,无需移动
if (this.layerIndex === this.targetIndex) {
console.log("图层已在顶部位置");
return true;
}
// 执行移动
if (this.parentLayer) {
const tempLayer = this.parentLayer.children[this.targetIndex];
this.parentLayer.children[this.layerIndex] = tempLayer;
this.parentLayer.children[this.targetIndex] = this.layer;
} else {
const tempLayer = this.layers.value[this.targetIndex];
this.layers.value[this.layerIndex] = tempLayer;
this.layers.value[this.targetIndex] = this.layer;
}
// 使用LayerSort工具重新排列画布对象如果可用
await this.layerSort?.rearrangeObjects();
console.log(`图层${this.layer.name}已经移动`);
}
async undo() {
const tempOldIndex = this.layerIndex;
this.layerIndex = this.targetIndex;
this.targetIndex = tempOldIndex;
await this.execute();
// 执行完成恢复索引
this.targetIndex = this.layerIndex;
this.layerIndex = tempOldIndex;
console.log(`↩️ 图层 ${this.layer.name} 已恢复到原位置`);
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
direction: this.direction,
};
}
}
/**
* 切换图层可见性命令
*/
export class ToggleLayerVisibilityCommand extends Command {
constructor(options) {
super({
name: "切换图层可见性",
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.layerManager = options.layerManager;
// 查找图层
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
this.layer = layer;
// this.oldVisibility = this.layer ? this.layer.visible : null;
}
async execute() {
if (!this.layer) {
console.error(`图层 ${this.layerId} 不存在`);
return false;
}
// 切换可见性
this.layer.visible = !this.layer.visible;
const ids = [this.layerId];
const childLayers = this.layer?.children || [];
childLayers.forEach((childLayer) => {
childLayer.visible = this.layer.visible;
ids.push(childLayer.id);
});
// 更新画布上图层对象的可见性
if (this.canvas) {
this.canvas.getObjects().forEach((obj) => {
if (ids.includes(obj.layerId)) {
obj.getObjects?.()?.forEach((item) => {
item.visible = this.layer.visible;
});
obj.visible = this.layer.visible;
}
});
}
// 更新画布上对象的可选择状态
await this.layerManager?.updateLayersObjectsInteractivity();
return this.layer.visible;
}
async undo() {
return await this.execute(); // 直接调用execute方法来恢复可见性
}
getInfo() {
return {
name: this.name,
layerName: this.layer?.name || "未知图层",
layerId: this.layerId,
newVisibility: this.layer?.visible,
};
}
}
/**
* 切换子图层可见性命令
*/
export class ToggleChildLayerVisibilityCommand extends Command {
constructor(options) {
super({
name: "切换子图层可见性",
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.parentId = options.parentId;
this.layerManager = options.layerManager;
// 查找父图层和子图层
const { layer, parent } = findLayerRecursively(
this.layers.value,
this.layerId
);
this.parentLayer = parent;
this.childLayer = layer;
// this.oldVisibility = this.childLayer ? this.childLayer.visible : null;
}
async execute(visible) {
if (!this.childLayer) {
throw new Error("找不到要切换可见性的子图层");
}
// 切换可见性
this.childLayer.visible = typeof visible === "boolean" ? visible : !this.childLayer.visible;
// 更新画布上图层对象的可见性
if (this.canvas) {
this.canvas.getObjects().forEach((obj) => {
if (obj.layerId === this.layerId) {
obj.getObjects?.()?.forEach((item) => {
item.visible = this.childLayer.visible;
});
obj.visible = this.childLayer.visible;
}
});
}
// 更新画布上对象的可选择状态
await this.layerManager?.updateLayersObjectsInteractivity();
return this.childLayer.visible;
}
async undo() {
return await this.execute(); // 直接调用execute方法来恢复可见性
}
getInfo() {
return {
name: this.name,
layerName: this.childLayer?.name || "未知子图层",
layerId: this.layerId,
parentId: this.parentId,
newVisibility: this.childLayer?.visible,
};
}
}
/**
* 重命名图层命令
*/
export class RenameLayerCommand extends Command {
constructor(options) {
super({
name: "重命名图层",
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.newName = options.newName;
// 查找图层
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
this.layer = layer;
this.oldName = this.layer ? this.layer.name : null;
}
execute() {
if (!this.layer) {
console.error(`图层 ${this.layerId} 不存在`);
return false;
}
// 更新图层名称
this.layer.name = this.newName;
// 更新图层对象上的图层名称
if (this.canvas) {
const layerObjects = this.canvas
.getObjects()
.filter((obj) => obj.layerId === this.layerId);
layerObjects.forEach((obj) => {
obj.layerName = this.newName;
});
}
return true;
}
undo() {
if (this.layer && this.oldName) {
// 恢复图层名称
this.layer.name = this.oldName;
// 恢复图层对象上的图层名称
if (this.canvas) {
const layerObjects = this.canvas
.getObjects()
.filter((obj) => obj.layerId === this.layerId);
layerObjects.forEach((obj) => {
obj.layerName = this.oldName;
});
}
}
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
oldName: this.oldName,
newName: this.newName,
};
}
}
/**
* 图层锁定/解锁命令
*/
export class LayerLockCommand extends Command {
constructor(options) {
super({
name: "图层锁定/解锁",
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.layerManager = options.layerManager;
// 查找图层(包括子图层)
// 查找图层
const { layer, parent } = findLayerRecursively(
this.layers.value,
this.layerId
);
this.layer = layer;
this.parentLayer = parent || null; // 父图层
this.oldLocked = this.layer ? this.layer.locked : null;
}
/**
* 更新图层及其子图层的锁定状态
* @param {Object} layer 要更新的图层
* @param {boolean} locked 锁定状态
* @private
*/
_updateLayerLockState(layer, locked) {
if (!layer) return;
// 更新当前图层的锁定状态
layer.locked = locked;
// 如果是组图层,递归更新所有子图层
if (
layer.children &&
Array.isArray(layer.children) && layer.children.length > 0
) {
layer.children.forEach((child) => {
this._updateLayerLockState(child, locked);
});
}
}
async execute() {
if (!this.layer) {
console.error(`图层 ${this.layerId} 不存在`);
return false;
}
// 切换锁定状态
const newLocked = !this.oldLocked;
// 更新图层及其子图层的锁定状态
this._updateLayerLockState(this.layer, newLocked);
// 更新画布上对象的可选择状态
await this.layerManager?.updateLayersObjectsInteractivity();
console.log(
`${newLocked ? "锁定" : "解锁"}图层: ${this.layer.name} (ID: ${
this.layerId
})`
);
return true;
}
async undo() {
if (this.layer) {
// 恢复锁定状态
this._updateLayerLockState(this.layer, this.oldLocked);
// 更新画布上对象的可选择状态
await this.layerManager?.updateLayersObjectsInteractivity();
console.log(
`恢复图层锁定状态: ${this.layer.name} (锁定: ${this.oldLocked})`
);
}
}
getInfo() {
return {
name: this.name,
layerName: this.layer?.name || "未知图层",
layerId: this.layerId,
isChildLayer: !!this.parentLayer,
parentLayerName: this.parentLayer?.name,
newLocked: this.layer?.locked,
oldLocked: this.oldLocked,
};
}
}
/**
* 设置图层不透明度命令
*/
export class SetLayerOpacityCommand extends Command {
constructor(options) {
super({
name: "设置图层不透明度",
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.opacity = options.opacity;
// 查找图层
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
this.layer = layer;
this.oldOpacity = this.layer ? this.layer.opacity : null;
}
execute() {
if (!this.layer) {
console.error(`图层 ${this.layerId} 不存在`);
return false;
}
// 设置图层不透明度
this.layer.opacity = this.opacity;
// 更新画布上对象的不透明度
if (this.canvas) {
const layerObjects = this.canvas
.getObjects()
.filter((obj) => obj.layerId === this.layerId);
layerObjects.forEach((obj) => {
obj.opacity = this.opacity;
});
this.canvas.renderAll();
}
EventManager.emit("object:opacity:execute", this.layerId, this.opacity);
return true;
}
undo() {
if (this.layer && this.oldOpacity !== null) {
// 恢复图层不透明度
this.layer.opacity = this.oldOpacity;
// 更新画布上对象的不透明度
if (this.canvas) {
const layerObjects = this.canvas
.getObjects()
.filter((obj) => obj.layerId === this.layerId);
layerObjects.forEach((obj) => {
obj.opacity = this.oldOpacity;
});
this.canvas.renderAll();
}
}
EventManager.emit("object:opacity:undo", this.layerId, this.opacity);
}
getInfo() {
return {
name: this.name,
layerName: this.layer?.name || "未知图层",
layerId: this.layerId,
oldOpacity: this.oldOpacity,
newOpacity: this.opacity,
};
}
}
/**
* 设置图层混合模式命令
*/
export class SetLayerBlendModeCommand extends Command {
constructor(options) {
super({
name: "设置图层混合模式",
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.blendMode = options.blendMode;
// 查找图层
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
this.layer = layer;
this.oldBlendMode = this.layer ? this.layer.blendMode : null;
}
execute() {
if (!this.layer) {
console.error(`图层 ${this.layerId} 不存在`);
return false;
}
// 设置图层混合模式
this.layer.blendMode = this.blendMode;
// 更新画布上对象的混合模式
if (this.canvas) {
const layerObjects = this.canvas
.getObjects()
.filter((obj) => obj.layerId === this.layerId);
layerObjects.forEach((obj) => {
obj.globalCompositeOperation = this.blendMode;
});
this.canvas.renderAll();
}
return true;
}
undo() {
if (this.layer && this.oldBlendMode) {
// 恢复图层混合模式
this.layer.blendMode = this.oldBlendMode;
// 更新画布上对象的混合模式
if (this.canvas) {
const layerObjects = this.canvas
.getObjects()
.filter((obj) => obj.layerId === this.layerId);
layerObjects.forEach((obj) => {
obj.globalCompositeOperation = this.oldBlendMode;
});
this.canvas.renderAll();
}
}
}
getInfo() {
return {
name: this.name,
layerName: this.layer?.name || "未知图层",
layerId: this.layerId,
oldBlendMode: this.oldBlendMode,
newBlendMode: this.blendMode,
};
}
}
/**
* 合并图层命令
*/
export class MergeLayersCommand extends Command {
constructor(options) {
super({
name: "合并图层",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerIds = options.layerIds;
this.newName = options.newName;
this.activeLayerId = options.activeLayerId; // <--- 新增
// 备份原图层
this.originalLayers = [...this.layers.value];
// 新图层ID
this.newLayerId = `merged_layer_${Date.now()}_${Math.floor(
Math.random() * 1000
)}`;
}
execute() {
if (
!this.layerIds ||
!Array.isArray(this.layerIds) ||
this.layerIds.length < 2
) {
console.error("合并图层至少需要两个图层");
return null;
}
// 查找所有要合并的图层
const layersToMerge = this.layerIds
.map((id) => this.layers.value.find((layer) => layer.id === id))
.filter(Boolean);
if (layersToMerge.length < 2) {
console.error("找不到足够的图层进行合并");
return null;
}
// 检查是否包含背景图层
if (layersToMerge.some((layer) => layer.isBackground)) {
console.error("不能合并背景图层");
return null;
}
// 查找所有要组合的图层
const layersToGroup = this.layerIds
.map((id) => {
const tempLayer = this.layers.value.find((layer) => layer.id === id); // 需要给子图层加上parentId
return tempLayer ? { ...tempLayer, parentId: this.groupId } : false;
})
.filter(Boolean);
const topLayerIndex = Math.min(
...layersToGroup.map((layer) =>
this.layers.value.findIndex((fLayer) => fLayer.id === layer.id)
)
);
// 获取要保留的所有对象
const allObjects = [];
layersToMerge.forEach((layer) => {
if (Array.isArray(layer.fabricObjects)) {
allObjects.push(...layer.fabricObjects);
}
});
// 创建新的合并图层
const mergedLayer = createLayer({
id: this.newLayerId,
name: this.newName || `合并图层`,
type: LayerType.BITMAP,
visible: true,
locked: false,
opacity: 1.0,
fabricObjects: allObjects,
});
// 更新对象与新图层的关联
allObjects.forEach((obj) => {
obj.layerId = mergedLayer.id;
obj.layerName = mergedLayer.name;
});
// 移除原图层
this.layers.value = this.layers.value.filter(
(layer) => !this.layerIds.includes(layer.id)
);
// 插入新图层
this.layers.value.splice(topLayerIndex, 0, mergedLayer);
// 更新当前活动图层
this.activeLayerId.value = this.newLayerId;
// 重新渲染画布
if (this.canvas) {
this.canvas.renderAll();
}
return this.newLayerId;
}
undo() {
// 恢复原始图层状态
this.layers.value = [...this.originalLayers];
// 恢复活动图层
if (this.activeLayerId) {
// 恢复到合并前的活动图层(取第一个合并前图层)
this.activeLayerId.value = this.layerIds[0];
}
// 重新渲染画布
if (this.canvas) {
this.canvas.renderAll();
}
}
getInfo() {
return {
name: this.name,
layerIds: this.layerIds,
newLayerId: this.newLayerId,
newName: this.newName,
};
}
}
/**
* 图层组合命令
*/
export class GroupLayersCommand extends Command {
constructor(options) {
super({
name: "组合图层",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerIds = options.layerIds;
this.groupName = options.groupName;
this.activeLayerId = options.activeLayerId; // <--- 新增
// 备份原图层
this.originalLayers = [...this.layers.value];
// 新组ID
this.groupId = options.id ||
generateId("group_layer_") ||
`group_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
this.originalActiveLayerId = this.activeLayerId.value; // 备份原活动图层ID
}
async execute() {
if (
!this.layerIds ||
!Array.isArray(this.layerIds) ||
this.layerIds.length < 2
) {
console.error("组合图层至少需要两个图层");
return null;
}
// 查找所有要组合的图层
const layersToGroup = this.layerIds
.map((id) => {
const tempLayer = this.layers.value.find((layer) => layer.id === id); // 需要给子图层加上parentId
return tempLayer ? { ...tempLayer, parentId: this.groupId } : false;
})
.filter(Boolean);
if (layersToGroup.length < 2) {
console.error("找不到足够的图层进行组合");
return null;
}
// 检查是否包含背景图层
if (layersToGroup.some((layer) => layer.isBackground)) {
console.error("不能组合背景图层");
return null;
}
// 查找最顶层图层的索引,用于插入组图层
const topLayerIndex = Math.min(
...layersToGroup.map((layer) =>
this.layers.value.findIndex((fLayer) => fLayer.id === layer.id)
)
);
// 创建新的组图层
const groupLayer = createLayer({
id: this.groupId,
name: this.groupName || `图层组`,
type: LayerType.GROUP,
visible: true,
locked: false,
opacity: 1.0,
fabricObjects: [],
children: layersToGroup,
});
// 移除原图层
this.layers.value = this.layers.value.filter(
(layer) => !this.layerIds.includes(layer.id)
);
// 插入新组图层
this.layers.value.splice(topLayerIndex, 0, groupLayer);
// 更新当前活动图层
this.activeLayerId.value = this.layerIds[0];
this.canvas?.thumbnailManager?.generateLayerThumbnail?.(this.groupId);
return this.groupId;
}
async undo() {
// 恢复原始图层状态
this.layers.value = [...this.originalLayers];
// 恢复活动图层为原先第一个合并前层
if (this.activeLayerId) {
this.activeLayerId.value = this.originalActiveLayerId;
}
}
getInfo() {
return {
name: this.name,
layerIds: this.layerIds,
groupId: this.groupId,
groupName: this.groupName,
};
}
}
/**
* 解组图层命令
*/
export class UngroupLayersCommand extends Command {
constructor(options) {
super({
name: "解组图层",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.groupId = options.groupId;
this.activeLayerId = options.activeLayerId; // <--- 新增
// 备份原图层
this.originalLayers = [...this.layers.value];
// 子图层ID列表
this.childLayerIds = [];
}
async execute() {
// 查找组图层
const groupIndex = this.layers.value.findIndex(
(layer) => layer.id === this.groupId
);
if (groupIndex === -1) {
console.error(`找不到组图层 ${this.groupId}`);
return null;
}
const groupLayer = this.layers.value[groupIndex];
if (!groupLayer.children || groupLayer.children.length === 0) {
console.error(`组图层 ${this.groupId} 没有子图层`);
return null;
}
// 收集子图层ID
this.childLayerIds = groupLayer.children.map((layer) => layer.id);
// 将子图层添加到原位置
this.layers.value.splice(
groupIndex,
1,
...(groupLayer?.children?.map((child) => {
// 为子图层添加parentId
delete child.parentId; // 删除parentId属性
return { ...child };
}) || {})
);
// 更新当前活动图层为第一个子图层
if (this.childLayerIds.length > 0 && this.activeLayerId) {
this.activeLayerId.value = this.childLayerIds[0];
}
return this.childLayerIds;
}
async undo() {
// 恢复原始图层状态
this.layers.value = [...this.originalLayers];
// 恢复活动图层为原始组ID
if (this.activeLayerId) {
this.activeLayerId.value = this.groupId;
}
}
getInfo() {
return {
name: this.name,
groupId: this.groupId,
childLayerIds: this.childLayerIds,
};
}
}
/**
* 合并图层内对象命令(重构版本)
* 将新的图像与图层内现有对象合并为一个高保真图像对象
*/
export class MergeLayerObjectsCommand extends Command {
constructor(options) {
super({
name: "合并图层内对象",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.fabricImage = options.fabricImage;
this.activeLayer = options.activeLayer;
// 备份原始对象,用于撤销
if (this.activeLayer && Array.isArray(this.activeLayer.fabricObjects)) {
this.originalObjects =
this.canvas
?.getObjects()
?.filter((fItem) => fItem.layerId === this.activeLayer.id) || [];
} else {
this.originalObjects = [];
}
// 新合并图像对象
this.mergedImage = null;
this.newImageId = `merged_image_${Date.now()}_${Math.floor(
Math.random() * 1000
)}`;
}
async execute() {
if (!this.activeLayer || !this.canvas) {
console.error("图层或Canvas未初始化");
return null;
}
// 获取所有需要合并的对象(按正确的层级顺序)
const objectsToMerge = [];
// 先添加图层中的现有对象(作为底层)
if (this.originalObjects.length > 0) {
objectsToMerge.push(...this.originalObjects);
}
// 再添加新的图像对象(作为顶层)
if (this.fabricImage) {
objectsToMerge.push(this.fabricImage);
}
if (objectsToMerge.length === 0) {
console.log("没有对象需要合并");
return null;
}
// 计算所有对象的合并边界
const bounds = this._calculateMergedBounds(objectsToMerge);
if (!bounds) {
console.error("无法计算合并边界");
return null;
}
// 异步处理图像合并
try {
const mergedImage = await this._createMergedImageAsync(
objectsToMerge,
bounds
);
this._setupMergedImage(mergedImage, bounds);
this._replaceObjects(mergedImage);
console.log("图像合并完成");
return this.newImageId;
} catch (error) {
console.error("图像合并执行失败:", error);
return null;
}
}
/**
* 异步创建合并图像
* @param {Array} objectsToMerge 要合并的对象
* @param {Object} bounds 边界信息
* @returns {Promise<fabric.Image>} 合并后的图像
* @private
*/
async _createMergedImageAsync(objectsToMerge, bounds) {
return new Promise((resolve, reject) => {
try {
// 创建高保真临时画布
const tempCanvas = this._createHighQualityTempCanvas(bounds);
const tempFabricCanvas = createStaticCanvas(tempCanvas, {
width: bounds.width,
height: bounds.height,
});
// 设置高质量渲染选项
tempFabricCanvas.enableRetinaScaling = true;
tempFabricCanvas.imageSmoothingEnabled = true;
// 将所有对象添加到临时画布并调整位置
this._addObjectsToTempCanvas(tempFabricCanvas, objectsToMerge, bounds);
// 渲染临时画布
tempFabricCanvas.renderAll();
// 生成高质量图像
const dataUrl = tempFabricCanvas.toDataURL({
format: "png",
quality: 1.0,
multiplier: 1,
});
// 创建新的合并图像
fabric.Image.fromURL(
dataUrl,
(mergedImg) => {
try {
// 清理临时资源
this._cleanupTempCanvas(tempFabricCanvas);
resolve(mergedImg);
} catch (error) {
console.error("设置合并图像时发生错误:", error);
this._cleanupTempCanvas(tempFabricCanvas);
reject(error);
}
},
{
crossOrigin: "anonymous",
}
);
} catch (error) {
console.error("合并过程中发生错误:", error);
reject(error);
}
});
}
/**
* 计算所有对象的合并边界
* @param {Array} objects 要合并的对象数组
* @returns {Object} 边界信息
* @private
*/
_calculateMergedBounds(objects) {
if (!objects || objects.length === 0) return null;
let minLeft = Infinity;
let minTop = Infinity;
let maxRight = -Infinity;
let maxBottom = -Infinity;
objects.forEach((obj) => {
if (!obj) return;
const bounds = obj.getBoundingRect(true, true);
minLeft = Math.min(minLeft, bounds.left);
minTop = Math.min(minTop, bounds.top);
maxRight = Math.max(maxRight, bounds.left + bounds.width);
maxBottom = Math.max(maxBottom, bounds.top + bounds.height);
});
const padding = 1;
return {
left: minLeft - padding,
top: minTop - padding,
width: maxRight - minLeft + padding * 2,
height: maxBottom - minTop + padding * 2,
};
}
/**
* 创建高质量临时画布
* @param {Object} bounds 边界信息
* @returns {HTMLCanvasElement} 临时画布
* @private
*/
_createHighQualityTempCanvas(bounds) {
const tempCanvas = document.createElement("canvas");
tempCanvas.width = Math.ceil(bounds.width);
tempCanvas.height = Math.ceil(bounds.height);
tempCanvas.style.width = bounds.width + "px";
tempCanvas.style.height = bounds.height + "px";
const ctx = tempCanvas.getContext("2d");
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = "high";
return tempCanvas;
}
/**
* 将对象添加到临时画布并调整位置
* @param {fabric.Canvas} tempCanvas 临时画布
* @param {Array} objects 对象数组
* @param {Object} bounds 边界信息
* @private
*/
_addObjectsToTempCanvas(tempCanvas, objects, bounds) {
objects.forEach((obj, index) => {
if (!obj) return;
try {
const clonedObj = fabric.util.object.clone(obj);
const objBounds = obj.getBoundingRect(true, true);
const offsetX = objBounds.left - bounds.left;
const offsetY = objBounds.top - bounds.top;
clonedObj.set({
left: offsetX + (clonedObj.width * clonedObj.scaleX) / 2,
top: offsetY + (clonedObj.height * clonedObj.scaleY) / 2,
originX: "center",
originY: "center",
});
tempCanvas.add(clonedObj);
console.log(
`添加对象 ${index + 1}/${objects.length}: ${obj.type || "unknown"}`
);
} catch (error) {
console.error(`添加对象到临时画布时发生错误:`, error);
}
});
}
/**
* 设置合并后的图像属性
* @param {fabric.Image} mergedImg 合并后的图像
* @param {Object} bounds 边界信息
* @private
*/
_setupMergedImage(mergedImg, bounds) {
mergedImg.set({
id: this.newImageId,
layerId: this.activeLayer.id,
layerName: this.activeLayer.name,
left: bounds.left + bounds.width / 2,
top: bounds.top + bounds.height / 2,
originX: "center",
originY: "center",
selectable: true,
evented: true,
});
this.mergedImage = mergedImg;
}
/**
* 替换原有对象为合并后的图像
* @param {fabric.Image} mergedImg 合并后的图像
* @private
*/
_replaceObjects(mergedImg) {
if (!mergedImg || !this.canvas || !this.activeLayer) {
console.error("_replaceObjects: 缺少必要的参数");
return;
}
const wasRenderOnAddRemove = this.canvas.renderOnAddRemove;
this.canvas.renderOnAddRemove = false;
try {
// 清空图层的对象列表
this.activeLayer.fabricObjects = [];
// 添加合并后的图像到画布和图层
this.canvas.add(mergedImg);
this.activeLayer.fabricObjects.push(mergedImg);
// 从画布中移除所有原始对象
this.originalObjects.forEach((obj) => {
if (obj && this.canvas.getObjects().includes(obj)) {
this.canvas.remove(obj);
}
});
// 如果有新的图像对象,也要移除
if (
this.fabricImage &&
this.canvas.getObjects().includes(this.fabricImage)
) {
this.canvas.remove(this.fabricImage);
}
console.log(
`成功替换图层 ${this.activeLayer.name} 中的 ${this.originalObjects.length} 个对象为合并图像`
);
} catch (error) {
console.error("替换对象时发生错误:", error);
} finally {
this.canvas.renderOnAddRemove = wasRenderOnAddRemove;
this.canvas.renderAll(); // 同步渲染画布
// 更新缩略图
if (this.canvas.thumbnailManager) {
setTimeout(() => {
this.canvas.thumbnailManager.generateLayerThumbnail(
this.activeLayer.id
);
}, 100);
}
}
}
undo() {
if (!this.activeLayer || !this.canvas) return;
const wasRenderOnAddRemove = this.canvas.renderOnAddRemove;
this.canvas.renderOnAddRemove = false;
try {
// 移除合并后的图像
if (this.mergedImage) {
this.canvas.remove(this.mergedImage);
const imageIndex = this.activeLayer.fabricObjects.findIndex(
(obj) => obj.id === this.newImageId
);
if (imageIndex !== -1) {
this.activeLayer.fabricObjects.splice(imageIndex, 1);
}
}
// 按原始顺序恢复对象到画布
this.originalObjects.forEach((obj) => {
if (obj) {
this.canvas.add(obj);
}
});
// 恢复图层对象列表
this.activeLayer.fabricObjects = [...this.originalObjects];
console.log(`成功撤销图层 ${this.activeLayer.name} 的对象合并操作`);
} catch (error) {
console.error("撤销合并操作时发生错误:", error);
} finally {
this.canvas.renderOnAddRemove = wasRenderOnAddRemove;
this.canvas.renderAll();
// 更新缩略图
if (this.canvas.thumbnailManager) {
setTimeout(() => {
this.canvas.thumbnailManager.generateLayerThumbnail(
this.activeLayer.id
);
}, 100);
}
}
}
/**
* 安全地清理临时画布资源
* @param {fabric.Canvas} tempCanvas 临时画布
* @private
*/
_cleanupTempCanvas(tempCanvas) {
if (!tempCanvas) return;
try {
tempCanvas.clear();
const objects = tempCanvas.getObjects();
objects.forEach((obj) => {
tempCanvas.remove(obj);
});
const canvasEl = tempCanvas.getElement();
if (canvasEl && canvasEl.getContext) {
const ctx = canvasEl.getContext("2d");
if (ctx) {
ctx.clearRect(0, 0, canvasEl.width, canvasEl.height);
}
}
if (typeof tempCanvas.destroy === "function") {
tempCanvas.destroy();
}
if (canvasEl && canvasEl.parentNode) {
canvasEl.parentNode.removeChild(canvasEl);
}
console.log("临时画布资源已安全清理");
} catch (error) {
console.warn("清理临时画布时发生警告:", error);
}
}
getInfo() {
return {
name: this.name,
layerId: this.activeLayer?.id,
layerName: this.activeLayer?.name || "未知图层",
originalObjectCount: this.originalObjects.length,
hasNewImage: !!this.fabricImage,
mergedImageId: this.newImageId,
};
}
}
/**
* 合并图层内对象成组的命令
* 将新的图像与图层内现有对象合并为一个组对象
* 支持向现有组添加对象,以及移除空组
*/
export class LayerObjectsToGroupCommand extends Command {
constructor(options) {
super({
name: "图层内对象合并为组",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.fabricImage = options.fabricImage;
this.activeLayer = options.activeLayer;
this.layerManager = options.layerManager;
// 存储对象ID而不是对象引用避免引用丢失问题
this.originalObjectIds = [];
this.addedObjectIds = [];
// 备份原始对象,用于撤销
if (this.activeLayer && Array.isArray(this.activeLayer.fabricObjects)) {
this.originalObjectIds = this.activeLayer.fabricObjects
.filter((obj) => obj && obj.id)
.map((obj) => obj.id);
}
// 组对象相关
this.existingGroupId = null;
this.groupObjectId = null;
this.newGroupId =
generateId("group") ||
`group_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
this.wasGroupCreated = false;
// 保存原始位置信息
this.originalObjectPositions = new Map();
this.originalObjectIds.forEach((id) => {
const result = findObjectById(this.canvas, id);
if (result.object) {
this.originalObjectPositions.set(id, {
left: result.object.left,
top: result.object.top,
scaleX: result.object.scaleX,
scaleY: result.object.scaleY,
angle: result.object.angle,
originX: result.object.originX,
originY: result.object.originY,
flipX: result.object.flipX,
flipY: result.object.flipY,
layerId: result.object.layerId,
layerName: result.object.layerName,
});
}
});
// 新增:保存新添加对象的位置信息
this.newObjectPositions = new Map();
if (this.fabricImage && this.fabricImage.id) {
this.newObjectPositions.set(this.fabricImage.id, {
left: this.fabricImage.left,
top: this.fabricImage.top,
scaleX: this.fabricImage.scaleX,
scaleY: this.fabricImage.scaleY,
angle: this.fabricImage.angle,
originX: this.fabricImage.originX,
originY: this.fabricImage.originY,
flipX: this.fabricImage.flipX,
flipY: this.fabricImage.flipY,
layerId: this.fabricImage.layerId,
layerName: this.fabricImage.layerName,
});
}
// 记录执行状态,用于区分首次执行和重做
this.isFirstExecution = true;
}
async execute() {
if (!this.activeLayer || !this.canvas) {
console.error("图层或Canvas未初始化");
return null;
}
this.activeLayer = this.layerManager.getActiveLayer();
// 查找图层中是否已有组对象
const existingGroup = this._findExistingGroup();
this.existingGroupId = existingGroup?.id || null;
// 准备要添加的新对象
const newObjectsToAdd = [];
if (this.fabricImage) {
// 如果是重做,恢复新对象的原始位置
if (
!this.isFirstExecution &&
this.newObjectPositions.has(this.fabricImage.id)
) {
const savedPosition = this.newObjectPositions.get(this.fabricImage.id);
this.fabricImage.set({
left: savedPosition.left,
top: savedPosition.top,
scaleX: savedPosition.scaleX,
scaleY: savedPosition.scaleY,
angle: savedPosition.angle,
originX: savedPosition.originX,
originY: savedPosition.originY,
flipX: savedPosition.flipX,
flipY: savedPosition.flipY,
});
console.log(
`🔄 重做时恢复新对象位置: (${savedPosition.left}, ${savedPosition.top})`
);
}
newObjectsToAdd.push(this.fabricImage);
this.addedObjectIds.push(this.fabricImage.id);
}
if (newObjectsToAdd.length === 0) {
console.log("没有新对象需要添加到组");
return this.existingGroupId;
}
try {
await optimizeCanvasRendering(this.canvas, async () => {
if (existingGroup) {
// 向现有组添加对象
this._addObjectsToExistingGroup(existingGroup, newObjectsToAdd);
this.groupObjectId = existingGroup.id;
this.wasGroupCreated = false;
} else {
// 创建新组包含所有对象
this._createNewGroupWithAllObjects(newObjectsToAdd);
this.groupObjectId = this.newGroupId;
this.wasGroupCreated = true;
await this.layerManager?.layerSort?.rearrangeObjects();
}
// 更新交互性
this.layerManager?.updateLayersObjectsInteractivity?.(false).then(()=>{
// 更新缩略图
this._updateThumbnail();
});
});
// 标记为非首次执行
this.isFirstExecution = false;
return this.groupObjectId;
} catch (error) {
console.error("执行组合操作时发生错误:", error);
return null;
}
}
/**
* 查找图层中现有的组对象
* @returns {fabric.Group|null}
* @private
*/
_findExistingGroup() {
// 查找当前的组对象
if (!this.activeLayer.fabricObjects) return null;
if (!this.existingGroupId) {
const groupObjects =
this.activeLayer.fabricObjects.find(
(obj) => obj && obj.type === "group"
) || null;
this.existingGroupId = groupObjects?.id || null;
}
if (!this.existingGroupId) {
console.warn("未找到有效的组对象");
return null;
}
const { object } = findObjectById(this.canvas, this.existingGroupId);
if (!object || object.type !== "group") {
console.warn("未找到有效的组对象");
return null;
}
return object;
}
/**
* 将新对象添加到现有组中
* @param {fabric.Group} existingGroup 现有组
* @param {Array} newObjects 要添加的新对象
* @private
*/
_addObjectsToExistingGroup(existingGroup, newObjects) {
// 先从画布移除新对象(避免重复添加)
newObjects.forEach((obj) => {
removeCanvasObjectByObject(this.canvas, obj);
});
// 使用 addWithUpdate 方法正确添加对象到组
newObjects.forEach((obj) => {
existingGroup.addWithUpdate(obj);
});
}
/**
* 创建包含所有对象的新组
* @param {Array} newObjects 新添加的对象
* @private
*/
_createNewGroupWithAllObjects(newObjects) {
// 获取原始对象通过ID重新查找
const originalObjects = this._getOriginalObjectsFromCanvas();
// 如果是重做,恢复原始对象的位置
if (!this.isFirstExecution) {
originalObjects.forEach((obj) => {
if (this.originalObjectPositions.has(obj.id)) {
const savedPosition = this.originalObjectPositions.get(obj.id);
obj.set({
left: savedPosition.left,
top: savedPosition.top,
scaleX: savedPosition.scaleX,
scaleY: savedPosition.scaleY,
angle: savedPosition.angle,
originX: savedPosition.originX,
originY: savedPosition.originY,
flipX: savedPosition.flipX,
flipY: savedPosition.flipY,
});
console.log(
`🔄 重做时恢复原始对象位置: ${obj.id} (${savedPosition.left}, ${savedPosition.top})`
);
}
});
}
const allObjects = [...originalObjects, ...newObjects];
const clipPath = allObjects?.[0]?.clipPath || null;
// 从画布中移除所有要组合的对象
allObjects.forEach((obj) => {
obj.clipPath = null;
obj.dirty = true; // 标记为脏对象
// obj.setCoords();
obj.opacity = 1;
removeCanvasObjectByObject(this.canvas, obj);
});
// 创建组对象
const groupObject = new fabric.Group(allObjects, {
id: this.newGroupId,
layerId: this.activeLayer.id,
layerName: this.activeLayer.name,
type: "group",
selectable: true,
evented: true,
});
// 添加组对象到画布
this.canvas.add(groupObject);
groupObject.clipPath = clipPath; // 恢复剪切路径
groupObject.dirty = true; // 标记为脏对象
groupObject.setCoords();
// 更新图层的对象列表
// this.activeLayer.fabricObjects = [groupObject];
this.activeLayer.fabricObjects = [
groupObject.toObject(["id", "layerId", "layerName"]),
];
}
/**
* 从画布中重新获取原始对象
* @returns {Array} 原始对象数组
* @private
*/
_getOriginalObjectsFromCanvas() {
const objects = [];
for (const objectId of this.originalObjectIds) {
const result = findObjectById(this.canvas, objectId);
if (result.object) {
objects.push(result.object);
}
}
return objects;
}
async undo() {
if (!this.activeLayer || !this.canvas || !this.groupObjectId) return;
this.activeLayer = this.layerManager.getActiveLayer();
try {
await optimizeCanvasRendering(this.canvas, async () => {
if (this.wasGroupCreated) {
// 如果是新创建的组,完全撤销到原始状态
this._undoNewGroupCreation();
} else {
// 如果是向现有组添加对象,只移除新添加的对象
this._undoAddToExistingGroup();
}
await this.layerManager?.updateLayersObjectsInteractivity?.(false);
// 更新缩略图
this._updateThumbnail();
});
// 重置为首次执行状态,以便重做时能正确恢复位置
this.isFirstExecution = false;
console.log(`↩️ 成功撤销图层 ${this.activeLayer.name} 的对象组合操作`);
} catch (error) {
console.error("撤销组合操作时发生错误:", error);
}
}
/**
* 撤销新组的创建(修正版 - 删除新添加的元素)
* @private
*/
_undoNewGroupCreation() {
// 查找当前的组对象
const groupResult = findObjectById(this.canvas, this.groupObjectId);
if (!groupResult.object) {
console.error("找不到要撤销的组对象");
return;
}
const groupObject = groupResult.object;
// 获取组内的所有对象
const groupObjects = groupObject.getObjects();
if (groupObjects.length === 0) {
console.warn("组对象为空,直接移除");
this.canvas.remove(groupObject);
return;
}
// 分离原始对象和新添加的对象
const objectsToRestore = [];
const objectsToDelete = [];
groupObjects.forEach((obj) => {
if (this.originalObjectIds.includes(obj.id)) {
// 这是原始对象,需要恢复
const originalPosition = this.originalObjectPositions.get(obj.id);
let restorePosition;
if (originalPosition) {
// 优先使用原始保存的位置
restorePosition = { ...originalPosition };
} else {
// 计算对象在画布中的当前绝对位置
restorePosition = this._calculateObjectAbsolutePosition(
obj,
groupObject
);
}
objectsToRestore.push({
object: obj,
position: restorePosition,
});
} else if (this.addedObjectIds.includes(obj.id)) {
// 这是新添加的对象,需要删除
objectsToDelete.push(obj);
}
});
// 从画布中移除组对象
this.canvas.remove(groupObject);
// 禁用渲染以提高性能
const wasRenderOnAddRemove = this.canvas.renderOnAddRemove;
this.canvas.renderOnAddRemove = false;
try {
// 逐个恢复原始对象到画布
const restoredObjects = [];
objectsToRestore.forEach(({ object: obj, position }) => {
try {
// 从组中移除对象(这会重置对象的变换状态)
groupObject.removeWithUpdate(obj);
// 重新设置对象的位置和属性
obj.set({
left: position.left,
top: position.top,
scaleX: position.scaleX || 1,
scaleY: position.scaleY || 1,
angle: position.angle || 0,
flipX: position.flipX || false,
flipY: position.flipY || false,
originX: position.originX || "center",
originY: position.originY || "center",
layerId: this.activeLayer.id,
layerName: this.activeLayer.name,
selectable: true,
evented: true,
opacity: position.opacity || 1,
});
// 更新对象坐标
obj.setCoords();
// 将对象添加回画布
this.canvas.add(obj);
restoredObjects.push(obj.toObject("id", "layerId", "layerName"));
console.log(
`✅ 恢复原始对象 ${obj.id || obj.type} 到位置 (${position.left}, ${
position.top
})`
);
} catch (error) {
console.error(`恢复对象 ${obj.id || obj.type} 时发生错误:`, error);
}
});
// 删除新添加的对象(不添加回画布)
objectsToDelete.forEach((obj) => {
try {
// 从组中移除对象
groupObject.removeWithUpdate(obj);
// 销毁对象以释放内存
if (typeof obj.destroy === "function") {
obj.destroy();
}
console.log(`🗑️ 删除新添加的对象 ${obj.id || obj.type}`);
} catch (error) {
console.error(`删除对象 ${obj.id || obj.type} 时发生错误:`, error);
}
});
// 更新图层对象列表(只包含恢复的原始对象)
this.activeLayer.fabricObjects = restoredObjects;
// 销毁组对象释放内存
if (typeof groupObject.destroy === "function") {
groupObject.destroy();
}
console.log(
`✅ 成功撤销组创建,恢复了 ${restoredObjects.length} 个原始对象,删除了 ${objectsToDelete.length} 个新对象`
);
} catch (error) {
console.error("撤销组创建过程中发生错误:", error);
} finally {
// 恢复渲染设置
this.canvas.renderOnAddRemove = wasRenderOnAddRemove;
this.canvas.renderAll();
}
}
/**
* 计算对象在画布中的绝对位置(改进版)
* @param {fabric.Object} obj 组内对象
* @param {fabric.Group} group 组对象
* @returns {Object} 绝对位置信息
* @private
*/
_calculateObjectAbsolutePosition(obj, group) {
try {
// 获取组的变换矩阵
const groupTransform = group.calcTransformMatrix();
// 获取对象在组内的相对位置
const objectPoint = new fabric.Point(obj.left || 0, obj.top || 0);
// 应用组的变换矩阵计算绝对位置
const absolutePoint = fabric.util.transformPoint(
objectPoint,
groupTransform
);
// 计算缩放比例
const totalScaleX = (group.scaleX || 1) * (obj.scaleX || 1);
const totalScaleY = (group.scaleY || 1) * (obj.scaleY || 1);
// 计算总旋转角度
const totalAngle = (group.angle || 0) + (obj.angle || 0);
return {
left: absolutePoint.x,
top: absolutePoint.y,
scaleX: totalScaleX,
scaleY: totalScaleY,
angle: totalAngle,
flipX: obj.flipX || false,
flipY: obj.flipY || false,
originX: obj.originX || "center",
originY: obj.originY || "center",
opacity: obj.opacity || 1,
};
} catch (error) {
console.warn("使用变换矩阵计算位置失败,使用简化计算:", error);
// 备选方案:基于组的中心点和对象的相对偏移计算
const groupCenterX = group.left || 0;
const groupCenterY = group.top || 0;
// 考虑组的缩放和旋转影响
const scaleX = group.scaleX || 1;
const scaleY = group.scaleY || 1;
const angle = group.angle || 0;
// 计算对象相对于组中心的偏移
const offsetX = (obj.left || 0) * scaleX;
const offsetY = (obj.top || 0) * scaleY;
// 如果组有旋转,需要旋转偏移量
let finalX = groupCenterX + offsetX;
let finalY = groupCenterY + offsetY;
if (angle !== 0) {
const cos = Math.cos(fabric.util.degreesToRadians(angle));
const sin = Math.sin(fabric.util.degreesToRadians(angle));
finalX = groupCenterX + offsetX * cos - offsetY * sin;
finalY = groupCenterY + offsetX * sin + offsetY * cos;
}
return {
left: finalX,
top: finalY,
scaleX: scaleX * (obj.scaleX || 1),
scaleY: scaleY * (obj.scaleY || 1),
angle: angle + (obj.angle || 0),
flipX: obj.flipX || false,
flipY: obj.flipY || false,
originX: obj.originX || "center",
originY: obj.originY || "center",
opacity: obj.opacity || 1,
};
}
}
/**
* 撤销向现有组添加对象的操作(优化版)
* @private
*/
_undoAddToExistingGroup() {
// 查找现有的组对象
const groupResult = findObjectById(this.canvas, this.existingGroupId);
if (!groupResult.object) {
console.error("找不到现有的组对象");
return;
}
const existingGroup = groupResult.object;
// 移除新添加的对象
for (const objectId of this.addedObjectIds) {
const objResult = objectIsInCanvas(this.canvas, { id: objectId });
if (objResult.flag && objResult.parent === existingGroup) {
// 对象在组中,使用 removeWithUpdate 移除
existingGroup.removeWithUpdate(objResult.object);
// 从画布中完全移除这个对象
if (this.canvas.getObjects().includes(objResult.object)) {
this.canvas.remove(objResult.object);
}
}
}
// 检查组的状态
const remainingObjects = existingGroup.getObjects();
if (remainingObjects.length === 0) {
// 组为空,移除组
this.canvas.remove(existingGroup);
const groupIndex = this.activeLayer.fabricObjects.indexOf(existingGroup);
if (groupIndex !== -1) {
this.activeLayer.fabricObjects.splice(groupIndex, 1);
}
} else if (remainingObjects.length === 1) {
// 只剩一个对象,解散组
const singleObj = remainingObjects[0];
// 从画布移除组
this.canvas.remove(existingGroup);
// 使用 removeWithUpdate 移除最后一个对象(会自动添加到画布)
existingGroup.removeWithUpdate(singleObj);
// 重新设置对象属性
singleObj.set({
layerId: this.activeLayer.id,
layerName: this.activeLayer.name,
});
// 更新图层对象列表
const groupIndex = this.activeLayer.fabricObjects.indexOf(existingGroup);
if (groupIndex !== -1) {
this.activeLayer.fabricObjects[groupIndex] = singleObj;
}
}
}
/**
* 更新缩略图
* @private
*/
_updateThumbnail() {
this.canvas?.thumbnailManager?.generateLayerThumbnail?.(
this.activeLayer.id
);
}
getInfo() {
return {
name: this.name,
layerId: this.activeLayer?.id,
layerName: this.activeLayer?.name || "未知图层",
originalObjectCount: this.originalObjectIds.length,
addedObjectsCount: this.addedObjectIds.length,
groupId: this.groupObjectId,
wasGroupCreated: this.wasGroupCreated,
};
}
}
/**
* 创建图片图层复合命令
* 包含创建图层、添加对象到图层、切换工具等操作的复合命令
*/
export class CreateImageLayerCommand extends Command {
constructor(options) {
super({
name: "创建图片图层",
saveState: true,
});
this.layerManager = options.layerManager;
this.fabricImage = options.fabricImage;
this.toolManager = options.toolManager;
this.layerName = options.layerName || null;
this.imageId = generateId("image_");
// 存储执行过程中的结果
this.newLayerId =
generateId("layer_image_") ||
`layer_image_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
this.commands = [];
this.executedCommands = [];
}
async execute() {
if (!this.layerManager || !this.fabricImage) {
throw new Error("图层管理器或图片对象无效");
}
try {
this.commands = [];
this.executedCommands = [];
// 生成图层名称
const fileName =
this.layerName || `${new Date().toLocaleTimeString()}`;
this.fabricImage.set({
id: this.imageId,
});
// 1. 创建新图层命令
const createLayerCmd = new AddLayerCommand({
canvas: this.layerManager.canvas,
layers: this.layerManager.layers,
newLayer: createLayer({
id: this.newLayerId,
name: fileName,
type: LayerType.BITMAP,
visible: true,
locked: false,
opacity: 1.0,
fabricObjects: [],
}),
activeLayerId: this.layerManager.activeLayerId,
insertIndex: this.layerManager._getInsertIndexAboveActiveLayer(),
});
// 执行创建图层命令
this.newLayerId = await createLayerCmd.execute();
this.commands.push(createLayerCmd);
this.executedCommands.push(createLayerCmd);
// 新加功能-选区套索内添加图片自动居中
const { parent } = findLayerRecursively(this.layerManager.layers.value, this.newLayerId);
if(parent && parent.selectObject){
let {top,left,width,height} = parent.selectObject;
const ltop = top + height / 2;
const lleft = left + width / 2;
this.fabricImage.set({
top: ltop,
left: lleft,
})
}
// 2. 添加图片对象到图层命令
const addObjectCmd = new AddObjectToLayerCommand({
canvas: this.layerManager.canvas,
layers: this.layerManager.layers,
layerManager: this.layerManager,
layerId: this.newLayerId,
layerName: this.layerName,
fabricObject: this.fabricImage,
});
// 执行添加对象命令
await addObjectCmd.execute();
this.commands.push(addObjectCmd);
this.executedCommands.push(addObjectCmd);
// 3. 切换工具到选择模式命令
if (this.toolManager) {
const toolCmd = new ToolCommand({
toolManager: this.toolManager,
tool: OperationType.SELECT,
previousTool: this.toolManager.getCurrentTool(),
});
// 执行工具切换命令
await toolCmd.execute();
this.commands.push(toolCmd);
this.executedCommands.push(toolCmd);
}
console.log(`✅ 创建图片图层完成: ${fileName}, ID: ${this.newLayerId}`);
return this.newLayerId;
} catch (error) {
console.error("创建图片图层失败:", error);
// 回滚已执行的命令
await this._rollbackExecutedCommands();
throw error;
}
}
async undo() {
if (this.executedCommands.length === 0) {
console.warn("没有已执行的命令需要撤销");
return true;
}
console.log(
`↩️ 开始撤销创建图片图层操作,共 ${this.executedCommands.length} 个子命令`
);
try {
// 逆序撤销已执行的命令
const commands = [...this.executedCommands].reverse();
for (const command of commands) {
if (typeof command.undo === "function") {
try {
console.log(`↩️ 撤销子命令: ${command.constructor.name}`);
const result = command.undo();
if (this._isPromise(result)) {
await result;
}
console.log(`✅ 子命令撤销成功: ${command.constructor.name}`);
} catch (error) {
console.error(
`❌ 子命令撤销失败: ${command.constructor.name}`,
error
);
}
}
}
this.executedCommands = [];
console.log(`✅ 创建图片图层撤销完成`);
return true;
} catch (error) {
console.error("❌ 撤销创建图片图层过程中发生错误:", error);
throw error;
}
}
/**
* 回滚已执行的命令(内部使用)
* @private
*/
async _rollbackExecutedCommands() {
console.log(`🔄 开始回滚已执行的 ${this.executedCommands.length} 个子命令`);
const commands = [...this.executedCommands].reverse();
for (const command of commands) {
if (typeof command.undo === "function") {
try {
console.log(`🔄 回滚子命令: ${command.constructor.name}`);
const result = command.undo();
if (this._isPromise(result)) {
await result;
}
console.log(`✅ 子命令回滚成功: ${command.constructor.name}`);
} catch (error) {
console.error(
`❌ 子命令回滚失败: ${command.constructor.name}`,
error
);
}
}
}
this.executedCommands = [];
console.log(`✅ 回滚完成`);
}
/**
* 检查返回值是否为Promise
* @private
*/
_isPromise(value) {
return (
value &&
typeof value === "object" &&
typeof value.then === "function" &&
typeof value.catch === "function"
);
}
getInfo() {
return {
name: this.name,
layerName: this.layerName,
layerId: this.newLayerId,
commandCount: this.commands.length,
executedCount: this.executedCommands.length,
};
}
}
/**
* 拖拽排序图层命令
*/
export class ReorderLayersCommand extends Command {
constructor(options) {
super({
name: "拖拽排序图层",
saveState: true,
});
this.layers = options.layers;
this.oldIndex = options.oldIndex;
this.newIndex = options.newIndex;
this.layerId = options.layerId;
this.canvas = options.canvas;
this.layerSort = options.layerSort || null; // LayerSort实例
}
async execute() {
// 验证索引有效性
if (
this.oldIndex < 0 ||
this.newIndex < 0 ||
this.oldIndex >= this.layers.value.length ||
this.newIndex >= this.layers.value.length ||
this.oldIndex === this.newIndex
) {
return false;
}
// 验证图层ID
const layer = this.layers.value[this.oldIndex];
if (!layer || layer.id !== this.layerId) {
return false;
}
// 不允许移动背景层和固定层
if (layer.isBackground || layer.isFixed) {
return false;
}
// 执行排序 - 直接操作数组 不重排页面数据
// const layersArray = [...this.layers.value];
// const [movedLayer] = layersArray.splice(this.oldIndex, 1);
// layersArray.splice(this.newIndex, 0, movedLayer);
// this.layers.value = layersArray;
// this.layers.value
// 更新父图层的children数组
this.layers.value[this.oldIndex] = this.layers.value[this.newIndex]; // 确保旧索引位置的图层ID正确
this.layers.value[this.newIndex] = layer; // 确保旧索引位置的图层ID正确
// 使用LayerSort工具重新排列画布对象如果可用
await this.layerSort?.rearrangeObjects();
return true;
}
async undo() {
// 交换索引进行反向操作
const tempOldIndex = this.oldIndex;
this.oldIndex = this.newIndex;
this.newIndex = tempOldIndex;
const result = await this.execute();
// 恢复原始索引
this.newIndex = this.oldIndex;
this.oldIndex = tempOldIndex;
return result;
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
oldIndex: this.oldIndex,
newIndex: this.newIndex,
};
}
}
/**
* 拖拽排序子图层命令
*/
export class ReorderChildLayersCommand extends Command {
constructor(options) {
super({
name: "拖拽排序子图层",
saveState: true,
});
this.layers = options.layers;
this.parentId = options.parentId;
this.oldIndex = options.oldIndex;
this.newIndex = options.newIndex;
this.layerId = options.layerId;
this.canvas = options.canvas;
this.layerSort = options.layerSort || null; // LayerSort实例
}
async execute() {
// 查找父图层
const parentLayer = this.layers.value.find(
(layer) => layer.id === this.parentId
);
if (!parentLayer) return false;
// 获取子图层
const childLayers = parentLayer?.children || [];
// 验证索引
if (
this.oldIndex < 0 ||
this.newIndex < 0 ||
this.oldIndex >= childLayers.length ||
this.newIndex >= childLayers.length ||
this.oldIndex === this.newIndex
) {
return false;
}
// 验证子图层ID
const layer = childLayers[this.oldIndex];
if (!layer || layer.id !== this.layerId) return false;
// 更新父图层的children数组
parentLayer.children[this.oldIndex] = parentLayer.children[this.newIndex]; // 确保旧索引位置的图层ID正确
parentLayer.children[this.newIndex] = layer; // 确保旧索引位置的图层ID正确
// 使用LayerSort工具重新排列画布对象如果可用
await this.layerSort?.rearrangeObjects();
return true;
}
async undo() {
// 交换索引进行反向操作
const tempOldIndex = this.oldIndex;
this.oldIndex = this.newIndex;
this.newIndex = tempOldIndex;
const result = await this.execute();
// 恢复原始索引
this.newIndex = this.oldIndex;
this.oldIndex = tempOldIndex;
return result;
}
getInfo() {
return {
name: this.name,
parentId: this.parentId,
layerId: this.layerId,
oldIndex: this.oldIndex,
newIndex: this.newIndex,
};
}
}
/**
* 复制图层命令
*/
export class CopyLayerCommand extends Command {
constructor(options) {
super({
name: "复制图层",
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.layerManager = options.layerManager;
this.clipboardData = null;
}
execute() {
const layer = this.layers.value.find((l) => l.id === this.layerId);
if (!layer) {
console.error(`图层 ${this.layerId} 不存在`);
return false;
}
// 不允许复制背景图层
if (layer.isBackground) {
console.warn("不能复制背景图层");
return false;
}
// 序列化图层中的对象
const serializedObjects = [];
if (layer.fabricObjects && layer.fabricObjects.length > 0) {
layer.fabricObjects.forEach((obj) => {
if (obj && typeof obj.toObject === "function") {
serializedObjects.push(obj.toObject(["id", "layerId", "layerName"]));
}
});
}
// 创建剪贴板数据
this.clipboardData = {
...layer,
serializedObjects,
isCut: false,
originalLayerId: layer.id,
};
// 保存到图层管理器的剪贴板
if (this.layerManager) {
this.layerManager.clipboardData = this.clipboardData;
}
console.log(`已复制图层:${layer.name}`);
return true;
}
undo() {
// 复制操作无需撤销,只需清空剪贴板
if (this.layerManager) {
this.layerManager.clipboardData = null;
}
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
};
}
}
/**
* 剪切图层命令
*/
export class CutLayerCommand extends Command {
constructor(options) {
super({
name: "剪切图层",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.activeLayerId = options.activeLayerId;
this.layerManager = options.layerManager;
this.layerIndex = -1;
this.cutLayer = null;
this.clipboardData = null;
this.wasActiveLayer = false;
// 生成新图层ID和名称
this.newLayerId =
generateId("layer_") ||
`layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
}
async execute() {
const { layer, parent } = findLayerRecursively(
this.layers.value,
this.layerId
);
const sourceLayer = layer;
const parentLayer = parent;
if (!sourceLayer) {
console.error(`源图层 ${this.layerId} 不存在`);
return null;
}
// 不允许复制背景图层
if (sourceLayer.isBackground) {
console.warn("不能复制背景图层");
return null;
}
const newName = `${sourceLayer.name} copy`;
// 创建新图层
this.newLayer = createLayer({
id: this.newLayerId,
name: newName,
type: sourceLayer.type,
visible: sourceLayer.visible,
locked: sourceLayer.locked,
opacity: sourceLayer.opacity,
blendMode: sourceLayer.blendMode,
fabricObjects: [],
children: sourceLayer.children ? [...sourceLayer.children] : [],
layerProperties: sourceLayer.layerProperties
? { ...sourceLayer.layerProperties }
: {},
metadata: sourceLayer.metadata ? { ...sourceLayer.metadata } : {},
parentId: parentLayer ? parentLayer.id : undefined, // 保持父图层关系
});
// 计算插入位置 - 区分主图层和子图层
let insertIndex;
if (parentLayer) {
// 处理子图层在父图层的children数组中插入
const sourceChildIndex = parentLayer.children.findIndex(
(child) => child.id === this.layerId
);
insertIndex =
this.insertIndex !== null ? this.insertIndex : sourceChildIndex + 1;
// 插入到父图层的children数组中
parentLayer.children.splice(insertIndex, 0, this.newLayer);
this.isChildLayer = true;
this.parentLayer = parentLayer;
this.childInsertIndex = insertIndex;
} else {
// 处理主图层:在主图层数组中插入
const sourceIndex = this.layers.value.findIndex(
(l) => l.id === this.layerId
);
insertIndex =
this.insertIndex !== null ? this.insertIndex : sourceIndex + 1;
// 插入到主图层数组中
this.layers.value.splice(insertIndex, 0, this.newLayer);
this.isChildLayer = false;
this.mainInsertIndex = insertIndex;
}
// 复制源图层中的对象
if (sourceLayer.fabricObjects && sourceLayer.fabricObjects.length > 0) {
await this._duplicateObjects(sourceLayer.fabricObjects);
}
// 设置为活动图层
this.activeLayerId.value = this.newLayerId;
// 重新渲染画布
await this.layerManager?.updateLayersObjectsInteractivity(false);
console.log(
`已复制图层:${newName} ${this.isChildLayer ? "(子图层)" : "(主图层)"}`
);
return this.newLayerId;
}
async undo() {
if (!this.newLayer) return;
if (this.isChildLayer && this.parentLayer) {
// 撤销子图层从父图层的children数组中删除
const childIndex = this.parentLayer.children.findIndex(
(child) => child.id === this.newLayerId
);
if (childIndex !== -1) {
this.parentLayer.children.splice(childIndex, 1);
}
} else {
// 撤销主图层:从主图层数组中删除
const index = this.layers.value.findIndex(
(l) => l.id === this.newLayerId
);
if (index !== -1) {
this.layers.value.splice(index, 1);
}
}
// 从画布中移除所有创建的对象
this.createdObjects.forEach((obj) => {
this.canvas.remove(obj);
});
// 恢复原活动图层
this.activeLayerId.value = this.layerId;
// 重新渲染画布
await this.layerManager?.updateLayersObjectsInteractivity(false);
}
async _duplicateObjects(sourceObjects) {
const serializedObjects = sourceObjects.map((obj) => {
// 序列化对象时保留必要的属性
const { object } = findObjectById(this.canvas, obj.id);
if (object) return object.toObject(["id", "layerId", "layerName"]);
return obj;
});
return new Promise((resolve) => {
fabric.util.enlivenObjects(serializedObjects, (objects) => {
objects.forEach((obj) => {
// 生成新的对象ID
const newObjId = `obj_${Date.now()}_${Math.floor(
Math.random() * 1000
)}`;
obj.id = newObjId;
obj.layerId = this.newLayerId;
obj.layerName = this.newLayer.name;
// 添加偏移量
const offset = 10;
if (obj.left !== undefined) obj.left += offset;
if (obj.top !== undefined) obj.top += offset;
// 添加到画布
this.canvas.add(obj);
// 添加到新图层
this.newLayer.fabricObjects.push(obj);
// 记录创建的对象
this.createdObjects.push(obj);
});
resolve();
});
});
}
getInfo() {
return {
name: this.name,
sourceLayerId: this.layerId,
newLayerId: this.newLayerId,
newLayerName: this.newLayer?.name,
objectCount: this.createdObjects.length,
isChildLayer: this.isChildLayer,
parentLayerId: this.parentLayer?.id,
};
}
}
/**
* 创建调整图层命令
*/
export class CreateAdjustmentLayerCommand extends Command {
constructor(options) {
super({
name: "创建调整图层",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.activeLayerId = options.activeLayerId;
this.adjustmentType = options.adjustmentType || "brightness";
this.adjustmentValue = options.adjustmentValue || 0;
this.insertIndex = options.insertIndex || null;
this.newLayer = null;
// 生成新图层ID
this.newLayerId =
generateId("adj_layer_") ||
`adj_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
}
execute() {
// 创建调整图层
this.newLayer = createLayer({
id: this.newLayerId,
name: `${this.adjustmentType} 调整`,
type: LayerType.ADJUSTMENT,
visible: true,
locked: false,
opacity: 1.0,
fabricObjects: [],
layerProperties: {
adjustmentType: this.adjustmentType,
value: this.adjustmentValue,
affectedLayerIds: [], // 可以指定受影响的图层
},
});
// 计算插入位置
const insertIndex =
this.insertIndex !== null
? this.insertIndex
: this._getInsertIndexAboveActiveLayer();
// 插入新图层
this.layers.value.splice(insertIndex, 0, this.newLayer);
// 设置为活动图层
this.activeLayerId.value = this.newLayerId;
console.log(`已创建调整图层:${this.newLayer.name}`);
return this.newLayerId;
}
_getInsertIndexAboveActiveLayer() {
const activeIndex = this.layers.value.findIndex(
(layer) => layer.id === this.activeLayerId.value
);
return activeIndex !== -1 ? activeIndex : 0;
}
undo() {
if (!this.newLayer) return;
// 从图层列表中删除调整图层
const index = this.layers.value.findIndex((l) => l.id === this.newLayerId);
if (index !== -1) {
this.layers.value.splice(index, 1);
}
// 恢复原活动图层
// 这里需要记录原来的活动图层ID
}
getInfo() {
return {
name: this.name,
adjustmentType: this.adjustmentType,
adjustmentValue: this.adjustmentValue,
newLayerId: this.newLayerId,
newLayerName: this.newLayer?.name,
};
}
}
/**
* 应用图层样式命令
*/
export class ApplyLayerStyleCommand extends Command {
constructor(options) {
super({
name: "应用图层样式",
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.styleType = options.styleType; // 'shadow', 'glow', 'stroke' etc.
this.styleOptions = options.styleOptions || {};
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
if (!layer) {
console.error(`图层 ${this.layerId} 不存在`);
return;
}
this.layer = layer;
this.oldStyles = this.layer
? { ...(this.layer.layerProperties?.styles || {}) }
: {};
}
execute() {
if (!this.layer) {
console.error(`图层 ${this.layerId} 不存在`);
return false;
}
// 初始化样式属性
if (!this.layer.layerProperties) {
this.layer.layerProperties = {};
}
if (!this.layer.layerProperties.styles) {
this.layer.layerProperties.styles = {};
}
// 应用新样式
this.layer.layerProperties.styles[this.styleType] = this.styleOptions;
// 更新画布上的对象样式
this._applyStyleToObjects();
// 重新渲染画布
this.canvas.renderAll();
console.log(`已应用${this.styleType}样式到图层:${this.layer.name}`);
return true;
}
_applyStyleToObjects() {
if (!this.layer.fabricObjects) return;
this.layer.fabricObjects.forEach((obj) => {
if (!obj) return;
switch (this.styleType) {
case "shadow":
if (this.styleOptions.enabled) {
obj.shadow = new fabric.Shadow({
color: this.styleOptions.color || "rgba(0,0,0,0.5)",
blur: this.styleOptions.blur || 5,
offsetX: this.styleOptions.offsetX || 5,
offsetY: this.styleOptions.offsetY || 5,
});
} else {
obj.shadow = null;
}
break;
case "stroke":
if (this.styleOptions.enabled) {
obj.stroke = this.styleOptions.color || "#000000";
obj.strokeWidth = this.styleOptions.width || 1;
} else {
obj.stroke = null;
obj.strokeWidth = 0;
}
break;
// 可以添加更多样式类型
}
});
}
undo() {
if (!this.layer) return;
// 恢复原样式
if (this.layer.layerProperties && this.layer.layerProperties.styles) {
this.layer.layerProperties.styles = { ...this.oldStyles };
}
// 重新应用所有样式
this._reapplyAllStyles();
// 重新渲染画布
this.canvas.renderAll();
}
_reapplyAllStyles() {
if (!this.layer.fabricObjects) return;
this.layer.fabricObjects.forEach((obj) => {
if (!obj) return;
// 重置样式
obj.shadow = null;
obj.stroke = null;
obj.strokeWidth = 0;
// 重新应用所有保存的样式
const styles = this.layer.layerProperties?.styles || {};
Object.keys(styles).forEach((styleType) => {
const styleOptions = styles[styleType];
// 这里可以复用 _applyStyleToObjects 中的逻辑
});
});
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
styleType: this.styleType,
styleOptions: this.styleOptions,
};
}
}
/**
* 图层剪贴蒙版命令
*/
export class LayerClippingMaskCommand extends Command {
constructor(options) {
super({
name: "创建/移除剪贴蒙版",
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.maskLayerId = options.maskLayerId || null; // null表示移除蒙版
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
if (!layer) {
console.error(`图层 ${this.layerId} 不存在`);
return;
}
this.layer = layer;
this.oldClippingMask = this.layer ? this.layer.clippingMask : null;
}
execute() {
if (!this.layer) {
console.error(`图层 ${this.layerId} 不存在`);
return false;
}
if (this.maskLayerId) {
// 创建剪贴蒙版
const maskLayer = this.layers.value.find(
(l) => l.id === this.maskLayerId
);
if (!maskLayer) {
console.error(`蒙版图层 ${this.maskLayerId} 不存在`);
return false;
}
this.layer.clippingMask = maskLayer.fabricObjects?.[0] || null;
console.log(`已为图层 ${this.layer.name} 创建剪贴蒙版`);
} else {
// 移除剪贴蒙版
this.layer.clippingMask = null;
console.log(`已移除图层 ${this.layer.name} 的剪贴蒙版`);
}
// 更新画布上的对象
this._updateObjectClipping();
// 重新渲染画布
this.canvas.renderAll();
return true;
}
_updateObjectClipping() {
if (!this.layer.fabricObjects) return;
this.layer.fabricObjects.forEach((obj) => {
if (this.layer.clippingMask) {
// 应用剪贴蒙版
obj.clipPath = this.layer.clippingMask;
} else {
// 移除剪贴蒙版
obj.clipPath = null;
}
});
}
undo() {
if (!this.layer) return;
// 恢复原剪贴蒙版
this.layer.clippingMask = this.oldClippingMask;
// 更新画布上的对象
this._updateObjectClipping();
// 重新渲染画布
this.canvas.renderAll();
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
maskLayerId: this.maskLayerId,
hasClippingMask: !!this.layer?.clippingMask,
};
}
}
/**
* 更换固定图层图像命令
* 专门用于更换固定图层(如背景图层)的图像
*/
export class ChangeFixedImageCommand extends Command {
constructor(options = {}) {
super({
name: "更换固定图层图像",
saveState: true,
});
this.canvas = options.canvas;
this.layerManager = options.layerManager;
this.imageUrl = options.imageUrl;
this.targetLayerType = options.targetLayerType || "fixed"; // 'background', 'fixed', etc.
this.position = options.position || { x: 0, y: 0 };
this.scale = options.scale || { x: 1, y: 1 };
this.preserveTransform = options.preserveTransform ?? false; // 默认不保留变换
// 用于回滚的状态
this.previousImage = null;
this.previousTransform = null;
this.previousObjectId = null; // 保存之前对象的ID
this.targetLayer = null;
this.newObjectId = null; // 保存新对象的ID
this.isExecuted = false;
// 错误处理
this.maxRetries = options.maxRetries || 3;
this.retryCount = 0;
this.timeoutMs = options.timeoutMs || 10000;
}
async execute() {
try {
// 查找目标图层
this.targetLayer = this.findTargetLayer();
if (!this.targetLayer) {
throw new Error(`找不到目标图层类型: ${this.targetLayerType}`);
}
// 保存当前状态
await this.saveCurrentState();
// 加载新图像
const newImage = await this.loadImageWithRetry();
// 应用图像到图层
await this.applyImageToLayer(newImage);
this.isExecuted = true;
return {
success: true,
layerId: this.targetLayer.id,
imageUrl: this.imageUrl,
};
} catch (error) {
console.error("ChangeFixedImageCommand执行失败:", error);
// 如果已经执行了部分操作,尝试回滚
if (this.isExecuted) {
try {
await this.undo();
} catch (rollbackError) {
console.error("回滚失败:", rollbackError);
}
}
throw error;
}
}
async undo() {
if (!this.isExecuted || !this.targetLayer) {
throw new Error("命令未执行或目标图层不存在");
}
try {
await optimizeCanvasRendering(this.canvas, async () => {
if (this.previousImage && this.previousObjectId) {
// 恢复之前的图像
await this.restorePreviousImage();
} else {
// 如果没有之前的图像,移除当前图像
await this.removeCurrentImage();
}
});
this.isExecuted = false;
return {
success: true,
action: "reverted",
layerId: this.targetLayer.id,
};
} catch (error) {
console.error("ChangeFixedImageCommand撤销失败:", error);
throw error;
}
}
findTargetLayer() {
const layers = this.layerManager.layers?.value || [];
switch (this.targetLayerType) {
case "background":
return layers.find((layer) => layer.isBackground);
case "fixed":
return layers.find((layer) => layer.isFixed);
default:
return layers.find((layer) => layer.type === this.targetLayerType);
}
}
async saveCurrentState() {
// 通过画布查找当前图层的对象,而不是直接使用图层引用
const currentObjects = this.canvas
.getObjects()
.filter((obj) => obj.layerId === this.targetLayer.id);
if (currentObjects.length > 0) {
const currentObj = currentObjects[0]; // 固定图层通常只有一个对象
// 验证对象确实在画布中
const canvasCheck = objectIsInCanvas(this.canvas, currentObj);
if (!canvasCheck.flag) {
console.warn("图层对象不在画布中,跳过状态保存");
return;
}
this.previousObjectId = currentObj.id;
// 使用帮助函数获取z-index位置
this.previousZIndex = getObjectZIndex(this.canvas, currentObj);
// 保存当前图像URL如果存在
this.previousImage = {
url: currentObj.getSrc ? currentObj.getSrc() : null,
element: currentObj._element ? currentObj._element.cloneNode() : null,
objectData: currentObj.toObject(["id", "layerId", "layerName"]), // 保存完整对象数据
zIndex: this.previousZIndex, // 保存z-index
};
// 保存变换状态
this.previousTransform = {
left: currentObj.left,
top: currentObj.top,
scaleX: currentObj.scaleX,
scaleY: currentObj.scaleY,
angle: currentObj.angle,
flipX: currentObj.flipX,
flipY: currentObj.flipY,
opacity: currentObj.opacity,
};
// console.log(`保存渲染顺序: z-index = ${this.previousZIndex}`);
}
}
async loadImageWithRetry() {
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
try {
return await this.loadImage();
} catch (error) {
this.retryCount = attempt;
if (attempt === this.maxRetries) {
throw new Error(
`图像加载失败,已重试${this.maxRetries}次: ${error.message}`
);
}
// 指数退避重试
const delay = Math.pow(2, attempt) * 1000;
await new Promise((resolve) => setTimeout(resolve, delay));
console.warn(
`图像加载重试 ${attempt + 1}/${this.maxRetries}:`,
error.message
);
}
}
}
loadImage() {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(
new Error(`图像加载超时 (${this.timeoutMs}ms): ${this.imageUrl}`)
);
}, this.timeoutMs);
fabric.Image.fromURL(
this.imageUrl,
(img) => {
clearTimeout(timeout);
if (!img || !img.getElement()) {
reject(new Error("图像加载失败或无效"));
return;
}
resolve(img);
},
{
crossOrigin: "anonymous",
}
);
});
}
async applyImageToLayer(newImage) {
await optimizeCanvasRendering(this.canvas, async () => {
// 生成新对象ID
this.newObjectId = generateId();
// 设置基本属性
newImage.set({
id: this.newObjectId,
layerId: this.targetLayer.id,
layerName: this.targetLayer.name,
isBackground: this.targetLayer.isBackground,
isFixed: this.targetLayer.isFixed,
});
// 移除旧对象(如果存在)
if (this.previousObjectId) {
const { object: oldObject } = findObjectById(
this.canvas,
this.previousObjectId
);
if (oldObject) {
const removeSuccess = removeCanvasObjectByObject(
this.canvas,
oldObject
);
if (!removeSuccess) {
console.warn("移除旧对象失败,但继续执行");
}
}
}
// 应用位置和变换
if (this.preserveTransform && this.previousTransform) {
newImage.set(this.previousTransform);
} else {
newImage.set({
left: this.position.x || this.canvas.width / 2,
top: this.position.y || this.canvas.height / 2,
scaleX: this.scale.x || 1,
scaleY: this.scale.y || 1,
originX: "center",
originY: "center",
});
}
// 使用帮助函数在指定z-index位置插入新图像
if (this.previousZIndex !== undefined && this.previousZIndex >= 0) {
const insertSuccess = insertObjectAtZIndex(
this.canvas,
newImage,
this.previousZIndex,
false
);
if (insertSuccess) {
// console.log(`新图像插入到z-index位置: ${this.previousZIndex}`);
} else {
// 如果插入失败,回退到普通添加
this.canvas.add(newImage);
console.log("z-index插入失败新图像添加到顶层");
}
} else {
// 否则直接添加到顶层
this.canvas.add(newImage);
console.log("新图像添加到顶层");
}
newImage.setCoords();
// 更新图层引用
// 更新图层管理器
this.layerManager.updateLayerObject(this.targetLayer.id, newImage);
});
}
async restorePreviousImage() {
if (!this.previousImage?.objectData) {
throw new Error("没有可恢复的图像数据");
}
return new Promise((resolve, reject) => {
fabric.util.enlivenObjects(
[this.previousImage.objectData],
async (objects) => {
try {
const restoredImage = objects[0];
await optimizeCanvasRendering(this.canvas, async () => {
// 移除当前对象
if (this.newObjectId) {
const { object: currentObject } = findObjectById(
this.canvas,
this.newObjectId
);
if (currentObject) {
removeCanvasObjectByObject(this.canvas, currentObject);
}
}
// 恢复之前的变换
if (this.previousTransform) {
restoredImage.set(this.previousTransform);
}
// 设置图层属性
restoredImage.set({
id: this.previousObjectId,
layerId: this.targetLayer.id,
layerName: this.targetLayer.name,
isBackground: this.targetLayer.isBackground,
isFixed: this.targetLayer.isFixed,
});
// 使用帮助函数在正确的z-index位置恢复对象
if (
this.previousZIndex !== undefined &&
this.previousZIndex >= 0
) {
const insertSuccess = insertObjectAtZIndex(
this.canvas,
restoredImage,
this.previousZIndex,
false
);
if (insertSuccess) {
console.log(`恢复图像到z-index位置: ${this.previousZIndex}`);
} else {
// 如果插入失败,回退到普通添加
this.canvas.add(restoredImage);
console.log("z-index恢复失败恢复图像添加到顶层");
}
} else {
// 如果没有保存的z-index添加到顶层
this.canvas.add(restoredImage);
console.log("恢复图像添加到顶层");
}
restoredImage.setCoords();
// 更新引用
this.targetLayer.fabricObject = restoredImage.toObject([
"id",
"layerId",
"type",
]);
this.layerManager.updateLayerObject(
this.targetLayer.id,
restoredImage
);
});
resolve();
} catch (error) {
reject(error);
}
}
);
});
}
async removeCurrentImage() {
await optimizeCanvasRendering(this.canvas, async () => {
if (this.newObjectId) {
const { object: currentObject } = findObjectById(
this.canvas,
this.newObjectId
);
if (currentObject) {
const removeSuccess = removeCanvasObjectByObject(
this.canvas,
currentObject
);
if (removeSuccess) {
this.targetLayer.fabricObject = null;
this.layerManager.updateLayerObject(this.targetLayer.id, null);
}
}
}
});
}
getInfo() {
return {
name: this.name,
targetLayerType: this.targetLayerType,
imageUrl: this.imageUrl,
isExecuted: this.isExecuted,
retryCount: this.retryCount,
targetLayerId: this.targetLayer?.id,
preserveTransform: this.preserveTransform,
};
}
}
/**
* 向图层添加图像命令
* 用于向指定图层添加新的图像对象
*/
export class AddImageToLayerCommand extends Command {
constructor(options = {}) {
super({
name: "向图层添加图像",
saveState: true,
});
this.canvas = options.canvas;
this.layerManager = options.layerManager;
this.imageUrl = options.imageUrl;
this.layerId = options.layerId;
this.position = options.position || { x: 100, y: 100 };
this.scale = options.scale || { x: 1, y: 1 };
this.zIndex = options.zIndex || null; // 可选的层级控制
// 用于回滚的状态
this.addedObject = null;
this.targetLayer = null;
this.isExecuted = false;
// 错误处理
this.maxRetries = options.maxRetries || 3;
this.retryCount = 0;
this.timeoutMs = options.timeoutMs || 10000;
}
async execute() {
try {
this.validateInputs();
// 查找目标图层
const { layer } = findLayerRecursively(
this.layerManager?.layers?.value || [],
this.layerId
);
this.targetLayer = layer;
if (!this.targetLayer) {
throw new Error(`找不到目标图层: ${this.layerId}`);
}
// 检查图层是否可编辑
this.validateLayerEditability();
// 加载新图像
const newImage = await this.loadImageWithRetry();
// 添加图像到图层
await this.addImageToLayer(newImage);
this.isExecuted = true;
// 触发成功事件
this.emitEvent("image:added", {
layerId: this.layerId,
objectId: this.addedObject.id,
imageUrl: this.imageUrl,
command: this,
});
return {
success: true,
layerId: this.layerId,
objectId: this.addedObject.id,
imageUrl: this.imageUrl,
};
} catch (error) {
console.error("AddImageToLayerCommand执行失败:", error);
// 如果已经添加了对象,尝试移除
if (this.addedObject) {
try {
await this.undo();
} catch (rollbackError) {
console.error("回滚失败:", rollbackError);
}
}
throw error;
}
}
async undo() {
if (!this.isExecuted || !this.addedObject) {
throw new Error("命令未执行或没有添加的对象");
}
try {
// 移除添加的对象
this.canvas.remove(this.addedObject);
// 从图层管理器中移除
this.layerManager.removeObjectFromLayer(
this.addedObject.id,
this.layerId
);
this.isExecuted = false;
// 触发撤销事件
this.emitEvent("image:removed", {
layerId: this.layerId,
objectId: this.addedObject.id,
command: this,
});
// 重新渲染
this.canvas.renderAll();
return {
success: true,
action: "removed",
layerId: this.layerId,
objectId: this.addedObject.id,
};
} catch (error) {
console.error("AddImageToLayerCommand撤销失败:", error);
throw error;
}
}
validateInputs() {
if (!this.canvas) throw new Error("Canvas实例是必需的");
if (!this.layerManager) throw new Error("LayerManager实例是必需的");
if (!this.imageUrl) throw new Error("图像URL是必需的");
if (!this.layerId) throw new Error("图层ID是必需的");
// 验证URL格式
try {
new URL(this.imageUrl);
} catch {
throw new Error("无效的图像URL格式");
}
}
findTargetLayer() {
const layers = this.layerManager.layers?.value || [];
return layers.find((layer) => layer.id === this.layerId);
}
validateLayerEditability() {
if (this.targetLayer.locked) {
throw new Error("目标图层已锁定,无法添加对象");
}
if (!this.targetLayer.visible) {
console.warn("目标图层不可见,添加的对象可能不会显示");
}
}
async loadImageWithRetry() {
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
try {
return await this.loadImage();
} catch (error) {
this.retryCount = attempt;
if (attempt === this.maxRetries) {
throw new Error(
`图像加载失败,已重试${this.maxRetries}次: ${error.message}`
);
}
// 指数退避重试
const delay = Math.pow(2, attempt) * 1000;
await new Promise((resolve) => setTimeout(resolve, delay));
console.warn(
`图像加载重试 ${attempt + 1}/${this.maxRetries}:`,
error.message
);
}
}
}
loadImage() {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(
new Error(`图像加载超时 (${this.timeoutMs}ms): ${this.imageUrl}`)
);
}, this.timeoutMs);
fabric.Image.fromURL(
this.imageUrl,
(img) => {
clearTimeout(timeout);
if (!img || !img.getElement()) {
reject(new Error("图像加载失败或无效"));
return;
}
resolve(img);
},
{
crossOrigin: "anonymous",
}
);
});
}
async addImageToLayer(newImage) {
// 生成唯一ID
const objectId = generateId();
// 设置图像属性
newImage.set({
id: objectId,
layerId: this.layerId,
layerName: this.targetLayer.name,
left: this.position.x,
top: this.position.y,
scaleX: this.scale.x,
scaleY: this.scale.y,
selectable: true,
evented: true,
});
// 添加到画布
this.canvas.add(newImage);
// 设置层级
if (this.zIndex !== null) {
this.setObjectZIndex(newImage, this.zIndex);
}
newImage.setCoords();
// 保存引用用于回滚
this.addedObject = newImage;
// 添加到图层管理器
this.layerManager.addObjectToLayer(newImage, this.layerId);
// 重新渲染画布
this.canvas.renderAll();
}
setObjectZIndex(object, zIndex) {
if (zIndex === "top") {
object.bringToFront();
} else if (zIndex === "bottom") {
object.sendToBack();
} else if (typeof zIndex === "number") {
object.moveTo(zIndex);
}
}
emitEvent(eventName, data) {
if (this.canvas && this.canvas.fire) {
this.canvas.fire(eventName, data);
}
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
imageUrl: this.imageUrl,
position: this.position,
scale: this.scale,
isExecuted: this.isExecuted,
retryCount: this.retryCount,
addedObjectId: this.addedObject?.id,
};
}
}
/**
* 删除子图层命令
*/
export class RemoveChildLayerCommand extends Command {
constructor(options) {
super({
name: "删除子图层",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.parentId = options.parentId;
this.activeLayerId = options.activeLayerId;
this.layerManager = options.layerManager;
// 查找父图层和子图层
const { parent } = findLayerRecursively(this.layers.value, this.layerId);
this.parentLayer = parent;
this.childIndex =
this.parentLayer?.children?.findIndex(
(child) => child.id === this.layerId
) ?? -1;
this.removedChild = this.parentLayer?.children?.[this.childIndex];
this.isActiveLayer = this.layerId === this.activeLayerId.value;
this.originalObjects = this.canvas.getObjects().filter((obj) => {
obj.parentId = this.parentId;
return obj.layerId === this.layerId;
});
}
async execute() {
if (!this.parentLayer || this.childIndex === -1 || !this.removedChild) {
throw new Error("找不到要删除的子图层");
}
// 从画布中移除子图层中的所有对象
if (
this.removedChild.fabricObjects &&
this.removedChild.fabricObjects.length > 0
) {
this.removedChild.fabricObjects.forEach((obj) => {
const { object } = findObjectById(this.canvas, obj.id);
if (object) {
this.canvas.remove(...this.originalObjects);
}
});
}
// 从父图层的children中删除
this.parentLayer.children.splice(this.childIndex, 1);
// 如果删除的是当前活动图层,需要更新活动图层
if (this.isActiveLayer) {
// 设置父图层为活动图层,或者选择另一个子图层
if (this.parentLayer.children.length > 0) {
this.activeLayerId.value = this.parentLayer.children[0].id;
} else {
this.activeLayerId.value =
this.layers.value.find(
(layer) => !layer.isBackground || !layer.isFixed
)?.[0]?.id || null;
}
}
// 重新渲染画布
await this.layerManager?.updateLayersObjectsInteractivity();
return true;
}
async undo() {
if (
!this.parentLayer ||
this.childIndex === -1 ||
!this.removedChild ||
this.originalObjects.length === 0
) {
return;
}
// 恢复子图层到原位置
this.parentLayer.children.splice(this.childIndex, 0, this.removedChild);
await new Promise((resolve) => {
optimizeCanvasRendering(this.canvas, async () => {
this.originalObjects.forEach((obj) => {
// 恢复对象到画布
this.canvas.add(obj);
// 恢复对象的图层信息
obj.layerId = this.layerId;
obj.layerName = this.removedChild.name;
obj.setCoords(); // 更新坐标
});
// 如果是原活动图层,恢复活动图层
if (this.isActiveLayer) {
this.activeLayerId.value = this.layerId;
}
// 重新渲染画布
await this.layerManager?.updateLayersObjectsInteractivity(false);
resolve(true);
});
});
return true;
}
getInfo() {
return {
name: this.name,
layerName: this.removedChild?.name || "未知子图层",
layerId: this.layerId,
parentId: this.parentId,
};
}
}
/**
* 重命名子图层命令
*/
export class RenameChildLayerCommand extends Command {
constructor(options) {
super({
name: "重命名子图层",
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.parentId = options.parentId;
this.newName = options.newName;
// 查找父图层和子图层
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
this.childLayer = layer;
this.oldName = this.childLayer ? this.childLayer.name : null;
}
async execute() {
if (!this.childLayer) {
throw new Error("找不到要重命名的子图层");
}
// 更新子图层名称
this.childLayer.name = this.newName;
// 更新画布上对象的图层名称
if (this.canvas && this.childLayer.fabricObjects) {
this.childLayer.fabricObjects.forEach((obj) => {
if (obj.layerName !== undefined) {
obj.layerName = this.newName;
}
});
}
return true;
}
async undo() {
if (this.childLayer && this.oldName) {
this.childLayer.name = this.oldName;
// 恢复画布上对象的图层名称
if (this.canvas && this.childLayer.fabricObjects) {
this.childLayer.fabricObjects.forEach((obj) => {
if (obj.layerName !== undefined) {
obj.layerName = this.oldName;
}
});
}
}
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
parentId: this.parentId,
oldName: this.oldName,
newName: this.newName,
};
}
}
/**
* 子图层锁定/解锁命令
*/
export class ChildLayerLockCommand extends Command {
constructor(options) {
super({
name: "子图层锁定/解锁",
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.parentId = options.parentId;
this.layerManager = options.layerManager;
// 查找父图层和子图层
const { layer, parent } = findLayerRecursively(
this.layers.value,
this.layerId
);
this.parentLayer = parent;
this.childLayer = layer;
this.oldLocked = this.childLayer ? this.childLayer.locked : null;
}
async execute() {
if (!this.childLayer) {
throw new Error("找不到要锁定/解锁的子图层");
}
// 切换锁定状态
this.childLayer.locked = !this.oldLocked;
// 更新画布上对象的可选择状态
await this.layerManager?.updateLayersObjectsInteractivity();
return true;
}
async undo() {
if (this.childLayer) {
// 恢复锁定状态
this.childLayer.locked = this.oldLocked;
// 更新画布上对象的可选择状态
await this.layerManager?.updateLayersObjectsInteractivity();
}
}
getInfo() {
return {
name: this.name,
layerName: this.childLayer?.name || "未知子图层",
layerId: this.layerId,
parentId: this.parentId,
newLocked: this.childLayer?.locked,
oldLocked: this.oldLocked,
};
}
}
/**
* 设置图层混合模式
*/
export class SetLayerCompositeCommand extends Command {
constructor(options) {
super({
name: "设置图层混合模式",
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerManager = options.layerManager;
this.layerId = options.layerId;
this.newValue = options.newValue;
this.oldValue = options.oldValue;
}
execute(isUndo = false) {
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
const { object } = findObjectByLayerId(this.canvas, this.layerId);
if (!layer || !object) {
console.error(`图层${this.layerId}不存在`);
return false;
}
// console.log("==========", this.newValue, this.oldValue);
const value = isUndo ? this.oldValue : this.newValue;
layer.blendMode = value;
object.set("globalCompositeOperation", value);
this.canvas.renderAll();
const event = isUndo ? "object:composite:undo" : "object:composite:execute";
EventManager.emit(event, object);
return true;
}
undo() {
return this.execute(true);
}
}
/**
* 设置颜色图层颜色
*/
export class SetColorLayerFillCommand extends Command {
constructor(options) {
super({
name: "设置颜色图层颜色",
saveState: false,
});
this.canvas = options.canvas;
this.layerManager = options.layerManager;
this.object = options.object;
this.layer = this.layerManager?.getLayerById(this.object.layerId);
this.newFill = options.newFill;
this.oldFill = JSON.parse(JSON.stringify(this.object.fill));
this.layer.blendMode = "multiply";
this.object.set("globalCompositeOperation", "multiply");
this.object.set("originColor", options.originColor);
}
async execute(isUndo = false) {
if (!this.object) {
console.error(`颜色图层不存在`);
return false;
}
const isVisible = this.layer?.visible;
if(!isVisible && this.layer) this.layer.visible = true;
const gradient = new fabric.Gradient({
type: "linear",
gradientUnits: "percentage",
...(isUndo ? this.oldFill : this.newFill),
});
this.object.setFill(gradient);
this.canvas.renderAll();
await this.canvas?.thumbnailManager?.generateLayerThumbnail?.(
this.object.id
);
if(!isVisible && this.layer) this.layer.visible = false;
this.layerManager?.updateLayersObjectsInteractivity();
return true;
}
undo() {
this.execute(true);
return true;
}
}