Files
aida_front/src/component/Canvas/CanvasEditor/managers/ToolManager.js
2026-01-26 16:16:40 +08:00

1638 lines
44 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 { 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.props = options.props;
// 红绿图模式状态
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: "default",
setup: this.setupPartTool.bind(this),
},
[OperationType.PART_RECTANGLE]: {
name: "部件选取工具-矩形",
icon: "part",
cursor: "crosshair",
setup: this.setupPartRectangleTool.bind(this),
},
[OperationType.PART_BRUSH]: {
name: "部件选取工具-画笔",
icon: "part",
cursor: "default",
setup: this.setupPartBrushTool.bind(this),
},
[OperationType.PART_ERASER]: {
name: "部件选取工具-橡皮擦",
icon: "part",
cursor: "default",
setup: this.setupPartEraserTool.bind(this),
},
// 红绿图模式专用工具
[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(true);
}
// 通知选区管理器工具已改变
if (this.canvasManager && this.canvasManager.selectionManager) {
this.canvasManager.selectionManager.setCurrentTool(toolId);
}
if (this.canvasManager && this.canvasManager.partManager) {
this.canvasManager.partManager.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(true);
}
}
/**
* 切换回先前使用的工具
*/
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?.isPrintTrims || !!layer?.isPrintTrimsGroup;
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
);
}
}
/**
* 设置部件选取工具
*/
setupPartTool(isExecute = false) {
if (!this.canvas) return;
this.canvas.isDrawingMode = false;
this.canvas.selection = false;
if (!isExecute && this.canvasManager && this.canvasManager.partManager) {
this.canvasManager.partManager.setCurrentTool(OperationType.PART);
}
}
/**
* 设置部件选取工具--矩形
*/
setupPartRectangleTool(isExecute = false) {
if (!this.canvas) return;
this.canvas.isDrawingMode = false;
this.canvas.selection = false;
if (!isExecute && this.canvasManager && this.canvasManager.partManager) {
this.canvasManager.partManager.setCurrentTool(OperationType.PART_RECTANGLE);
}
}
/**
* 设置部件选取工具--画笔
*/
setupPartBrushTool(isExecute = false) {
if (!this.canvas) return;
this.canvas.isDrawingMode = true;
this.canvas.selection = false;
if (!isExecute && this.canvasManager && this.canvasManager.partManager) {
this.canvasManager.partManager.setCurrentTool(OperationType.PART_BRUSH);
}
const greenColor = "#0f0";
// 确保有笔刷管理器
if (this.brushManager) {
// 设置绿色笔刷
this.brushManager.setBrushColor(greenColor); // 纯绿色
this.brushManager.setBrushOpacity(200/255); // 完全不透明
this.brushManager.setBrushType("pencil"); // 铅笔类型
// 更新笔刷大小(使用当前大小)
if (BrushStore && BrushStore.state.size) {
this.brushManager.setBrushSize(BrushStore.state.size);
}
// 更新应用到画布
this.brushManager.updateBrush();
}
// 启用笔刷指示器并设置绿色
this._enableBrushIndicator(greenColor);
}
/**
* 设置部件选取工具--橡皮擦
*/
setupPartEraserTool(isExecute = false) {
if (!this.canvas) return;
this.canvas.isDrawingMode = true;
this.canvas.selection = false;
if (this.brushManager) {
this.brushManager.createEraser();
}
// 启用笔刷指示器
this._enableBrushIndicator();
if (!isExecute && this.canvasManager && this.canvasManager.partManager) {
this.canvasManager.partManager.setCurrentTool(OperationType.PART_ERASER);
}
}
/**
* 设置波浪工具
*/
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,
OperationType.PART_BRUSH,
OperationType.PART_ERASER,
];
return brushTools.includes(currentTool);
}
}