Files
aida_front/src/component/Canvas/CanvasEditor/managers/LayerManager.js

2199 lines
59 KiB
JavaScript
Raw Normal View History

2025-06-09 10:25:54 +08:00
import {
AddLayerCommand,
PasteLayerCommand,
RemoveLayerCommand,
MoveLayerCommand,
ToggleLayerVisibilityCommand,
RenameLayerCommand,
LayerLockCommand,
SetLayerOpacityCommand,
SetLayerBlendModeCommand,
MergeLayersCommand,
GroupLayersCommand,
UngroupLayersCommand,
MergeLayerObjectsCommand,
LayerObjectsToGroupCommand,
ReorderLayersCommand,
ReorderChildLayersCommand,
} from "../commands/LayerCommands";
import {
SetActiveLayerCommand,
AddObjectToLayerCommand,
RemoveObjectFromLayerCommand,
} from "../commands/ObjectLayerCommands";
import {
LayerType,
BlendMode,
createLayer,
createBackgroundLayer,
createFixedLayer,
OperationType,
OperationTypes,
} from "../utils/layerHelper";
import {
CreateBackgroundLayerCommand,
UpdateBackgroundCommand,
BackgroundSizeCommand,
BackgroundSizeWithScaleCommand,
} from "../commands/BackgroundCommands";
import CanvasConfig from "../config/canvasConfig";
/**
* 图层管理器 - 负责管理画布上的所有图层
* 包含图层的创建删除修改排序等操作
* 现在统一使用命令管理器进行状态管理
*/
export class LayerManager {
/**
* 创建图层管理器
* @param {Object} options 配置选项
* @param {Object} options.canvas fabric.js画布实例
* @param {Object} options.layers 图层数组响应式引用
* @param {Object} options.activeLayerId 当前激活图层ID响应式引用
* @param {Object} options.commandManager 命令管理器
* @param {Object} options.canvasManager 画布管理器
* @param {String} options.editorMode 编辑器模式
* @param {Number} options.canvasWidth 画布宽度
* @param {Number} options.canvasHeight 画布高度
* @param {String} options.backgroundColor 背景颜色
*/
constructor(options) {
this.canvas = options.canvas;
this.layers = options.layers;
this.activeLayerId = options.activeLayerId;
this.commandManager = options.commandManager;
this.canvasManager = options.canvasManager || null;
// 编辑器模式draw(绘画)、select(选择)、pan(拖拽)
this.editorMode = options.editorMode || CanvasConfig.defaultTool;
// 画布尺寸
this.canvasWidth = options.canvasWidth || 800;
this.canvasHeight = options.canvasHeight || 600;
// 默认背景颜色
this.backgroundColor = options.backgroundColor || "#ffffff";
// 复制粘贴相关
this.clipboardData = null;
// 操作状态标志,用于控制状态保存
this.isExecutingCommand = false;
// 是否正在执行操作
this.operationInProgress = false;
// 红绿图模式相关
this.isRedGreenMode = false;
this.redGreenModeManager = null;
// 初始化相关命令
this.initCommandManager();
}
/**
* 初始化命令管理器
* 现在直接使用命令类不再需要注册命令
*/
initCommandManager() {
// 命令注册逻辑已移除,现在直接使用命令类实例化和执行
console.log("CommandManager 已初始化,使用直接命令调用模式");
}
/**
* 设置编辑器模式
* @param {string} mode 'draw''select''pan'
*/
toolChanged(mode) {
if (!OperationTypes.includes(mode)) {
console.warn(`不支持的编辑器模式: ${mode}`);
return;
}
this.editorMode = mode;
// 更新所有对象的交互性
this.updateLayersObjectsInteractivity();
console.log(`已切换到${mode}模式`);
}
setToolManager(toolManager) {
this.toolManager = toolManager;
}
/**
* 更新所有画布对象的交互性
* 根据当前编辑模式和图层状态设置对象的交互属性
* @private
*/
updateLayersObjectsInteractivity() {
if (!this.canvas) return;
// 性能优化使用requestAnimationFrame
requestAnimationFrame(() => {
// 暂停渲染以提高性能
this.canvas.skipTargetFind = true;
// this.canvas.discardActiveObject();
// 暂停实时渲染和对象查找
const wasRenderOnAddRemove = this.canvas.renderOnAddRemove;
this.canvas.renderOnAddRemove = false;
// 应用图层交互规则
this._applyInteractionRules();
// 恢复渲染设置
this.canvas.renderOnAddRemove = wasRenderOnAddRemove;
this.canvas.skipTargetFind = false;
// this.canvas.renderAll();
this.canvas.renderAll(); // 确保画布重新渲染 - 同步渲染
});
}
// 私有方法:应用交互规则
_applyInteractionRules() {
console.log("updateLayersObjectsInteractivity ===>", this.editorMode);
const objects = this.canvas.getObjects();
const editorMode = this.editorMode || CanvasConfig.defaultTool;
const layers = this.layers?.value || [];
// 创建缓存以避免重复查找
const layerMap = {};
layers.forEach((layer) => {
layerMap[layer.id] = layer;
});
// 获取当前活动图层ID
const currentActiveLayerId = this.activeLayerId?.value;
// 批量更新对象
objects.forEach((obj) => {
if (!obj.layerId) {
// 没有关联图层的对象使用默认设置
obj.selectable = false;
obj.evented = false;
obj.erasable = false; // 未关联图层的对象不可擦除
return;
}
const layer = layerMap[obj.layerId];
if (!layer) return;
// 设置可见性
obj.visible = layer.visible;
// 判断对象是否在当前活动图层上
const isInActiveLayer = obj.layerId === currentActiveLayerId;
// 基于 fabric-with-erasing 库的 erasable 属性设置擦除权限
// 只有活动图层、可见、非锁定、非背景、非固定图层的对象才可擦除
obj.erasable =
isInActiveLayer &&
layer.visible &&
!layer.locked &&
!layer.isBackground &&
!layer.isFixed;
// 图层状态决定交互性
if (layer.isBackground || obj.isBackground || layer.isFixed) {
// 背景层永远不可选择和擦除
obj.selectable = false;
obj.evented = false;
obj.erasable = false;
} else if (layer.locked) {
// 锁定图层不可交互和擦除
obj.selectable = false;
obj.evented = false;
obj.erasable = false;
} else {
// 根据编辑模式设置交互性
switch (editorMode) {
case OperationType.SELECT:
obj.selectable = true;
obj.evented = true;
break;
case OperationType.ERASER:
// 橡皮擦模式:利用 fabric-with-erasing 的内置机制
// 只需要设置 erasable 属性,库会自动处理擦除逻辑
obj.selectable = false;
obj.evented = true; // 需要设置为 true 以接收鼠标事件
// erasable 已在上面根据图层状态设置
break;
case OperationType.DRAW:
case OperationType.EYEDROPPER:
case OperationType.PAN:
case OperationType.WAVE:
case OperationType.LIQUIFY:
case OperationType.LASSO:
case OperationType.LASSO_RECTANGLE:
case OperationType.AREA_CUSTOM:
case OperationType.AREA_RECTANGLE:
obj.selectable = false;
obj.evented = false;
break;
default:
obj.selectable = false;
obj.evented = false;
}
// 平移模式下,禁用多选和擦除
if (editorMode === OperationType.PAN) {
obj.selectable = false;
obj.evented = false;
obj.erasable = false;
}
}
// 应用图层视觉属性
if (layer.opacity !== undefined) obj.opacity = layer.opacity;
if (layer.blendMode) obj.globalCompositeOperation = layer.blendMode;
});
}
/**
* 创建新图层
* @param {string} name 图层名称
* @param {string} type 图层类型
* @param {Object} options 额外选项
* @returns {string} 新创建的图层ID
*/
createLayer(name = null, type = LayerType.EMPTY, options = {}) {
// 生成唯一ID
const layerId = `layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
const layerIndex = this.layers.value.length;
// 计算插入位置如果没有指定insertIndex则根据当前选中图层决定插入位置
// 添加到图层列表
let insertIndex = this._getInsertIndexAboveActiveLayer();
if (options.insertIndex !== undefined) {
insertIndex = options.insertIndex;
}
// 创建新图层
const newLayer = createLayer({
id: layerId,
name: name || `图层 ${layerIndex + 1}`,
type: type,
visible: true,
locked: false,
opacity: 1.0,
blendMode: BlendMode.NORMAL,
fabricObjects: [],
children: [],
...options,
});
// 直接创建和执行命令
const command = new AddLayerCommand({
canvas: this.canvas,
layers: this.layers,
newLayer: newLayer,
activeLayerId: this.activeLayerId,
insertIndex: insertIndex,
});
// 计算普通图层数量(非背景、非固定)
const normalLayersCount = this.layers.value.filter(
(layer) => !layer.isBackground && !layer.isFixed
).length;
// 如果是第一个图层或者普通图层数量小于等于3设置为不可撤销
if (this.layers.value.length === 1 || normalLayersCount <= 3) {
command.undoable = false;
}
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
return layerId;
}
/**
* 创建背景图层
* @param {string} name 图层名称
* @returns {string} 创建的背景层ID
*/
createBackgroundLayer(name = "背景") {
// 检查是否已有背景图层
const hasBackgroundLayer = this.layers.value.some(
(layer) => layer.isBackground
);
if (hasBackgroundLayer) {
console.warn("已存在背景层,不再创建新的背景层");
return null;
}
// 创建背景图层
const bgLayer = createBackgroundLayer({
name: name,
canvasWidth: this.canvasWidth,
canvasHeight: this.canvasHeight,
backgroundColor: this.backgroundColor,
});
// 直接创建和执行命令
const command = new CreateBackgroundLayerCommand({
canvas: this.canvas,
layers: this.layers,
activeLayerId: this.activeLayerId,
canvasManager: this.canvasManager,
backgroundLayer: bgLayer,
});
// 背景图层设置为不可撤销
command.undoable = false;
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
// 返回创建的背景层ID
return bgLayer.id;
}
/**
* 创建固定图层 - 位于背景图层之上普通图层之下
* @param {string} name 图层名称
* @returns {string} 创建的固定图层ID
*/
createFixedLayer(name = "固定图层") {
// 检查是否已有固定图层
const hasFixedLayer = this.layers.value.some((layer) => layer.isFixed);
if (hasFixedLayer) {
console.warn("已存在固定图层,不再创建新的固定图层");
return null;
}
// 生成唯一ID
const layerId = `fixed_layer_${Date.now()}_${Math.floor(
Math.random() * 1000
)}`;
// 创建固定图层
const fixedLayer = createFixedLayer({
id: layerId,
name: name,
});
// 直接创建和执行命令
const command = new AddLayerCommand({
canvas: this.canvas,
layers: this.layers,
newLayer: fixedLayer,
activeLayerId: this.activeLayerId,
insertIndex: this._getFixedLayerInsertionIndex(),
});
// 固定图层设置为不可撤销
command.undoable = false;
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
return layerId;
}
/**
* 获取应该插入固定图层的位置索引在背景图层之上
* @private
* @returns {Number} 插入索引
*/
_getFixedLayerInsertionIndex() {
// 找到背景图层的位置
const bgIndex = this.layers.value.findIndex((layer) => layer.isBackground);
if (bgIndex !== -1) {
return bgIndex; // 插入到背景图层之前(在数组中这意味着位于背景图层之上)
}
return this.layers.value.length; // 如果没有背景图层,则添加到最后
}
/**
* 创建普通图层
* @param {String} name 图层名称 (默认: null将生成自动名称)
* @param {String} type 图层类型 (默认: LayerType.EMPTY)
* @param {Object} options 附加选项
* @returns {String} 新创建的图层ID
*/
createLayer(name = null, type = LayerType.EMPTY, options = {}) {
// 生成唯一ID
const layerId = `layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
const layerIndex = this.layers.value.length;
// 计算插入位置如果没有指定insertIndex则根据当前选中图层决定插入位置
// 添加到图层列表
let insertIndex = this._getInsertIndexAboveActiveLayer();
if (options.insertIndex !== undefined) {
insertIndex = options.insertIndex;
}
// 创建新图层
const newLayer = createLayer({
id: layerId,
name: name || `图层 ${layerIndex + 1}`,
type: type,
visible: true,
locked: false,
opacity: 1.0,
blendMode: BlendMode.NORMAL,
fabricObjects: [],
children: [],
...options,
});
// 直接创建和执行命令
const command = new AddLayerCommand({
canvas: this.canvas,
layers: this.layers,
newLayer: newLayer,
activeLayerId: this.activeLayerId,
insertIndex: insertIndex,
});
// 如果是第一个图层,设置为不可撤销
if (this.layers.value.length === 1) {
command.undoable = false;
}
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
return layerId;
}
/**
* 创建背景图层
* @param {string} name 图层名称
* @returns {string} 创建的背景层ID
*/
createBackgroundLayer(name = "背景") {
// 检查是否已有背景图层
const hasBackgroundLayer = this.layers.value.some(
(layer) => layer.isBackground
);
if (hasBackgroundLayer) {
console.warn("已存在背景层,不再创建新的背景层");
return null;
}
// 创建背景图层
const bgLayer = createBackgroundLayer({
name: name,
canvasWidth: this.canvasWidth,
canvasHeight: this.canvasHeight,
backgroundColor: this.backgroundColor,
});
// 直接创建和执行命令
const command = new CreateBackgroundLayerCommand({
canvas: this.canvas,
layers: this.layers,
activeLayerId: this.activeLayerId,
canvasManager: this.canvasManager,
backgroundLayer: bgLayer,
});
// 背景图层设置为不可撤销
command.undoable = false;
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
// 返回创建的背景层ID
return bgLayer.id;
}
/**
* 初始化图层确保有背景层固定图层和一个空白图层
*/
initializeLayers() {
// 如果没有任何图层,创建背景层、固定图层和一个空白图层
if (this.layers.value.length === 0) {
// 创建背景图层
this.createBackgroundLayer();
// 创建固定图层,位于背景图层之上
this.createFixedLayer();
// 创建一个空白图层(默认位于背景图层和固定图层之上)
this.createLayer("图层 1");
} else {
// 检查是否已有背景层
const hasBackgroundLayer = this.layers.value.some(
(layer) => layer.isBackground
);
if (!hasBackgroundLayer) {
this.createBackgroundLayer();
}
// 检查是否已有固定图层
const hasFixedLayer = this.layers.value.some((layer) => layer.isFixed);
if (!hasFixedLayer) {
this.createFixedLayer();
}
// 检查是否至少有一个普通图层(非背景、非固定)
const hasNormalLayer = this.layers.value.some(
(layer) => !layer.isBackground && !layer.isFixed
);
if (!hasNormalLayer) {
this.createLayer("图层 1");
}
}
// 排序图层
this.sortLayers();
// 更新对象交互性
this.updateLayersObjectsInteractivity();
}
/**
* 添加对象到图层
* @param {Object} fabricObject fabric对象
* @param {string} layerId 目标图层ID如果不提供则使用当前活动图层
* @returns {Object} 添加的对象
*/
addObjectToLayer(fabricObject, layerId = null) {
const targetLayerId = layerId || this.activeLayerId.value;
// 如果没有指定图层ID也没有活动图层则返回错误
if (!targetLayerId) {
console.warn("没有指定目标图层ID且没有活动图层无法添加对象");
return null;
}
// 验证目标图层是否存在
const targetLayer = this.getLayerById(targetLayerId);
if (!targetLayer) {
console.error(`目标图层 ${targetLayerId} 不存在`);
return null;
}
// 直接创建和执行命令
const command = new AddObjectToLayerCommand({
canvas: this.canvas,
layers: this.layers,
layerId: targetLayerId,
fabricObject: fabricObject,
});
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
return fabricObject;
}
/**
* 向固定图层添加对象
* @param {Object} fabricObject fabric对象
* @returns {Object|null} 添加的对象或null如果添加失败
*/
addObjectToFixedLayer(fabricObject) {
// 查找固定图层
const fixedLayer = this.layers.value.find((layer) => layer.isFixed);
// 如果没有固定图层,则创建一个
if (!fixedLayer) {
const fixedLayerId = this.createFixedLayer();
return this.addObjectToLayer(fabricObject, fixedLayerId);
}
// 添加对象到固定图层
return this.addObjectToLayer(fabricObject, fixedLayer.id);
}
/**
* 从图层中移除对象
* @param {string|Object} objectOrId 要移除的对象或其ID
* @returns {boolean} 是否移除成功
*/
removeObjectFromLayer(objectOrId) {
// 获取对象ID
const objectId =
typeof objectOrId === "string" ? objectOrId : objectOrId.id;
if (!objectId) {
console.error("无效的对象ID");
return false;
}
// 直接创建和执行命令
const command = new RemoveObjectFromLayerCommand({
canvas: this.canvas,
layers: this.layers,
objectId: objectId,
objectOrId: objectOrId,
});
// 执行命令
if (this.commandManager) {
return this.commandManager.execute(command);
} else {
return command.execute();
}
}
/**
* 设置活动图层
* @param {string} layerId 图层ID
*/
setActiveLayer(layerId, options = {}) {
// 直接创建和执行命令
const command = new SetActiveLayerCommand({
layers: this.layers,
canvas: this.canvas,
layerManager: this,
activeLayerId: this.activeLayerId,
layerId: layerId,
editorMode: this.editorMode,
...options,
});
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
}
/**
* 获取当前活动图层
* @return {Object} layer 图层对象
*/
getActiveLayer() {
// 查找当前活动图层
const activeLayer = this.layers.value.find(
(layer) => layer.id === this.activeLayerId.value
);
if (activeLayer) {
return activeLayer;
} else {
console.warn("没有活动图层");
return null;
}
}
// 获取当前活动图层ID
getActiveLayerId() {
return this.activeLayerId.value;
}
/**
* 根据ID获取图层
* @param {string} layerId 图层ID
* @returns {Object|null} 图层对象或null
*/
getLayerById(layerId) {
if (!layerId || !this.layers.value) return null;
return this.layers.value.find((layer) => layer.id === layerId) || null;
}
/**
* 获取当前图层对象的列表
* @param {string} layerId 可选指定图层ID默认使用当前活动图层
* @returns {Array} 图层中的对象列表
*/
getLayerObjects(layerId = null) {
const targetLayerId = layerId || this.activeLayerId.value;
if (!targetLayerId) return [];
const layer = this.getLayerById(targetLayerId);
if (!layer) return [];
// 如果是背景图层且有单个对象
if (layer.isBackground && layer.fabricObject) {
return [layer.fabricObject];
}
// 普通图层返回对象列表
return Array.isArray(layer.fabricObjects) ? layer.fabricObjects : [];
}
/**
* 移除图层
* @param {string} layerId 图层ID
* @returns {boolean} 是否移除成功
*/
removeLayer(layerId) {
// 查找要删除的图层
const layer = this.layers.value.find((layer) => layer.id === layerId);
// 如果是背景层或固定层,不允许删除
if (layer && (layer.isBackground || layer.isFixed)) {
console.warn(layer.isBackground ? "背景层不可删除" : "固定层不可删除");
return false;
}
// 如果图层有子图层,提示确认
if (layer && layer.children && layer.children.length > 0) {
console.warn("该图层包含子图层,删除将同时删除所有子图层");
}
// 直接创建和执行命令
const command = new RemoveLayerCommand({
canvas: this.canvas,
layers: this.layers,
layerId: layerId,
activeLayerId: this.activeLayerId,
});
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
return true;
}
/**
* 移动图层位置
* @param {string} layerId 图层ID
* @param {string} direction 移动方向'up''down'
* @returns {boolean} 是否移动成功
*/
moveLayer(layerId, direction) {
// 查找要移动的图层
const layer = this.layers.value.find((layer) => layer.id === layerId);
// 如果是背景层或固定层,不允许移动
if (layer && (layer.isBackground || layer.isFixed)) {
console.warn(layer.isBackground ? "背景层不可移动" : "固定层不可移动");
return false;
}
// 直接创建和执行命令
const command = new MoveLayerCommand({
canvas: this.canvas,
layers: this.layers,
layerId: layerId,
direction: direction,
});
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
// 更新画布渲染顺序
this._rearrangeObjects();
return true;
}
/**
* 切换图层可见性
* @param {string} layerId 图层ID
* @returns {boolean} 更新后的可见性状态
*/
toggleLayerVisibility(layerId) {
// 直接创建和执行命令
const command = new ToggleLayerVisibilityCommand({
canvas: this.canvas,
layers: this.layers,
layerId: layerId,
});
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
// 更新对象交互性
this.updateLayersObjectsInteractivity();
// 获取当前可见性
const layer = this.layers.value.find((layer) => layer.id === layerId);
return layer ? layer.visible : false;
}
/**
* 切换图层锁定状态
* @param {string} layerId 图层ID
* @returns {boolean} 更新后的锁定状态
*/
toggleLayerLock(layerId) {
// 直接创建和执行命令
const command = new LayerLockCommand({
canvas: this.canvas,
layers: this.layers,
layerId: layerId,
});
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
// 更新对象交互性
this.updateLayersObjectsInteractivity();
// 获取当前锁定状态
const layer = this.layers.value.find((layer) => layer.id === layerId);
return layer ? layer.locked : false;
}
/**
* 设置图层不透明度
* @param {string} layerId 图层ID
* @param {number} opacity 不透明度值 (0-1)
*/
setLayerOpacity(layerId, opacity) {
// 直接创建和执行命令
const command = new SetLayerOpacityCommand({
canvas: this.canvas,
layers: this.layers,
layerId: layerId,
opacity: opacity,
});
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
// 更新图层对象不透明度
const layer = this.layers.value.find((layer) => layer.id === layerId);
if (layer && layer.fabricObjects) {
layer.fabricObjects.forEach((obj) => {
obj.opacity = opacity;
});
this.canvas.renderAll();
}
}
/**
* 设置图层混合模式
* @param {string} layerId 图层ID
* @param {string} blendMode 混合模式
*/
setLayerBlendMode(layerId, blendMode) {
// 直接创建和执行命令
const command = new SetLayerBlendModeCommand({
canvas: this.canvas,
layers: this.layers,
layerId: layerId,
blendMode: blendMode,
});
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
// 更新图层对象混合模式
const layer = this.layers.value.find((layer) => layer.id === layerId);
if (layer && layer.fabricObjects) {
layer.fabricObjects.forEach((obj) => {
obj.globalCompositeOperation = blendMode;
});
this.canvas.renderAll();
}
}
/**
* 重命名图层
* @param {string} layerId 图层ID
* @param {string} newName 新名称
*/
renameLayer(layerId, newName) {
// 直接创建和执行命令
const command = new RenameLayerCommand({
canvas: this.canvas,
layers: this.layers,
layerId: layerId,
newName: newName,
});
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
// 更新图层对象上的图层名称
const layer = this.layers.value.find((layer) => layer.id === layerId);
if (layer && layer.fabricObjects) {
layer.fabricObjects.forEach((obj) => {
obj.layerName = newName;
});
}
}
/**
* 合并多个图层
* @param {Array<string>} layerIds 要合并的图层ID数组
* @param {string} newName 合并后的图层名称可选
* @returns {string} 合并后的新图层ID
*/
mergeLayers(layerIds, newName = null) {
// 检查参数
if (!layerIds || !Array.isArray(layerIds) || layerIds.length < 2) {
console.error("合并图层至少需要两个图层ID");
return null;
}
// 直接创建和执行命令
const command = new MergeLayersCommand({
canvas: this.canvas,
layers: this.layers,
layerIds: layerIds,
newName: newName,
});
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
return command.newLayerId;
}
/**
* 将多个图层组合为一个组
* @param {Array<string>} layerIds 要组合的图层ID数组
* @param {string} groupName 组名称可选
* @returns {string} 新组图层ID
*/
groupLayers(layerIds, groupName = null) {
// 检查参数
if (!layerIds || !Array.isArray(layerIds) || layerIds.length < 2) {
console.error("组合图层至少需要两个图层ID");
return null;
}
// 直接创建和执行命令
const command = new GroupLayersCommand({
canvas: this.canvas,
layers: this.layers,
layerIds: layerIds,
groupName: groupName,
});
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
return command.groupId;
}
/**
* 解组一个组图层
* @param {string} groupId 要解组的组图层ID
* @returns {Array<string>} 解组后的图层ID数组
*/
ungroupLayers(groupId) {
// 查找组图层
const groupLayer = this.layers.value.find((l) => l.id === groupId);
if (
!groupLayer ||
!groupLayer.children ||
groupLayer.children.length === 0
) {
console.error(`${groupId} 不是有效的组图层或不包含子图层`);
return null;
}
// 直接创建和执行命令
const command = new UngroupLayersCommand({
canvas: this.canvas,
layers: this.layers,
groupId: groupId,
});
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
return command.childLayerIds;
}
/**
* 调整画布和背景图层尺寸
* @param {number} width 宽度
* @param {number} height 高度
*/
resizeCanvas(width, height, options = {}) {
// 直接创建和执行命令
const command = new BackgroundSizeCommand({
canvas: this.canvas,
layers: this.layers,
canvasManager: this.canvasManager,
newWidth: width,
newHeight: height,
isRedGreenMode: this.isInRedGreenMode(), // 传递红绿图模式状态
});
command.undoable = !!options.undoable; // 设置为可撤销
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
// 更新存储的尺寸
this.canvasWidth = width;
this.canvasHeight = height;
}
/**
* 调整背景大小并等比缩放所有其他元素
* @param {number} width 宽度
* @param {number} height 高度
*/
resizeCanvasWithScale(width, height, options = {}) {
// 检查是否有除背景层外的其他元素
const hasOtherElements = this.canvas
.getObjects()
.some((obj) => !obj.isBackground);
if (hasOtherElements) {
// 有其他元素时使用带缩放的命令
const command = new BackgroundSizeWithScaleCommand({
canvas: this.canvas,
layers: this.layers,
canvasManager: this.canvasManager,
newWidth: width,
newHeight: height,
isRedGreenMode: this.isInRedGreenMode(), // 传递红绿图模式状态
});
command.undoable = !!options.undoable; // 设置为可撤销
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
} else {
// 没有其他元素时使用普通的背景尺寸调整命令
this.resizeCanvas(width, height, options);
}
// 更新存储的尺寸
this.canvasWidth = width;
this.canvasHeight = height;
}
/**
* 排序图层确保图层顺序: 普通图层 > 固定图层 > 背景图层
*/
sortLayers() {
// 对图层进行排序:背景图层在最底层(数组最后),固定图层在中间
this.layers.value.sort((a, b) => {
// 如果a是背景图层它应该排在后面最底层
if (a.isBackground) return 1;
// 如果b是背景图层它应该排在后面最底层
if (b.isBackground) return -1;
// 如果a是固定图层而b不是固定图层a应该排在后面固定图层在普通图层下方
if (a.isFixed && !b.isFixed) return 1;
// 如果b是固定图层而a不是固定图层b应该排在后面固定图层在普通图层下方
if (b.isFixed && !a.isFixed) return -1;
// 其他情况保持原有顺序
return 0;
});
// 更新画布对象顺序
this._rearrangeObjects();
}
/**
* 重新排列画布上的对象以匹配图层顺序
* @private
*/
_rearrangeObjects() {
if (!this.canvas) return;
// 获取画布上的所有对象
const canvasObjects = [...this.canvas.getObjects()];
// 清空画布
this.canvas.clear();
// 按图层顺序(从底到顶)重新添加对象
// 注意:图层数组是从顶到底的顺序,需要反向遍历
for (let i = this.layers.value.length - 1; i >= 0; i--) {
const layer = this.layers.value[i];
// 跳过不可见图层
if (!layer.visible) continue;
if (layer.isBackground) {
// 背景图层特殊处理
if (layer.fabricObject) {
const bgObject = canvasObjects.find(
(obj) => obj.id === layer.fabricObject.id
);
if (bgObject) {
this.canvas.add(bgObject);
} else if (layer.fabricObject) {
this.canvas.add(layer.fabricObject);
}
}
} else if (
Array.isArray(layer.fabricObjects) &&
layer.fabricObjects.length > 0
) {
// 普通图层添加所有fabricObjects
layer.fabricObjects.forEach((obj) => {
const originalObj = canvasObjects.find((o) => o.id === obj.id);
if (originalObj) {
this.canvas.add(originalObj);
} else {
this.canvas.add(obj);
}
});
}
}
// 更新对象交互性
this.updateLayersObjectsInteractivity();
// 渲染画布
this.canvas.renderAll();
}
/**
* 同步画布对象到图层数据
* 确保画布上的对象和图层数据一致
*/
syncCanvasToLayers() {
if (!this.canvas) return;
// 获取画布上的所有对象
const canvasObjects = this.canvas.getObjects();
// 遍历所有图层
this.layers.value.forEach((layer) => {
if (layer.isBackground) {
// 背景图层处理
if (layer.fabricObject) {
const existsOnCanvas = canvasObjects.some(
(obj) => obj.id === layer.fabricObject.id
);
if (!existsOnCanvas) {
this.canvas.add(layer.fabricObject);
}
}
} else if (Array.isArray(layer.fabricObjects)) {
// 更新图层中的对象列表
const updatedObjects = [];
// 处理已有对象
layer.fabricObjects.forEach((obj) => {
const canvasObj = canvasObjects.find((cObj) => cObj.id === obj.id);
if (canvasObj) {
updatedObjects.push(canvasObj);
} else {
// 对象不在画布上,添加到画布
this.canvas.add(obj);
updatedObjects.push(obj);
}
});
// 检查是否有新对象需要添加到图层
canvasObjects.forEach((canvasObj) => {
if (
canvasObj.layerId === layer.id &&
!updatedObjects.some((obj) => obj.id === canvasObj.id)
) {
updatedObjects.push(canvasObj);
}
});
// 更新图层的对象列表
layer.fabricObjects = updatedObjects;
}
});
// 重新排列对象以匹配图层顺序
this._rearrangeObjects();
}
/**
* 导出当前图层数据
* @returns {Object} 图层数据对象
*/
exportLayersData() {
// 深拷贝图层数据,避免修改原始数据
const layersData = JSON.parse(JSON.stringify(this.layers.value));
// 移除无法序列化的属性
layersData.forEach((layer) => {
if (layer.fabricObjects) {
// 序列化对象
layer.serializedObjects = layer.fabricObjects
.map((obj) => {
if (typeof obj.toObject === "function") {
return obj.toObject(["id", "layerId", "layerName"]);
}
return null;
})
.filter(Boolean);
// 删除原始对象引用
delete layer.fabricObjects;
}
if (layer.fabricObject) {
layer.serializedBackgroundObject =
typeof layer.fabricObject.toObject === "function"
? layer.fabricObject.toObject(["id", "layerId", "layerName"])
: null;
delete layer.fabricObject;
}
});
return {
layers: layersData,
activeLayerId: this.activeLayerId.value,
canvasWidth: this.canvasWidth,
canvasHeight: this.canvasHeight,
backgroundColor: this.backgroundColor,
editorMode: this.editorMode,
};
}
/**
* 导入图层数据
* @param {Object} data 图层数据对象
* @returns {boolean} 是否导入成功
*/
importLayersData(data) {
if (!data || !data.layers || !Array.isArray(data.layers)) {
console.error("无效的图层数据");
return false;
}
const fabric = window.fabric;
if (!fabric) {
console.error("未找到fabric库");
return false;
}
// 清除画布
this.canvas.clear();
// 清空图层列表
this.layers.value = [];
// 设置画布尺寸
if (data.canvasWidth && data.canvasHeight) {
this.canvasWidth = data.canvasWidth;
this.canvasHeight = data.canvasHeight;
this.canvas.setWidth(data.canvasWidth);
this.canvas.setHeight(data.canvasHeight);
}
// 设置背景颜色
if (data.backgroundColor) {
this.backgroundColor = data.backgroundColor;
}
// 设置编辑模式
if (data.editorMode) {
this.editorMode = data.editorMode;
}
// 导入图层
const promises = data.layers.map((layerData) => {
return new Promise((resolve) => {
const newLayer = {
...layerData,
fabricObjects: [],
children: layerData.children || [],
};
// 如果有序列化的对象,恢复它们
if (
layerData.serializedObjects &&
Array.isArray(layerData.serializedObjects)
) {
fabric.util.enlivenObjects(layerData.serializedObjects, (objects) => {
objects.forEach((obj) => {
// 关联到图层
obj.layerId = newLayer.id;
obj.layerName = newLayer.name;
// 添加到画布
this.canvas.add(obj);
// 添加到图层
newLayer.fabricObjects.push(obj);
});
resolve(newLayer);
});
} else if (
layerData.isBackground &&
layerData.serializedBackgroundObject
) {
// 恢复背景对象
fabric.util.enlivenObjects(
[layerData.serializedBackgroundObject],
([bgObject]) => {
if (bgObject) {
bgObject.layerId = newLayer.id;
bgObject.layerName = newLayer.name;
this.canvas.add(bgObject);
newLayer.fabricObject = bgObject;
}
resolve(newLayer);
}
);
} else {
resolve(newLayer);
}
});
});
// 等待所有图层加载完成
Promise.all(promises).then((layers) => {
// 更新图层列表
this.layers.value = layers;
// 设置活动图层
if (data.activeLayerId) {
const activeLayer = layers.find(
(layer) => layer.id === data.activeLayerId
);
if (activeLayer && !activeLayer.isBackground && !activeLayer.locked) {
this.activeLayerId.value = data.activeLayerId;
} else {
// 查找第一个非背景、非锁定的图层
const firstNormalLayer = layers.find(
(layer) => !layer.isBackground && !layer.locked
);
if (firstNormalLayer) {
this.activeLayerId.value = firstNormalLayer.id;
}
}
}
// 确保至少有一个背景图层和一个普通图层
this.initializeLayers();
// 更新对象交互性
this.updateLayersObjectsInteractivity();
// 重新排列对象
this._rearrangeObjects();
});
return true;
}
/**
* 复制图层数据到剪贴板
* @param {string} layerId 要复制的图层ID
* @returns {Object} 复制的图层数据
*/
copyLayer(layerId) {
const layer = this.layers.value.find((l) => l.id === layerId);
if (!layer) {
console.error(`图层 ${layerId} 不存在`);
return null;
}
// 不允许复制背景图层
if (layer.isBackground) {
console.warn("不能复制背景图层");
return null;
}
// 序列化图层对象
const layerCopy = JSON.parse(JSON.stringify(layer));
// 序列化fabricObjects数组
if (layer.fabricObjects && layer.fabricObjects.length > 0) {
layerCopy.serializedObjects = layer.fabricObjects
.map((obj) =>
typeof obj.toObject === "function"
? obj.toObject(["id", "layerId", "layerName"])
: null
)
.filter(Boolean);
}
// 存储到剪贴板
this.clipboardData = layerCopy;
console.log(`已复制图层:${layer.name}`);
return this.clipboardData;
}
/**
* 剪切图层数据到剪贴板
* @param {string} layerId 要剪切的图层ID
* @returns {Object} 剪切的图层数据
*/
cutLayer(layerId) {
const layer = this.layers.value.find((l) => l.id === layerId);
if (!layer) {
console.error(`图层 ${layerId} 不存在`);
return null;
}
// 不允许剪切背景图层
if (layer.isBackground) {
console.warn("不能剪切背景图层");
return null;
}
// 检查是否是唯一的普通图层
const normalLayers = this.layers.value.filter((l) => !l.isBackground);
if (normalLayers.length === 1) {
console.warn("不能剪切唯一的普通图层");
return null;
}
// 序列化图层对象
const layerCopy = JSON.parse(JSON.stringify(layer));
// 序列化fabricObjects数组
if (layer.fabricObjects && layer.fabricObjects.length > 0) {
layerCopy.serializedObjects = layer.fabricObjects
.map((obj) =>
typeof obj.toObject === "function"
? obj.toObject(["id", "layerId", "layerName"])
: null
)
.filter(Boolean);
}
// 存储到剪贴板
this.clipboardData = layerCopy;
// 记录是剪切操作,用于粘贴时的处理
this.clipboardData.isCut = true;
// 从画布中移除图层中的所有对象
if (layer.fabricObjects && layer.fabricObjects.length > 0) {
layer.fabricObjects.forEach((obj) => {
this.canvas.remove(obj);
});
}
// 如果剪切的是当前活动图层,需要切换到其他图层
if (this.activeLayerId.value === layerId) {
// 查找下一个可用的图层
const nextLayer = this._findNextAvailableLayer(layerId);
if (nextLayer) {
this.setActiveLayer(nextLayer.id);
}
}
// 直接创建和执行命令
const command = new RemoveLayerCommand({
canvas: this.canvas,
layers: this.layers,
layerId: layerId,
activeLayerId: this.activeLayerId,
});
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
// 更新对象交互性
this.updateLayersObjectsInteractivity();
console.log(`已剪切图层:${layer.name}`);
return this.clipboardData;
}
/**
* 粘贴图层
* @returns {string} 新创建的图层ID
*/
/**
* 粘贴图层
* @returns {string} 新创建的图层ID
*/
pasteLayer() {
if (!this.clipboardData) {
console.error("剪贴板中没有图层数据");
return null;
}
// 使用命令管理器执行粘贴命令
if (this.commandManager) {
return this.commandManager.executeByName("PasteLayer", {
canvas: this.canvas,
layers: this.layers,
activeLayerId: this.activeLayerId,
clipboardData: this.clipboardData,
layerManager: this, // 传递LayerManager实例
});
} else {
// 创建粘贴图层命令
const command = new PasteLayerCommand({
canvas: this.canvas,
layers: this.layers,
activeLayerId: this.activeLayerId,
clipboardData: this.clipboardData,
layerManager: this, // 传递LayerManager实例
});
// 执行命令
return command.execute();
}
}
/**
* 查找下一个可用的图层非背景非锁定
* @param {string} excludeLayerId 要排除的图层ID
* @returns {Object|null} 下一个可用的图层
* @private
*/
_findNextAvailableLayer(excludeLayerId) {
// 查找第一个非背景、非锁定的图层,排除指定的图层
return (
this.layers.value.find(
(layer) =>
layer.id !== excludeLayerId && !layer.isBackground && !layer.locked
) || null
);
}
/**
* 获取活动图层上方的插入索引
* @returns {number} 插入索引
* @private
*/
_getInsertIndexAboveActiveLayer() {
if (!this.activeLayerId.value) return 0;
const activeLayerIndex = this.layers.value.findIndex(
(layer) => layer.id === this.activeLayerId.value
);
return activeLayerIndex !== -1 ? activeLayerIndex : 0;
}
/**
* 保存画布状态
* 现在统一通过命令管理器的智能状态保存
*/
saveCanvasState() {
if (this.commandManager) {
// 使用智能状态保存,避免不必要的状态保存
this.commandManager.saveStateIfNeeded({
name: "图层状态更新",
stateType: "full",
});
}
}
/**
* 执行带状态保存的操作
* 统一的状态管理入口
*/
executeWithState(operation, name = "图层操作") {
if (this.commandManager) {
return this.commandManager.executeWithState(operation, {
name,
stateType: "full",
});
} else {
// 降级处理
return typeof operation === "function" ? operation() : operation;
}
}
/**
* 批量执行图层操作
*/
batchExecute(operations, name = "批量图层操作") {
if (this.commandManager) {
return this.commandManager.batch(operations, name);
} else {
// 降级处理
const results = [];
for (const operation of operations) {
results.push(typeof operation === "function" ? operation() : operation);
}
return results;
}
}
/**
* 清理画布移除所有图层
*/
clearCanvas() {
// 清空画布
this.canvas.clear();
// 清空图层列表
this.layers.value = [];
// 重新初始化基本图层
this.initializeLayers();
console.log("已清空画布");
}
/**
* 合并图层内的对象为单一图像
* @param {string} layerId 图层ID默认使用当前活动图层
* @param {fabric.Image} newImage 要合并的新图像可选
* @returns {Promise<string>} 合并后的图像ID
*/
async mergeLayerObjects(activeLayer, fabricImage = null) {
if (!activeLayer) {
console.error(`活动图层不存在`);
return null;
}
// 直接创建和执行命令
const command = new MergeLayerObjectsCommand({
canvas: this.canvas,
layers: this.layers,
fabricImage,
activeLayer,
});
// 执行命令
return command;
}
/**
* 合并图层内对象成组的命令
* 将新的图像与图层内现有对象合并为一个组对象
* 注意此命令与 MergeLayerObjectsCommand 类似但它创建一个组而不是单个图像对象
*/
async LayerObjectsToGroup(activeLayer, fabricImage = null) {
// 检查活动图层是否存在
if (!activeLayer) {
console.error(`活动图层不存在`);
return null;
}
// 直接创建和执行命令
const command = new LayerObjectsToGroupCommand({
canvas: this.canvas,
layers: this.layers,
fabricImage,
activeLayer,
});
// 执行命令
return command;
}
/**
* 更新背景图层颜色
* @param {string} backgroundColor 背景颜色
*/
updateBackgroundColor(backgroundColor) {
// 查找背景图层
const backgroundLayer = this.layers.value.find(
(layer) => layer.isBackground
);
if (!backgroundLayer) {
console.warn("没有找到背景图层");
return;
}
// 直接创建和执行命令
const command = new UpdateBackgroundCommand({
canvas: this.canvas,
layers: this.layers,
canvasManager: this.canvasManager,
backgroundColor: backgroundColor,
});
// 执行命令
if (this.commandManager) {
this.commandManager.execute(command);
} else {
command.execute();
}
// 更新存储的背景颜色
this.backgroundColor = backgroundColor;
}
/**
* 获取图层缩略图
* @param {string} layerId 图层ID
* @param {number} width 缩略图宽度
* @param {number} height 缩略图高度
* @returns {string} Base64编码的缩略图
*/
getLayerThumbnail(layerId, width = 100, height = 100) {
const layer = this.getLayerById(layerId);
if (!layer) {
console.error(`图层 ${layerId} 不存在`);
return null;
}
// 创建临时画布
const tempCanvas = document.createElement("canvas");
tempCanvas.width = width;
tempCanvas.height = height;
const ctx = tempCanvas.getContext("2d");
// 设置背景色
ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, width, height);
try {
if (layer.isBackground && layer.fabricObject) {
// 背景图层
const bgObj = layer.fabricObject;
if (bgObj.toCanvasElement) {
const element = bgObj.toCanvasElement();
ctx.drawImage(element, 0, 0, width, height);
}
} else if (layer.fabricObjects && layer.fabricObjects.length > 0) {
// 普通图层
layer.fabricObjects.forEach((obj) => {
if (obj.toCanvasElement) {
const element = obj.toCanvasElement();
const scaleX = width / this.canvasWidth;
const scaleY = height / this.canvasHeight;
ctx.save();
ctx.scale(scaleX, scaleY);
ctx.drawImage(element, obj.left || 0, obj.top || 0);
ctx.restore();
}
});
}
return tempCanvas.toDataURL();
} catch (error) {
console.error("生成图层缩略图失败:", error);
return null;
}
}
/**
* 检查图层是否为空
* @param {string} layerId 图层ID
* @returns {boolean} 是否为空图层
*/
isLayerEmpty(layerId) {
const layer = this.getLayerById(layerId);
if (!layer) return true;
if (layer.isBackground) {
return !layer.fabricObject;
}
return !layer.fabricObjects || layer.fabricObjects.length === 0;
}
/**
* 获取图层统计信息
* @returns {Object} 图层统计信息
*/
getLayerStats() {
const stats = {
totalLayers: this.layers.value.length,
backgroundLayers: 0,
normalLayers: 0,
lockedLayers: 0,
hiddenLayers: 0,
emptyLayers: 0,
totalObjects: 0,
};
this.layers.value.forEach((layer) => {
if (layer.isBackground) {
stats.backgroundLayers++;
if (layer.fabricObject) {
stats.totalObjects++;
}
} else {
stats.normalLayers++;
if (layer.fabricObjects) {
stats.totalObjects += layer.fabricObjects.length;
}
}
if (layer.locked) stats.lockedLayers++;
if (!layer.visible) stats.hiddenLayers++;
if (this.isLayerEmpty(layer.id)) stats.emptyLayers++;
});
return stats;
}
/**
* 清理空图层
* @returns {Array<string>} 被清理的图层ID数组
*/
cleanupEmptyLayers() {
const emptyLayerIds = [];
// 找出所有空的非背景图层
this.layers.value.forEach((layer) => {
if (!layer.isBackground && this.isLayerEmpty(layer.id)) {
emptyLayerIds.push(layer.id);
}
});
// 删除空图层
emptyLayerIds.forEach((layerId) => {
this.removeLayer(layerId);
});
if (emptyLayerIds.length > 0) {
console.log(`已清理 ${emptyLayerIds.length} 个空图层`);
}
return emptyLayerIds;
}
/**
* 销毁图层管理器
* 清理所有引用和事件监听器
*/
dispose() {
// 清空画布
if (this.canvas) {
this.canvas.clear();
}
// 清空图层数据
if (this.layers && this.layers.value) {
this.layers.value = [];
}
// 清空剪贴板
this.clipboardData = null;
// 清除引用
this.canvas = null;
this.layers = null;
this.activeLayerId = null;
this.commandManager = null;
this.canvasManager = null;
this.toolManager = null;
console.log("LayerManager 已销毁");
}
/**
* 创建文本图层并添加文本对象
* @param {Object} textObject Fabric文本对象
* @param {Object} options 文本选项
* @returns {Object} 创建的文本对象
*/
createTextLayerWithObject(textObject, options = {}) {
if (!this.canvas || !textObject) return null;
// 确保对象有ID
textObject.id =
textObject.id || `text_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
// 创建文本图层
const layerName = options.name || "文本图层";
const layerId = this.createLayer(layerName, LayerType.TEXT, {
layerProperties: {
text: options.text || textObject.text || "新文本",
fontFamily: options.fontFamily || textObject.fontFamily || "Arial",
fontSize: options.fontSize || textObject.fontSize || 24,
fontWeight: options.fontWeight || textObject.fontWeight || "normal",
fontStyle: options.fontStyle || textObject.fontStyle || "normal",
textAlign: options.textAlign || textObject.textAlign || "left",
underline: options.underline || textObject.underline || false,
linethrough: options.linethrough || textObject.linethrough || false,
overline: options.overline || textObject.overline || false,
fill: options.fill || textObject.fill || "#000000",
textBackgroundColor:
options.textBackgroundColor ||
textObject.textBackgroundColor ||
"transparent",
lineHeight: options.lineHeight || textObject.lineHeight || 1.16,
charSpacing: options.charSpacing || textObject.charSpacing || 0,
},
});
// 把对象添加到新图层
textObject.layerId = layerId;
textObject.layerName = layerName;
// 添加到画布,如果还未添加
const isOnCanvas = this.canvas
.getObjects()
.some((obj) => obj.id === textObject.id);
if (!isOnCanvas) {
this.canvas.add(textObject);
}
// 更新图层中的对象列表
const layer = this.getLayerById(layerId);
if (layer) {
layer.fabricObjects = layer.fabricObjects || [];
layer.fabricObjects.push(textObject);
}
// 设置此图层为活动图层
this.setActiveLayer(layerId);
// 更新交互性
this.updateLayersObjectsInteractivity();
return textObject;
}
/**
* 根据fabric对象查找所属图层
* @param {Object} fabricObject fabric对象
* @returns {Object|null} 图层对象或null
*/
findLayerByObject(fabricObject) {
if (!fabricObject || !fabricObject.id) {
return null;
}
// 遍历所有图层查找包含该对象的图层
for (const layer of this.layers.value) {
// 检查背景图层
if (layer.isBackground && layer.fabricObject) {
if (layer.fabricObject.id === fabricObject.id) {
return layer;
}
}
// 检查普通图层
if (layer.fabricObjects && Array.isArray(layer.fabricObjects)) {
const foundObject = layer.fabricObjects.find(
(obj) => obj.id === fabricObject.id
);
if (foundObject) {
return layer;
}
}
}
return null;
}
/**
* 拖拽排序图层
* @param {number} oldIndex 原索引
* @param {number} newIndex 新索引
* @param {string} layerId 图层ID
* @returns {boolean} 是否排序成功
*/
reorderLayers(oldIndex, newIndex, layerId) {
// 检查索引有效性
if (
oldIndex < 0 ||
newIndex < 0 ||
oldIndex >= this.layers.value.length ||
newIndex >= this.layers.value.length
) {
console.warn("图层排序索引无效");
return false;
}
// 检查是否是同一位置
if (oldIndex === newIndex) {
return true;
}
// 获取要移动的图层
const layer = this.layers.value[oldIndex];
if (!layer || layer.id !== layerId) {
console.warn("图层ID与索引不匹配");
return false;
}
// 检查是否是背景层或固定层(不允许排序)
if (layer.isBackground || layer.isFixed) {
console.warn("背景层和固定层不能参与排序");
return false;
}
// 检查目标位置是否合法(不能移到背景层或固定层的位置)
const targetLayer = this.layers.value[newIndex];
if (targetLayer && (targetLayer.isBackground || targetLayer.isFixed)) {
console.warn("不能移动到背景层或固定层的位置");
return false;
}
// 创建并执行拖拽排序命令
const command = new ReorderLayersCommand({
layers: this.layers,
oldIndex: oldIndex,
newIndex: newIndex,
layerId: layerId,
canvas: this.canvas,
});
// 执行命令
if (this.commandManager) {
return this.commandManager.execute(command);
} else {
return command.execute();
}
}
/**
* 拖拽排序子图层
* @param {string} parentId 父图层ID
* @param {number} oldIndex 原索引
* @param {number} newIndex 新索引
* @param {string} layerId 子图层ID
* @returns {boolean} 是否排序成功
*/
reorderChildLayers(parentId, oldIndex, newIndex, layerId) {
// 检查父图层是否存在
const parentLayer = this.getLayerById(parentId);
if (!parentLayer) {
console.warn(`父图层 ${parentId} 不存在`);
return false;
}
// 获取所有子图层
const childLayers = this.layers.value.filter(
(layer) => layer.parentId === parentId
);
// 检查索引有效性
if (
oldIndex < 0 ||
newIndex < 0 ||
oldIndex >= childLayers.length ||
newIndex >= childLayers.length
) {
console.warn("子图层排序索引无效");
return false;
}
// 检查是否是同一位置
if (oldIndex === newIndex) {
return true;
}
// 验证图层ID
const layer = childLayers[oldIndex];
if (!layer || layer.id !== layerId) {
console.warn("子图层ID与索引不匹配");
return false;
}
// 创建并执行子图层拖拽排序命令
const command = new ReorderChildLayersCommand({
layers: this.layers,
parentId: parentId,
oldIndex: oldIndex,
newIndex: newIndex,
layerId: layerId,
canvas: this.canvas,
});
// 执行命令
if (this.commandManager) {
return this.commandManager.execute(command);
} else {
return command.execute();
}
}
// 设置红绿图模式管理器
setRedGreenModeManager(redGreenModeManager) {
this.redGreenModeManager = redGreenModeManager;
}
// 启用红绿图模式
enableRedGreenMode() {
this.isRedGreenMode = true;
console.log("图层管理器:红绿图模式已启用");
}
// 禁用红绿图模式
disableRedGreenMode() {
this.isRedGreenMode = false;
console.log("图层管理器:红绿图模式已禁用");
}
// 检查是否为红绿图模式
isInRedGreenMode() {
return this.isRedGreenMode;
}
// 检查背景图层是否需要跟随画布大小变化(红绿图模式下)
shouldBackgroundFollowCanvasSize() {
return this.isRedGreenMode;
}
// 在红绿图模式下创建图层 - 限制功能
createLayerInRedGreenMode() {
console.warn("红绿图模式下不支持创建新图层");
return null;
}
// 在红绿图模式下移除图层 - 限制功能
removeLayerInRedGreenMode(layerId) {
console.warn("红绿图模式下不支持删除图层");
return false;
}
}