import { generateId, optimizeCanvasRendering, getLayerObjectsZIndex } from "../utils/helper"; import { createLayer, LayerType, OperationType } from "../utils/layerHelper"; import { Command } from "./Command"; import i18n from "@/lang/index.ts"; const { t } = i18n.global; /** * 文本内容命令 * 用于更改文本图层的文本内容 */ export class TextContentCommand extends Command { constructor(options) { super({ name: "修改文本内容", description: "修改文本图层的文本内容", }); this.canvas = options.canvas; this.textObject = options.textObject; this.newText = options.newText; this.oldText = this.textObject.text; } execute() { this.textObject.set("text", this.newText); this.canvas.renderAll(); return true; } undo() { this.textObject.set("text", this.oldText); this.canvas.renderAll(); return true; } } /** * 文本字体命令 * 用于更改文本图层的字体 */ export class TextFontCommand extends Command { constructor(options) { super({ name: "修改文本字体", description: "修改文本图层的字体", }); this.canvas = options.canvas; this.textObject = options.textObject; this.newFont = options.newFont; this.oldFont = this.textObject.fontFamily; } execute() { this.textObject.set("fontFamily", this.newFont); this.canvas.renderAll(); return true; } undo() { this.textObject.set("fontFamily", this.oldFont); this.canvas.renderAll(); return true; } } /** * 文本尺寸命令 * 用于更改文本图层的字体大小 */ export class TextSizeCommand extends Command { constructor(options) { super({ name: "修改文本尺寸", description: "修改文本图层的字体大小", }); this.canvas = options.canvas; this.textObject = options.textObject; this.newSize = options.newSize; this.oldSize = this.textObject.fontSize; } execute() { this.textObject.set("fontSize", this.newSize); this.canvas.renderAll(); return true; } undo() { this.textObject.set("fontSize", this.oldSize); this.canvas.renderAll(); return true; } } /** * 文本颜色命令 * 用于更改文本图层的颜色 */ export class TextColorCommand extends Command { constructor(options) { super({ name: "修改文本颜色", description: "修改文本图层的颜色", }); this.canvas = options.canvas; this.textObject = options.textObject; this.newColor = options.newColor; this.oldColor = this.textObject.fill; } execute() { this.textObject.set("fill", this.newColor); this.canvas.renderAll(); return true; } undo() { this.textObject.set("fill", this.oldColor); this.canvas.renderAll(); return true; } } /** * 文本对齐方式命令 * 用于更改文本图层的对齐方式 */ export class TextAlignCommand extends Command { constructor(options) { super({ name: "修改文本对齐", description: "修改文本图层的对齐方式", }); this.canvas = options.canvas; this.textObject = options.textObject; this.newAlign = options.newAlign; this.oldAlign = this.textObject.textAlign; } execute() { this.textObject.set("textAlign", this.newAlign); this.canvas.renderAll(); return true; } undo() { this.textObject.set("textAlign", this.oldAlign); this.canvas.renderAll(); return true; } } /** * 文本样式命令 * 用于更改文本图层的样式(粗体、斜体、下划线等) */ export class TextStyleCommand extends Command { constructor(options) { super({ name: "修改文本样式", description: "修改文本图层的样式", }); this.canvas = options.canvas; this.textObject = options.textObject; this.property = options.property; // 'fontWeight', 'fontStyle', 'underline', 'linethrough', 'overline' this.newValue = options.newValue; this.oldValue = this.textObject[this.property]; } execute() { this.textObject.set(this.property, this.newValue); this.canvas.renderAll(); return true; } undo() { this.textObject.set(this.property, this.oldValue); this.canvas.renderAll(); return true; } } /** * 文本间距命令 * 用于更改文本图层的字符间距或行高 */ export class TextSpacingCommand extends Command { constructor(options) { super({ name: "修改文本间距", description: "修改文本图层的字符间距或行高", }); this.canvas = options.canvas; this.textObject = options.textObject; this.property = options.property; // 'charSpacing' 或 'lineHeight' this.newValue = options.newValue; this.oldValue = this.textObject[this.property]; } execute() { this.textObject.set(this.property, this.newValue); this.canvas.renderAll(); return true; } undo() { this.textObject.set(this.property, this.oldValue); this.canvas.renderAll(); return true; } } /** * 文本背景颜色命令 * 用于更改文本图层的背景颜色 */ export class TextBackgroundCommand extends Command { constructor(options) { super({ name: "修改文本背景", description: "修改文本图层的背景颜色", }); this.canvas = options.canvas; this.textObject = options.textObject; this.newColor = options.newColor; this.oldColor = this.textObject.textBackgroundColor; } execute() { this.textObject.set("textBackgroundColor", this.newColor); this.canvas.renderAll(); return true; } undo() { this.textObject.set("textBackgroundColor", this.oldColor); this.canvas.renderAll(); return true; } } /** * 文本透明度命令 * 用于更改文本图层的透明度 */ export class TextOpacityCommand extends Command { constructor(options) { super({ name: "修改文本透明度", description: "修改文本图层的透明度", }); this.canvas = options.canvas; this.textObject = options.textObject; this.newOpacity = options.newOpacity; this.oldOpacity = this.textObject.opacity; } execute() { this.textObject.set("opacity", this.newOpacity); this.canvas.renderAll(); return true; } undo() { this.textObject.set("opacity", this.oldOpacity); this.canvas.renderAll(); return true; } } /** * 组合文本编辑命令 * 用于一次性应用多个文本属性更改 */ export class CompositeTextCommand extends Command { constructor(options) { super({ name: "组合文本编辑", description: "组合多个文本编辑操作", }); this.canvas = options.canvas; this.textObject = options.textObject; this.changes = options.changes; // {property: newValue} 形式的对象 this.oldValues = {}; // 保存所有属性的旧值 for (const property in this.changes) { if (this.textObject[property] !== undefined) { this.oldValues[property] = this.textObject[property]; } } } execute() { for (const property in this.changes) { this.textObject.set(property, this.changes[property]); } this.canvas.renderAll(); return true; } undo() { for (const property in this.oldValues) { this.textObject.set(property, this.oldValues[property]); } this.canvas.renderAll(); return true; } } /** * 创建文本命令 * 用于创建文本对象和图层的组合操作 */ export class CreateTextCommand extends Command { constructor(options) { super({ name: "创建文本", }); this.canvas = options.canvas; this.layerManager = options.layerManager; this.x = options.x; this.y = options.y; this.textOptions = options.textOptions || {}; // 生成唯一ID this.textId = options?.textId || generateId("text_"); this.layerId = options?.layerId || generateId("text_layer_"); // 生成的对象和图层信息 this.textObject = null; this.oldActiveLayerId = null; // 默认文本属性 this.defaultOptions = { text: t('Canvas.DoubleClickText'), fontFamily: "Arial", fontSize: 24, fontWeight: "normal", fontStyle: "normal", textAlign: "left", fill: "#000000", opacity: 1, underline: false, overline: false, linethrough: false, textBackgroundColor: "transparent", lineHeight: 1.16, charSpacing: 0, }; } async execute() { if (!this.canvas || !this.layerManager) { console.error("Canvas或LayerManager不存在"); return null; } // 保存当前活动图层 this.oldActiveLayerId = this.layerManager.activeLayerId?.value; // 合并默认选项和用户选项 const finalOptions = { ...this.defaultOptions, ...this.textOptions, left: this.x, top: this.y, }; try { await optimizeCanvasRendering(this.canvas, async () => { // 创建文本对象 this.textObject = new fabric.IText(finalOptions.text, { ...finalOptions, originX: "center", originY: "center", }); // 创建文本图层 const layerName = this.textOptions.layerName || "文本图层"; const layer = createLayer({ id: this.layerId, name: layerName, type: LayerType.TEXT, }); // 设置对象的图层关联 this.textObject.set({ id: this.textId, layerId: this.layerId, layerName: layerName, }); // 智能插入图层到合适位置 this._insertLayerAtCorrectPosition(layer); // 添加到画布 this.canvas.add(this.textObject); // 取消其他对象的选中状态 this.canvas.discardActiveObject(); // 设置新创建的文本对象为活动对象 this.canvas.setActiveObject(this.textObject); // 更新图层的对象列表 if (layer) { layer.fabricObjects = layer.fabricObjects || []; layer.fabricObjects.push(this.textObject.toObject(["id", "layerId", "layerName"])); } // 现在可以安全地设置为活动图层 this.layerManager.setActiveLayer(this.layerId); // 更新对象交互性 await this.layerManager?.updateLayersObjectsInteractivity?.(false); // 切换到选择工具 this.layerManager?.toolManager?.setTool?.(OperationType.SELECT); }); console.log(`✅ 文本对象已创建: "${finalOptions.text}",位置: (${this.x}, ${this.y})`); return this.textObject; } catch (error) { console.error("创建文本对象失败:", error); // 如果创建失败,需要清理已创建的资源 await this.undo(); throw error; } } /** * 智能插入图层到正确位置 * 根据当前激活图层位置确定新图层插入位置 * @param {Object} newLayer 要插入的新图层 * @private */ _insertLayerAtCorrectPosition(newLayer) { const layers = this.layerManager.layers.value; const currentActiveLayerId = this.layerManager.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.layerManager.layers.value; // 先在一级图层中查找 for (let i = 0; i < layers.length; i++) { const layer = layers[i]; 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, textId: this.textObject?.id, layerId: this.layerId, text: this.textOptions.text || this.defaultOptions.text, position: { x: this.x, y: this.y }, }; } async undo() { try { // 从画布移除文本对象 if (this.textObject && this.canvas) { this.canvas.remove(this.textObject); } const layerObjects = getLayerObjectsZIndex(this.canvas, this.layerId); layerObjects.forEach((obj) => { if (obj.id === this.textObject?.id) { this.canvas.remove(obj.object); } }); // 智能移除创建的图层 if (this.layerId && this.layerManager) { this._removeLayerFromCorrectPosition(); } // 恢复原活动图层 if (this.oldActiveLayerId && this.layerManager) { // 检查原活动图层是否还存在 const originalLayer = this.layerManager.getLayerById(this.oldActiveLayerId); if (originalLayer) { this.layerManager.setActiveLayer(this.oldActiveLayerId); } else { // 如果原图层不存在,设置为第一个可用的普通图层 const availableLayers = this.layerManager.layers.value.filter( (layer) => !layer.isBackground && !layer.isFixed && !layer.locked ); if (availableLayers.length > 0) { this.layerManager.setActiveLayer(availableLayers[0].id); } } } // 更新对象交互性 await this.layerManager.updateLayersObjectsInteractivity(); // 重新渲染画布 if (this.canvas) { this.canvas.renderAll(); } console.log(`↩️ 文本创建操作已撤销`); return true; } catch (error) { console.error("撤销文本创建操作失败:", error); return false; } } /** * 智能移除图层 * 根据图层位置(一级图层或子图层)进行相应的移除操作 * @private */ _removeLayerFromCorrectPosition() { const layers = this.layerManager.layers.value; // 查找图层位置信息 const positionInfo = this._findLayerPosition(this.layerId); if (!positionInfo.layer) { console.warn(`要移除的图层不存在: ${this.layerId}`); return; } if (positionInfo.parent) { // 从子图层中移除 if (positionInfo.parent.children && positionInfo.index >= 0) { positionInfo.parent.children.splice(positionInfo.index, 1); console.log(`已从子图层移除: ${this.layerId} (父图层: ${positionInfo.parent.name})`); } } else { // 从一级图层中移除 if (positionInfo.index >= 0) { layers.splice(positionInfo.index, 1); console.log(`已从一级图层移除: ${this.layerId}`); } } } }