Files
aida_front/src/component/Canvas/CanvasEditor/utils/layerHelper.js
X1627315083 584f6a7db0 合并画布
2025-06-22 13:52:28 +08:00

631 lines
18 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.
/**
* 图层类型枚举
*/
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", // 背景图层 - 位于固定图层之、普通图层之下
};
/**
* 画布操作模式枚举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,
// 确保不是背景图层
isBackground: false,
// Fabric.js 对象列表
fabricObjects: options.fabricObjects || [],
// 嵌套结构 - 适用于组图层
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 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 null;
}
console.warn(`图层 ${layerId} 未找到`);
return 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 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) {
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);
}