import { BrushStore } from "../store/BrushStore"; import { BrushManager } from "./brushes/brushManager"; import { BrushIndicator } from "./BrushIndicator"; import { ToolCommand } from "../commands/ToolCommands"; import { CreateTextCommand } from "../commands/TextCommands"; import { findLayerRecursively, OperationType } from "../utils/layerHelper"; import CanvasConfig from "../config/canvasConfig"; import { fabric } from "fabric-with-all"; import { InitLiquifyToolCommand } from "../commands/LiquifyCommands"; import { RasterizeLayerCommand } from "../commands/RasterizeLayerCommand"; import { message, Modal } from "ant-design-vue"; import { h } from "vue"; import { findObjectById } from "../utils/helper"; /** * 工具管理器 * 负责管理编辑器中的各种工具 */ export class ToolManager { /** * 创建工具管理器 * @param {Object} options 配置选项 * @param {Object} options.canvas fabric.js画布实例 * @param {Object} options.commandManager 命令管理器实例 * @param {Object} options.canvasManager 画布管理实例 * @param {Object} options.layerManager 图层管理实例 * @param {Object} options.brushManager 画笔管理器实例(可选,如果不提供会创建一个) * @param {Object} options.activeTool 当前活动工具的响应式引用 * @param {Function} options.t 国际化函数 */ constructor(options = {}) { this.canvas = options.canvas; this.commandManager = options.commandManager; this.canvasManager = options.canvasManager; this.layerManager = options.layerManager; this.t = options.t this.activeTool = options.activeTool || { value: OperationType.SELECT, }; // 红绿图模式状态 this.isRedGreenMode = false; this.redGreenModeManager = null; // 使用传入的brushManager或创建新的实例 this.brushManager = options.brushManager || new BrushManager({ canvas: this.canvas, brushSize: options.brushSize, layerManager: this.layerManager, // 传入图层管理器引用 t:this.t }); // 初始化笔刷指示器 this.brushIndicator = null; if (this.canvas) { this.brushIndicator = new BrushIndicator(this.canvas, { strokeColor: "rgba(0, 0, 0, 0.6)", strokeWidth: 1, fillColor: "rgba(0, 0, 0, 0.1)", }); } // 观察者列表 this.observers = []; // 工具列表 - 与OperationType保持一致 this.tools = { // 禁用工具 [OperationType.DISABLED]: { name: "禁用工具", icon: "disabled", cursor: "not-allowed", }, // 基础工具 [OperationType.SELECT]: { name: "选择工具", icon: "select", cursor: "default", shortcut: "V", setup: this.setupSelectTool.bind(this), allowedInRedGreen: false, }, [OperationType.DRAW]: { name: "画笔工具", icon: "brush", cursor: "crosshair", shortcut: "B", setup: this.setupBrushTool.bind(this), allowedInRedGreen: false, specialLayerDisabled: true, }, [OperationType.ERASER]: { name: "橡皮擦", icon: "eraser", cursor: "crosshair", shortcut: "E", setup: this.setupEraserTool.bind(this), allowedInRedGreen: true, // 红绿图模式允许橡皮擦 specialLayerDisabled: true, }, [OperationType.EYEDROPPER]: { name: "吸色工具", icon: "eyedropper", cursor: "crosshair", shortcut: "I", setup: this.setupEyedropperTool.bind(this), allowedInRedGreen: false, }, [OperationType.PAN]: { name: "移动画布", icon: "hand", cursor: "grab", shortcut: "H", setup: this.setupHandTool.bind(this), allowedInRedGreen: false, // 红绿图模式不允许PAN }, // 套索工具 [OperationType.LASSO]: { name: "套索工具", icon: "lasso", cursor: "crosshair", shortcut: "L", setup: this.setupLassoTool.bind(this), allowedInRedGreen: false, specialLayerDisabled: true, }, [OperationType.LASSO_RECTANGLE]: { name: "矩形套索工具", icon: "lasso", cursor: "crosshair", // shortcut: "L", altKey: true, setup: this.setupRectangleLassoTool.bind(this), allowedInRedGreen: false, specialLayerDisabled: true, }, [OperationType.LASSO_ELLIPSE]: { name: "椭圆形套索工具", icon: "lasso", cursor: "crosshair", // shortcut: "L", altKey: true, setup: this.setupEllipseLassoTool.bind(this), allowedInRedGreen: false, specialLayerDisabled: true, }, // 选区工具 - 只需要矩形选区 [OperationType.AREA_RECTANGLE]: { name: "矩形选区工具", icon: "area-rectangle", cursor: "crosshair", shortcut: "M", altKey: true, setup: this.setupRectangleAreaTool.bind(this), allowedInRedGreen: false, }, // 特效工具 [OperationType.WAVE]: { name: "波浪工具", icon: "wave", cursor: "crosshair", shortcut: "W", setup: this.setupWaveTool.bind(this), allowedInRedGreen: false, }, [OperationType.LIQUIFY]: { name: "液化工具", icon: "liquify", cursor: "crosshair", shortcut: "J", setup: this.setupLiquifyTool.bind(this), allowedInRedGreen: false, // 红绿图模式不允许液化 specialLayerDisabled: true, }, [OperationType.TEXT]: { name: "文本工具", icon: "text", cursor: "text", shortcut: "T", setup: this.setupTextTool.bind(this), allowedInRedGreen: false, // 红绿图模式不允许文本 }, // 部件选取工具 [OperationType.PART]: { name: "部件选取工具", icon: "part", cursor: "crosshair", // setup: this.setupLassoTool.bind(this), specialLayerDisabled: true, }, [OperationType.PART_RECTANGLE]: { name: "部件选取工具-矩形", icon: "part", cursor: "crosshair", // setup: this.setupRectangleLassoTool.bind(this), specialLayerDisabled: true, }, [OperationType.PART_BRUSH]: { name: "部件选取工具-画笔", icon: "part", cursor: "crosshair", // setup: this.setupEllipseLassoTool.bind(this), specialLayerDisabled: true, }, [OperationType.PART_ERASER]: { name: "部件选取工具-橡皮擦", icon: "part", cursor: "crosshair", // setup: this.setupEllipseLassoTool.bind(this), specialLayerDisabled: true, }, // 红绿图模式专用工具 [OperationType.RED_BRUSH]: { name: "红色笔刷", icon: "brush", cursor: "crosshair", shortcut: "R", setup: this.setupRedBrushTool.bind(this), allowedInRedGreen: true, redGreenOnly: true, // 只在红绿图模式显示 }, [OperationType.GREEN_BRUSH]: { name: "绿色笔刷", icon: "brush", cursor: "crosshair", shortcut: "G", setup: this.setupGreenBrushTool.bind(this), allowedInRedGreen: true, redGreenOnly: true, // 只在红绿图模式显示 }, }; // 记录先前的工具 this.previousTool = null; // 初始化默认工具 this.setTool(this.activeTool.value); // 初始化工具快捷键 this.initKeyboardShortcuts(); // 设置文本编辑事件 this.setupTextEditingEvents(); // 添加观察者 // this.addObserver(this.brushManager); this.addObserver(this.layerManager); this.addObserver(this.canvasManager); } /** * 添加观察者 * @param {Object} observer 观察者对象,必须实现toolChanged方法 */ addObserver(observer) { if (typeof observer.toolChanged === "function") { this.observers.push(observer); } else { console.warn("Observer must implement toolChanged method"); } } /** * 移除观察者 * @param {Object} observer 要移除的观察者对象 */ removeObserver(observer) { this.observers = this.observers.filter((obs) => obs !== observer); } /** * 通知所有观察者工具已更改 * @param {String} toolId 工具ID */ notifyObservers(toolId) { this.observers.forEach((observer) => { observer.toolChanged(toolId, this.tools[toolId]); }); } /** * 初始化工具快捷键 */ initKeyboardShortcuts() { // 可以在这里设置工具快捷键的全局监听 // 如需要由外部统一管理键盘事件,则不需要此方法 } /** * 处理快捷键事件 * @param {KeyboardEvent} event 键盘事件 */ handleKeyboardShortcut(event) { const key = event.key.toUpperCase(); const altKey = event.altKey; const ctrlKey = event.ctrlKey; const shiftKey = event.shiftKey; // 当处于输入状态时不触发快捷键 if ( event.target.tagName === "INPUT" || event.target.tagName === "TEXTAREA" ) { return; } // 在红绿图模式下,只允许特定快捷键 if (this.isRedGreenMode) { const allowedKeys = ["E", "R", "G"]; // 橡皮擦、红色笔刷、绿色笔刷 if (!allowedKeys.includes(key)) { return; // 忽略不允许的快捷键 } } // 查找匹配的工具 for (const [toolId, tool] of Object.entries(this.tools)) { if (tool.shortcut && tool.shortcut.toUpperCase() === key) { // 检查可能的辅助键要求 if ( (tool.altKey && !altKey) || (tool.ctrlKey && !ctrlKey) || (tool.shiftKey && !shiftKey) ) { continue; } // 在红绿图模式下检查工具可用性 if ( this.isRedGreenMode && !this.isToolAvailableInRedGreenMode(toolId) ) { continue; } // 切换到该工具 this.setToolWithCommand(toolId); event.preventDefault(); return; } } } /** * 获取所有可用工具列表 * @returns {Array} 工具列表 */ getTools() { return Object.keys(this.tools).map((key) => { return { id: key, ...this.tools[key], }; }); } /** * 获取当前工具 * @returns {String} 当前工具ID */ getCurrentTool() { return this.activeTool.value; } /** * 设置当前活动工具 * @param {String} toolId 工具ID */ setTool(toolId) { const tool = this.tools[toolId]; // 检查工具是否存在 if (!tool) { console.error(`工具 '${toolId}' 不存在`); return; } // 在红绿图模式下检查工具可用性 if (this.isRedGreenMode && !this.isToolAvailableInRedGreenMode(toolId)) { console.warn(`工具 '${toolId}' 在红绿图模式下不可用`); return; } // 在普通模式下检查是否为红绿图专用工具 if (!this.isRedGreenMode && this.isRedGreenOnlyTool(toolId)) { console.warn(`工具 '${toolId}' 只能在红绿图模式下使用`); return; } if(tool?.specialLayerDisabled && this.checkToolCanOperateSelectedObject()){ console.warn(`工具 '${toolId}' 不能在当前选中对象上操作`); toolId = OperationType.DISABLED; } // 保存先前的工具 this.previousTool = this.activeTool.value; // 取消画布的选中状态 if(toolId !== OperationType.DISABLED){ this.canvas?.discardActiveObject(); this.canvasManager?.layerManager?.updateLayersObjectsInteractivity?.(); this.canvas?.renderAll(); } // 隐藏文本编辑面板 this.hideTextEditor(); // 如果切换到非画笔工具,禁用笔刷指示器 if (!this._shouldShowBrushIndicator(toolId)) { this._disableBrushIndicator(); } // 设置新工具 this.activeTool.value = toolId; // 设置光标 if (this.canvas) { this.canvas.defaultCursor = this.tools[toolId].cursor; } // 设置工具特定的状态 if (tool && typeof tool.setup === "function") { console.log(`画布切换工具:${tool.name}(${toolId})`) this.canvas.toolId = toolId; tool.setup(); } // 通知选区管理器工具已改变 if (this.canvasManager && this.canvasManager.selectionManager) { this.canvasManager.selectionManager.setCurrentTool(toolId); } // 通知观察者 this.notifyObservers(toolId); return this.activeTool.value; } /** * 通过命令模式设置工具 * @param {String} toolId 工具ID */ setToolWithCommand(toolId, options = {}) { if (!this.commandManager) { this.setTool(toolId); return; } // 创建工具切换命令 const command = new ToolCommand({ toolManager: this, tool: toolId, previousTool: this.activeTool.value, }); command.undoable = options.undoable !== undefined ? options.undoable : true; // 执行命令 this.commandManager.execute(command, { ...options }); } /** * 恢复当前工具的选择状态 * 在拖拽结束时调用,确保canvas.selection状态与当前工具一致 */ restoreSelectionState() { if (!this.canvas) return; const currentTool = this.activeTool.value; const tool = this.tools[currentTool]; if(tool?.specialLayerDisabled && this.checkToolCanOperateSelectedObject()) return; // 根据当前工具设置selection状态 if (currentTool === OperationType.SELECT) { this.canvas.selection = true; } else { // 对于大多数工具,selection应该是false this.canvas.selection = false; } // 如有必要,可以调用当前工具的setup方法来全面恢复状态 if (tool && typeof tool.setup === "function") { tool.setup(); } } /** * 切换回先前使用的工具 */ togglePreviousTool() { if (this.previousTool && this.previousTool !== this.activeTool.value) { this.setTool(this.previousTool); } } /** * 设置选择工具 */ setupSelectTool() { if (!this.canvas) return; this.canvas.isDrawingMode = false; this.canvas.selection = true; } /** * 检查当前工具是否禁止操作当前选中的对象 * @returns {Boolean} 是否可以切换 */ checkToolCanOperateSelectedObject() { const layer = this.layerManager?.getActiveLayer(); const isSpecialLayer = !!layer?.specialType; if (isSpecialLayer) { this._disableBrushIndicator(); this.canvas.defaultCursor = "not-allowed"; } return isSpecialLayer; } /** * 设置画笔工具 */ setupBrushTool() { if (!this.canvas) return; if (this.checkToolCanOperateSelectedObject()) return; this.canvas.isDrawingMode = true; this.canvas.selection = false; // 确保有笔刷管理器 if (this.brushManager) { // 检查画笔是否正在更新中 if (this.brushManager.isUpdatingBrush) { console.warn("画笔正在更新中,请稍候..."); return; } if (BrushStore) { // 同步基本属性 this.brushManager.setBrushSize(BrushStore.state.size); this.brushManager.setBrushColor(BrushStore.state.color); this.brushManager.setBrushOpacity(BrushStore.state.opacity); // 同步笔刷类型 - 修复方法名,使用正确的setBrushType方法 this.brushManager.setBrushType( BrushStore.state.type === "eraser" ? "pencil" : BrushStore.state.type ); // 同步材质设置 if (BrushStore.state.textureEnabled && BrushStore.state.texturePath) { this.brushManager.setTexturePath(BrushStore.state.texturePath); this.brushManager.setTextureScale(BrushStore.state.textureScale); } } // 更新应用到画布 this.brushManager.updateBrush(); } // 启用笔刷指示器并同步颜色 this._enableBrushIndicator(); } /** * 设置橡皮擦工具 */ setupEraserTool() { if (!this.canvas) return; if (this.checkToolCanOperateSelectedObject()) return; this.canvas.isDrawingMode = true; this.canvas.selection = false; // 确保有笔刷管理器 if (this.brushManager) { this.brushManager.createEraser(); } // 启用笔刷指示器 this._enableBrushIndicator(); } /** * 设置吸色工具 */ setupEyedropperTool() { if (!this.canvas || !this.brushManager) return; this.canvas.isDrawingMode = false; this.canvas.selection = false; // 保存当前工具,以便吸色完成后还原 const currentTool = this.activeTool.value; // 使用吸色工具 this.brushManager.createEyedropper((color) => { // 设置画笔颜色 this.brushManager.setBrushColor(color); // 吸色完成后,恢复到之前的工具 this.setTool(currentTool); }); } /** * 设置移动画布工具 */ setupHandTool() { if (!this.canvas) return; this.canvas.isDrawingMode = false; this.canvas.selection = false; // 设置画布为可拖动状态 this.canvas.defaultCursor = "grab"; } /** * 设置套索工具 */ setupLassoTool() { if (!this.canvas) return; if (this.checkToolCanOperateSelectedObject()) return; this.canvas.isDrawingMode = false; this.canvas.selection = false; // 通知选区管理器切换到自由套索工具 if (this.canvasManager && this.canvasManager.selectionManager) { this.canvasManager.selectionManager.setCurrentTool(OperationType.LASSO); } } /** * 设置矩形套索工具 */ setupRectangleLassoTool() { if (!this.canvas) return; this.canvas.isDrawingMode = false; this.canvas.selection = false; // 通知选区管理器切换到矩形套索工具 if (this.canvasManager && this.canvasManager.selectionManager) { this.canvasManager.selectionManager.setCurrentTool( OperationType.LASSO_RECTANGLE ); } } /** * 设置椭圆形套索工具 */ setupEllipseLassoTool() { if (!this.canvas) return; this.canvas.isDrawingMode = false; this.canvas.selection = false; // 通知选区管理器切换到椭圆套索工具 if (this.canvasManager && this.canvasManager.selectionManager) { this.canvasManager.selectionManager.setCurrentTool( OperationType.LASSO_ELLIPSE ); } } /** * 设置自由选区工具 */ setupCustomAreaTool() { if (!this.canvas) return; this.canvas.isDrawingMode = false; this.canvas.selection = false; // 通知选区管理器切换到椭圆套索工具 if (this.canvasManager && this.canvasManager.selectionManager) { this.canvasManager.selectionManager.setCurrentTool( OperationType.AREA_CUSTOM ); } } /** * 设置矩形选区工具 */ setupRectangleAreaTool() { if (!this.canvas) return; this.canvas.isDrawingMode = false; this.canvas.selection = false; // // 设置矩形选区模式 // // 这里需要具体的矩形选区工具实现 console.log("矩形选区工具已激活"); if (this.canvasManager && this.canvasManager.selectionManager) { this.canvasManager.selectionManager.setCurrentTool( OperationType.AREA_RECTANGLE ); } } /** * 设置波浪工具 */ setupWaveTool() { if (!this.canvas) return; this.canvas.isDrawingMode = false; this.canvas.selection = false; } /** * 设置液化工具 */ setupLiquifyTool() { if (!this.canvas || !this.layerManager) return; if (this.checkToolCanOperateSelectedObject()) return; this.canvas.isDrawingMode = false; this.canvas.selection = false; // 获取当前活动图层 const activeLayerId = this.layerManager.getActiveLayerId(); // 准备液化面板显示的详情信息 let panelDetail = { activeLayerId: activeLayerId, layerStatus: null, canLiquify: false, targetObject: null, originalImageData: null, }; // 如果有活动图层,检查其状态 if (activeLayerId) { const liquifyManager = this.canvasManager?.liquifyManager; if (liquifyManager) { // 检查图层状态 const checkResult = liquifyManager.checkLayerForLiquify(activeLayerId); panelDetail.layerStatus = checkResult; // 获取图层对象 // const layer = this.layerManager.getLayerById(activeLayerId); const { layer } = findLayerRecursively( this.layerManager.layers?.value ?? this.layerManager.layers, activeLayerId ); // 检查图层是否为空 if (!checkResult.isEmpty) { // 图层不为空,判断是否可直接液化或需要栅格化 if (checkResult.valid) { // 可以直接液化 (单个图像对象) panelDetail.canLiquify = true; // 设置目标对象 if (layer) { if (layer.isBackground || layer.type === "background") { panelDetail.targetObject = findObjectById( this.canvas, layer.fabricObject?.id )?.object; } else if ( layer.fabricObjects && layer.fabricObjects.length > 0 ) { panelDetail.targetObject = findObjectById( this.canvas, layer.fabricObjects?.[0]?.id )?.object; } // 准备液化环境,获取原始图像数据 if (panelDetail.targetObject && liquifyManager) { liquifyManager.initialize({ canvas: this.canvas, layerManager: this.layerManager, }); // 异步获取原始图像数据 liquifyManager .prepareForLiquify(panelDetail.targetObject) .then((result) => { if (result && result.originalImageData) { // 当获取到原始图像数据后触发更新 const updatedDetail = { ...panelDetail, originalImageData: result.originalImageData, }; // 重新触发液化面板显示事件,这次包含原始图像数据 document.dispatchEvent( new CustomEvent("showLiquifyPanel", { detail: updatedDetail, }) ); } }) .catch((err) => { console.error("准备液化环境失败:", err); }); } } } else if (checkResult.needsRasterization) { // 需要栅格化 (多个对象或组) // 使用Modal询问用户是否要栅格化 this._showRasterizeConfirmModal(checkResult.isGroup, activeLayerId); return; // 等待用户确认,不继续执行 } } } } // 总是触发液化面板显示事件,不论图层状态如何 document.dispatchEvent( new CustomEvent("showLiquifyPanel", { detail: panelDetail, }) ); this._enableBrushIndicator(); } /** * 显示栅格化确认Modal对话框 * @param {Boolean} isGroup 是否为组对象 * @param {String} layerId 图层ID * @private */ _showRasterizeConfirmModal(isGroup, layerId) { const title = this.t("Canvas.RasterizedLayer"); const content = this.t("Canvas.rasterizeImmediately"); Modal.confirm({ title, content, okText: this.t("Canvas.ConfirmRasterization"), cancelText: this.t("Canvas.close"), centered: true, icon: h("span", { style: "color: #faad14;" }, "⚠️"), onOk: () => { // 用户确认栅格化,执行栅格化操作 this._rasterizeLayerForLiquify(layerId); }, onCancel: () => { console.log("用户取消了栅格化操作"); // 用户取消,触发液化面板显示事件但不能液化 document.dispatchEvent( new CustomEvent("showLiquifyPanel", { detail: { activeLayerId: layerId, layerStatus: { needsRasterization: true, isGroup }, canLiquify: false, targetObject: null, originalImageData: null, }, }) ); }, }); } /** * 栅格化图层用于液化操作 * @param {String} layerId 图层ID * @private */ async _rasterizeLayerForLiquify(layerId) { if (!this.commandManager || !this.layerManager) return; // 显示加载Modal const loadingModal = Modal.info({ title: this.t('Canvas.beingRasterized'), content: this.t('Canvas.waitRasterizing'), okButtonProps: { style: { display: "none" } }, centered: true, closable: false, maskClosable: false, }); try { // 创建栅格化命令 const rasterizeCommand = new RasterizeLayerCommand({ canvas: this.canvas, layerManager: this.layerManager, layerId: layerId, layers: this.layerManager.layers, activeLayerId: this.layerManager.activeLayerId, }); // 执行命令 const result = await this.commandManager.execute(rasterizeCommand); if (result) { // 栅格化成功,启动液化 message.success(this.t('Canvas.successRasterizing')); this._startLiquify(result); this.setTool(OperationType.LIQUIFY); // 切换到液化工具 } else { // 栅格化失败 Modal.error({ title: this.t('Canvas.gridingFailed'), content: this.t('Canvas.gridingFailedNoOperation'), okText: this.t('Canvas.ok'), centered: true, }); } } catch (error) { console.error("栅格化图层失败:", error); Modal.error({ title: this.t('Canvas.gridingError'), content: `${this.t('Canvas.gridingFailed')}:${error.message}`, okText: this.t('Canvas.ok'), centered: true, }); } finally { // 关闭加载Modal loadingModal.destroy(); } } /** * 开始液化操作 * @param {String} layerId 图层ID * @private */ async _startLiquify(layerId) { // 获取图层信息 // const layer = this.layerManager.getLayerById(layerId); const { layer } = findLayerRecursively( this.layerManager.layers?.value ?? this.layerManager.layers, layerId ); if (!layer) { Modal.error({ title: this.t('Canvas.LayerError'), content: this.t('Canvas.LayerDoesNotExist'), okText: this.t('Canvas.ok'), centered: true, }); return; } // 检查图层是否为空 let targetObject = null; if (layer.isBackground) { // 背景图层使用 fabricObject (单数) if (!layer.fabricObject) { Modal.warning({ title: this.t('Canvas.backgroundEmpty'), content: this.t('Canvas.backgroundEmptyNoLiquidation'), okText: this.t('Canvas.ok'), centered: true, }); return; } targetObject = layer.fabricObject; } else { // 普通图层使用 fabricObjects (复数) if (!layer.fabricObjects || layer.fabricObjects.length === 0) { Modal.warning({ title: this.t('Canvas.layerEmpty'), content: this.t('Canvas.layerEmptyNoLiquidation'), okText: this.t('Canvas.ok'), centered: true, }); return; } targetObject = layer.fabricObjects[0]; } // 确保liquifyManager可用 const liquifyManager = this.canvasManager?.liquifyManager; if (!liquifyManager) { Modal.error({ title: this.t('Canvas.liqueficationManagerError'), content: this.t('Canvas.liqueficationManagerErrorInitialized'), okText: this.t('Canvas.ok'), centered: true, }); return; } try { // 显示准备中的Modal const preparingModal = Modal.info({ title: this.t('Canvas.liquefactionEnvironment'), content: this.t('Canvas.liquefactionEnvironmentLoading'), okButtonProps: { style: { display: "none" } }, centered: true, closable: false, maskClosable: false, }); // 准备液化环境 liquifyManager.initialize({ canvas: this.canvas, layerManager: this.layerManager, }); // 准备液化操作,获取原始图像数据 const prepareResult = await liquifyManager.prepareForLiquify( targetObject ); // 创建和初始化命令 const initCommand = new InitLiquifyToolCommand({ canvas: this.canvas, layerManager: this.layerManager, liquifyManager, toolManager: this, }); // 执行初始化命令 await this.commandManager.execute(initCommand); // 关闭准备Modal preparingModal.destroy(); // 触发液化面板显示事件 document.dispatchEvent( new CustomEvent("showLiquifyPanel", { detail: { targetObject, targetLayerId: layerId, originalImageData: prepareResult.originalImageData, }, }) ); } catch (error) { console.error("启动液化工具失败:", error); Modal.error({ title: this.t('Canvas.LiqueficationFailed'), content: `${this.t('Canvas.LiqueficationFailed')}:${error.message}`, okText: this.t('Canvas.ok'), centered: true, }); } } /** * 触发文件上传操作 */ openFile() { this.onFileSelected?.(); } /** * 设置文件选择回调 * @param {Function} callback 回调函数 */ setFileUploadHandler(callback) { this.onFileSelected = callback; } /** * 更新笔刷大小 * @param {Number} size 笔刷大小 */ updateBrushSize(size) { if (!this.canvas || !this.brushManager) return; // 更新BrushStore BrushStore.setBrushSize(size); // 直接更新笔刷管理器 this.brushManager.setBrushSize(size); // 更新应用到画布 this.brushManager.updateBrush(); // 更新笔刷指示器大小 this.updateBrushIndicatorSize(size); } /** * 创建文字对象并添加到画布 * @param {Number} x 文本位置x坐标 * @param {Number} y 文本位置y坐标 * @param {String} [text] 文本内容 * @param {Object} [options] 文本选项 */ async createText(x, y, text, options = {}) { // 使用命令模式创建文本 if (!this.canvas || !this.layerManager) return null; if (this.commandManager) { const command = new CreateTextCommand({ canvas: this.canvas, layerManager: this.layerManager, x, y, text, textOptions: options, }); // 执行命令 return await this.commandManager.execute(command); } else { // 如果没有命令管理器,直接调用原有方法(兼容性) return await this._createTextDirect(x, y, options); } } /** * 直接创建文本的方法(用于向后兼容) * @param {Number} x 文本位置x坐标 * @param {Number} y 文本位置y坐标 * @param {Object} options 文本选项 * @private */ _createTextDirect(x, y, options = {}) { // 默认文本属性 const defaultOptions = { text: this.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, }; // 合并默认选项和用户选项 const textOptions = { ...defaultOptions, ...options, left: x, top: y }; // 创建文本对象 const textObj = new fabric.IText(textOptions.text, { ...textOptions, originX: "center", originY: "center", id: options.id || this.generateId(), // 生成唯一ID }); // 创建文本图层并通过LayerManager添加到画布 this.layerManager.createTextLayerWithObject(textObj, textOptions); return textObj; } /** * 生成唯一ID * @returns {String} 唯一ID */ generateId() { return "text_" + Date.now() + "_" + Math.floor(Math.random() * 1000); } /** * 更新笔刷颜色 * @param {String} color 颜色值,如 "#ff0000" */ updateBrushColor(color) { if (!this.canvas || !this.brushManager) return; // 更新BrushStore BrushStore.setBrushColor(color); // 直接更新笔刷管理器 this.brushManager.setBrushColor(color); // 更新应用到画布 this.brushManager.updateBrush(); // 更新笔刷指示器颜色 this.updateBrushIndicatorColor(color); } /** * 更新笔刷透明度 * @param {Number} opacity 透明度值,范围 0-1 */ updateBrushOpacity(opacity) { if (!this.canvas || !this.brushManager) return; // 更新BrushStore BrushStore.setBrushOpacity(opacity); // 直接更新笔刷管理器 this.brushManager.setBrushOpacity(opacity); // 更新应用到画布 this.brushManager.updateBrush(); } /** * 设置双击文本的事件监听 * 当用户双击文本对象时,显示文本编辑弹窗 */ setupTextEditingEvents() { if (!this.canvas) return; // 如果已有监听器,先移除以避免重复 if (this._textEditHandler) { this.canvas.off("mouse:dblclick", this._textEditHandler); } // 创建双击事件处理函数 this._textEditHandler = (e) => { const target = e.target; if ( target && (target.type === "text" || target.type === "i-text" || target.type === "textbox") ) { // 获取对应的图层 // const layer = this.layerManager.getLayerById(target.layerId); const { layer } = findLayerRecursively( this.layerManager.layers?.value ?? this.layerManager.layers, target.layerId ); if (layer) { // 显示文本编辑面板 this.showTextEditor(target, layer); } } }; // 添加双击事件监听 this.canvas.on("mouse:dblclick", this._textEditHandler); } /** * 显示文本编辑面板 * @param {Object} textObject 文本对象 * @param {Object} layer 图层对象 */ showTextEditor(textObject, layer) { // 这个方法将在TextEditorPanel组件实现后调用 console.log("显示文本编辑面板", textObject, layer); // 将发出一个事件,让Vue组件捕获并显示编辑面板 document.dispatchEvent( new CustomEvent("showTextEditor", { detail: { textObject, layer, }, }) ); } /** * 隐藏文本编辑面板 */ hideTextEditor() { // 这个方法将在TextEditorPanel组件实现后调用 console.log("隐藏文本编辑面板"); // 将发出一个事件,让Vue组件捕获并隐藏编辑面板 document.dispatchEvent( new CustomEvent("hideTextEditor", { detail: {}, }) ); } /** * 清理资源 */ dispose() { if (this.brushManager) { this.brushManager.dispose(); } // 清理笔刷指示器 if (this.brushIndicator) { this.brushIndicator.dispose(); this.brushIndicator = null; console.log("笔刷指示器已清理"); } // 移除文本编辑相关事件监听器 if (this.canvas) { this.canvas.off("mouse:dblclick", this._textEditHandler); } this._textEditHandler = null; this.observers = []; // 清空观察者 this.canvas = null; this.commandManager = null; this.onFileSelected = null; } /** * 设置文本工具 */ setupTextTool() { if (!this.canvas) return; this.canvas.isDrawingMode = false; this.canvas.selection = false; console.log("文本工具已激活"); } /** * 设置红色笔刷工具(红绿图模式专用) */ setupRedBrushTool() { if (!this.canvas) return; this.canvas.isDrawingMode = true; this.canvas.selection = false; const redColor = "#FF0000"; // 确保有笔刷管理器 if (this.brushManager) { // 设置红色笔刷 this.brushManager.setBrushColor(redColor); // 纯红色 this.brushManager.setBrushOpacity(1.0); // 完全不透明 this.brushManager.setBrushType("pencil"); // 铅笔类型 // 更新笔刷大小(使用当前大小) if (BrushStore && BrushStore.state.size) { this.brushManager.setBrushSize(BrushStore.state.size); } // 更新应用到画布 this.brushManager.updateBrush(); } // 启用笔刷指示器并设置红色 this._enableBrushIndicator(redColor); } /** * 设置绿色笔刷工具(红绿图模式专用) */ setupGreenBrushTool() { if (!this.canvas) return; this.canvas.isDrawingMode = true; this.canvas.selection = false; const greenColor = "#00FF00"; // 确保有笔刷管理器 if (this.brushManager) { // 设置绿色笔刷 this.brushManager.setBrushColor(greenColor); // 纯绿色 this.brushManager.setBrushOpacity(1.0); // 完全不透明 this.brushManager.setBrushType("pencil"); // 铅笔类型 // 更新笔刷大小(使用当前大小) if (BrushStore && BrushStore.state.size) { this.brushManager.setBrushSize(BrushStore.state.size); } // 更新应用到画布 this.brushManager.updateBrush(); } // 启用笔刷指示器并设置绿色 this._enableBrushIndicator(greenColor); } /** * 进入红绿图模式 * @param {Object} redGreenModeManager 红绿图模式管理器实例 */ enterRedGreenMode(redGreenModeManager) { this.isRedGreenMode = true; this.redGreenModeManager = redGreenModeManager; // 切换到红色笔刷工具作为默认工具 this.setTool(OperationType.RED_BRUSH); console.log("工具管理器已进入红绿图模式"); } /** * 退出红绿图模式 */ exitRedGreenMode() { this.isRedGreenMode = false; this.redGreenModeManager = null; // 切换回选择工具 this.setTool(OperationType.SELECT); console.log("工具管理器已退出红绿图模式"); } /** * 检查工具是否在红绿图模式下可用 * @param {String} toolId 工具ID * @returns {Boolean} 是否可用 */ isToolAvailableInRedGreenMode(toolId) { if (!this.isRedGreenMode) return true; const tool = this.tools[toolId]; return tool && tool.allowedInRedGreen === true; } /** * 获取红绿图模式下可用的工具列表 * @returns {Array} 工具列表 */ getRedGreenModeTools() { return Object.keys(this.tools) .filter((toolId) => this.tools[toolId].allowedInRedGreen === true) .map((toolId) => ({ id: toolId, ...this.tools[toolId], })); } /** * 检查是否为红绿图模式专用工具 * @param {String} toolId 工具ID * @returns {Boolean} 是否为红绿图模式专用工具 */ isRedGreenOnlyTool(toolId) { const tool = this.tools[toolId]; return tool && tool.redGreenOnly === true; } /** * 启用笔刷指示器 * @param {String} color 笔刷颜色(可选) * @private */ _enableBrushIndicator(color) { if (!this.brushIndicator) return; // 获取当前笔刷大小 const brushSize = this._getCurrentBrushSize(); // 获取当前笔刷颜色 const brushColor = color || this._getCurrentBrushColor(); // 启用指示器 this.brushIndicator.enable(brushSize); // 更新指示器颜色 this.brushIndicator.updateColor(brushColor); console.log(`笔刷指示器已启用,大小: ${brushSize}, 颜色: ${brushColor}`); } /** * 禁用笔刷指示器 * @private */ _disableBrushIndicator() { if (!this.brushIndicator) return; this.brushIndicator.disable(); console.log("笔刷指示器已禁用"); } /** * 更新笔刷指示器大小 * @param {Number} size 新的笔刷大小 */ updateBrushIndicatorSize(size) { if (!this.brushIndicator) return; this.brushIndicator.updateSize(size); console.log(`笔刷指示器大小已更新为: ${size}`); } /** * 更新笔刷指示器颜色 * @param {String} color 新的笔刷颜色 */ updateBrushIndicatorColor(color) { if (!this.brushIndicator) return; this.brushIndicator.updateColor(color); console.log(`笔刷指示器颜色已更新为: ${color}`); } /** * 获取当前笔刷大小 * @private * @returns {Number} 当前笔刷大小 */ _getCurrentBrushSize() { // 优先从 BrushStore 获取 if (BrushStore && BrushStore.state.size) { return BrushStore.state.size; } // 从笔刷管理器获取 if (this.brushManager && this.brushManager.getBrushSize) { return this.brushManager.getBrushSize(); } // 从画布笔刷获取 if ( this.canvas && this.canvas.freeDrawingBrush && this.canvas.freeDrawingBrush.width ) { return this.canvas.freeDrawingBrush.width; } // 默认值 return 10; } /** * 获取当前笔刷颜色 * @private * @returns {String} 当前笔刷颜色 */ _getCurrentBrushColor() { // 优先从 BrushStore 获取 if (BrushStore && BrushStore.state.color) { return BrushStore.state.color; } // 从笔刷管理器获取 if (this.brushManager && this.brushManager.getBrushColor) { return this.brushManager.getBrushColor(); } // 从画布笔刷获取 if ( this.canvas && this.canvas.freeDrawingBrush && this.canvas.freeDrawingBrush.color ) { return this.canvas.freeDrawingBrush.color; } // 默认值 return "#000000"; } /** * 检查当前工具是否需要显示笔刷指示器 * @param {String} toolId 工具ID(可选,不传则使用当前工具) * @returns {Boolean} 是否需要显示 */ _shouldShowBrushIndicator(toolId) { const currentTool = toolId || this.activeTool.value; // 画笔相关工具需要显示指示器 const brushTools = [ OperationType.DRAW, OperationType.ERASER, OperationType.RED_BRUSH, OperationType.GREEN_BRUSH, OperationType.LIQUIFY, ]; return brushTools.includes(currentTool); } }