Files
aida_front/src/component/Canvas/CanvasEditor/managers/ToolManager.js

1450 lines
38 KiB
JavaScript
Raw Normal View History

2025-06-09 10:25:54 +08:00
import { BrushStore } from "../store/BrushStore";
import { BrushManager } from "./brushes/brushManager";
import { BrushIndicator } from "./BrushIndicator";
2025-06-09 10:25:54 +08:00
import { ToolCommand } from "../commands/ToolCommands";
2025-06-22 13:52:28 +08:00
import { CreateTextCommand } from "../commands/TextCommands";
2025-06-09 10:25:54 +08:00
import { OperationType } from "../utils/layerHelper";
import CanvasConfig from "../config/canvasConfig";
2025-06-18 11:05:23 +08:00
import { fabric } from "fabric-with-all";
import { InitLiquifyToolCommand } from "../commands/LiquifyCommands";
2025-06-22 13:52:28 +08:00
import { RasterizeLayerCommand } from "../commands/RasterizeLayerCommand";
2025-06-18 11:05:23 +08:00
import { message, Modal } from "ant-design-vue";
import { h } from "vue";
import { findObjectById } from "../utils/helper";
2025-06-09 10:25:54 +08:00
/**
* 工具管理器
* 负责管理编辑器中的各种工具
*/
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 当前活动工具的响应式引用
*/
constructor(options = {}) {
this.canvas = options.canvas;
this.commandManager = options.commandManager;
this.canvasManager = options.canvasManager;
this.layerManager = options.layerManager;
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, // 传入图层管理器引用
});
// 初始化笔刷指示器
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)",
});
}
2025-06-09 10:25:54 +08:00
// 观察者列表
this.observers = [];
// 工具列表 - 与OperationType保持一致
this.tools = {
// 基础工具
[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,
},
[OperationType.ERASER]: {
name: "橡皮擦",
icon: "eraser",
cursor: "crosshair",
shortcut: "E",
setup: this.setupEraserTool.bind(this),
allowedInRedGreen: 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,
},
[OperationType.LASSO_RECTANGLE]: {
name: "矩形套索工具",
icon: "lasso",
cursor: "crosshair",
// shortcut: "L",
altKey: true,
setup: this.setupRectangleLassoTool.bind(this),
allowedInRedGreen: false,
},
[OperationType.LASSO_ELLIPSE]: {
name: "椭圆形套索工具",
icon: "lasso",
cursor: "crosshair",
// shortcut: "L",
altKey: true,
setup: this.setupEllipseLassoTool.bind(this),
allowedInRedGreen: false,
},
// 选区工具 - 只需要矩形选区
[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, // 红绿图模式不允许液化
},
[OperationType.TEXT]: {
name: "文本工具",
icon: "text",
cursor: "text",
shortcut: "T",
setup: this.setupTextTool.bind(this),
allowedInRedGreen: false, // 红绿图模式不允许文本
},
// 红绿图模式专用工具
[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"
) {
2025-06-09 10:25:54 +08:00
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)
) {
2025-06-09 10:25:54 +08:00
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) {
// 检查工具是否存在
if (!this.tools[toolId]) {
console.error(`工具 '${toolId}' 不存在`);
return;
}
// 在红绿图模式下检查工具可用性
if (this.isRedGreenMode && !this.isToolAvailableInRedGreenMode(toolId)) {
console.warn(`工具 '${toolId}' 在红绿图模式下不可用`);
return;
}
// 在普通模式下检查是否为红绿图专用工具
if (!this.isRedGreenMode && this.isRedGreenOnlyTool(toolId)) {
console.warn(`工具 '${toolId}' 只能在红绿图模式下使用`);
return;
}
// 保存先前的工具
this.previousTool = this.activeTool.value;
// 如果切换到非画笔工具,禁用笔刷指示器
if (!this._shouldShowBrushIndicator(toolId)) {
this._disableBrushIndicator();
}
2025-06-09 10:25:54 +08:00
// 设置新工具
this.activeTool.value = toolId;
// 设置光标
if (this.canvas) {
this.canvas.defaultCursor = this.tools[toolId].cursor;
}
// 设置工具特定的状态
const tool = this.tools[toolId];
if (tool && typeof tool.setup === "function") {
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,
});
2025-06-18 11:05:23 +08:00
command.undoable = options.undoable !== undefined ? options.undoable : true;
2025-06-09 10:25:54 +08:00
// 执行命令
this.commandManager.execute(command, { ...options });
}
/**
* 恢复当前工具的选择状态
* 在拖拽结束时调用确保canvas.selection状态与当前工具一致
*/
restoreSelectionState() {
if (!this.canvas) return;
const currentTool = this.activeTool.value;
const tool = this.tools[currentTool];
// 根据当前工具设置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;
}
/**
* 设置画笔工具
*/
setupBrushTool() {
if (!this.canvas) 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
);
2025-06-09 10:25:54 +08:00
// 同步材质设置
if (BrushStore.state.textureEnabled && BrushStore.state.texturePath) {
this.brushManager.setTexturePath(BrushStore.state.texturePath);
this.brushManager.setTextureScale(BrushStore.state.textureScale);
}
}
// 更新应用到画布
this.brushManager.updateBrush();
}
// 启用笔刷指示器并同步颜色
this._enableBrushIndicator();
2025-06-09 10:25:54 +08:00
}
/**
* 设置橡皮擦工具
*/
setupEraserTool() {
if (!this.canvas) return;
this.canvas.isDrawingMode = true;
this.canvas.selection = false;
// 确保有笔刷管理器
if (this.brushManager) {
this.brushManager.createEraser();
}
// 启用笔刷指示器
this._enableBrushIndicator();
2025-06-09 10:25:54 +08:00
}
/**
* 设置吸色工具
*/
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;
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
);
2025-06-09 10:25:54 +08:00
}
}
/**
* 设置椭圆形套索工具
*/
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
);
2025-06-09 10:25:54 +08:00
}
}
/**
* 设置自由选区工具
*/
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
);
2025-06-09 10:25:54 +08:00
}
}
/**
* 设置矩形选区工具
*/
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
);
2025-06-09 10:25:54 +08:00
}
}
/**
* 设置波浪工具
*/
setupWaveTool() {
if (!this.canvas) return;
this.canvas.isDrawingMode = false;
this.canvas.selection = false;
}
/**
* 设置液化工具
*/
setupLiquifyTool() {
if (!this.canvas || !this.layerManager) 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);
// 检查图层是否为空
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;
2025-06-09 10:25:54 +08:00
}
// 准备液化环境,获取原始图像数据
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) {
// 需要栅格化 (多个对象或组)
2025-06-18 11:05:23 +08:00
// 使用Modal询问用户是否要栅格化
this._showRasterizeConfirmModal(checkResult.isGroup, activeLayerId);
return; // 等待用户确认,不继续执行
2025-06-09 10:25:54 +08:00
}
}
}
}
// 总是触发液化面板显示事件,不论图层状态如何
document.dispatchEvent(
new CustomEvent("showLiquifyPanel", {
detail: panelDetail,
})
);
}
/**
2025-06-18 11:05:23 +08:00
* 显示栅格化确认Modal对话框
* @param {Boolean} isGroup 是否为组对象
2025-06-09 10:25:54 +08:00
* @param {String} layerId 图层ID
* @private
*/
2025-06-18 11:05:23 +08:00
_showRasterizeConfirmModal(isGroup, layerId) {
const title = "栅格化图层";
const content = "需要先栅格化才能进行液化操作,是否立即栅格化?";
Modal.confirm({
title,
content,
okText: "确定栅格化",
cancelText: "取消",
centered: true,
icon: h("span", { style: "color: #faad14;" }, "⚠️"),
onOk: () => {
// 用户确认栅格化,执行栅格化操作
2025-06-09 10:25:54 +08:00
this._rasterizeLayerForLiquify(layerId);
2025-06-18 11:05:23 +08:00
},
onCancel: () => {
console.log("用户取消了栅格化操作");
// 用户取消,触发液化面板显示事件但不能液化
document.dispatchEvent(
new CustomEvent("showLiquifyPanel", {
detail: {
activeLayerId: layerId,
layerStatus: { needsRasterization: true, isGroup },
canLiquify: false,
targetObject: null,
originalImageData: null,
},
})
);
},
});
2025-06-09 10:25:54 +08:00
}
/**
* 栅格化图层用于液化操作
* @param {String} layerId 图层ID
* @private
*/
async _rasterizeLayerForLiquify(layerId) {
if (!this.commandManager || !this.layerManager) return;
try {
2025-06-18 11:05:23 +08:00
// 显示加载Modal
const loadingModal = Modal.info({
title: "正在栅格化",
content: "正在栅格化图层,请稍候...",
okButtonProps: { style: { display: "none" } },
centered: true,
closable: false,
maskClosable: false,
});
2025-06-09 10:25:54 +08:00
// 创建栅格化命令
2025-06-18 11:05:23 +08:00
const rasterizeCommand = new RasterizeLayerCommand({
2025-06-09 10:25:54 +08:00
canvas: this.canvas,
layerManager: this.layerManager,
layerId: layerId,
2025-06-18 11:05:23 +08:00
layers: this.layerManager.layers,
activeLayerId: this.layerManager.activeLayerId,
2025-06-09 10:25:54 +08:00
});
// 执行命令
const result = await this.commandManager.execute(rasterizeCommand);
2025-06-18 11:05:23 +08:00
// 关闭加载Modal
loadingModal.destroy();
2025-06-09 10:25:54 +08:00
if (result) {
// 栅格化成功,启动液化
2025-06-18 11:05:23 +08:00
message.success("图层已成功栅格化,可以进行液化操作");
2025-06-09 10:25:54 +08:00
this._startLiquify(layerId);
2025-06-18 11:05:23 +08:00
} else {
// 栅格化失败
Modal.error({
title: "栅格化失败",
content: "栅格化失败,无法进行液化操作",
okText: "确定",
centered: true,
});
2025-06-09 10:25:54 +08:00
}
} catch (error) {
console.error("栅格化图层失败:", error);
2025-06-18 11:05:23 +08:00
Modal.error({
title: "栅格化错误",
content: `栅格化失败:${error.message}`,
okText: "确定",
centered: true,
});
2025-06-09 10:25:54 +08:00
}
}
/**
* 开始液化操作
* @param {String} layerId 图层ID
* @private
*/
async _startLiquify(layerId) {
// 获取图层信息
const layer = this.layerManager.getLayerById(layerId);
if (!layer) {
2025-06-18 11:05:23 +08:00
Modal.error({
title: "图层错误",
content: "图层不存在",
okText: "确定",
centered: true,
});
2025-06-09 10:25:54 +08:00
return;
}
// 检查图层是否为空
let targetObject = null;
if (layer.isBackground) {
// 背景图层使用 fabricObject (单数)
if (!layer.fabricObject) {
2025-06-18 11:05:23 +08:00
Modal.warning({
title: "背景图层为空",
content: "背景图层为空,无法进行液化操作",
okText: "确定",
centered: true,
});
2025-06-09 10:25:54 +08:00
return;
}
targetObject = layer.fabricObject;
} else {
// 普通图层使用 fabricObjects (复数)
if (!layer.fabricObjects || layer.fabricObjects.length === 0) {
2025-06-18 11:05:23 +08:00
Modal.warning({
title: "图层为空",
content: "图层为空,无法进行液化操作",
okText: "确定",
centered: true,
});
2025-06-09 10:25:54 +08:00
return;
}
targetObject = layer.fabricObjects[0];
}
// 确保liquifyManager可用
const liquifyManager = this.canvasManager?.liquifyManager;
if (!liquifyManager) {
2025-06-18 11:05:23 +08:00
Modal.error({
title: "液化管理器错误",
content: "液化管理器未初始化",
okText: "确定",
centered: true,
});
2025-06-09 10:25:54 +08:00
return;
}
try {
2025-06-18 11:05:23 +08:00
// 显示准备中的Modal
const preparingModal = Modal.info({
title: "准备液化环境",
content: "正在准备液化环境,请稍候...",
okButtonProps: { style: { display: "none" } },
centered: true,
closable: false,
maskClosable: false,
});
2025-06-09 10:25:54 +08:00
// 准备液化环境
liquifyManager.initialize({
canvas: this.canvas,
layerManager: this.layerManager,
});
// 准备液化操作,获取原始图像数据
const prepareResult = await liquifyManager.prepareForLiquify(
targetObject
);
2025-06-09 10:25:54 +08:00
// 创建和初始化命令
const initCommand = new InitLiquifyToolCommand({
canvas: this.canvas,
layerManager: this.layerManager,
liquifyManager,
toolManager: this,
});
// 执行初始化命令
await this.commandManager.execute(initCommand);
2025-06-18 11:05:23 +08:00
// 关闭准备Modal
preparingModal.destroy();
2025-06-09 10:25:54 +08:00
// 触发液化面板显示事件
document.dispatchEvent(
new CustomEvent("showLiquifyPanel", {
detail: {
targetObject,
targetLayerId: layerId,
originalImageData: prepareResult.originalImageData,
},
})
);
} catch (error) {
console.error("启动液化工具失败:", error);
2025-06-18 11:05:23 +08:00
Modal.error({
title: "液化工具启动失败",
content: `启动液化工具失败:${error.message}`,
okText: "确定",
centered: true,
});
2025-06-09 10:25:54 +08:00
}
}
/**
* 触发文件上传操作
*/
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);
2025-06-09 10:25:54 +08:00
}
/**
* 创建文字对象并添加到画布
* @param {Number} x 文本位置x坐标
* @param {Number} y 文本位置y坐标
* @param {Object} options 文本选项
*/
2025-06-22 13:52:28 +08:00
async createText(x, y, options = {}) {
// 使用命令模式创建文本
2025-06-09 10:25:54 +08:00
if (!this.canvas || !this.layerManager) return null;
2025-06-22 13:52:28 +08:00
if (this.commandManager) {
const command = new CreateTextCommand({
canvas: this.canvas,
layerManager: this.layerManager,
x,
y,
textOptions: options,
});
// 执行命令
return await this.commandManager.execute(command);
} else {
// 如果没有命令管理器,直接调用原有方法(兼容性)
return await this._createTextDirect(x, y, options);
}
}
2025-06-09 10:25:54 +08:00
2025-06-22 13:52:28 +08:00
/**
* 直接创建文本的方法用于向后兼容
* @param {Number} x 文本位置x坐标
* @param {Number} y 文本位置y坐标
* @param {Object} options 文本选项
* @private
*/
_createTextDirect(x, y, options = {}) {
2025-06-09 10:25:54 +08:00
// 默认文本属性
const defaultOptions = {
text: "双击编辑文本",
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);
2025-06-09 10:25:54 +08:00
}
/**
* 更新笔刷透明度
* @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")
2025-06-09 10:25:54 +08:00
) {
// 获取对应的图层
const layer = this.layerManager.getLayerById(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,
},
})
);
}
/**
* 清理资源
*/
dispose() {
if (this.brushManager) {
this.brushManager.dispose();
}
// 清理笔刷指示器
if (this.brushIndicator) {
this.brushIndicator.dispose();
this.brushIndicator = null;
}
2025-06-09 10:25:54 +08:00
// 移除文本编辑相关事件监听器
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";
2025-06-09 10:25:54 +08:00
// 确保有笔刷管理器
if (this.brushManager) {
// 设置红色笔刷
this.brushManager.setBrushColor(redColor); // 纯红色
2025-06-09 10:25:54 +08:00
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);
2025-06-09 10:25:54 +08:00
}
/**
* 设置绿色笔刷工具红绿图模式专用
*/
setupGreenBrushTool() {
if (!this.canvas) return;
this.canvas.isDrawingMode = true;
this.canvas.selection = false;
const greenColor = "#00FF00";
2025-06-09 10:25:54 +08:00
// 确保有笔刷管理器
if (this.brushManager) {
// 设置绿色笔刷
this.brushManager.setBrushColor(greenColor); // 纯绿色
2025-06-09 10:25:54 +08:00
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);
2025-06-09 10:25:54 +08:00
}
/**
* 进入红绿图模式
* @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);
}
/**
* 更新笔刷指示器颜色
* @param {String} color 新的笔刷颜色
*/
updateBrushIndicatorColor(color) {
if (!this.brushIndicator) return;
this.brushIndicator.updateColor(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,
];
return brushTools.includes(currentTool);
}
2025-06-09 10:25:54 +08:00
}