import { reactive, readonly } from "vue"; // import texturePresetManager from "../managers/brushes/TexturePresetManager"; class texturePresetManager { } export class BrushState { constructor(options = {}) { this.state = reactive({ // 笔刷基础属性 size: options.size || 5, // 笔刷大小 color: options.color || "#000000", // 笔刷颜色 opacity: options.opacity || 1, // 笔刷透明度 type: options.type || "pencil", // 当前笔刷类型 // 阴影相关属性 shadowEnabled: false, // 是否启用阴影 shadowColor: "#000000", // 阴影颜色(默认为笔刷颜色) shadowWidth: 0, // 阴影宽度 shadowOffsetX: 0, // 阴影X偏移 shadowOffsetY: 0, // 阴影Y偏移 // 笔刷材质相关 textureScale: 1, // 材质缩放 textureEnabled: false, // 是否启用材质 texturePath: "", // 材质图片路径 textureOpacity: 1, // 材质透明度 textureRepeat: "repeat", // 材质重复模式 textureAngle: 0, // 材质旋转角度 selectedTextureId: null, // 当前选中的材质ID // 可用笔刷类型列表 (由BrushManager初始化) availableBrushes: [], // 自定义笔刷列表 customBrushes: [], // 笔刷预设 presets: [ // { name: "细线", size: 2, opacity: 1, color: "#000000", type: "pencil" }, // { name: "中粗", size: 5, opacity: 1, color: "#000000", type: "pencil" }, // { name: "粗线", size: 10, opacity: 1, color: "#000000", type: "pencil" }, // { name: "水彩", size: 15, opacity: 0.7, color: "#3366ff", type: "marker" }, // { name: "喷枪", size: 20, opacity: 0.5, color: "#ff6633", type: "spray" }, ], // 材质预设 texturePresets: [ { name: "默认纹理", textureId: "preset_texture_0", scale: 1, opacity: 1, repeat: "repeat", angle: 0, }, { name: "细纹理", textureId: "preset_texture_1", scale: 0.5, opacity: 0.8, repeat: "repeat", angle: 0, }, { name: "粗纹理", textureId: "preset_texture_2", scale: 2, opacity: 1, repeat: "repeat", angle: 45, }, { name: "水彩纹理", textureId: "preset_texture_5", scale: 1.5, opacity: 0.6, repeat: "no-repeat", angle: 0, } ], // 上传的纹理缓存列表 uploadedTextures: [], // 最近使用的颜色 recentColors: ["#000000", "#ffffff", "#ff0000", "#00ff00", "#0000ff"], // 最近使用的材质 recentTextures: [], // 当前笔刷可配置属性(由当前选中笔刷动态设置) currentBrushProperties: [], // 当前笔刷实例的引用 currentBrushInstance: null, // 笔刷属性值的映射,存储可由UI修改的属性值 propertyValues: {}, }); } setBrushSize(size) { this.state.size = Math.max(0.5, Math.min(100, size)); } setBrushColor(color) { this.state.color = color; // 添加到最近使用的颜色 if (!this.state.recentColors.includes(color)) { this.state.recentColors.unshift(color); if (this.state.recentColors.length > 10) { this.state.recentColors.pop(); } } } setBrushOpacity(opacity) { this.state.opacity = Math.max(0.05, Math.min(1, opacity)); } setBrushType(type) { if (this.state.availableBrushes.some((brush) => brush.id === type)) { this.state.type = type; } } setTextureScale(scale) { this.state.textureScale = Math.max(0.1, Math.min(10, scale)); } setTextureEnabled(enabled) { this.state.textureEnabled = enabled; } setTexturePath(path) { this.state.texturePath = path; } // 阴影相关方法 setShadowEnabled(enabled) { this.state.shadowEnabled = enabled; } setShadowColor(color) { this.state.shadowColor = color; } setShadowWidth(width) { this.state.shadowWidth = Math.max(0, Math.min(50, width)); } setShadowOffsetX(offsetX) { this.state.shadowOffsetX = Math.max(-50, Math.min(50, offsetX)); } setShadowOffsetY(offsetY) { this.state.shadowOffsetY = Math.max(-50, Math.min(50, offsetY)); } setAvailableBrushes(brushes) { this.state.availableBrushes = brushes; } addCustomBrush(brush) { if (!brush.id) { brush.id = `custom_${Date.now()}`; } this.state.customBrushes.push(brush); return brush.id; } removeCustomBrush(brushId) { const index = this.state.customBrushes.findIndex((b) => b.id === brushId); if (index !== -1) { this.state.customBrushes.splice(index, 1); return true; } return false; } // 应用预设 applyPreset(presetIndex) { const preset = this.state.presets[presetIndex]; if (preset) { this.state.size = preset.size; this.state.opacity = preset.opacity; this.state.color = preset.color; this.state.type = preset.type; return true; } return false; } // 将当前设置保存为新预设 saveCurrentAsPreset(name) { const newPreset = { name: name || `预设 ${this.state.presets.length + 1}`, size: this.state.size, opacity: this.state.opacity, color: this.state.color, type: this.state.type, textureEnabled: this.state.textureEnabled, textureScale: this.state.textureScale, texturePath: this.state.texturePath, }; this.state.presets.push(newPreset); return this.state.presets.length - 1; // 返回新预设的索引 } /** * 设置当前笔刷实例 * @param {Object} brushInstance BaseBrush实例 */ setCurrentBrushInstance(brushInstance) { this.state.currentBrushInstance = brushInstance; // 获取并设置当前笔刷的可配置属性 if (brushInstance && brushInstance.getConfigurableProperties) { const properties = brushInstance.getConfigurableProperties(); this.state.currentBrushProperties = properties; // 初始化属性值 properties.forEach((prop) => { // 如果是基础属性,使用已有值 if (prop.id === "size") { this.state.propertyValues[prop.id] = this.state.size; } else if (prop.id === "color") { this.state.propertyValues[prop.id] = this.state.color; } else if (prop.id === "opacity") { this.state.propertyValues[prop.id] = this.state.opacity; } else { // 对于特殊属性,使用默认值 this.state.propertyValues[prop.id] = prop.defaultValue; } }); } else { // 如果没有实例或方法,清空属性列表 this.state.currentBrushProperties = []; } } /** * 更新笔刷属性值 * @param {String} propId 属性ID * @param {any} value 属性值 */ updatePropertyValue(propId, value) { // 更新Store中的值 this.state.propertyValues[propId] = value; // 同步更新基础属性 if (propId === "size") { this.state.size = value; } else if (propId === "color") { this.state.color = value; } else if (propId === "opacity") { this.state.opacity = value; } // 如果有当前笔刷实例且有更新方法,则调用 if (this.state.currentBrushInstance && this.state.currentBrushInstance.updateProperty) { this.state.currentBrushInstance.updateProperty(propId, value); } } /** * 获取属性值 * @param {String} propId 属性ID * @param {any} defaultValue 默认值 * @returns {any} 属性值 */ getPropertyValue(propId, defaultValue) { // 检查属性值是否存在 if (Object.prototype.hasOwnProperty.call(this.state.propertyValues, propId)) { return this.state.propertyValues[propId]; } // 对于基础属性,返回store中的值 if (propId === "size") { return this.state.size; } else if (propId === "color") { return this.state.color; } else if (propId === "opacity") { return this.state.opacity; } // 否则返回默认值 return defaultValue; } /** * 按分类获取当前笔刷可配置属性 * @returns {Object} 按分类分组的属性对象 */ getPropertiesByCategory() { const result = {}; this.state.currentBrushProperties.forEach((prop) => { const category = prop.category || "默认"; if (!result[category]) { result[category] = []; } result[category].push({ ...prop, value: this.getPropertyValue(prop.id, prop.defaultValue), }); }); // 按order排序每个分类中的属性 Object.keys(result).forEach((category) => { result[category].sort((a, b) => (a.order || 0) - (b.order || 0)); }); return result; } /** * 材质相关方法 */ setTextureOpacity(opacity) { this.state.textureOpacity = Math.max(0, Math.min(1, opacity)); } setTextureRepeat(repeat) { const validModes = ["repeat", "repeat-x", "repeat-y", "no-repeat"]; if (validModes.includes(repeat)) { this.state.textureRepeat = repeat; } } setTextureAngle(angle) { this.state.textureAngle = angle % 360; } setSelectedTextureId(textureId) { this.state.selectedTextureId = textureId; // 添加到最近使用的材质 if (textureId && !this.state.recentTextures.includes(textureId)) { this.state.recentTextures.unshift(textureId); if (this.state.recentTextures.length > 8) { this.state.recentTextures.pop(); } } } /** * 应用材质预设 * @param {Number} presetIndex 预设索引 * @returns {Boolean} 是否应用成功 */ applyTexturePreset(presetIndex) { const preset = this.state.texturePresets[presetIndex]; if (preset) { this.state.selectedTextureId = preset.textureId; this.state.textureScale = preset.scale; this.state.textureOpacity = preset.opacity; this.state.textureRepeat = preset.repeat; this.state.textureAngle = preset.angle; // 添加到最近使用 this.setSelectedTextureId(preset.textureId); return true; } return false; } /** * 将当前材质设置保存为新预设 * @param {String} name 预设名称 * @returns {Number} 新预设的索引 */ saveCurrentTextureAsPreset(name) { const newPreset = { name: name || `材质预设 ${this.state.texturePresets.length + 1}`, textureId: this.state.selectedTextureId, scale: this.state.textureScale, opacity: this.state.textureOpacity, repeat: this.state.textureRepeat, angle: this.state.textureAngle, }; this.state.texturePresets.push(newPreset); return this.state.texturePresets.length - 1; } /** * 删除材质预设 * @param {Number} presetIndex 预设索引 * @returns {Boolean} 是否删除成功 */ removeTexturePreset(presetIndex) { if (presetIndex >= 0 && presetIndex < this.state.texturePresets.length) { this.state.texturePresets.splice(presetIndex, 1); return true; } return false; } /** * 获取所有可用材质(预设+自定义) * @returns {Array} 材质列表 */ getAllTextures() { return texturePresetManager.getAllTextures(); } /** * 根据ID获取材质信息 * @param {String} textureId 材质ID * @returns {Object|null} 材质对象 */ getTextureById(textureId) { return texturePresetManager.getTextureById(textureId); } /** * 按分类获取材质 * @param {String} category 分类名称 * @returns {Array} 材质列表 */ getTexturesByCategory(category) { return texturePresetManager.getTexturesByCategory(category); } /** * 获取材质分类列表 * @returns {Array} 分类名称数组 */ getTextureCategories() { return texturePresetManager.getCategories(); } /** * 搜索材质 * @param {String} keyword 搜索关键词 * @returns {Array} 匹配的材质列表 */ searchTextures(keyword) { return texturePresetManager.searchTextures(keyword); } /** * 添加自定义材质 * @param {Object} textureData 材质数据 * @returns {String} 材质ID */ addCustomTexture(textureData) { const textureId = texturePresetManager.addCustomTexture(textureData); // 保存到本地存储 texturePresetManager.saveCustomTexturesToStorage(); return textureId; } /** * 删除自定义材质 * @param {String} textureId 材质ID * @returns {Boolean} 是否删除成功 */ removeCustomTexture(textureId) { const success = texturePresetManager.removeCustomTexture(textureId); if (success) { // 如果删除的是当前选中的材质,清空选择 if (this.state.selectedTextureId === textureId) { this.state.selectedTextureId = null; } // 从最近使用中移除 const recentIndex = this.state.recentTextures.indexOf(textureId); if (recentIndex !== -1) { this.state.recentTextures.splice(recentIndex, 1); } // 保存到本地存储 texturePresetManager.saveCustomTexturesToStorage(); } return success; } /** * 从文件上传自定义材质 * @param {File} file 图片文件 * @param {String} name 材质名称(可选) * @returns {Promise} 材质ID */ uploadCustomTexture(file, name) { return new Promise((resolve, reject) => { // 验证文件 if (!texturePresetManager.validateTextureFile(file)) { reject(new Error("无效的材质文件")); return; } // 读取文件 const reader = new FileReader(); reader.onload = (e) => { try { const textureData = { name: name || file.name.replace(/\.[^/.]+$/, ""), path: e.target.result, preview: e.target.result, description: `用户上传的材质: ${file.name}`, }; const textureId = this.addCustomTexture(textureData); resolve(textureId); } catch (error) { reject(error); } }; reader.onerror = () => { reject(new Error("文件读取失败")); }; reader.readAsDataURL(file); }); } /** * 导出材质预设配置 * @returns {String} JSON格式的配置 */ exportTexturePresets() { const config = { texturePresets: this.state.texturePresets, customTextures: texturePresetManager.exportCustomTextures(), }; return JSON.stringify(config, null, 2); } /** * 导入材质预设配置 * @param {String} configJson JSON格式的配置 * @returns {Boolean} 是否导入成功 */ importTexturePresets(configJson) { try { const config = JSON.parse(configJson); // 导入材质预设 if (config.texturePresets && Array.isArray(config.texturePresets)) { this.state.texturePresets = [...this.state.texturePresets, ...config.texturePresets]; } // 导入自定义材质 if (config.customTextures) { texturePresetManager.importCustomTextures(config.customTextures); } return true; } catch (error) { console.error("导入材质预设失败:", error); return false; } } /** * 初始化材质预设管理器 */ initializeTexturePresets() { // 从本地存储加载自定义材质 texturePresetManager.loadCustomTexturesFromStorage(); // 确保预设材质引用的是有效的材质ID this.state.texturePresets.forEach((preset, index) => { const texture = texturePresetManager.getTextureById(preset.textureId); if (!texture) { console.warn(`材质预设 "${preset.name}" 引用的材质 ${preset.textureId} 不存在`); // 可以选择使用默认材质替换或删除该预设 if (texturePresetManager.getAllTextures().length > 0) { preset.textureId = texturePresetManager.getAllTextures()[0].id; } } }); } /** * 清空上传的纹理缓存 */ clearUploadedTextures() { this.state.uploadedTextures = []; } /** * 添加纹理到缓存 * @param {String} textureId 材质ID */ cacheUploadedTexture(textureId) { const texture = texturePresetManager.getTextureById(textureId); if (texture && !this.state.uploadedTextures.includes(textureId)) { this.state.uploadedTextures.push(textureId); } } /** * 从缓存中移除纹理 * @param {String} textureId 材质ID */ removeCachedTexture(textureId) { const index = this.state.uploadedTextures.indexOf(textureId); if (index !== -1) { this.state.uploadedTextures.splice(index, 1); } } // 辅助方法 getRGBAColor() { // 解析十六进制颜色并添加透明度 const hex = this.state.color.replace("#", ""); const r = parseInt(hex.substring(0, 2), 16); const g = parseInt(hex.substring(2, 4), 16); const b = parseInt(hex.substring(4, 6), 16); return `rgba(${r}, ${g}, ${b}, ${this.state.opacity})`; } /** * 获取当前笔刷的实际绘制颜色(包含透明度) * @returns {String} RGBA格式的颜色字符串 */ getCurrentBrushColor() { return this.getRGBAColor(); } /** * 从RGBA颜色字符串中提取RGB值 * @param {String} rgbaColor RGBA颜色字符串 * @returns {Object} {r, g, b, a} 颜色值对象 */ parseRGBAColor(rgbaColor) { const rgbaMatch = rgbaColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/); if (rgbaMatch) { return { r: parseInt(rgbaMatch[1]), g: parseInt(rgbaMatch[2]), b: parseInt(rgbaMatch[3]), a: rgbaMatch[4] ? parseFloat(rgbaMatch[4]) : 1, }; } return null; } /** * 将RGB值转换为十六进制颜色 * @param {Number} r 红色值 (0-255) * @param {Number} g 绿色值 (0-255) * @param {Number} b 蓝色值 (0-255) * @returns {String} 十六进制颜色字符串 */ rgbToHex(r, g, b) { return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); } /** * 获取当前阴影配置对象 * @returns {Object|null} fabric.Shadow配置对象或null */ getShadowConfig() { if (!this.state.shadowEnabled) { return null; } return { color: this.state.shadowColor, blur: this.state.shadowWidth, offsetX: this.state.shadowOffsetX, offsetY: this.state.shadowOffsetY, }; } /** * 创建fabric.Shadow实例 * @returns {fabric.Shadow|null} fabric.Shadow实例或null */ createFabricShadow() { const config = this.getShadowConfig(); if (!config) { return null; } // 确保fabric已加载 if (typeof fabric !== "undefined" && fabric.Shadow) { return new fabric.Shadow(config); } return null; } }