990 lines
27 KiB
JavaScript
990 lines
27 KiB
JavaScript
import { fabric } from "fabric-with-all";
|
||
import "./fabric.brushes.js";
|
||
import { BrushStore } from "../../store/BrushStore";
|
||
import { brushRegistry } from "./BrushRegistry";
|
||
|
||
// 导入基础笔刷类型
|
||
import { PencilBrush } from "./types/PencilBrush";
|
||
import { TextureBrush } from "./types/TextureBrush";
|
||
|
||
// 导入集成的笔刷类型
|
||
import { CrayonBrush } from "./types/CrayonBrush";
|
||
import { FurBrush } from "./types/FurBrush";
|
||
import { InkBrush } from "./types/InkBrush";
|
||
import { LongfurBrush } from "./types/LongfurBrush";
|
||
import { WritingBrush } from "./types/WritingBrush";
|
||
import { MarkerBrush } from "./types/MarkerBrush";
|
||
import { CustomPenBrush } from "./types/CustomPenBrush";
|
||
import { RibbonBrush } from "./types/RibbonBrush";
|
||
import { ShadedBrush } from "./types/ShadedBrush";
|
||
import { EraserStateManager } from "../EraserStateManager";
|
||
import { SprayBrush } from "./types/SprayBrush";
|
||
// import { SketchyBrush } from "./types/SketchyBrush";
|
||
// import { SpraypaintBrush } from "./types/SpraypaintBrush";
|
||
|
||
/**
|
||
* 笔刷管理器
|
||
* 负责管理和切换不同的笔刷类型
|
||
*/
|
||
export class BrushManager {
|
||
/**
|
||
* 构造函数
|
||
* @param {Object} options 配置选项
|
||
* @param {Object} options.canvas fabric.js画布实例
|
||
* @param {Object} options.brushStore 笔刷数据存储(可选)
|
||
* @param {Object} options.layerManager 图层管理器实例(可选)
|
||
* @param {Function} options.t 国际化函数
|
||
*/
|
||
constructor(options = {}) {
|
||
this.canvas = options.canvas;
|
||
this.brushStore = options.brushStore || BrushStore;
|
||
this.layerManager = options.layerManager; // 添加图层管理器引用
|
||
this.t = options.t
|
||
|
||
// 当前活动笔刷
|
||
this.activeBrush = null;
|
||
this.activeBrushId = null;
|
||
|
||
// 初始化笔刷注册
|
||
this._registerDefaultBrushes();
|
||
|
||
// 初始化橡皮擦状态管理器
|
||
this.eraserStateManager = null;
|
||
this.isErasingActive = false;
|
||
this.currentErasedObjects = []; // 当前擦除会话中被影响的对象
|
||
}
|
||
|
||
/**
|
||
* 注册默认笔刷
|
||
* @private
|
||
*/
|
||
_registerDefaultBrushes() {
|
||
// 注册铅笔笔刷
|
||
brushRegistry.register("pencil", PencilBrush, {
|
||
name: this.t("Canvas.Pencil"),
|
||
description: "基础铅笔工具,适合精细线条绘制",
|
||
t:this.t,
|
||
category: this.t('Canvas.BasicBrushes'),
|
||
imgUrl:'./image/brush/pencil.jpg',
|
||
});
|
||
|
||
// 注册材质笔刷
|
||
brushRegistry.register("texture", TextureBrush, {
|
||
name: this.t("Canvas.Texture"),
|
||
description: "使用纹理图片作为笔刷,支持缩放和透明度",
|
||
t:this.t,
|
||
category: this.t('Canvas.BasicBrushes'),
|
||
imgUrl:'./image/brush/texture.jpg',
|
||
});
|
||
|
||
// 注册集成的笔刷类型
|
||
brushRegistry.register("crayon", CrayonBrush, {
|
||
name: this.t("Canvas.Crayon"),
|
||
description: "使用纹理图片作为笔刷,支持缩放和透明度",
|
||
t:this.t,
|
||
category: this.t('Canvas.BasicBrushes'),
|
||
imgUrl:'./image/brush/crayon.jpg',
|
||
});
|
||
brushRegistry.register("fur", FurBrush, {
|
||
name: this.t("Canvas.Fur"),
|
||
description: "使用纹理图片作为笔刷,支持缩放和透明度",
|
||
t:this.t,
|
||
category: this.t('Canvas.BasicBrushes'),
|
||
imgUrl:'./image/brush/fur.jpg',
|
||
});
|
||
brushRegistry.register("ink", InkBrush, {
|
||
name: this.t("Canvas.Ink"),
|
||
description: "墨水笔刷,适合书写和绘图",
|
||
t:this.t,
|
||
category: this.t('Canvas.BasicBrushes'),
|
||
imgUrl:'./image/brush/ink.jpg',
|
||
});
|
||
brushRegistry.register("", LongfurBrush, {
|
||
name: this.t("Canvas.Longfur"),
|
||
description: "长毛发笔刷,适合绘制动物毛皮、草或头发",
|
||
t:this.t,
|
||
category: this.t('Canvas.BasicBrushes'),
|
||
imgUrl:'./image/brush/longFur.jpg',
|
||
});
|
||
brushRegistry.register("writing", WritingBrush, {
|
||
name: this.t("Canvas.Writing"),
|
||
description: "书法笔刷,模拟中国传统书法毛笔效果,具有笔锋和墨色变化",
|
||
t:this.t,
|
||
category: this.t('Canvas.BasicBrushes'),
|
||
imgUrl:'./image/brush/writing.jpg',
|
||
});
|
||
brushRegistry.register("marker", MarkerBrush, {
|
||
name: this.t("Canvas.Marker"),
|
||
description: "马克笔笔刷,适合粗线条和填充",
|
||
t:this.t,
|
||
category: this.t('Canvas.BasicBrushes'),
|
||
imgUrl:'./image/brush/marker.jpg',
|
||
});
|
||
brushRegistry.register("pen", CustomPenBrush, {
|
||
name: this.t("Canvas.Pen"),
|
||
description: "自定义钢笔笔刷,适合书写和绘图",
|
||
t:this.t,
|
||
category: this.t('Canvas.BasicBrushes'),
|
||
imgUrl:'./image/brush/pen.jpg',
|
||
});
|
||
brushRegistry.register("ribbon", RibbonBrush, {
|
||
name: this.t("Canvas.Ribbon"),
|
||
description: "丝带笔刷,适合创建流动的丝带效果",
|
||
t:this.t,
|
||
category: this.t('Canvas.BasicBrushes'),
|
||
imgUrl:'./image/brush/ribbon.jpg',
|
||
});
|
||
brushRegistry.register("shaded", ShadedBrush, {
|
||
name: this.t("Canvas.Shaded"),
|
||
description: "阴影笔刷,适合创建渐变和阴影效果",
|
||
t:this.t,
|
||
category: this.t('Canvas.BasicBrushes'),
|
||
imgUrl:'./image/brush/shaded.jpg',
|
||
});
|
||
|
||
brushRegistry.register("spray", SprayBrush, {
|
||
name: this.t("Canvas.Spray"),
|
||
description: "模拟喷枪效果,创建散点效果",
|
||
t:this.t,
|
||
category: this.t('Canvas.BasicBrushes'),
|
||
imgUrl:'./image/brush/spray.jpg',
|
||
});
|
||
|
||
// brushRegistry.register("sketchy", SketchyBrush);
|
||
// brushRegistry.register("spraypaint", SpraypaintBrush, {
|
||
// name: "Spraypaint",
|
||
// description: "喷漆笔刷,模拟喷漆效果",
|
||
// t:this.t,
|
||
// category: this.t('Canvas.BasicBrushes'),
|
||
// });
|
||
|
||
// // // 注册喷枪笔刷
|
||
// brushRegistry.register(
|
||
// "spray",
|
||
// class SprayBrush extends PencilBrush {
|
||
// constructor(canvas, options = {}) {
|
||
// super(canvas, {
|
||
// id: "spray",
|
||
// name: "Spray",
|
||
// description: "模拟喷枪效果,创建散点效果",
|
||
// category: this.t('Canvas.BasicBrushes'),
|
||
// ...options,
|
||
// });
|
||
// }
|
||
|
||
// create() {
|
||
// this.brush = new fabric.SprayBrush(this.canvas);
|
||
// this.configure(this.brush, this.options);
|
||
// return this.brush;
|
||
// }
|
||
|
||
// configure(brush, options = {}) {
|
||
// super.configure(brush, options);
|
||
|
||
// if (options.density !== undefined) {
|
||
// brush.density = options.density;
|
||
// }
|
||
|
||
// if (options.randomOpacity !== undefined) {
|
||
// brush.randomOpacity = options.randomOpacity;
|
||
// }
|
||
|
||
// if (options.dotWidth !== undefined) {
|
||
// brush.dotWidth = options.dotWidth;
|
||
// }
|
||
// }
|
||
// },
|
||
// {
|
||
// name: "喷枪",
|
||
// description: "模拟喷枪效果,创建散点效果",
|
||
// }
|
||
// );
|
||
// 注册橡皮擦笔刷
|
||
const outerThis = this;
|
||
brushRegistry.register(
|
||
"eraser",
|
||
class EraserBrush extends PencilBrush {
|
||
constructor(canvas, options = {}) {
|
||
super(canvas, {
|
||
id: "eraser",
|
||
name: "橡皮擦",
|
||
t:outerThis.t,
|
||
description: "擦除已绘制的内容",
|
||
category: "工具",
|
||
...options,
|
||
});
|
||
}
|
||
|
||
create() {
|
||
// 直接使用 fabric-with-erasing 库提供的 EraserBrush
|
||
this.brush = new fabric.EraserBrush(this.canvas);
|
||
this.configure(this.brush, this.options);
|
||
|
||
// 配置橡皮擦特有属性
|
||
this.brush.inverted = this.options.inverted || false; // 是否反向擦除(恢复擦除)
|
||
|
||
return this.brush;
|
||
}
|
||
|
||
configure(brush, options = {}) {
|
||
super.configure(brush, options);
|
||
|
||
// 橡皮擦特有配置
|
||
if (options.inverted !== undefined) {
|
||
brush.inverted = options.inverted;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 设置反向擦除模式
|
||
* @param {Boolean} inverted 是否启用反向擦除(撤销擦除效果)
|
||
*/
|
||
setInverted(inverted) {
|
||
if (this.brush) {
|
||
this.brush.inverted = inverted;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取橡皮擦配置属性
|
||
* @returns {Array} 可配置属性数组
|
||
*/
|
||
getConfigurableProperties() {
|
||
return [
|
||
...super.getConfigurableProperties(),
|
||
{
|
||
id: "inverted",
|
||
name: "反向擦除",
|
||
type: "boolean",
|
||
description: "启用时可以恢复已擦除的内容",
|
||
defaultValue: false,
|
||
min: null,
|
||
max: null,
|
||
},
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 更新橡皮擦属性
|
||
* @param {String} propId 属性ID
|
||
* @param {any} value 属性值
|
||
*/
|
||
updateProperty(propId, value) {
|
||
if (propId === "inverted") {
|
||
this.setInverted(value);
|
||
} else {
|
||
super.updateProperty(propId, value);
|
||
}
|
||
}
|
||
}
|
||
);
|
||
|
||
// // 注册水彩笔刷
|
||
// brushRegistry.register(
|
||
// "watercolor",
|
||
// class WatercolorBrush extends PencilBrush {
|
||
// constructor(canvas, options = {}) {
|
||
// super(canvas, {
|
||
// id: "watercolor",
|
||
// name: "水彩",
|
||
// description: "模拟水彩效果,带有流动感和透明感",
|
||
// category: "特效笔刷",
|
||
// ...options,
|
||
// });
|
||
// }
|
||
|
||
// create() {
|
||
// // 创建一个自定义的PencilBrush来模拟水彩效果
|
||
// this.brush = new fabric.PencilBrush(this.canvas);
|
||
// this.configure(this.brush, this.options);
|
||
|
||
// // 水彩效果特有的属性
|
||
// this.brush.globalCompositeOperation = "multiply";
|
||
// this.brush.shadow = new fabric.Shadow({
|
||
// color: this.options.color || "#000",
|
||
// blur: 5,
|
||
// offsetX: 0,
|
||
// offsetY: 0,
|
||
// });
|
||
|
||
// return this.brush;
|
||
// }
|
||
|
||
// configure(brush, options = {}) {
|
||
// super.configure(brush, options);
|
||
|
||
// // 水彩笔刷特有的配置
|
||
// brush.opacity = Math.min(0.5, options.opacity || 0.3); // 默认透明度30%
|
||
// }
|
||
// }
|
||
// );
|
||
|
||
// // 注册粉笔笔刷
|
||
// brushRegistry.register(
|
||
// "chalk",
|
||
// class ChalkBrush extends PencilBrush {
|
||
// constructor(canvas, options = {}) {
|
||
// super(canvas, {
|
||
// id: "chalk",
|
||
// name: "粉笔",
|
||
// description: "模拟粉笔效果,有颗粒感和不连续性",
|
||
// category: "特效笔刷",
|
||
// ...options,
|
||
// });
|
||
// }
|
||
|
||
// create() {
|
||
// this.brush = new fabric.PencilBrush(this.canvas);
|
||
// this.configure(this.brush, this.options);
|
||
|
||
// // 自定义绘画方法来模拟粉笔效果
|
||
// const originalOnMouseMove = this.brush.onMouseMove;
|
||
// this.brush.onMouseMove = function (pointer, options) {
|
||
// // 随机调整坐标位置,增加粉笔质感
|
||
// const jitter = 2;
|
||
// pointer.x += (Math.random() - 0.5) * jitter;
|
||
// pointer.y += (Math.random() - 0.5) * jitter;
|
||
|
||
// // 调用原始方法
|
||
// originalOnMouseMove.call(this, pointer, options);
|
||
// };
|
||
|
||
// return this.brush;
|
||
// }
|
||
|
||
// configure(brush, options = {}) {
|
||
// super.configure(brush, options);
|
||
|
||
// // 粉笔特有的设置
|
||
// brush.strokeDashArray = [5, 5]; // 虚线效果
|
||
// }
|
||
// }
|
||
// );
|
||
}
|
||
|
||
/**
|
||
* 获取所有可用笔刷类型
|
||
* @returns {Array} 笔刷类型数组,包含id、name和description
|
||
*/
|
||
getBrushTypes() {
|
||
// 从注册表获取所有笔刷信息
|
||
const brushes = brushRegistry.getAllBrushes();
|
||
|
||
// 将笔刷信息转换为期望的格式
|
||
return brushes.map((brushInfo) => ({
|
||
id: brushInfo.id,
|
||
name: brushInfo.metadata.name || brushInfo.id,
|
||
description: brushInfo.metadata.description || "",
|
||
category: brushInfo.metadata.category || "默认",
|
||
icon: brushInfo.metadata.icon || null,
|
||
imgUrl: brushInfo.metadata.imgUrl || null,
|
||
}));
|
||
}
|
||
|
||
/**
|
||
* 初始化笔刷列表并更新BrushStore
|
||
*/
|
||
initializeBrushes() {
|
||
// 获取所有笔刷
|
||
const allBrushes = this.getBrushTypes();
|
||
|
||
// 更新BrushStore中的可用笔刷列表
|
||
this.brushStore.setAvailableBrushes(allBrushes);
|
||
|
||
// 设置默认笔刷
|
||
if (!this.activeBrushId && allBrushes.length > 0) {
|
||
this.setBrushType(allBrushes[0].id);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 设置笔刷类型
|
||
* @param {String} brushId 笔刷ID
|
||
* @returns {Object|null} 设置的笔刷实例
|
||
*/
|
||
setBrushType(brushId) {
|
||
// 如果相同笔刷,不做处理
|
||
if (this.activeBrushId === brushId) {
|
||
return this.activeBrush;
|
||
}
|
||
|
||
// 销毁当前笔刷
|
||
if (this.activeBrush) {
|
||
// 调用生命周期方法
|
||
if (this.activeBrush.onDeselected) {
|
||
this.activeBrush.onDeselected();
|
||
}
|
||
this.activeBrush.destroy();
|
||
}
|
||
// 创建新笔刷实例
|
||
try {
|
||
const brushInstance = brushRegistry.createBrushInstance(
|
||
brushId,
|
||
this.canvas,
|
||
{
|
||
color: brushId === "eraser" ? this.brushStore.state.color : undefined,
|
||
width: this.brushStore.state.size,
|
||
opacity: this.brushStore.state.opacity,
|
||
|
||
// 阴影相关配置
|
||
shadowEnabled: this.brushStore.state.shadowEnabled,
|
||
shadowColor: this.brushStore.state.shadowColor,
|
||
shadowWidth: this.brushStore.state.shadowWidth,
|
||
shadowOffsetX: this.brushStore.state.shadowOffsetX,
|
||
shadowOffsetY: this.brushStore.state.shadowOffsetY,
|
||
|
||
// 材质笔刷特有配置
|
||
textureEnabled: this.brushStore.state.textureEnabled,
|
||
texturePath: this.brushStore.state.texturePath,
|
||
textureScale: this.brushStore.state.textureScale,
|
||
}
|
||
);
|
||
|
||
if (brushInstance) {
|
||
// 创建笔刷
|
||
const fabricBrush = brushInstance.create();
|
||
|
||
// 更新画布的当前笔刷
|
||
if (fabricBrush) {
|
||
this.canvas.freeDrawingBrush = fabricBrush;
|
||
}
|
||
|
||
// 更新当前笔刷引用
|
||
this.activeBrush = brushInstance;
|
||
this.activeBrushId = brushId;
|
||
|
||
// 调用生命周期方法
|
||
if (this.activeBrush.onSelected) {
|
||
this.activeBrush.onSelected();
|
||
}
|
||
|
||
// 更新Store的笔刷类型
|
||
this.brushStore.setBrushType(brushId);
|
||
|
||
// 更新Store的当前笔刷实例,用于动态属性系统
|
||
this.brushStore.setCurrentBrushInstance(brushInstance);
|
||
|
||
return brushInstance;
|
||
}
|
||
} catch (error) {
|
||
console.error(`创建笔刷 ${brushId} 失败:`, error);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 设置笔刷颜色
|
||
* @param {String} color 十六进制颜色值
|
||
*/
|
||
setBrushColor(color) {
|
||
if (!this.canvas.freeDrawingBrush) return;
|
||
|
||
// 更新笔刷颜色
|
||
this.canvas.freeDrawingBrush.color = color;
|
||
|
||
// 更新活动笔刷
|
||
if (this.activeBrush) {
|
||
this.activeBrush.configure(this.canvas.freeDrawingBrush, { color });
|
||
}
|
||
|
||
// 更新Store
|
||
this.brushStore.setBrushColor(color);
|
||
}
|
||
|
||
/**
|
||
* 设置笔刷大小
|
||
* @param {Number} size 笔刷大小
|
||
*/
|
||
setBrushSize(size) {
|
||
if (!this.canvas.freeDrawingBrush) return;
|
||
|
||
// 限制大小范围
|
||
const brushSize = Math.max(0.1, Math.min(100, size));
|
||
|
||
// 更新笔刷大小
|
||
this.canvas.freeDrawingBrush.width = brushSize;
|
||
|
||
// 更新活动笔刷
|
||
if (this.activeBrush) {
|
||
this.activeBrush.configure(this.canvas.freeDrawingBrush, {
|
||
width: brushSize,
|
||
});
|
||
}
|
||
|
||
// 更新Store
|
||
this.brushStore.setBrushSize(brushSize);
|
||
|
||
return brushSize;
|
||
}
|
||
|
||
/**
|
||
* 增加笔刷大小
|
||
* @param {Number} amount 增加量
|
||
* @returns {Number} 新的笔刷大小
|
||
*/
|
||
increaseBrushSize(amount = 1) {
|
||
const currentSize = this.brushStore.state.size;
|
||
return this.setBrushSize(currentSize + amount);
|
||
}
|
||
|
||
/**
|
||
* 减少笔刷大小
|
||
* @param {Number} amount 减少量
|
||
* @returns {Number} 新的笔刷大小
|
||
*/
|
||
decreaseBrushSize(amount = 1) {
|
||
const currentSize = this.brushStore.state.size;
|
||
return this.setBrushSize(currentSize - amount);
|
||
}
|
||
|
||
/**
|
||
* 增加笔刷透明度
|
||
* @param {Number} amount 增加量
|
||
* @returns {Number} 新的笔刷大小
|
||
*/
|
||
increaseBrushOpacity(amount = 0.01) {
|
||
const currentSize = this.brushStore.state.opacity;
|
||
return this.setBrushOpacity(currentSize + amount);
|
||
}
|
||
|
||
/**
|
||
* 减少笔刷大小
|
||
* @param {Number} amount 减少量
|
||
* @returns {Number} 新的笔刷大小
|
||
*/
|
||
decreaseBrushOpacity(amount = 0.01) {
|
||
const currentSize = this.brushStore.state.opacity;
|
||
return this.setBrushOpacity(currentSize - amount);
|
||
}
|
||
|
||
/**
|
||
* 设置笔刷透明度
|
||
* @param {Number} opacity 透明度 (0-1)
|
||
*/
|
||
setBrushOpacity(opacity) {
|
||
if (!this.canvas.freeDrawingBrush) return;
|
||
|
||
// 限制透明度范围
|
||
const brushOpacity = Math.max(0.05, Math.min(1, opacity));
|
||
|
||
// 不再设置fabric笔刷的opacity属性,而是通过颜色的RGBA值来实现透明度
|
||
// this.canvas.freeDrawingBrush.opacity = brushOpacity;
|
||
|
||
// 更新活动笔刷配置,使用当前颜色和新的透明度
|
||
if (this.activeBrush) {
|
||
const currentColor = this.brushStore.state.color;
|
||
this.activeBrush.configure(this.canvas.freeDrawingBrush, {
|
||
color: currentColor,
|
||
opacity: brushOpacity,
|
||
});
|
||
}
|
||
|
||
// 确保上下文透明度始终为1,避免全局透明度问题
|
||
if (this.canvas.contextTop) {
|
||
this.canvas.contextTop.globalAlpha = 1;
|
||
}
|
||
|
||
// 更新Store
|
||
this.brushStore.setBrushOpacity(brushOpacity);
|
||
|
||
return brushOpacity;
|
||
}
|
||
|
||
/**
|
||
* 设置材质缩放
|
||
* @param {Number} scale 缩放比例
|
||
*/
|
||
setTextureScale(scale) {
|
||
// 限制缩放范围
|
||
const textureScale = Math.max(0.1, Math.min(10, scale));
|
||
|
||
// 更新活动笔刷
|
||
if (this.activeBrush && this.activeBrush.setTextureScale) {
|
||
this.activeBrush.setTextureScale(textureScale);
|
||
}
|
||
|
||
// 更新Store
|
||
this.brushStore.setTextureScale(textureScale);
|
||
|
||
return textureScale;
|
||
}
|
||
|
||
/**
|
||
* 增加材质缩放
|
||
* @param {Number} amount 增加量
|
||
*/
|
||
increaseTextureScale(amount = 0.1) {
|
||
const currentScale = this.brushStore.state.textureScale;
|
||
return this.setTextureScale(currentScale + amount);
|
||
}
|
||
|
||
/**
|
||
* 减少材质缩放
|
||
* @param {Number} amount 减少量
|
||
*/
|
||
decreaseTextureScale(amount = 0.1) {
|
||
const currentScale = this.brushStore.state.textureScale;
|
||
return this.setTextureScale(currentScale - amount);
|
||
}
|
||
|
||
/**
|
||
* 设置材质路径
|
||
* @param {String} path 材质图片路径
|
||
*/
|
||
setTexturePath(path) {
|
||
// 更新活动笔刷
|
||
if (this.activeBrush && this.activeBrush.setTexturePath) {
|
||
this.activeBrush.setTexturePath(path);
|
||
}
|
||
|
||
// 更新Store
|
||
this.brushStore.setTexturePath(path);
|
||
|
||
return path;
|
||
}
|
||
|
||
/**
|
||
* 启用/禁用材质
|
||
* @param {Boolean} enabled 是否启用
|
||
*/
|
||
setTextureEnabled(enabled) {
|
||
// 更新Store
|
||
this.brushStore.setTextureEnabled(enabled);
|
||
|
||
// 如果启用材质,且当前不是材质笔刷,需要切换
|
||
if (enabled && this.activeBrushId !== "texture") {
|
||
this.setBrushType("texture");
|
||
}
|
||
|
||
return enabled;
|
||
}
|
||
|
||
/**
|
||
* 注册新笔刷
|
||
* @param {String} id 笔刷ID
|
||
* @param {Class} brushClass 笔刷类
|
||
* @param {Object} metadata 笔刷元数据
|
||
* @returns {Boolean} 是否注册成功
|
||
*/
|
||
registerBrush(id, brushClass, metadata = {}) {
|
||
const success = brushRegistry.register(id, brushClass, metadata);
|
||
|
||
if (success) {
|
||
// 更新可用笔刷列表
|
||
this.initializeBrushes();
|
||
}
|
||
|
||
return success;
|
||
}
|
||
|
||
/**
|
||
* 设置依赖管理器
|
||
*/
|
||
setManagers({ layerManager, commandManager }) {
|
||
this.layerManager = layerManager;
|
||
this.commandManager = commandManager;
|
||
|
||
// 初始化橡皮擦状态管理器
|
||
if (this.canvas && this.layerManager) {
|
||
this.eraserStateManager = new EraserStateManager(
|
||
this.canvas,
|
||
this.layerManager
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 绑定橡皮擦事件处理器
|
||
* @private
|
||
*/
|
||
_bindEraserEvents() {
|
||
if (!this.canvas || !this.eraserStateManager) return;
|
||
|
||
// 监听擦除开始事件
|
||
this.canvas.on("erasing:start", this._handleErasingStart.bind(this));
|
||
|
||
// 监听擦除结束事件
|
||
this.canvas.on("erasing:end", this._handleErasingEnd.bind(this));
|
||
}
|
||
|
||
/**
|
||
* 解绑橡皮擦事件处理器
|
||
* @private
|
||
*/
|
||
_unbindEraserEvents() {
|
||
if (!this.canvas) return;
|
||
|
||
this.canvas.off("erasing:start", this._handleErasingStart.bind(this));
|
||
this.canvas.off("erasing:end", this._handleErasingEnd.bind(this));
|
||
}
|
||
|
||
/**
|
||
* 处理擦除开始事件
|
||
* @param {Object} e 事件对象
|
||
* @private
|
||
*/
|
||
_handleErasingStart(e) {
|
||
console.log("橡皮擦开始擦除");
|
||
|
||
if (!this.eraserStateManager) return;
|
||
|
||
// 标记擦除状态
|
||
this.isErasingActive = true;
|
||
this.currentErasedObjects = [];
|
||
|
||
// 捕获擦除前的状态
|
||
this.eraserStateManager.startErasing();
|
||
}
|
||
|
||
/**
|
||
* 处理擦除结束事件
|
||
* @param {Object} e 事件对象
|
||
* @private
|
||
*/
|
||
_handleErasingEnd(e) {
|
||
console.log("橡皮擦擦除结束", e);
|
||
|
||
if (!this.eraserStateManager || !this.isErasingActive) return;
|
||
|
||
// 获取被擦除的对象
|
||
const affectedObjects = e.targets || [];
|
||
|
||
// 创建橡皮擦命令
|
||
const eraserCommand = this.eraserStateManager.endErasing(affectedObjects);
|
||
|
||
// 如果有有效的命令且有命令管理器,执行命令
|
||
if (eraserCommand && this.commandManager) {
|
||
// 注意:不需要调用 execute(),因为擦除操作已经完成
|
||
// 只需要将命令添加到历史记录中以支持撤销
|
||
this.commandManager.addToHistory(eraserCommand);
|
||
console.log("橡皮擦操作已添加到命令历史");
|
||
}
|
||
|
||
// 重置状态
|
||
this.isErasingActive = false;
|
||
this.currentErasedObjects = [];
|
||
}
|
||
|
||
/**
|
||
* 取消当前擦除操作
|
||
*/
|
||
cancelErasing() {
|
||
if (!this.isErasingActive) return;
|
||
|
||
if (this.eraserStateManager) {
|
||
this.eraserStateManager.cancelErasing();
|
||
}
|
||
|
||
this.isErasingActive = false;
|
||
this.currentErasedObjects = [];
|
||
|
||
console.log("当前擦除操作已取消");
|
||
}
|
||
|
||
/**
|
||
* 获取当前笔刷类型
|
||
* @returns {String} 当前笔刷类型ID
|
||
*/
|
||
getCurrentBrushType() {
|
||
return this.activeBrushId;
|
||
}
|
||
|
||
/**
|
||
* 获取当前笔刷大小
|
||
* @returns {Number} 当前笔刷大小
|
||
*/
|
||
getBrushSize() {
|
||
return this.brushStore.state.size;
|
||
}
|
||
|
||
/**
|
||
* 获取当前笔刷颜色
|
||
* @returns {String} 当前笔刷颜色
|
||
*/
|
||
getBrushColor() {
|
||
return this.brushStore.state.color;
|
||
}
|
||
|
||
/**
|
||
* 获取当前笔刷透明度
|
||
* @returns {Number} 当前笔刷透明度
|
||
*/
|
||
getBrushOpacity() {
|
||
return this.brushStore.state.opacity;
|
||
}
|
||
|
||
/**
|
||
* 获取材质缩放
|
||
* @returns {Number} 材质缩放比例
|
||
*/
|
||
getTextureScale() {
|
||
return this.brushStore.state.textureScale;
|
||
}
|
||
|
||
/**
|
||
* 创建材质笔刷
|
||
* 这个方法保留用于向下兼容
|
||
* @deprecated 请使用setBrushType('texture')代替
|
||
* @returns {Object} 材质笔刷实例
|
||
*/
|
||
createTextureBrush() {
|
||
console.warn('createTextureBrush方法已废弃,请使用setBrushType("texture")');
|
||
return this.setBrushType("texture");
|
||
}
|
||
|
||
/**
|
||
* 更新笔刷
|
||
* 根据当前设置应用笔刷属性到画布
|
||
*/
|
||
updateBrush() {
|
||
if (!this.canvas) return;
|
||
|
||
// 如果有活动的笔刷实例,重新配置它
|
||
if (this.activeBrush && this.canvas.freeDrawingBrush) {
|
||
this.activeBrush.configure(this.canvas.freeDrawingBrush, {
|
||
color: this.brushStore.state.color,
|
||
width: this.brushStore.state.size,
|
||
opacity: this.brushStore.state.opacity,
|
||
});
|
||
} else {
|
||
// 如果没有活动笔刷,创建一个默认的
|
||
this.setBrushType(this.activeBrushId || "pencil");
|
||
}
|
||
|
||
// 更新画布状态
|
||
this?.canvas?.renderAll?.();
|
||
|
||
return this.canvas.freeDrawingBrush;
|
||
}
|
||
|
||
/**
|
||
* 更新笔刷阴影设置
|
||
*/
|
||
updateShadow() {
|
||
if (this.activeBrush && this.activeBrush.updateShadow) {
|
||
this.activeBrush.updateShadow();
|
||
}
|
||
}
|
||
|
||
// /**
|
||
// * 创建橡皮擦
|
||
// * @param {Object} options 橡皮擦选项
|
||
// */
|
||
// createEraser(options = {}) {
|
||
// if (!this.canvas) {
|
||
// console.error("画布未初始化");
|
||
// return null;
|
||
// }
|
||
|
||
// try {
|
||
// // 直接使用 fabric-with-erasing 库提供的 EraserBrush
|
||
// this.brush = new fabric.EraserBrush(this.canvas);
|
||
|
||
// // 应用配置
|
||
// this.configure(this.brush, {
|
||
// width: this.brushSize.value,
|
||
// color: this.brushColor.value,
|
||
// opacity: this.brushOpacity.value,
|
||
// inverted: options.inverted || false,
|
||
// ...options,
|
||
// });
|
||
|
||
// // 设置画布为绘图模式
|
||
// this.canvas.isDrawingMode = true;
|
||
// this.canvas.freeDrawingBrush = this.brush;
|
||
|
||
// // 绑定橡皮擦事件处理器
|
||
// // this._bindEraserEvents();
|
||
|
||
// console.log("橡皮擦创建成功");
|
||
// return this.brush;
|
||
// } catch (error) {
|
||
// console.error("创建橡皮擦失败:", error);
|
||
// return null;
|
||
// }
|
||
// }
|
||
|
||
/**
|
||
* 创建橡皮擦
|
||
* @returns {Object} 橡皮擦笔刷
|
||
*/
|
||
createEraser() {
|
||
return this.setBrushType("eraser");
|
||
}
|
||
|
||
/**
|
||
* 创建吸色工具
|
||
* @param {Function} callback 选择颜色后的回调函数
|
||
*/
|
||
createEyedropper(callback) {
|
||
// 保存当前状态
|
||
const previousBrushId = this.activeBrushId;
|
||
|
||
// 一次性事件处理程序
|
||
const handleMouseDown = (event) => {
|
||
const pointer = this.canvas.getPointer(event.e);
|
||
const ctx = this.canvas.getContext();
|
||
|
||
// 获取点击位置的像素
|
||
const imageData = ctx.getImageData(pointer.x, pointer.y, 1, 1).data;
|
||
|
||
// 将RGB转换为十六进制颜色
|
||
const color = `#${(
|
||
(1 << 24) +
|
||
(imageData[0] << 16) +
|
||
(imageData[1] << 8) +
|
||
imageData[2]
|
||
)
|
||
.toString(16)
|
||
.slice(1)}`;
|
||
|
||
// 调用回调函数
|
||
if (typeof callback === "function") {
|
||
callback(color);
|
||
}
|
||
|
||
// 恢复之前的笔刷
|
||
this.setBrushType(previousBrushId);
|
||
|
||
// 移除事件监听器
|
||
this.canvas.off("mouse:down", handleMouseDown);
|
||
};
|
||
|
||
// 添加事件监听器
|
||
this.canvas.on("mouse:down", handleMouseDown);
|
||
|
||
// 设置吸色光标
|
||
this.canvas.defaultCursor = "crosshair";
|
||
|
||
console.log("吸色工具已激活,点击画布选择颜色");
|
||
}
|
||
|
||
/**
|
||
* 销毁笔刷管理器
|
||
*/
|
||
dispose() {
|
||
// 解绑事件
|
||
// this._unbindEraserEvents();
|
||
|
||
// 取消进行中的擦除操作
|
||
this.cancelErasing();
|
||
|
||
// 清理状态管理器
|
||
if (this.eraserStateManager) {
|
||
this.eraserStateManager = null;
|
||
}
|
||
|
||
// 销毁当前笔刷
|
||
if (this.activeBrush) {
|
||
this.activeBrush.destroy();
|
||
this.activeBrush = null;
|
||
}
|
||
|
||
this.canvas = null;
|
||
}
|
||
}
|
||
|
||
// 导出单例
|
||
export default BrushManager;
|