From 24a98d215e8ad157cf15728bb972cf7722cc5c78 Mon Sep 17 00:00:00 2001 From: bighuixiang <472705331@qq.com> Date: Mon, 4 Aug 2025 23:01:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=96=B7=E6=9E=AA?= =?UTF-8?q?=E7=AC=94=E5=88=B7=E7=B1=BB=E5=9E=8B=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E9=A2=97=E7=B2=92=E6=84=9F=E5=92=8C=E7=BA=B9=E7=90=86=E6=95=88?= =?UTF-8?q?=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../managers/brushes/brushManager.js | 126 +++++---- .../managers/brushes/types/SprayBrush.js | 246 ++++++++++++++++++ 2 files changed, 319 insertions(+), 53 deletions(-) create mode 100644 src/component/Canvas/CanvasEditor/managers/brushes/types/SprayBrush.js diff --git a/src/component/Canvas/CanvasEditor/managers/brushes/brushManager.js b/src/component/Canvas/CanvasEditor/managers/brushes/brushManager.js index 0e356d4f..4cf6ca3b 100644 --- a/src/component/Canvas/CanvasEditor/managers/brushes/brushManager.js +++ b/src/component/Canvas/CanvasEditor/managers/brushes/brushManager.js @@ -18,6 +18,7 @@ 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"; @@ -116,6 +117,13 @@ export class BrushManager { description: "阴影笔刷,适合创建渐变和阴影效果", category: "基础笔刷", }); + + brushRegistry.register("spray", SprayBrush, { + name: "spray", + description: "模拟喷枪效果,创建散点效果", + category: "基础笔刷", + }); + // brushRegistry.register("sketchy", SketchyBrush); // brushRegistry.register("spraypaint", SpraypaintBrush, { // name: "Spraypaint", @@ -123,47 +131,47 @@ export class BrushManager { // category: "基础笔刷", // }); - // // 注册喷枪笔刷 - brushRegistry.register( - "spray", - class SprayBrush extends PencilBrush { - constructor(canvas, options = {}) { - super(canvas, { - id: "spray", - name: "Spray", - description: "模拟喷枪效果,创建散点效果", - category: "基础笔刷", - ...options, - }); - } + // // // 注册喷枪笔刷 + // brushRegistry.register( + // "spray", + // class SprayBrush extends PencilBrush { + // constructor(canvas, options = {}) { + // super(canvas, { + // id: "spray", + // name: "Spray", + // description: "模拟喷枪效果,创建散点效果", + // category: "基础笔刷", + // ...options, + // }); + // } - create() { - this.brush = new fabric.SprayBrush(this.canvas); - this.configure(this.brush, this.options); - return this.brush; - } + // create() { + // this.brush = new fabric.SprayBrush(this.canvas); + // this.configure(this.brush, this.options); + // return this.brush; + // } - configure(brush, options = {}) { - super.configure(brush, options); + // configure(brush, options = {}) { + // super.configure(brush, options); - if (options.density !== undefined) { - brush.density = options.density; - } + // if (options.density !== undefined) { + // brush.density = options.density; + // } - if (options.randomOpacity !== undefined) { - brush.randomOpacity = options.randomOpacity; - } + // if (options.randomOpacity !== undefined) { + // brush.randomOpacity = options.randomOpacity; + // } - if (options.dotWidth !== undefined) { - brush.dotWidth = options.dotWidth; - } - } - }, - { - name: "喷枪", - description: "模拟喷枪效果,创建散点效果", - } - ); + // if (options.dotWidth !== undefined) { + // brush.dotWidth = options.dotWidth; + // } + // } + // }, + // { + // name: "喷枪", + // description: "模拟喷枪效果,创建散点效果", + // } + // ); // 注册橡皮擦笔刷 brushRegistry.register( "eraser", @@ -380,23 +388,27 @@ export class BrushManager { } // 创建新笔刷实例 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, + 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, + // 阴影相关配置 + 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, - }); + // 材质笔刷特有配置 + textureEnabled: this.brushStore.state.textureEnabled, + texturePath: this.brushStore.state.texturePath, + textureScale: this.brushStore.state.textureScale, + } + ); if (brushInstance) { // 创建笔刷 @@ -645,7 +657,10 @@ export class BrushManager { // 初始化橡皮擦状态管理器 if (this.canvas && this.layerManager) { - this.eraserStateManager = new EraserStateManager(this.canvas, this.layerManager); + this.eraserStateManager = new EraserStateManager( + this.canvas, + this.layerManager + ); } } @@ -885,7 +900,12 @@ export class BrushManager { const imageData = ctx.getImageData(pointer.x, pointer.y, 1, 1).data; // 将RGB转换为十六进制颜色 - const color = `#${((1 << 24) + (imageData[0] << 16) + (imageData[1] << 8) + imageData[2]) + const color = `#${( + (1 << 24) + + (imageData[0] << 16) + + (imageData[1] << 8) + + imageData[2] + ) .toString(16) .slice(1)}`; diff --git a/src/component/Canvas/CanvasEditor/managers/brushes/types/SprayBrush.js b/src/component/Canvas/CanvasEditor/managers/brushes/types/SprayBrush.js new file mode 100644 index 00000000..b37d33cf --- /dev/null +++ b/src/component/Canvas/CanvasEditor/managers/brushes/types/SprayBrush.js @@ -0,0 +1,246 @@ +import { BaseBrush } from "../BaseBrush"; + +/** + * 喷枪笔刷 + * 模拟喷枪效果,具有颗粒感和纹理 + */ +export class SprayBrush extends BaseBrush { + /** + * 构造函数 + * @param {Object} canvas fabric画布实例 + * @param {Object} options 配置选项 + */ + constructor(canvas, options = {}) { + super(canvas, { + id: "crayon", + name: "喷枪", + description: "模拟喷枪效果,具有颗粒感和纹理", + category: "特效笔刷", + icon: "crayon", + ...options, + }); + + // 喷枪笔刷特有属性 + this._baseWidth = options._baseWidth || 15; + this._size = options._size || 0; + this._sep = options._sep || options._sep === 0 ? options._sep : 1; + this._inkAmount = options._inkAmount || 10; + this.randomness = options.randomness || 0.8; // 随机性 + this.texture = options.texture || "default"; // 纹理类型 + } + + /** + * 创建笔刷实例 + * @returns {Object} fabric笔刷实例 + */ + create() { + if (!this.canvas) { + throw new Error("画布实例不存在"); + } + + // 创建fabric原生喷枪笔刷 + this.brush = new fabric.CrayonBrush(this.canvas); + + // 配置笔刷 + this.configure(this.brush, this.options); + + return this.brush; + } + + /** + * 配置笔刷 + * @param {Object} brush fabric笔刷实例 + * @param {Object} options 配置选项 + */ + configure(brush, options = {}) { + if (!brush) return; + + options._sep = options._sep || this._sep; + options._inkAmount = options._inkAmount || this._inkAmount; + + // 基础属性配置 + if (options.width !== undefined) { + brush.width = options.width; + // 更新笔刷相关属性 + this._baseWidth = options.width / 2; + this._size = options.width / 2 + this._baseWidth; + } + + if (options.color !== undefined) { + brush.color = options.color; + } + + if (options.opacity !== undefined) { + brush.opacity = options.opacity; + } + + // 喷枪笔刷特有属性 + if (options._baseWidth !== undefined) { + brush._baseWidth = options._baseWidth; + this._baseWidth = options._baseWidth; + this._size = this.width / 2 + this._baseWidth; + } + if (options._sep !== undefined) { + brush._sep = options._sep; + this._sep = options._sep; + } + + if (options._inkAmount !== undefined) { + brush._inkAmount = options._inkAmount; + this._inkAmount = options._inkAmount; + } + } + + /** + * 设置颗粒分离度 + * @param {Number} sep 分离度值 + */ + setSeparation(sep) { + this._sep = Math.max(0.5, Math.min(10, sep)); + + if (this.brush) { + this.brush._sep = this._sep; + } + + return this._sep; + } + + /** + * 设置墨量 + * @param {Number} amount 墨量值 + */ + setInkAmount(amount) { + this._inkAmount = Math.max(1, Math.min(50, amount)); + + if (this.brush) { + this.brush._inkAmount = this._inkAmount; + } + + return this._inkAmount; + } + + /** + * 设置随机性 + * @param {Number} value 随机性值(0-1) + */ + setRandomness(value) { + this.randomness = Math.max(0, Math.min(1, value)); + return this.randomness; + } + + /** + * 设置纹理类型 + * @param {String} type 纹理类型 + */ + setTexture(type) { + this.texture = type; + // 实际应用可能需要更多的实现逻辑 + return this.texture; + } + + /** + * 获取笔刷可配置属性 + * @returns {Array} 可配置属性描述数组 + * @override + */ + getConfigurableProperties() { + // 获取基础属性 + const baseProperties = super.getConfigurableProperties(); + + // 定义喷枪笔刷特有属性 + const crayonProperties = [ + { + id: "separation", + name: "颗粒分离度", + type: "slider", + defaultValue: this._sep, + min: 0.5, + max: 10, + step: 0.5, + description: "控制喷枪颗粒的分离程度", + category: "喷枪设置", + order: 100, + }, + { + id: "inkAmount", + name: "墨量", + type: "slider", + defaultValue: this._inkAmount, + min: 1, + max: 50, + step: 1, + description: "控制喷枪的颜料量", + category: "喷枪设置", + order: 110, + }, + { + id: "randomness", + name: "随机性", + type: "slider", + defaultValue: this.randomness, + min: 0, + max: 1, + step: 0.05, + description: "控制喷枪纹理的随机程度", + category: "喷枪设置", + order: 120, + }, + { + id: "texture", + name: "纹理类型", + type: "select", + defaultValue: this.texture, + options: [ + { value: "default", label: "默认" }, + { value: "rough", label: "粗糙" }, + { value: "smooth", label: "平滑" }, + ], + description: "设置喷枪的纹理类型", + category: "喷枪设置", + order: 130, + }, + ]; + + // 合并并返回所有属性 + return [...baseProperties, ...crayonProperties]; + } + + /** + * 更新笔刷属性 + * @param {String} propId 属性ID + * @param {any} value 属性值 + * @returns {Boolean} 是否更新成功 + * @override + */ + updateProperty(propId, value) { + // 先检查基类能否处理此属性 + if (super.updateProperty(propId, value)) { + return true; + } + + // 处理喷枪笔刷特有属性 + if (propId === "separation") { + this.setSeparation(value); + return true; + } else if (propId === "inkAmount") { + this.setInkAmount(value); + return true; + } else if (propId === "randomness") { + this.setRandomness(value); + return true; + } else if (propId === "texture") { + this.setTexture(value); + return true; + } + + return false; + } + + /** + * 获取预览图 + * @returns {String} 预览图URL + */ + getPreview() { + return "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cmVjdCB4PSIxMCIgeT0iMTAiIHdpZHRoPSI4MCIgaGVpZ2h0PSI4MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjIiLz48cmVjdCB4PSIyMCIgeT0iMjAiIHdpZHRoPSI2MCIgaGVpZ2h0PSI2MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjIiLz48cmVjdCB4PSIzMCIgeT0iMzAiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjIiLz48L3N2Zz4="; + } +}