Files
aida_front/src/component/Canvas/CanvasEditor/commands/ObjectLayerCommands.js

1540 lines
44 KiB
JavaScript
Raw Normal View History

2025-06-18 11:05:23 +08:00
import { findLayerRecursively, OperationType } from "../utils/layerHelper";
2025-06-09 10:25:54 +08:00
import { Command } from "./Command";
2025-06-18 11:05:23 +08:00
import {
generateId,
optimizeCanvasRendering,
findObjectById,
objectIsInCanvas,
removeCanvasObjectByObject,
getObjectZIndex,
insertObjectAtZIndex,
} from "../utils/helper";
import { fabric } from "fabric-with-all";
2025-06-09 10:25:54 +08:00
/**
* 设置活动图层命令
*/
export class SetActiveLayerCommand extends Command {
constructor(options) {
super({
name: "设置活动图层",
saveState: false,
});
this.layers = options.layers;
this.canvas = options.canvas;
this.activeLayerId = options.activeLayerId;
this.layerId = options.layerId;
2025-06-18 11:05:23 +08:00
this.parentId = options.parentId;
2025-06-09 10:25:54 +08:00
this.oldActiveLayerId = this.activeLayerId.value;
this.layerManager = options.layerManager;
this.oldActiveObjects = [];
this.newLayer = null;
this.editorMode = options.editorMode;
}
execute() {
2025-06-18 11:05:23 +08:00
const { layer } = findLayerRecursively(
this.layers.value,
this.layerId,
this.parentId
2025-06-09 10:25:54 +08:00
);
2025-06-18 11:05:23 +08:00
this.newLayer = layer;
2025-06-09 10:25:54 +08:00
if (!this.newLayer) {
console.error(`图层 ${this.layerId} 不存在`);
return false;
}
// 如果是背景层,不设置为活动图层
if (this.newLayer.isBackground) {
console.warn("背景层不能设为活动图层");
return false;
}
// 如果图层已锁定,不设置为活动图层
if (this.newLayer.locked) {
console.warn("锁定图层不能设为活动图层");
return false;
}
this.oldActiveObjects = this.canvas.getActiveObjects();
// 设置为活动图层
this.activeLayerId.value = this.layerId;
// 如果在选择模式下,取消所有选择
if (this.editorMode === OperationType.SELECT && this.canvas) {
this.canvas.discardActiveObject();
// 设置为新的图层下的对象为激活,但需要确保对象存在于画布上
if (
this.newLayer.fabricObjects &&
this.newLayer.fabricObjects.length > 0
) {
const canvasObjects = this.canvas.getObjects();
const validObjects = this.newLayer.fabricObjects.filter(
(obj) => obj && canvasObjects.includes(obj)
);
if (validObjects.length > 0) {
if (validObjects.length === 1) {
// 只有一个对象时直接设置
this.canvas.setActiveObject(validObjects[0]);
} else {
// 多个对象时创建活动选择组
const activeSelection = new fabric.ActiveSelection(validObjects, {
canvas: this.canvas,
});
this.canvas.setActiveObject(activeSelection);
}
}
}
this.canvas.renderAll();
}
return true;
}
undo() {
// 恢复原活动图层ID
this.activeLayerId.value = this.oldActiveLayerId;
// 如果在选择模式下,恢复取消的所有选择
if (this.editorMode === OperationType.SELECT && this.canvas) {
this.canvas.discardActiveObject();
// 修复:确保对象存在于画布上才激活
if (this.oldActiveObjects && this.oldActiveObjects.length > 0) {
const canvasObjects = this.canvas.getObjects();
const validObjects = this.oldActiveObjects.filter(
(obj) => obj && canvasObjects.includes(obj)
);
if (validObjects.length > 0) {
if (validObjects.length > 1) {
// 如果有多个对象,需要创建一个活动选择组
const activeSelection = new fabric.ActiveSelection(validObjects, {
canvas: this.canvas,
});
this.canvas.setActiveObject(activeSelection);
} else {
// 只有一个对象时直接设置
this.canvas.setActiveObject(validObjects[0]);
}
}
}
this.canvas.renderAll();
}
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
oldActiveLayerId: this.oldActiveLayerId,
};
}
}
/**
* 添加对象到图层命令
*/
export class AddObjectToLayerCommand extends Command {
constructor(options) {
super({
name: "添加对象到图层",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
this.fabricObject = options.fabricObject;
2025-06-18 11:05:23 +08:00
this.layerManager = options.layerManager;
2025-06-09 10:25:54 +08:00
// 保存对象原始状态和ID
this.objectId =
this.fabricObject.id ||
`obj_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
2025-06-18 11:05:23 +08:00
this.fabricObject.set({
id: this.objectId,
layerId: options.layerId,
layerName: options.layerName || "",
});
// 保存完整的对象状态,包括位置和变换信息
2025-06-09 10:25:54 +08:00
this.originalObjectState = this.fabricObject.toObject([
"id",
"layerId",
"layerName",
]);
2025-06-18 11:05:23 +08:00
// // 新增:保存详细的位置和变换信息,用于重做时恢复
// this.originalPosition = {
// left: this.originalObjectState.left || 0,
// top: this.originalObjectState.top || 0,
// scaleX: this.fabricObject.scaleX || 1,
// scaleY: this.fabricObject.scaleY || 1,
// angle: this.fabricObject.angle || 0,
// flipX: this.fabricObject.flipX || false,
// flipY: this.fabricObject.flipY || false,
// opacity: this.fabricObject.opacity || 1,
// originX: this.fabricObject.originX || "left",
// originY: this.fabricObject.originY || "top",
// };
// 记录执行状态,用于区分首次执行和重做
this.isFirstExecution = true;
2025-06-09 10:25:54 +08:00
}
2025-06-18 11:05:23 +08:00
async execute() {
2025-06-09 10:25:54 +08:00
// 查找目标图层
2025-06-18 11:05:23 +08:00
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
2025-06-09 10:25:54 +08:00
if (!layer) {
console.error(`图层 ${this.layerId} 不存在`);
return null;
}
// 如果是背景层,不允许添加对象
if (layer.isBackground) {
console.warn("不能向背景层添加对象");
return null;
}
2025-06-18 11:05:23 +08:00
console.log(this.originalObjectState);
// 优化渲染 - 统一批处理 支持异步回调
await optimizeCanvasRendering(this.canvas, async () => {
// const positionToUse = this.isFirstExecution
// ? {
// left: this.fabricObject.left || 0,
// top: this.fabricObject.top || 0,
// scaleX: this.fabricObject.scaleX || 1,
// scaleY: this.fabricObject.scaleY || 1,
// angle: this.fabricObject.angle || 0,
// flipX: this.fabricObject.flipX || false,
// flipY: this.fabricObject.flipY || false,
// opacity: this.fabricObject.opacity || 1,
// originX: this.fabricObject.originX || "left",
// originY: this.fabricObject.originY || "top",
// }
// : this.originalPosition;
// if (!this.isFirstExecution) {
// fabric.util.enlivenObjects([this.originalObjectState], (objects) => {
// this.fabricObject = objects[0];
// // 将对象添加到画布
// this.fabricObject.set({
// id: this.objectId, // 确保对象有唯一ID
// layerId: this.layerId, // 设置图层ID
// layerName: layer.name, // 设置图层名称
// isBackground: layer.isBackground || false, // 是否为背景层
// isFixed: layer.isFixed || false, // 是否为固定层
// isLocked: layer.locked || false, // 是否锁定
// isVisible: layer.visible !== false, // 是否可见
// eraser: layer.eraser || false, // 是否为橡皮擦
// type: this.fabricObject.type || "object", // 对象类型
// selectable: true, // 设置对象可选择
// evented: true, // 设置对象可事件
// });
// });
// } else {
// // 将对象添加到画布
// this.fabricObject.set({
// ...positionToUse,
// id: this.objectId, // 确保对象有唯一ID
// layerId: this.layerId, // 设置图层ID
// layerName: layer.name, // 设置图层名称
// isBackground: layer.isBackground || false, // 是否为背景层
// isFixed: layer.isFixed || false, // 是否为固定层
// isLocked: layer.locked || false, // 是否锁定
// isVisible: layer.visible !== false, // 是否可见
// eraser: layer.eraser || false, // 是否为橡皮擦
// type: this.fabricObject.type || "object", // 对象类型
// selectable: true, // 设置对象可选择
// evented: true, // 设置对象可事件
// });
// }
fabric.util.enlivenObjects([this.originalObjectState], (objects) => {
this.fabricObject = objects[0];
// 将对象添加到画布
this.fabricObject.set({
id: this.objectId, // 确保对象有唯一ID
layerId: this.layerId, // 设置图层ID
layerName: layer.name, // 设置图层名称
isBackground: layer.isBackground || false, // 是否为背景层
isFixed: layer.isFixed || false, // 是否为固定层
isLocked: layer.locked || false, // 是否锁定
isVisible: layer.visible !== false, // 是否可见
eraser: layer.eraser || false, // 是否为橡皮擦
type: this.fabricObject.type || "object", // 对象类型
selectable: true, // 设置对象可选择
evented: true, // 设置对象可事件
});
});
2025-06-09 10:25:54 +08:00
2025-06-18 11:05:23 +08:00
this.canvas.add(this.fabricObject);
// 将对象添加到图层的fabricObjects数组
layer.fabricObjects = layer.fabricObjects || [];
layer.fabricObjects.push(
this.fabricObject?.toObject?.(["id", "layerId", "layerName"]) ||
this.fabricObject
);
2025-06-09 10:25:54 +08:00
2025-06-18 11:05:23 +08:00
await this.layerManager?.updateLayersObjectsInteractivity?.(false);
// 标记为非首次执行
this.isFirstExecution = false;
console.log(
`✅ 对象已添加到图层 "${layer.name}",位置: (${this.fabricObject.left}, ${this.fabricObject.top})`
);
});
2025-06-09 10:25:54 +08:00
2025-06-18 11:05:23 +08:00
// 如果是重做,使用保存的原始位置
// this.canvas.discardActiveObject();
// // 确保对象确实存在于画布上才激活
// const canvasObjects = this.canvas.getObjects();
// const validObjects = layer.fabricObjects.filter(
// (obj) => obj && canvasObjects.includes(obj)
// );
// if (validObjects.length > 0) {
// if (validObjects.length === 1) {
// // 只有一个对象时直接设置
// this.canvas.setActiveObject(validObjects[0]);
// } else {
// // 多个对象时创建活动选择组
// const activeSelection = new fabric.ActiveSelection(validObjects, {
// canvas: this.canvas,
// });
// this.canvas.setActiveObject(activeSelection);
// }
// }
2025-06-09 10:25:54 +08:00
return this.fabricObject;
}
2025-06-18 11:05:23 +08:00
async undo() {
2025-06-09 10:25:54 +08:00
// 查找图层
2025-06-18 11:05:23 +08:00
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
2025-06-09 10:25:54 +08:00
if (!layer) {
return false;
}
// 从图层的fabricObjects数组中移除对象
if (layer.fabricObjects) {
layer.fabricObjects = layer.fabricObjects.filter(
(obj) => obj.id !== this.objectId
);
}
2025-06-18 11:05:23 +08:00
// 优化渲染 - 统一批处理 支持异步回调
optimizeCanvasRendering(this.canvas, async () => {
// 从画布移除对象
const object = this.canvas
.getObjects()
.find((obj) => obj.id === this.objectId);
if (object) {
// 先丢弃活动对象,避免控制点渲染错误
this.canvas.discardActiveObject();
this.canvas.remove(object);
}
this.layerManager?.updateLayersObjectsInteractivity?.(false);
// 重置为首次执行状态,以便重做时能正确恢复位置
this.isFirstExecution = false; // 保持为false因为已经执行过一次了
});
2025-06-09 10:25:54 +08:00
return true;
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
objectId: this.objectId,
2025-06-18 11:05:23 +08:00
isFirstExecution: this.isFirstExecution,
originalPosition: this.originalPosition,
2025-06-09 10:25:54 +08:00
};
}
}
/**
* 从图层中移除对象命令
*/
export class RemoveObjectFromLayerCommand extends Command {
constructor(options) {
super({
name: "从图层中移除对象",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.objectId = options.objectId;
// 查找对象和图层
this.object =
typeof options.objectOrId === "object"
? options.objectOrId
: this.canvas.getObjects().find((obj) => obj.id === this.objectId);
if (this.object) {
this.layerId = this.object.layerId;
this.objectData = this.object.toObject(["id", "layerId", "layerName"]);
}
}
execute() {
if (!this.object) {
console.error(`对象 ${this.objectId} 不存在`);
return false;
}
if (!this.layerId) {
console.error(`对象 ${this.objectId} 未关联到任何图层`);
return false;
}
// 查找图层
2025-06-18 11:05:23 +08:00
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
2025-06-09 10:25:54 +08:00
if (!layer) {
console.error(`图层 ${this.layerId} 不存在`);
return false;
}
// 从画布移除对象
this.canvas.remove(this.object);
// 从图层的fabricObjects数组移除对象
if (layer.fabricObjects) {
layer.fabricObjects = layer.fabricObjects.filter(
(obj) => obj.id !== this.objectId
);
}
// 更新画布
this.canvas.renderAll();
return true;
}
undo() {
if (!this.objectData || !this.layerId) {
return false;
}
// 查找图层
2025-06-18 11:05:23 +08:00
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
2025-06-09 10:25:54 +08:00
if (!layer) {
return false;
}
// 恢复对象到画布
fabric.util.enlivenObjects([this.objectData], (objects) => {
const restoredObject = objects[0];
// 将对象添加到画布
this.canvas.add(restoredObject);
// 将对象添加回图层
layer.fabricObjects = layer.fabricObjects || [];
layer.fabricObjects.push(restoredObject);
// 更新画布
this.canvas.renderAll();
});
return true;
}
getInfo() {
return {
name: this.name,
objectId: this.objectId,
layerId: this.layerId,
};
}
}
/**
* 更换固定图层图像命令
* 专门用于更换固定图层如背景图层的图像
*/
export class ChangeFixedImageCommand extends Command {
constructor(options = {}) {
super();
this.canvas = options.canvas;
this.layerManager = options.layerManager;
this.imageUrl = options.imageUrl;
2025-06-18 11:05:23 +08:00
this.targetLayerType = options.targetLayerType || "fixed"; // 'background', 'fixed', etc.
2025-06-09 10:25:54 +08:00
this.position = options.position || { x: 0, y: 0 };
this.scale = options.scale || { x: 1, y: 1 };
2025-06-18 11:05:23 +08:00
this.preserveTransform = options.preserveTransform ?? false; // 默认不保留变换
2025-06-09 10:25:54 +08:00
// 用于回滚的状态
this.previousImage = null;
this.previousTransform = null;
2025-06-18 11:05:23 +08:00
this.previousObjectId = null; // 保存之前对象的ID
2025-06-09 10:25:54 +08:00
this.targetLayer = null;
2025-06-18 11:05:23 +08:00
this.newObjectId = null; // 保存新对象的ID
2025-06-09 10:25:54 +08:00
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}`);
}
2025-06-18 11:05:23 +08:00
// 保存当前状态
2025-06-09 10:25:54 +08:00
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 {
2025-06-18 11:05:23 +08:00
await optimizeCanvasRendering(this.canvas, async () => {
if (this.previousImage && this.previousObjectId) {
// 恢复之前的图像
await this.restorePreviousImage();
} else {
// 如果没有之前的图像,移除当前图像
await this.removeCurrentImage();
}
});
2025-06-09 10:25:54 +08:00
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() {
2025-06-18 11:05:23 +08:00
// 通过画布查找当前图层的对象,而不是直接使用图层引用
const currentObjects = this.canvas
.getObjects()
.filter((obj) => obj.layerId === this.targetLayer.id);
2025-06-09 10:25:54 +08:00
2025-06-18 11:05:23 +08:00
if (currentObjects.length > 0) {
const currentObj = currentObjects[0]; // 固定图层通常只有一个对象
2025-06-09 10:25:54 +08:00
2025-06-18 11:05:23 +08:00
// 验证对象确实在画布中
const canvasCheck = objectIsInCanvas(this.canvas, currentObj);
if (!canvasCheck.flag) {
console.warn("图层对象不在画布中,跳过状态保存");
return;
}
2025-06-09 10:25:54 +08:00
2025-06-18 11:05:23 +08:00
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}`);
}
2025-06-09 10:25:54 +08:00
}
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) {
2025-06-18 11:05:23 +08:00
await optimizeCanvasRendering(this.canvas, async () => {
// 生成新对象ID
this.newObjectId = generateId();
2025-06-09 10:25:54 +08:00
2025-06-18 11:05:23 +08:00
// 设置基本属性
2025-06-09 10:25:54 +08:00
newImage.set({
2025-06-18 11:05:23 +08:00
id: this.newObjectId,
layerId: this.targetLayer.id,
layerName: this.targetLayer.name,
isBackground: this.targetLayer.isBackground,
isFixed: this.targetLayer.isFixed,
2025-06-09 10:25:54 +08:00
});
2025-06-18 11:05:23 +08:00
// 移除旧对象(如果存在)
if (this.previousObjectId) {
const { object: oldObject } = findObjectById(
this.canvas,
this.previousObjectId
);
if (oldObject) {
const removeSuccess = removeCanvasObjectByObject(
this.canvas,
oldObject
);
if (!removeSuccess) {
console.warn("移除旧对象失败,但继续执行");
}
}
}
2025-06-09 10:25:54 +08:00
2025-06-18 11:05:23 +08:00
// 应用位置和变换
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: "cehnter",
});
}
2025-06-09 10:25:54 +08:00
2025-06-18 11:05:23 +08:00
// 使用帮助函数在指定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("新图像添加到顶层");
}
2025-06-09 10:25:54 +08:00
2025-06-18 11:05:23 +08:00
newImage.setCoords();
2025-06-09 10:25:54 +08:00
2025-06-18 11:05:23 +08:00
// 更新图层引用
this.targetLayer.fabricObject = newImage;
2025-06-09 10:25:54 +08:00
2025-06-18 11:05:23 +08:00
// 更新图层管理器
this.layerManager.updateLayerObject(this.targetLayer.id, newImage);
2025-06-09 10:25:54 +08:00
});
2025-06-18 11:05:23 +08:00
}
2025-06-09 10:25:54 +08:00
2025-06-18 11:05:23 +08:00
async restorePreviousImage() {
if (!this.previousImage?.objectData) {
throw new Error("没有可恢复的图像数据");
2025-06-09 10:25:54 +08:00
}
2025-06-18 11:05:23 +08:00
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;
this.layerManager.updateLayerObject(
this.targetLayer.id,
restoredImage
);
});
2025-06-09 10:25:54 +08:00
2025-06-18 11:05:23 +08:00
resolve();
} catch (error) {
reject(error);
}
}
);
});
2025-06-09 10:25:54 +08:00
}
async removeCurrentImage() {
2025-06-18 11:05:23 +08:00
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);
2025-06-09 10:25:54 +08:00
}
2025-06-18 11:05:23 +08:00
}
}
2025-06-09 10:25:54 +08:00
});
}
emitEvent(eventName, data) {
if (this.canvas && this.canvas.fire) {
this.canvas.fire(eventName, data);
}
}
// 获取命令信息用于调试
getCommandInfo() {
return {
type: "ChangeFixedImageCommand",
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();
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();
// 查找目标图层
this.targetLayer = this.findTargetLayer();
if (!this.targetLayer) {
throw new Error(`找不到目标图层: ${this.layerId}`);
}
// 检查图层是否可编辑
2025-06-18 11:05:23 +08:00
// this.validateLayerEditability();
2025-06-09 10:25:54 +08:00
// 加载新图像
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);
}
}
// 获取命令信息用于调试
getCommandInfo() {
return {
type: "AddImageToLayerCommand",
layerId: this.layerId,
imageUrl: this.imageUrl,
position: this.position,
scale: this.scale,
isExecuted: this.isExecuted,
retryCount: this.retryCount,
addedObjectId: this.addedObject?.id,
};
}
}
2025-06-18 11:05:23 +08:00
export class SelectAllLayersCommand extends Command {
constructor(options) {
super({
name: "设置全选图层",
saveState: false,
});
this.layers = options.layers;
this.canvas = options.canvas;
this.layerManager = options.layerManager || null;
this.activeLayerId = options.activeLayerId;
this.oldActiveLayerId = this.activeLayerId.value;
this.editorMode = options.editorMode || OperationType.SELECT;
}
execute() {
this.oldActiveObjects = this.canvas.getActiveObjects();
// 如果在选择模式下,取消所有选择
if (this.editorMode === OperationType.SELECT && this.canvas) {
this.canvas.discardActiveObject();
// 设置为新的图层下的对象为激活,但需要确保对象存在于画布上
const canvasObjects =
this.canvas.getObjects()?.filter((fItem) => {
const layerId = fItem.layerId;
if (!layerId) return false; // 忽略没有图层ID的对象
// 确保当前图层存在且可见
const currLayer = this.layers.value.find((l) => l.id === layerId);
return (
!currLayer.isBackground &&
!currLayer.isFixed &&
!currLayer.isLocked &&
!currLayer.isVisible
);
}) || [];
// 多个对象时创建活动选择组
const activeSelection = new fabric.ActiveSelection(canvasObjects, {
canvas: this.canvas,
});
// 设置活动选择组
this.canvas.setActiveObject(activeSelection);
}
this.canvas.renderAll();
return true;
}
undo() {
// 恢复原活动图层ID
this.activeLayerId.value = this.oldActiveLayerId;
// 如果在选择模式下,恢复取消的所有选择
if (this.canvas) {
this.canvas?.discardActiveObject();
// 修复:确保对象存在于画布上才激活
if (this.oldActiveObjects && this.oldActiveObjects.length > 0) {
const canvasObjects = this.canvas.getObjects();
const validObjects = this.oldActiveObjects.filter(
(obj) => obj && canvasObjects.includes(obj)
);
if (validObjects.length > 0) {
if (validObjects.length > 1) {
// 如果有多个对象,需要创建一个活动选择组
const activeSelection = new fabric.ActiveSelection(validObjects, {
canvas: this.canvas,
});
this.canvas.setActiveObject(activeSelection);
} else {
// 只有一个对象时直接设置
this.canvas.setActiveObject(validObjects[0]);
}
}
}
this.canvas.renderAll();
}
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
oldActiveLayerId: this.oldActiveLayerId,
};
}
}
export class ClearSelectionCommand extends Command {
constructor(options) {
super({
name: "设置取消所有图层",
saveState: false,
});
this.layers = options.layers;
this.canvas = options.canvas;
this.layerManager = options.layerManager || null;
this.activeLayerId = options.activeLayerId;
this.oldActiveLayerId = this.activeLayerId.value;
this.editorMode = options.editorMode || OperationType.SELECT;
}
execute() {
this.oldActiveObjects = this.canvas.getActiveObjects();
// 如果在选择模式下,取消所有选择
if (this.editorMode === OperationType.SELECT && this.canvas) {
this.canvas.discardActiveObject();
}
this.canvas.renderAll();
return true;
}
undo() {
// 恢复原活动图层ID
this.activeLayerId.value = this.oldActiveLayerId;
// 如果在选择模式下,恢复取消的所有选择
if (this.canvas) {
this.canvas?.discardActiveObject();
// 修复:确保对象存在于画布上才激活
if (this.oldActiveObjects && this.oldActiveObjects.length > 0) {
const canvasObjects = this.canvas.getObjects();
const validObjects = this.oldActiveObjects.filter(
(obj) => obj && canvasObjects.includes(obj)
);
if (validObjects.length > 0) {
if (validObjects.length > 1) {
// 如果有多个对象,需要创建一个活动选择组
const activeSelection = new fabric.ActiveSelection(validObjects, {
canvas: this.canvas,
});
this.canvas.setActiveObject(activeSelection);
} else {
// 只有一个对象时直接设置
this.canvas.setActiveObject(validObjects[0]);
}
}
}
this.canvas.renderAll();
}
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
oldActiveLayerId: this.oldActiveLayerId,
};
}
}
/**
* 移动图层到顶部命令
*/
export class MoveLayerToTopCommand extends Command {
constructor(options) {
super({
name: "置顶图层",
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
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 = 0;
}
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) {
this.parentLayer?.children?.splice(this.layerIndex, 1);
this.parentLayer?.children?.splice(this.targetIndex, 0, this.layer);
} else {
this.layers.value.splice(this.layerIndex, 1);
this.layers.value.splice(this.targetIndex, 0, this.layer);
}
// 使用LayerSort工具重新排列画布对象如果可用
await this.layerSort?.rearrangeObjects();
console.log(`✅ 图层 ${this.layer.name} 已置顶`);
return true;
}
async undo() {
const tempOldIndex = this.layerIndex;
this.targetIndex = tempOldIndex;
this.layerIndex = this.targetIndex;
await this.execute();
// 执行完成恢复索引
this.layerIndex = tempOldIndex;
this.targetIndex = this.layerIndex;
console.log(`↩️ 图层 ${this.layer.name} 已恢复到原位置`);
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
layerName: this.layer?.name,
originalIndex: this.originalIndex,
targetIndex: this.targetIndex,
};
}
}
/**
* 移动图层到底部命令
*/
export class MoveLayerToBottomCommand extends Command {
constructor(options) {
super({
name: "置底图层",
saveState: false,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId;
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 = this._calculateBottomPosition();
}
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;
}
// 执行移动
this.layers.value.splice(this.layerIndex, 1);
this.layers.value.splice(this.targetIndex, 0, this.layer);
// 更新画布渲染顺序
this.layerSort?.rearrangeObjects?.();
console.log(`✅ 图层 ${this.layer.name} 已置底`);
return true;
}
async undo() {
if (this.originalIndex !== -1 && this.layer) {
// 获取当前位置
const currentIndex = this.layers.value.findIndex(
(layer) => layer.id === this.layerId
);
if (currentIndex !== -1) {
// 移除当前位置
this.layers.value.splice(currentIndex, 1);
// 插入到原位置
this.layers.value.splice(this.originalIndex, 0, this.layer);
// 更新画布渲染顺序
this._rearrangeCanvasObjects();
console.log(`↩️ 图层 ${this.layer.name} 已恢复到原位置`);
}
}
}
/**
* 计算置底的目标位置
* @returns {number} 目标索引
* @private
*/
_calculateBottomPosition() {
// 找到最后一个非背景、非固定图层的位置
for (let i = this.layers.value.length - 1; i >= 0; i--) {
const layer = this.layers.value[i];
if (!layer.isBackground && !layer.isFixed) {
return i;
}
}
return this.layers.value.length - 1;
}
/**
* 重新排列画布对象
* @private
*/
_rearrangeCanvasObjects() {
if (!this.canvas) return;
// 获取画布上的所有对象
const canvasObjects = [...this.canvas.getObjects()];
// 清空画布
this.canvas.clear();
// 按图层顺序(从底到顶)重新添加对象
for (let i = this.layers.value.length - 1; i >= 0; i--) {
const layer = this.layers.value[i];
if (layer.isBackground && layer.fabricObject) {
// 背景图层
const originalObj = canvasObjects.find(
(o) => o.id === layer.fabricObject.id
);
if (originalObj) {
this.canvas.add(originalObj);
}
} else if (
Array.isArray(layer.fabricObjects) &&
layer.fabricObjects.length > 0
) {
// 普通图层和固定图层
layer.fabricObjects.forEach((obj) => {
const originalObj = canvasObjects.find((o) => o.id === obj.id);
if (originalObj) {
this.canvas.add(originalObj);
}
});
}
}
this.canvas.renderAll();
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
layerName: this.layer?.name,
originalIndex: this.originalIndex,
targetIndex: this.targetIndex,
};
}
}