import { fabric } from "fabric-with-all"; import { generateId } from "../utils/helper"; import { OperationType } from "../utils/layerHelper"; import { CreateSelectionCommand } from "../commands/SelectionCommands"; import { ClearSelectionCommand } from "../commands/LassoCutoutCommand"; import addIcon from "@/assets/images/canvas/add.png"; import removeIcon from "@/assets/images/canvas/remove.png"; import { Https } from "@/tool/https"; import store from "@/store"; /** * 部件选择管理器 */ export class PartManager { /** * 创建部件选择管理器 * @param {Object} options 配置选项 * @param {Object} options.canvas fabric.js画布实例 * @param {Object} options.commandManager 命令管理器实例 * @param {Object} options.canvasManager 画布管理实例 * @param {Object} options.layerManager 图层管理实例 * @param {Object} options.toolManager 工具管理实例 */ constructor(options = {}) { this.canvas = options.canvas; this.commandManager = options.commandManager; this.layerManager = options.layerManager; this.canvasManager = options.canvasManager; this.toolManager = options.toolManager; this.props = options.props; // 状态 this.isActive = false; this.partObject = null; // 当前选区对象 this.partId = "part_selector"; this.defaultCursor = "default"; // 绘制状态 this.drawingObject = null; this.startPoint = null; this.partPath = null; // 存储选区路径数据 // 不再直接绑定事件处理函数 this._mouseDownHandler = null; this._mouseMoveHandler = null; this._mouseUpHandler = null; this._keyDownHandler = null; // 选区相关的工具类型 this.tools = [ OperationType.PART, OperationType.PART_RECTANGLE, OperationType.PART_BRUSH, OperationType.PART_ERASER, ]; // 当前工具 this.activeTool = this.toolManager.activeTool; // 选区状态变化回调 this.onSelectionChanged = null; } /** * 设置当前工具 * @param {String} toolId 工具ID */ setCurrentTool(toolId) { // 检查是否为选区工具 const wasActive = this.isActive; this.isActive = this.tools.includes(toolId); // 如果从非选区工具切换到选区工具,初始化事件 if (!wasActive && this.isActive) { this.initEvents(); } // 如果从选区工具切换到非选区工具,清理事件和选区 else if (wasActive && !this.isActive) { this.cleanupEvents(); this.clearSelection(); } } /** * 初始化选区相关事件 */ initEvents() { if (!this.canvas || this._mouseDownHandler) return; // 避免重复初始化 this.defaultCursor = this.canvas.defaultCursor; // 保存实例引用,用于事件处理函数中 const self = this; // 鼠标按下事件处理 this._mouseDownHandler = (options) => { // 如果选区功能未激活,不处理事件 if (!this.isActive) return; // 阻止事件冒泡,避免与 CanvasEventManager 冲突 options.e.stopPropagation(); switch (this.activeTool.value) { case OperationType.PART: this._pointDownkHandler(options); break; case OperationType.PART_RECTANGLE: this._rectangleDownHandler(options); break; case OperationType.PART_BRUSH: this._brushDownHandler(options); break; case OperationType.PART_ERASER: this._eraseDownHandler(options); break; default: break; } }; // 鼠标移动事件处理 this._mouseMoveHandler = (options) => { // 如果选区功能未激活或没有正在绘制的对象,不处理事件 if (!this.isActive) return; // 阻止事件冒泡 options.e.stopPropagation(); switch (this.activeTool.value) { case OperationType.PART: this._pointMoveHandler(options); break; case OperationType.PART_RECTANGLE: this._rectangleMoveHandler(options); break; case OperationType.PART_BRUSH: this._brushMoveHandler(options); break; case OperationType.PART_ERASER: this._eraseMoveHandler(options); break; default: break; } }; // 鼠标抬起事件处理 this._mouseUpHandler = (options) => { // 如果选区功能未激活或没有正在绘制的对象,不处理事件 if (!this.isActive) return; // 阻止事件冒泡 if (options && options.e) { options.e.stopPropagation(); } switch (this.activeTool.value) { case OperationType.PART: this._pointUpHandler(options); break; case OperationType.PART_RECTANGLE: this._rectangleUpHandler(options); break; case OperationType.PART_BRUSH: this._brushUpHandler(options); break; case OperationType.PART_ERASER: this._eraseUpHandler(options); break; default: break; } }; // 键盘事件处理 this._keyDownHandler = (event) => { // 只在选区功能激活时处理键盘事件 if (!this.isActive) return; }; // 添加事件监听 this.canvas.on("mouse:down", this._mouseDownHandler); this.canvas.on("mouse:move", this._mouseMoveHandler); this.canvas.on("mouse:up", this._mouseUpHandler); // 添加键盘事件监听 document.addEventListener("keydown", this._keyDownHandler); } /** * 清理事件监听 */ cleanupEvents() { if (!this.canvas) return; // 移除事件监听 if (this._mouseDownHandler) { this.canvas.off("mouse:down", this._mouseDownHandler); this._mouseDownHandler = null; } if (this._mouseMoveHandler) { this.canvas.off("mouse:move", this._mouseMoveHandler); this._mouseMoveHandler = null; } if (this._mouseUpHandler) { this.canvas.off("mouse:up", this._mouseUpHandler); this._mouseUpHandler = null; } if (this._keyDownHandler) { document.removeEventListener("keydown", this._keyDownHandler); this._keyDownHandler = null; } } // 点选工具模式下点击事件处理 _pointDownkHandler(options) { const button = options.button; const isLeft = button === 1;// 左键1(添加) 右键3(删除) const icon = `url("${isLeft ? addIcon : removeIcon}") 16 16, default` this.canvas.upperCanvasEl.style.cursor = icon; } // 点选工具模式下移动事件处理 _pointMoveHandler(options) { } // 点选工具模式下抬起事件处理 _pointUpHandler(options) { const button = options.button; const isLeft = button === 1;// 左键1(添加) 右键3(删除) this.canvas.upperCanvasEl.style.cursor = this.defaultCursor; const fixedObject = this.canvasManager.getFixedLayerObject(); if (!fixedObject) return console.warn("未找到固定图层"); const { x, y } = options.pointer; const width = fixedObject.width * fixedObject.scaleX; const height = fixedObject.height * fixedObject.scaleY; const X = x - (fixedObject.left - width / 2); const Y = y - (fixedObject.top - height / 2); this.getSegAnythingImage({ image_path: "aida-users/24299/sketch/70bb39cc-63e0-44a9-a627-3542d0f9cd70.png", type: "point", points: [[X, Y], [X - 10, Y - 10]], labels: [1, 0], }); } // 框选工具模式下点击事件处理 _rectangleDownHandler(options) { } // 框选工具模式下移动事件处理 _rectangleMoveHandler(options) { } // 框选工具模式下抬起事件处理 _rectangleUpHandler(options) { } // 绘制工具模式下点击事件处理 _brushDownHandler(options) { } // 绘制工具模式下移动事件处理 _brushMoveHandler(options) { } // 绘制工具模式下抬起事件处理 _brushUpHandler(options) { } // 擦除工具模式下抬起事件处理 _eraseUpHandler(options) { } // 擦除工具模式下点击事件处理 _eraseDownHandler(options) { } // 擦除工具模式下移动事件处理 _eraseMoveHandler(options) { } // 获取分隔后图片 async getSegAnythingImage(obj) { const user_id = store.state.UserHabit.userDetail.userId; const data = { user_id, ...obj, } Https.axiosPost(Https.httpUrls.segAnything, data) .then(response => { console.log(response); }) .catch(error => { console.error(error); }); } /** * 清除选区 */ clearSelection() { // 移除选区对象 // this.removeSelectionFromCanvas(); // 重置选区状态 this.partObject = null; this.partPath = null; // 触发选区变化回调 if (this.onSelectionChanged && typeof this.onSelectionChanged === "function") { this.onSelectionChanged(); } return true; } /** * 清理资源 */ dispose() { this.cleanupEvents(); this.clearSelection(); this.canvas = null; this.commandManager = null; this.layerManager = null; } }