Files
FiDA_Front/src/components/Canvas/DepthCanvas/manager/brushes/BaseBrush.js

360 lines
9.8 KiB
JavaScript
Raw Normal View History

2026-03-11 15:34:56 +08:00
/**
* 笔刷基类
* 所有笔刷类型应继承此基类并实现必要的方法
*/
export class BaseBrush {
/**
* 构造函数
* @param {Object} canvas fabric画布实例
* @param {Object} options 笔刷配置选项
* @param {Object} t 翻译函数
*/
constructor(canvas, options = {}) {
this.canvas = canvas;
this.options = options;
this.t = options.t;
// 基本属性
this.id = options.id || this.constructor.name;
this.name = options.name || "未命名笔刷";
this.description = options.description || "";
this.icon = options.icon || null;
this.category = options.category || "默认";
// 笔刷实例
this.brush = null;
}
/**
* 创建笔刷实例必须由子类实现
* @returns {Object} fabric笔刷实例
*/
create() {
throw new Error("必须由子类实现create方法");
}
/**
* 配置笔刷必须由子类实现
* @param {Object} brush fabric笔刷实例
* @param {Object} options 配置选项
*/
configure(brush, options = {}) {
if (!brush) return;
// 基础属性配置
if (options.width !== undefined) {
brush.width = options.width;
}
if (options.color !== undefined && options.opacity !== undefined) {
// 使用RGBA颜色而不是设置globalAlpha
brush.color = this._createRGBAColor(options.color, options.opacity);
brush.opacity = 1; // 保持fabric层面的opacity为1
} else if (options.color !== undefined) {
brush.color = options.color;
} else if (options.opacity !== undefined) {
// 如果只设置了透明度基于当前颜色创建RGBA
const currentColor = brush.color || this.options.color || "#000000";
brush.color = this._createRGBAColor(currentColor, options.opacity);
brush.opacity = 1;
}
// 配置阴影
this.configureShadow(brush, options);
// 确保不使用globalAlpha避免圆圈绘制问题
if (brush.canvas && brush.canvas.contextTop) {
brush.canvas.contextTop.globalAlpha = 1;
brush.canvas.contextTop.lineCap = "round";
brush.canvas.contextTop.lineJoin = "round";
brush.canvas.contextTop.globalCompositeOperation = "source-over";
}
}
/**
* 配置笔刷阴影
* @param {Object} brush fabric笔刷实例
* @param {Object} options 配置选项
*/
configureShadow(brush, options = {}) {
if (!brush) return;
// 简化的阴影配置获取方法
let shadowConfig = null;
// 尝试从全局获取BrushStore在Vue组件中已经导入
if (typeof window !== "undefined" && window.BrushStore) {
shadowConfig = window.BrushStore.getShadowConfig();
} else {
// 如果没有全局BrushStore尝试从选项中获取
if (options.shadowEnabled) {
shadowConfig = {
color: options.shadowColor || "#000000",
blur: options.shadowWidth || 0,
offsetX: options.shadowOffsetX || 0,
offsetY: options.shadowOffsetY || 0,
};
}
}
if (shadowConfig) {
// 创建fabric.Shadow实例
if (typeof fabric !== "undefined" && fabric.Shadow) {
brush.shadow = new fabric.Shadow(shadowConfig);
}
} else {
// 清除阴影
brush.shadow = null;
}
}
/**
* 更新笔刷阴影设置
*/
updateShadow() {
if (this.brush) {
this.configureShadow(this.brush);
}
}
/**
* 创建RGBA颜色字符串
* @private
* @param {String} color 十六进制颜色或已有颜色
* @param {Number} opacity 透明度 (0-1)
* @returns {String} RGBA颜色字符串
*/
_createRGBAColor(color, opacity) {
// 如果已经是rgba颜色先提取RGB部分
if (color.startsWith("rgba")) {
const rgbaMatch = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/);
if (rgbaMatch) {
const [, r, g, b] = rgbaMatch;
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
}
}
// 如果是rgb颜色提取RGB部分
if (color.startsWith("rgb")) {
const rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
if (rgbMatch) {
const [, r, g, b] = rgbMatch;
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
}
}
// 处理十六进制颜色
if (color.startsWith("#")) {
const hex = color.replace("#", "");
let r, g, b;
if (hex.length === 3) {
r = parseInt(hex[0] + hex[0], 16);
g = parseInt(hex[1] + hex[1], 16);
b = parseInt(hex[2] + hex[2], 16);
} else if (hex.length === 6) {
r = parseInt(hex.substring(0, 2), 16);
g = parseInt(hex.substring(2, 4), 16);
b = parseInt(hex.substring(4, 6), 16);
} else {
// 无效的十六进制颜色,使用默认
r = g = b = 0;
}
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
}
// 如果是其他格式的颜色,尝试转换(例如颜色名称)
// 这里简化处理,实际项目中可以使用更复杂的颜色解析
return color; // fallback到原颜色
}
/**
* 获取笔刷的元数据
* @returns {Object} 笔刷元数据
*/
getMetadata() {
return {
id: this.id,
name: this.name,
description: this.description,
icon: this.icon,
category: this.category,
};
}
/**
* 获取笔刷预览
* @returns {String|null} 预览图URL或null
*/
getPreview() {
return null;
}
/**
* 获取笔刷可配置属性
* 这个方法返回一个对象数组每个对象描述一个可配置属性
* 每个属性对象包含
* - id: 属性标识符
* - name: 属性显示名称
* - type: 属性类型例如'slider', 'color', 'checkbox', 'select'
* - defaultValue: 默认值
* - min/max/step: 对于slider类型的限制值
* - options: 对于select类型的选项
* - description: 属性描述
* - category: 属性分类
* - order: 显示顺序越小越靠前
* - visibleWhen: 函数或对象定义何时显示该属性
* - dynamicOptions: 函数返回动态的选项列表
* @returns {Array} 可配置属性描述数组
*/
getConfigurableProperties() {
// 返回基础属性,所有笔刷都有这些属性
return [
{
id: "size",
name: this.t('Canvas.BrushSize'),
type: "slider",
defaultValue: 5,
min: 0.5,
max: 100,
step: 0.5,
description: this.t('Canvas.BrushDeSize'),
category: this.t('Canvas.basic'),
order: 10,
},
{
id: "color",
name: this.t('Canvas.BrushColor'),
type: "color",
defaultValue: "#000000",
description: this.t('Canvas.BrushDeColor'),
category: this.t('Canvas.basic'),
order: 20,
},
{
id: "opacity",
name: this.t('Canvas.BrushOpacity'),
type: "slider",
defaultValue: 1,
min: 0.05,
max: 1,
step: 0.01,
description: this.t('Canvas.BrushdeOpacity'),
category: this.t('Canvas.basic'),
order: 30,
},
];
}
/**
* 合并特有属性与基本属性
* 子类应该调用此方法来合并自身特有属性与基类提供的基本属性
* @param {Array} specificProperties 特有属性数组
* @returns {Array} 合并后的属性数组
*/
mergeWithBaseProperties(specificProperties) {
const baseProperties = super.getConfigurableProperties();
// 过滤掉同名属性(子类优先)
const basePropsFiltered = baseProperties.filter(
(baseProp) => !specificProperties.some((specificProp) => specificProp.id === baseProp.id)
);
return [...basePropsFiltered, ...specificProperties];
}
/**
* 更新笔刷属性
* @param {String} propId 属性ID
* @param {any} value 属性值
* @returns {Boolean} 是否更新成功
*/
updateProperty(propId, value) {
if (propId === "size") {
if (this.brush) {
this.brush.width = value;
this.configure(this.brush, { width: value });
}
return true;
} else if (propId === "color") {
if (this.brush) {
this.brush.color = value;
this.configure(this.brush, { color: value });
}
return true;
} else if (propId === "opacity") {
if (this.brush) {
this.brush.opacity = value;
this.configure(this.brush, { opacity: value });
}
return true;
}
return false;
}
/**
* 检查属性是否可见
* @param {Object} property 属性对象
* @param {Object} currentValues 当前所有属性的值
* @returns {Boolean} 是否可见
*/
isPropertyVisible(property, currentValues) {
// 如果没有visibleWhen条件则始终显示
if (!property.visibleWhen) {
return true;
}
// 如果visibleWhen是函数则调用函数判断
if (typeof property.visibleWhen === "function") {
return property.visibleWhen(currentValues);
}
// 如果visibleWhen是对象检查条件是否满足
if (typeof property.visibleWhen === "object") {
for (const [key, value] of Object.entries(property.visibleWhen)) {
if (currentValues[key] !== value) {
return false;
}
}
return true;
}
return true;
}
/**
* 获取动态选项
* @param {Object} property 属性对象
* @param {Object} currentValues 当前所有属性的值
* @returns {Array} 选项数组
*/
getDynamicOptions(property, currentValues) {
if (property.dynamicOptions && typeof property.dynamicOptions === "function") {
return property.dynamicOptions(currentValues);
}
return property.options || [];
}
/**
* 生命周期方法笔刷被选中
*/
onSelected() {
// 可由子类覆盖
}
/**
* 生命周期方法笔刷被取消选中
*/
onDeselected() {
// 可由子类覆盖
}
/**
* 销毁笔刷实例并清理资源
*/
destroy() {
this.brush = null;
}
}