/** * 笔刷基类 * 所有笔刷类型应继承此基类并实现必要的方法 */ 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; } }