import { generateId } from "./helper"; /** * 图层类型枚举 */ export const LayerType = { EMPTY: "empty", // 空图层 BITMAP: "bitmap", // 位图图层 VECTOR: "vector", // 矢量图层 TEXT: "text", // 文字图层 GROUP: "group", // 组图层 ADJUSTMENT: "adjustment", // 调整图层 SMART_OBJECT: "smartObject", // 智能对象 SHAPE: "shape", // 形状图层 VIDEO: "video", // 视频图层 (预留) AUDIO: "audio", // 音频图层 (预留) FIXED: "fixed", // 固定图层 - 位于背景图层之上,普通图层之下 BACKGROUND: "background", // 背景图层 - 位于固定图层之、普通图层之下 }; /** * 特殊图层ID */ export const SpecialLayerId = { SPECIAL_GROUP: "group_special", // 特殊组 COLOR: "special_color", // 颜色图层 } /** * 特殊类型 */ export const SpecialType = { PRINT_TRIMS_G: "print_trims_group", // 印花和元素图层组 PRINT_TRIMS_L: "print_trims_layer", // 印花和元素图层 PRINT_TRIMS_O: "print_trims_object", // 印花和元素图层对象 REPEAT_L: "repeat_layer",// 平铺图层 REPEAT_O: "repeat_object",// 平铺图层对象 } /** * 画布操作模式枚举:draw(绘画)、select(选择)、pan(拖拽).... */ export const OperationType = { // 编辑器模式 DRAW: "draw", // 绘画模式 ERASER: "eraser", // 橡皮擦模式 SELECT: "select", // 选择模式 PAN: "pan", // 拖拽模式 EYEDROPPER: "eyedropper", // 吸色器模式 // 套索工具 LASSO: "lasso", // 套索工具模式 - 自由套索模式 LASSO_RECTANGLE: "lasso_rectangle", // 套索工具模式 - 矩形模式 LASSO_ELLIPSE: "lasso_ellipse", // 套索工具模式 - 椭圆 // 创建临时选区工具模式 - 类似于临时图层 在这个区域的操作不会影响其他图层 AREA_RECTANGLE: "area_rectangle", // 矩形选区模式 // 材质笔刷工具模式 TEXTURE: "texture", // 选择材质笔刷工具模式 - // 选择材质笔刷后会切换到绘画模式 笔刷固定到材质笔刷 // 液化工具 LIQUIFY: "liquify", // 液化工具模式 // 矢量工具 // VECTOR: "vector", // 矢量工具模式 // 矢量工具模式 - 自由绘制 // VECTOR_FREE: "vector_free", TEXT: "text", // 文字工具模式 // 红绿图模式 RED_GREEN: "red_green", // 红绿图模式 - 只有红色和绿色笔刷还有橡皮擦 不支持添加其他图片 特殊模式 RED_BRUSH: "red_brush", // 红色笔刷 GREEN_BRUSH: "green_brush", // 绿色笔刷 // SHAPE: "shape", // 形状模式 // 可以根据需要添加更多工具 }; // 所有操作模式类型列表 export const OperationTypes = Object.values(OperationType); /** * 混合模式枚举 * 与 fabricjs 和 CSS3 的 globalCompositeOperation 对应 */ export const BlendMode = { NORMAL: "source-over", // 正常模式 MULTIPLY: "multiply", // 正片叠底 SCREEN: "screen", // 滤色 OVERLAY: "overlay", // 叠加 DARKEN: "darken", // 变暗 LIGHTEN: "lighten", // 变亮 COLOR_DODGE: "color-dodge", // 颜色减淡 COLOR_BURN: "color-burn", // 颜色加深 HARD_LIGHT: "hard-light", // 强光 SOFT_LIGHT: "soft-light", // 柔光 DIFFERENCE: "difference", // 差值 EXCLUSION: "exclusion", // 排除 HUE: "hue", // 色相 SATURATION: "saturation", // 饱和度 COLOR: "color", // 颜色 LUMINOSITY: "luminosity", // 明度 DESTINATION_IN: "destination-in", // 目标内 DESTINATION_OUT: "destination-out", // 目标外 }; /** * 判断图层是否为组图层 * @param {Object} layer 要检查的图层 * @returns {boolean} 是否为组图层 */ export function isGroupLayer(layer) { if (!layer) return false; return ( layer.type === LayerType.GROUP || (Array.isArray(layer.children) && layer.children.length > 0) ); } /** * 从fabric对象创建图层 * @param {Object} fabricObject fabric对象 * @param {String} layerType 图层类型 * @param {Object} options 其他选项 * @returns {Object} 创建的图层对象 */ export function createLayerFromFabricObject( fabricObject, layerType = "bitmap", options = {} ) { if (!fabricObject) return null; // 确定图层类型 let type = layerType; if (fabricObject.type === "textbox" || fabricObject.type === "text") { type = LayerType.TEXT; } else if ( fabricObject.type === "rect" || fabricObject.type === "circle" || fabricObject.type === "polygon" || fabricObject.type === "polyline" ) { type = LayerType.SHAPE; } else if (fabricObject.type === "path" || fabricObject.type === "line") { type = LayerType.VECTOR; } else if (fabricObject.type === "image") { type = LayerType.BITMAP; } // 创建基础图层 let layer = createLayer({ ...options, type: type, name: options.name || `${ fabricObject.type.charAt(0).toUpperCase() + fabricObject.type.slice(1) } 图层`, parentId: options.parentId || null, }); // 添加对象到图层 if (Array.isArray(layer.fabricObjects)) { layer.fabricObjects.push(fabricObject); } else { layer.fabricObjects = [fabricObject]; } // 如果对象有自己的ID,将其与图层关联 if (fabricObject.id) { fabricObject.layerId = layer.id; fabricObject.layerName = layer.name; } return layer; } /** * 创建标准图层对象 * @param {Object} options 图层选项 * @returns {Object} 图层对象 */ export function createLayer(options = {}) { const id = options.id || generateId("layer_") || `layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`; return { id: id, // 图层基本属性 name: options.name || `图层 ${id.substring(id.lastIndexOf("_") + 1)}`, type: options.type || LayerType.EMPTY, visible: options.visible !== undefined ? options.visible : true, locked: options.locked !== undefined ? options.locked : false, opacity: options.opacity !== undefined ? options.opacity : 1.0, blendMode: options.blendMode || BlendMode.NORMAL, isHidenDragHandle: options.isHidenDragHandle || false, isDisableUnlock: options.isDisableUnlock || false, isFixedOther: options.isFixedOther || false, isFixedClipMask: options.isFixedClipMask || false, // 确保不是背景图层 isBackground: false, // Fabric.js 对象列表 fabricObjects: options.fabricObjects || [], fabricObject: options.fabricObject || null, // 嵌套结构 - 适用于组图层 children: options.children || [], // 剪切蒙版 clippingMask: options.clippingMask || null, // 位置和大小信息(可选) bounds: options.bounds || null, // 图层特定属性 layerProperties: options.layerProperties || {}, // 元数据 - 可用于存储任意数据 metadata: options.metadata || {}, }; } /** * 创建背景图层 * @param {Object} options 背景图层选项 * @returns {Object} 背景图层对象 */ export function createBackgroundLayer(options = {}) { const id = options.id || `bg_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`; return { id: id, // 图层基本属性 name: options.name || "背景", type: LayerType.BITMAP, visible: true, locked: true, // 背景图层默认锁定 opacity: 1.0, // 背景图层始终不透明 blendMode: BlendMode.NORMAL, // 背景图层始终使用正常混合模式 // 标记为背景图层 isBackground: true, // 画布尺寸 canvasWidth: options.canvasWidth || 800, canvasHeight: options.canvasHeight || 600, backgroundColor: options.backgroundColor || "#ffffff", // Fabric.js 背景对象 (单个矩形对象) fabricObject: null, // 创建后设置 // Fabric.js 对象列表 fabricObjects: [], // 创建后设置 // 无子图层 children: [], // 元数据 - 可用于存储任意数据 metadata: options.metadata || {}, }; } /** * 创建位图图层 * @param {Object} options 图层选项 * @returns {Object} 位图图层对象 */ export function createBitmapLayer(options = {}) { const baseLayer = createLayer({ ...options, type: LayerType.BITMAP, }); // 添加位图特定属性 baseLayer.layerProperties = { ...baseLayer.layerProperties, filters: options.filters || [], // 滤镜数组 imageUrl: options.imageUrl || null, // 图片URL imageElement: options.imageElement || null, // 图片元素 }; return baseLayer; } /** * 创建文本图层 * @param {Object} options 图层选项 * @returns {Object} 文本图层对象 */ export function createTextLayer(options = {}) { const baseLayer = createLayer({ ...options, type: LayerType.TEXT, }); // 添加文字特定属性 baseLayer.layerProperties = { ...baseLayer.layerProperties, text: options.text || "新文本", fontFamily: options.fontFamily || "Arial", fontSize: options.fontSize || 24, fontWeight: options.fontWeight || "normal", fontStyle: options.fontStyle || "normal", textAlign: options.textAlign || "left", underline: options.underline || false, overline: options.overline || false, linethrough: options.linethrough || false, textBackgroundColor: options.textBackgroundColor || "transparent", lineHeight: options.lineHeight || 1.16, charSpacing: options.charSpacing || 0, }; return baseLayer; } /** * 创建矢量图层 * @param {Object} options 图层选项 * @returns {Object} 矢量图层对象 */ export function createVectorLayer(options = {}) { const baseLayer = createLayer({ ...options, type: LayerType.VECTOR, }); // 添加矢量特定属性 baseLayer.layerProperties = { ...baseLayer.layerProperties, vectorType: options.vectorType || "path", // path, polygon, polyline等 strokeWidth: options.strokeWidth !== undefined ? options.strokeWidth : 1, strokeColor: options.strokeColor || "#000000", fillColor: options.fillColor || "transparent", fillRule: options.fillRule || "nonzero", strokeLineCap: options.strokeLineCap || "butt", strokeLineJoin: options.strokeLineJoin || "miter", strokeDashArray: options.strokeDashArray || null, strokeDashOffset: options.strokeDashOffset || 0, }; return baseLayer; } /** * 创建形状图层 * @param {Object} options 图层选项 * @returns {Object} 形状图层对象 */ export function createShapeLayer(options = {}) { const baseLayer = createLayer({ ...options, type: LayerType.SHAPE, }); // 添加形状特定属性 baseLayer.layerProperties = { ...baseLayer.layerProperties, shapeType: options.shapeType || "rect", // rect, circle, ellipse等 strokeWidth: options.strokeWidth !== undefined ? options.strokeWidth : 1, strokeColor: options.strokeColor || "#000000", fillColor: options.fillColor || "#ffffff", rx: options.rx || 0, // 矩形圆角 ry: options.ry || 0, // 矩形圆角 }; return baseLayer; } /** * 创建调整图层 * @param {Object} options 图层选项 * @returns {Object} 调整图层对象 */ export function createAdjustmentLayer(options = {}) { const baseLayer = createLayer({ ...options, type: LayerType.ADJUSTMENT, }); // 添加调整图层特定属性 baseLayer.layerProperties = { ...baseLayer.layerProperties, adjustmentType: options.adjustmentType || "brightness", // brightness, contrast, hue, saturation等 value: options.value !== undefined ? options.value : 0, affectedLayerIds: options.affectedLayerIds || [], // 受影响的图层ID列表 }; return baseLayer; } /** * 创建智能对象图层 * @param {Object} options 图层选项 * @returns {Object} 智能对象图层 */ export function createSmartObjectLayer(options = {}) { const baseLayer = createLayer({ ...options, type: LayerType.SMART_OBJECT, }); // 添加智能对象特定属性 baseLayer.layerProperties = { ...baseLayer.layerProperties, sourceType: options.sourceType || "image", // image, vector, embedded等 sourceUrl: options.sourceUrl || null, sourceData: options.sourceData || null, originalWidth: options.originalWidth || 0, originalHeight: options.originalHeight || 0, embedded: options.embedded !== undefined ? options.embedded : true, }; return baseLayer; } /** * 创建固定图层 - 位于背景图层之上,普通图层之下 * @param {Object} options 固定图层选项 * @returns {Object} 固定图层对象 */ export function createFixedLayer(options = {}) { const id = options.id || `fixed_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`; return { id: id, // 图层基本属性 name: options.name || "固定图层", type: LayerType.FIXED, visible: true, // 固定图层始终可见 locked: true, // 固定图层默认锁定 opacity: options.opacity !== undefined ? options.opacity : 1.0, blendMode: options.blendMode || BlendMode.NORMAL, // 标记为固定图层 isFixed: true, isBackground: false, // Fabric.js 对象列表 fabricObjects: options.fabricObjects || [], // 无子图层 children: [], // 元数据 - 可用于存储任意数据 metadata: options.metadata || {}, }; } /** * 深拷贝图层对象 * @param {Object} layer 要拷贝的图层 * @returns {Object} 拷贝后的图层 */ export function cloneLayer(layer) { if (!layer) return null; // 基本属性深拷贝 const clonedLayer = { ...JSON.parse(JSON.stringify(layer)), // 深拷贝基本属性 fabricObjects: [], // 重置,后面处理 }; // 复制 fabric 对象 (如果存在) if (Array.isArray(layer.fabricObjects)) { clonedLayer.fabricObjects = layer.fabricObjects.map((obj) => { return obj && typeof obj.clone === "function" ? obj.clone() : JSON.parse(JSON.stringify(obj)); }); } // 复制背景对象 (如果存在) if (layer.isBackground && layer.fabricObject) { clonedLayer.fabricObject = typeof layer.fabricObject.clone === "function" ? layer.fabricObject.clone() : JSON.parse(JSON.stringify(layer.fabricObject)); } // 递归复制子图层 if (Array.isArray(layer.children) && layer.children.length > 0) { clonedLayer.children = layer.children.map((child) => cloneLayer(child)); } return clonedLayer; } /** * 递归查找图层(包括子图层) * @param {Array} layers 图层数组 * @param {string} layerId 要查找的图层ID * @param {Object} parent 父图层(可选,用于内部递归) * @returns {Object|null} 包含layer和parent的对象,如果未找到返回null */ export function findLayerRecursively(layers, layerId, parent = null) { try { if (!layers || !Array.isArray(layers) || !layerId) { return { layer: null, parent: null, }; } // 在当前图层列表中查找 for (const layer of layers) { if (layer && layer.id === layerId) { return { layer, parent }; } // 如果是组图层,递归查找子图层 if ( layer && (layer.type === "group" || layer.type === LayerType.GROUP || (layer.children && Array.isArray(layer.children))) ) { const result = findInChildLayers(layer.children, layerId, layer); if (result) { return result; } } } } catch (error) { console.error(`查找图层 ${layerId} 时出错:`, error); return { layer: null, parent: null, }; } console.warn(`图层 ${layerId} 未找到`); return { layer: null, parent: null, }; } /** * 在子图层中递归查找 * @param {Array} children 子图层数组 * @param {string} layerId 要查找的图层ID * @param {Object} parent 父图层 * @returns {Object|null} 包含layer和parent的对象,如果未找到返回null */ export function findInChildLayers(children, layerId, parent) { if (!children || !Array.isArray(children) || !layerId) { return { layer: null, parent: null, }; } for (const child of children) { if (child && child.id === layerId) { return { layer: child, parent }; } // 如果子图层也是组,继续递归查找 if ( child && (child.type === "group" || child.type === LayerType.GROUP) && child.children && Array.isArray(child.children) ) { const result = findInChildLayers(child.children, layerId, child); if (result && result.layer) { return result; } } } return null; } /** * 简单查找图层(仅在顶级图层中查找,不递归子图层) * @param {Array} layers 图层数组 * @param {string} layerId 要查找的图层ID * @returns {Object|null} 找到的图层对象,如果未找到返回null */ export function findLayer(layers, layerId) { if (!layers || !Array.isArray(layers) || !layerId) { return null; } return layers.find((layer) => layer && layer.id === layerId) || null; } /** * 根据图层名称查找图层 * @param {Array} layers 图层数组 * @param {string} layerName 要查找的图层名称 * @param {boolean} recursive 是否递归查找子图层,默认false * @returns {Object|null} 找到的图层对象,如果未找到返回null */ export function findLayerByName(layers, layerName, recursive = false) { if (!layers || !Array.isArray(layers) || !layerName) { return null; } for (const layer of layers) { if (layer && layer.name === layerName) { return layer; } // 如果需要递归查找且是组图层 if ( recursive && layer && (layer.type === "group" || layer.type === LayerType.GROUP || (layer.children && Array.isArray(layer.children))) ) { const found = findLayerByName(layer.children, layerName, true); if (found) { return found; } } } return null; } /** * 获取图层的完整路径(包含父图层信息) * @param {Array} layers 图层数组 * @param {string} layerId 要查找的图层ID * @returns {Array} 图层路径数组,从根图层到目标图层 */ export function getLayerPath(layers, layerId) { if (!layers || !Array.isArray(layers) || !layerId) { return []; } function findPath(currentLayers, targetId, currentPath = []) { for (const layer of currentLayers) { if (!layer) continue; const newPath = [...currentPath, layer]; if (layer.id === targetId) { return newPath; } // 如果是组图层,递归查找 if ( layer.type === "group" || layer.type === LayerType.GROUP || (layer.children && Array.isArray(layer.children)) ) { const foundPath = findPath(layer.children, targetId, newPath); if (foundPath.length > 0) { return foundPath; } } } return []; } return findPath(layers, layerId); }