Files
FiDA_Front/src/components/Canvas/DepthCanvas/manager/brushes/BrushStore.js
2026-03-31 13:29:46 +08:00

694 lines
17 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.
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<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;
}
}