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

694 lines
17 KiB
JavaScript
Raw Normal View History

2026-03-11 15:34:56 +08:00
import { reactive, readonly } from "vue";
// import texturePresetManager from "../managers/brushes/TexturePresetManager";
class texturePresetManager { }
export class BrushState {
2026-03-31 13:29:46 +08:00
constructor(options = {}) {
2026-03-11 15:34:56 +08:00
this.state = reactive({
// 笔刷基础属性
2026-03-31 13:29:46 +08:00
size: options.size || 5, // 笔刷大小
color: options.color || "#000000", // 笔刷颜色
opacity: options.opacity || 1, // 笔刷透明度
type: options.type || "pencil", // 当前笔刷类型
2026-03-11 15:34:56 +08:00
// 阴影相关属性
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<String>} 材质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;
}
}