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

1533 lines
43 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 { findLayerRecursively, OperationType } from "../utils/layerHelper";
import { Command } from "./Command";
import {
generateId,
optimizeCanvasRendering,
findObjectById,
objectIsInCanvas,
removeCanvasObjectByObject,
getObjectZIndex,
insertObjectAtZIndex,
} from "../utils/helper";
import { fabric } from "fabric-with-all";
import { imageModeHandler } from "../utils/imageHelper";
import { restoreFabricObject } from "../utils/objectHelper";
/**
* 设置活动图层命令
*/
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;
this.parentId = options.parentId;
this.oldActiveLayerId = this.activeLayerId.value;
this.layerManager = options.layerManager;
this.oldActiveObjects = [];
this.newLayer = null;
this.editorMode = options.editorMode;
}
execute() {
const { layer } = findLayerRecursively(
this.layers.value,
this.layerId,
this.parentId
);
this.newLayer = layer;
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;
this.layerManager = options.layerManager;
// 保存对象原始状态和ID
this.objectId =
this.fabricObject.id ||
`obj_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
this.fabricObject.set({
id: this.objectId,
layerId: options.layerId,
layerName: options.layerName || "",
});
// 保存完整的对象状态,包括位置和变换信息
this.originalObjectState = this.fabricObject.toObject([
"id",
"layerId",
"layerName",
]);
// // 新增:保存详细的位置和变换信息,用于重做时恢复
// 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;
}
async execute() {
// 查找目标图层
const { layer, parent } = findLayerRecursively(
this.layers.value,
this.layerId
);
if (!layer) {
console.error(`图层 ${this.layerId} 不存在`);
return null;
}
// 如果是背景层,不允许添加对象
if (layer.isBackground) {
console.warn("不能向背景层添加对象");
return null;
}
console.log(this.originalObjectState);
// 优化渲染 - 统一批处理 支持异步回调
await optimizeCanvasRendering(this.canvas, async () => {
fabric.util.enlivenObjects(
[this.originalObjectState],
async (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, // 设置对象可事件
});
// 如果对象父图层有 裁剪 则更新裁剪
if (parent.clippingMask) {
const clippingMaskFabricObject = await restoreFabricObject(
parent.clippingMask,
this.canvas
);
clippingMaskFabricObject.clipPath = null;
clippingMaskFabricObject.set({ absolutePositioned: true });
this.fabricObject.clipPath = clippingMaskFabricObject;
// 标记为脏对象
this.fabricObject.dirty = true;
this.fabricObject.setCoords();
}
}
);
// this.canvas.renderAll();
this.canvas.add(this.fabricObject);
// this.canvas.setActiveObject(this.fabricObject);
// 将对象添加到图层的fabricObjects数组
layer.fabricObjects = layer.fabricObjects || [];
layer.fabricObjects.push(
this.fabricObject?.toObject?.(["id", "layerId", "layerName"]) ||
this.fabricObject
);
// 标记为非首次执行
this.isFirstExecution = false;
console.log(
`✅ 对象已添加到图层 "${layer.name}",位置: (${this.fabricObject.left}, ${this.fabricObject.top})`
);
});
await this.layerManager?.updateLayersObjectsInteractivity?.();
this.layerManager?.updateLayersObjectsInteractivity?.();
// 如果是重做,使用保存的原始位置
// 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);
// }
// }
return this.fabricObject;
}
async undo() {
// 查找图层
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
if (!layer) {
return false;
}
// 从图层的fabricObjects数组中移除对象
if (layer.fabricObjects) {
layer.fabricObjects = layer.fabricObjects.filter(
(obj) => obj.id !== this.objectId
);
}
// 优化渲染 - 统一批处理 支持异步回调
optimizeCanvasRendering(this.canvas, async () => {
// 从画布移除对象
const object = this.canvas
.getObjects()
.find((obj) => obj.id === this.objectId);
if (object) {
// 先丢弃活动对象,避免控制点渲染错误
this.canvas.discardActiveObject();
this.canvas.remove(object);
}
await this.layerManager?.updateLayersObjectsInteractivity?.(false);
// 重置为首次执行状态,以便重做时能正确恢复位置
this.isFirstExecution = false; // 保持为false因为已经执行过一次了
});
return true;
}
getInfo() {
return {
name: this.name,
layerId: this.layerId,
objectId: this.objectId,
isFirstExecution: this.isFirstExecution,
originalPosition: this.originalPosition,
};
}
}
/**
* 从图层中移除对象命令
*/
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;
}
// 查找图层
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
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;
}
// 查找图层
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
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;
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.options = options || {};
this.scale.x = options.scaleX || 1;
this.scale.y = options.scaleY || 1;
this.position.x = options.left || this.canvas.width / 2;
this.position.y = options.top || this.canvas.height / 2;
this.canvasWidth = options?.canvasWidth?.value || this.canvas.width;
this.canvasHeight = options?.canvasHeight?.value || this.canvas.height;
// 底图加载方式 1.平铺 2.拉伸 3.拉伸平铺 4.拉伸平铺并裁剪 5.包含
this.imageMode = options?.imageMode || ""; // 默认 contains, stretch,tile stretchTile, stretchTileCrop
// 用于回滚的状态
this.previousImage = null;
this.previousTransform = null;
this.previousObjectId = null; // 保存之前对象的ID
this.targetLayer = null;
this.newObjectId = generateId("fixed_"); // 保存新对象的ID
this.isExecuted = false;
// 错误处理
this.maxRetries = options.maxRetries || 3;
this.retryCount = 0;
this.timeoutMs = options.timeoutMs || 10000;
// 查找目标图层
this.targetLayer = this.findTargetLayer();
}
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 () => {
// 设置基本属性
newImage.set({
id: this.targetLayer?.fabricObject?.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: "cehnter",
});
}
// 通用处理图片模式
imageModeHandler({
imageMode: this.imageMode,
newImage,
canvasWidth: this.canvasWidth,
canvasHeight: this.canvasHeight,
});
// 使用帮助函数在指定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.targetLayer.fabricObject = newImage;
// 更新图层管理器
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;
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);
}
}
}
});
}
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.imageId = generateId("image_");
// 错误处理
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}`);
}
// 检查图层是否可编辑
// this.validateLayerEditability();
// 加载新图像
const newImage = await this.loadImageWithRetry();
// 添加图像到图层
await this.addImageToLayer(newImage, this.imageId);
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, objectId) {
// 设置图像属性
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,
};
}
}
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,
};
}
}