Files
FiDA_Front/src/components/Canvas/DepthCanvas/manager/brushes/BaseBrush.js
2026-03-11 15:34:56 +08:00

360 lines
9.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 笔刷基类
* 所有笔刷类型应继承此基类并实现必要的方法
*/
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;
}
}