import { OperationType } from "../utils/layerHelper"; import { Command } from "./Command"; import { generateId } from "../utils/helper"; /** * 设置活动图层命令 */ 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.oldActiveLayerId = this.activeLayerId.value; this.layerManager = options.layerManager; this.oldActiveObjects = []; this.newLayer = null; this.editorMode = options.editorMode; } execute() { this.newLayer = this.layers.value.find( (layer) => layer.id === this.layerId ); 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; // 保存对象原始状态和ID this.objectId = this.fabricObject.id || `obj_${Date.now()}_${Math.floor(Math.random() * 1000)}`; this.originalObjectState = this.fabricObject.toObject([ "id", "layerId", "layerName", ]); } execute() { // 查找目标图层 const layer = this.layers.value.find((l) => l.id === this.layerId); if (!layer) { console.error(`图层 ${this.layerId} 不存在`); return null; } // 如果是背景层,不允许添加对象 if (layer.isBackground) { console.warn("不能向背景层添加对象"); return null; } // 为对象生成唯一ID this.fabricObject.id = this.objectId; // 设置对象与图层的关联 this.fabricObject.layerId = this.layerId; this.fabricObject.layerName = layer.name; // 设置对象可操作可选择 this.fabricObject.selectable = true; this.fabricObject.evented = true; // 将对象添加到画布 this.canvas.add(this.fabricObject); // 将对象添加到图层的fabricObjects数组 layer.fabricObjects = layer.fabricObjects || []; layer.fabricObjects.push(this.fabricObject); 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); } } // 更新画布 this.canvas.renderAll(); return this.fabricObject; } undo() { // 查找图层 const layer = this.layers.value.find((l) => l.id === this.layerId); if (!layer) { return false; } // 从图层的fabricObjects数组中移除对象 if (layer.fabricObjects) { layer.fabricObjects = layer.fabricObjects.filter( (obj) => obj.id !== this.objectId ); } // 从画布移除对象 const object = this.canvas .getObjects() .find((obj) => obj.id === this.objectId); if (object) { // 先丢弃活动对象,避免控制点渲染错误 this.canvas.discardActiveObject(); this.canvas.remove(object); // 更新画布 this.canvas.renderAll(); } return true; } getInfo() { return { name: this.name, layerId: this.layerId, objectId: this.objectId, }; } } /** * 从图层中移除对象命令 */ 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 = this.layers.value.find((l) => l.id === 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 = this.layers.value.find((l) => l.id === 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 || "background"; // '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.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.targetLayerType}`); } // 保存当前状态用于回滚 await this.saveCurrentState(); // 加载新图像 const newImage = await this.loadImageWithRetry(); // 应用图像到图层 await this.applyImageToLayer(newImage); this.isExecuted = true; // 触发成功事件 this.emitEvent("image:changed", { layerId: this.targetLayer.id, newImageUrl: this.imageUrl, command: this, }); 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 { if (this.previousImage) { // 恢复之前的图像 await this.restorePreviousImage(); } else { // 如果没有之前的图像,移除当前图像 await this.removeCurrentImage(); } this.isExecuted = false; // 触发撤销事件 this.emitEvent("image:reverted", { layerId: this.targetLayer.id, command: this, }); return { success: true, action: "reverted", layerId: this.targetLayer.id, }; } catch (error) { console.error("ChangeFixedImageCommand撤销失败:", 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是必需的"); // 验证URL格式 try { new URL(this.imageUrl); } catch { throw new Error("无效的图像URL格式"); } } 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() { if (!this.targetLayer.fabricObject) return; const currentObj = this.targetLayer.fabricObject; // 保存当前图像URL(如果存在) this.previousImage = { url: currentObj.getSrc ? currentObj.getSrc() : null, element: currentObj._element ? currentObj._element.cloneNode() : null, }; // 保存变换状态 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, }; } 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) { const currentObj = this.targetLayer.fabricObject; // 设置基本属性 newImage.set({ id: currentObj?.id || generateId(), layerId: this.targetLayer.id, layerName: this.targetLayer.name, isBackground: this.targetLayer.isBackground, isFixed: this.targetLayer.isFixed, }); // 应用位置和变换 if (this.preserveTransform && this.previousTransform) { newImage.set(this.previousTransform); } else { newImage.set({ left: this.position.x, top: this.position.y, scaleX: this.scale.x, scaleY: this.scale.y, }); } // 移除旧对象(如果存在) if (currentObj) { this.canvas.remove(currentObj); } // 添加新图像 this.canvas.add(newImage); newImage.setCoords(); // 更新图层引用 this.targetLayer.fabricObject = newImage; // 更新图层管理器 this.layerManager.updateLayerObject(this.targetLayer.id, newImage); // 重新渲染画布 this.canvas.renderAll(); } async restorePreviousImage() { if (!this.previousImage.url) return; const restoredImage = await this.loadImageFromUrl(this.previousImage.url); // 恢复之前的变换 if (this.previousTransform) { restoredImage.set(this.previousTransform); } // 设置图层属性 restoredImage.set({ id: this.targetLayer.fabricObject?.id || generateId(), layerId: this.targetLayer.id, layerName: this.targetLayer.name, isBackground: this.targetLayer.isBackground, isFixed: this.targetLayer.isFixed, }); // 替换当前对象 if (this.targetLayer.fabricObject) { this.canvas.remove(this.targetLayer.fabricObject); } this.canvas.add(restoredImage); restoredImage.setCoords(); // 更新引用 this.targetLayer.fabricObject = restoredImage; this.layerManager.updateLayerObject(this.targetLayer.id, restoredImage); this.canvas.renderAll(); } async removeCurrentImage() { if (this.targetLayer.fabricObject) { this.canvas.remove(this.targetLayer.fabricObject); this.targetLayer.fabricObject = null; this.layerManager.updateLayerObject(this.targetLayer.id, null); this.canvas.renderAll(); } } loadImageFromUrl(url) { return new Promise((resolve, reject) => { fabric.Image.fromURL( url, (img) => { if (!img || !img.getElement()) { reject(new Error("恢复图像加载失败")); return; } resolve(img); }, { crossOrigin: "anonymous" } ); }); } 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}`); } // 检查图层是否可编辑 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); } } // 获取命令信息用于调试 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, }; } }