feat: 添加喷枪笔刷类型,支持颗粒感和纹理效果
This commit is contained in:
@@ -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,7 +388,10 @@ export class BrushManager {
|
||||
}
|
||||
// 创建新笔刷实例
|
||||
try {
|
||||
const brushInstance = brushRegistry.createBrushInstance(brushId, this.canvas, {
|
||||
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,
|
||||
@@ -396,7 +407,8 @@ export class BrushManager {
|
||||
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)}`;
|
||||
|
||||
|
||||
@@ -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=";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user