import { findObjectById } from "../utils/helper"; import { findLayerRecursively } from "../utils/layerHelper"; import { restoreFabricObject } from "../utils/objectHelper"; import { Command } from "./Command"; /** * 对象变换命令 * 轻量级命令,只记录对象的变换属性变化(位置、缩放、旋转) * 不保存整个对象或画布状态,只关注变换属性 */ export class TransformCommand extends Command { constructor(options) { super({ name: options.name || "对象变换", description: options.description || "移动、缩放或旋转对象", saveState: false, // 自己管理状态,避免递归 }); this.canvas = options.canvas; this.objectId = options.objectId; this.initialState = options.initialState || null; this.finalState = options.finalState || null; this.objectType = options.objectType || "object"; this.layerManager = options.layerManager; this.layers = options.layers || null; this.lastSelectLayerId = options.lastSelectLayerId || null; // 最后选择的图层ID const targetObject = findObjectById(this.canvas, this.objectId)?.object || null; const { layer, parent } = findLayerRecursively( this.layers.value, targetObject?.layerId ); this.layer = layer; this.parent = parent; this.isSginleObject = parent?.id === this.lastSelectLayerId?.value; // 是否需要记录遮罩的变换位置 如果是组图层且组下只有一个图层有对象 且 用户最后点击的是父图层 则记录遮罩变更 } /** * 执行命令 * 如果是首次执行,记录初始和最终状态 * 如果是重做,应用最终状态 */ async execute() { if (!this.finalState) { console.warn("没有最终状态可应用"); return false; } // 查找目标对象 const targetObject = this._findObject(this.objectId); if (!targetObject) { console.warn(`未找到ID为 ${this.objectId} 的对象`); return false; } // 应用最终变换状态 await this._applyTransform(targetObject, this.finalState); setTimeout(() => { // 现在图层就是元素本身,直接更新元素的缩略图 this?.layerManager?.canvasManager?.thumbnailManager?.generateLayerThumbnail?.( this.layer.id ); if (this.parent) { // 如果有父图层,更新父图层的缩略图 this?.layerManager?.canvasManager?.thumbnailManager?.generateLayerThumbnail?.( this.parent.id ); } }, 300); // 触发画布更新 this.canvas.renderAll(); return true; } /** * 撤销命令 * 应用初始状态 */ async undo() { if (!this.initialState) { console.warn("没有初始状态可恢复"); return false; } // 查找目标对象 const targetObject = this._findObject(this.objectId); if (!targetObject) { console.warn(`未找到ID为 ${this.objectId} 的对象`); return false; } // 应用初始变换状态 await this._applyTransform(targetObject, this.initialState); setTimeout(() => { // 现在图层就是元素本身,直接更新元素的缩略图 this?.layerManager?.canvasManager?.thumbnailManager?.generateLayerThumbnail?.( this.layer.id ); if (this.parent) { // 如果有父图层,更新父图层的缩略图 this?.layerManager?.canvasManager?.thumbnailManager?.generateLayerThumbnail?.( this.parent.id ); } }, 300); // 触发画布更新 this.canvas.renderAll(); return true; } /** * 查找对象 * @private */ _findObject(objectId) { if (!this.canvas) return null; return this.canvas.getObjects().find((obj) => obj.id === objectId); } /** * 应用变换状态到对象 * @private */ async _applyTransform(object, transformState) { if (!object || !transformState) return; // 变换遮罩层 - 如果当前图层是组图层,且有遮罩并且组下只有一个图层有对象 则应用遮罩转换 if ( this.parent && this.parent?.clippingMask && // this.parent?.children?.length === 1 && this.isSginleObject ) { // 计算对象的变换位置 const moveLeft = object.left - transformState.left; // 计算移动的水平距离 const moveTop = object.top - transformState.top; // 计算移动的垂直距离 this.parent.clippingMask.left -= moveLeft; this.parent.clippingMask.top -= moveTop; if (this.parent.selectObject) { // 如果有选区 则选区位置也要更新 this.parent.selectObject.left = this.parent.clippingMask.left; this.parent.selectObject.top = this.parent.clippingMask.top; const { object } = findObjectById( this.canvas, this.parent.selectObject?.id ); object?.set({ left: this.parent.clippingMask.left, top: this.parent.clippingMask.top, }); object?.setCoords(); } // 重新创建遮罩对象 const clippingMaskFabricObject = await restoreFabricObject( this.parent.clippingMask, this.canvas ); if (clippingMaskFabricObject) { clippingMaskFabricObject.clipPath = null; clippingMaskFabricObject.set({ absolutePositioned: true, }); clippingMaskFabricObject.dirty = true; clippingMaskFabricObject.setCoords(); // const clippingMask = this.parent.clippingMask; // object.clipPath = clippingMask; object.clipPath = clippingMaskFabricObject; object.dirty = true; } } // 应用变换属性,只设置真正变化的值 Object.entries(transformState).forEach(([key, value]) => { object.set(key, value); }); // 确保对象更新 object.setCoords(); } /** * 获取命令信息 */ getInfo() { return { name: this.name, description: this.description, objectId: this.objectId, objectType: this.objectType, changedProps: this.finalState ? Object.keys(this.finalState) : [], }; } /** * 捕获对象的变换状态 * @static */ static captureTransformState(object) { if (!object) return null; // 只捕获变换相关的属性 return { left: object.left, top: object.top, scaleX: object.scaleX, scaleY: object.scaleY, angle: object.angle, flipX: object.flipX, flipY: object.flipY, skewX: object.skewX, skewY: object.skewY, }; } }