768 lines
21 KiB
JavaScript
768 lines
21 KiB
JavaScript
|
|
import { Command } from "./Command";
|
|||
|
|
import { isGroupLayer } from "../utils/layerHelper";
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 跨层级移动命令基类
|
|||
|
|
*/
|
|||
|
|
export class CrossLevelMoveCommand extends Command {
|
|||
|
|
constructor(options) {
|
|||
|
|
super({
|
|||
|
|
name: "跨层级移动",
|
|||
|
|
undoable: true,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
this.layers = options.layers;
|
|||
|
|
this.layerManager = options.layerManager;
|
|||
|
|
this.canvas = options.canvas;
|
|||
|
|
|
|||
|
|
// 移动相关参数
|
|||
|
|
this.layerId = options.layerId;
|
|||
|
|
this.fromContainerType = options.fromContainerType; // 'root' | 'child'
|
|||
|
|
this.toContainerType = options.toContainerType; // 'root' | 'child'
|
|||
|
|
this.fromParentId = options.fromParentId;
|
|||
|
|
this.toParentId = options.toParentId;
|
|||
|
|
this.newIndex = options.newIndex;
|
|||
|
|
this.oldIndex = options.oldIndex;
|
|||
|
|
|
|||
|
|
// 保存状态用于撤销
|
|||
|
|
this.beforeState = null;
|
|||
|
|
this.afterState = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 保存移动前的状态
|
|||
|
|
*/
|
|||
|
|
saveBeforeState() {
|
|||
|
|
this.beforeState = {
|
|||
|
|
layerStructure: this.cloneLayerStructure(),
|
|||
|
|
fabricObjects: this.saveFabricObjectStates(),
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 保存移动后的状态
|
|||
|
|
*/
|
|||
|
|
saveAfterState() {
|
|||
|
|
this.afterState = {
|
|||
|
|
layerStructure: this.cloneLayerStructure(),
|
|||
|
|
fabricObjects: this.saveFabricObjectStates(),
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 克隆图层结构
|
|||
|
|
*/
|
|||
|
|
cloneLayerStructure() {
|
|||
|
|
return JSON.parse(
|
|||
|
|
JSON.stringify(
|
|||
|
|
this.layers.value.map((layer) => ({
|
|||
|
|
id: layer.id,
|
|||
|
|
name: layer.name,
|
|||
|
|
parentId: layer.parentId,
|
|||
|
|
children: layer.children
|
|||
|
|
? layer.children.map((child) => ({
|
|||
|
|
id: child.id,
|
|||
|
|
name: child.name,
|
|||
|
|
parentId: child.parentId,
|
|||
|
|
}))
|
|||
|
|
: [],
|
|||
|
|
isBackground: layer.isBackground,
|
|||
|
|
isFixed: layer.isFixed,
|
|||
|
|
visible: layer.visible,
|
|||
|
|
locked: layer.locked,
|
|||
|
|
}))
|
|||
|
|
)
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 保存fabric对象状态
|
|||
|
|
*/
|
|||
|
|
saveFabricObjectStates() {
|
|||
|
|
const states = {};
|
|||
|
|
|
|||
|
|
// 只保存fabric对象的容器关系,不保存具体的属性
|
|||
|
|
this.layers.value.forEach((layer) => {
|
|||
|
|
if (layer.fabricObject) {
|
|||
|
|
states[layer.id] = {
|
|||
|
|
isInCanvas: this.canvas
|
|||
|
|
? this.canvas.contains(layer.fabricObject)
|
|||
|
|
: false,
|
|||
|
|
parentGroupId: null,
|
|||
|
|
visible: layer.fabricObject.visible,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 检查是否在某个组中
|
|||
|
|
this.layers.value.forEach((otherLayer) => {
|
|||
|
|
if (
|
|||
|
|
otherLayer.fabricObject &&
|
|||
|
|
otherLayer.fabricObject.type === "group" &&
|
|||
|
|
otherLayer.fabricObject.contains &&
|
|||
|
|
otherLayer.fabricObject.contains(layer.fabricObject)
|
|||
|
|
) {
|
|||
|
|
states[layer.id].parentGroupId = otherLayer.id;
|
|||
|
|
states[layer.id].isInCanvas = false;
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
return states;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 查找图层
|
|||
|
|
*/
|
|||
|
|
findLayer(layerId, containerType, parentId) {
|
|||
|
|
if (containerType === "root") {
|
|||
|
|
return this.layers.value.find((layer) => layer.id === layerId);
|
|||
|
|
} else if (containerType === "child" && parentId) {
|
|||
|
|
const parent = this.layers.value.find((layer) => layer.id === parentId);
|
|||
|
|
return parent?.children?.find((child) => child.id === layerId);
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 验证移动的有效性
|
|||
|
|
*/
|
|||
|
|
validateMove() {
|
|||
|
|
const layer = this.findLayer(
|
|||
|
|
this.layerId,
|
|||
|
|
this.fromContainerType,
|
|||
|
|
this.fromParentId
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
if (!layer) {
|
|||
|
|
throw new Error(`找不到要移动的图层: ${this.layerId}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查是否为不可移动的图层
|
|||
|
|
if (layer.isBackground || layer.isFixed) {
|
|||
|
|
throw new Error("背景层和固定层不能移动");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查是否试图将图层移动到自己的子层级中(防止循环引用)
|
|||
|
|
if (
|
|||
|
|
this.toContainerType === "child" &&
|
|||
|
|
this.toParentId &&
|
|||
|
|
this.isDescendantOf(this.toParentId, this.layerId)
|
|||
|
|
) {
|
|||
|
|
throw new Error("不能将图层移动到自己的子层级中");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查目标父图层是否为组
|
|||
|
|
if (this.toContainerType === "child") {
|
|||
|
|
const targetParent = this.layers.value.find(
|
|||
|
|
(layer) => layer.id === this.toParentId
|
|||
|
|
);
|
|||
|
|
if (!targetParent || !isGroupLayer(targetParent)) {
|
|||
|
|
throw new Error("目标图层不是组图层");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return layer;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 检查是否为子层级关系(防止循环引用)
|
|||
|
|
*/
|
|||
|
|
isDescendantOf(ancestorId, layerId) {
|
|||
|
|
const checkChildren = (children) => {
|
|||
|
|
if (!children) return false;
|
|||
|
|
for (const child of children) {
|
|||
|
|
if (child.id === layerId) return true;
|
|||
|
|
if (child.children && checkChildren(child.children)) return true;
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const ancestor = this.layers.value.find((layer) => layer.id === ancestorId);
|
|||
|
|
return ancestor ? checkChildren(ancestor.children) : false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
execute() {
|
|||
|
|
console.log("🎯 执行跨层级移动命令:", {
|
|||
|
|
layerId: this.layerId,
|
|||
|
|
from: this.fromContainerType,
|
|||
|
|
to: this.toContainerType,
|
|||
|
|
fromParentId: this.fromParentId,
|
|||
|
|
toParentId: this.toParentId,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 验证移动
|
|||
|
|
const draggedLayer = this.validateMove();
|
|||
|
|
|
|||
|
|
// 保存移动前状态
|
|||
|
|
this.saveBeforeState();
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 根据移动类型执行对应操作
|
|||
|
|
if (
|
|||
|
|
this.fromContainerType === "root" &&
|
|||
|
|
this.toContainerType === "child"
|
|||
|
|
) {
|
|||
|
|
this.moveRootToGroup(draggedLayer);
|
|||
|
|
} else if (
|
|||
|
|
this.fromContainerType === "child" &&
|
|||
|
|
this.toContainerType === "root"
|
|||
|
|
) {
|
|||
|
|
this.moveGroupToRoot(draggedLayer);
|
|||
|
|
} else if (
|
|||
|
|
this.fromContainerType === "child" &&
|
|||
|
|
this.toContainerType === "child" &&
|
|||
|
|
this.fromParentId !== this.toParentId
|
|||
|
|
) {
|
|||
|
|
this.moveGroupToGroup(draggedLayer);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 保存移动后状态
|
|||
|
|
this.saveAfterState();
|
|||
|
|
|
|||
|
|
// 刷新画布
|
|||
|
|
if (this.canvas) {
|
|||
|
|
this.canvas.renderAll();
|
|||
|
|
console.log("🎨 画布已刷新");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log("✅ 跨层级移动命令执行成功");
|
|||
|
|
return true;
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error("❌ 跨层级移动命令执行失败:", error);
|
|||
|
|
|
|||
|
|
// 如果执行失败,尝试恢复到之前的状态
|
|||
|
|
if (this.beforeState) {
|
|||
|
|
try {
|
|||
|
|
this.restoreLayerStructure(this.beforeState.layerStructure);
|
|||
|
|
this.restoreFabricObjectStates(this.beforeState.fabricObjects);
|
|||
|
|
if (this.canvas) {
|
|||
|
|
this.canvas.renderAll();
|
|||
|
|
}
|
|||
|
|
console.log("🔄 已恢复到移动前状态");
|
|||
|
|
} catch (restoreError) {
|
|||
|
|
console.error("❌ 恢复状态失败:", restoreError);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
throw error;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
undo() {
|
|||
|
|
if (!this.beforeState) {
|
|||
|
|
throw new Error("没有保存的前置状态,无法撤销");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log("🔄 撤销跨层级移动命令");
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 恢复图层结构
|
|||
|
|
this.restoreLayerStructure(this.beforeState.layerStructure);
|
|||
|
|
|
|||
|
|
// 恢复fabric对象状态
|
|||
|
|
this.restoreFabricObjectStates(this.beforeState.fabricObjects);
|
|||
|
|
|
|||
|
|
// 刷新画布
|
|||
|
|
if (this.canvas) {
|
|||
|
|
// 使用 requestAnimationFrame 确保DOM更新完成后再渲染
|
|||
|
|
requestAnimationFrame(() => {
|
|||
|
|
this.canvas.renderAll();
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log("✅ 跨层级移动命令撤销成功");
|
|||
|
|
return true;
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error("❌ 跨层级移动命令撤销失败:", error);
|
|||
|
|
|
|||
|
|
// 尝试基本的恢复操作
|
|||
|
|
try {
|
|||
|
|
console.log("🔄 尝试基本恢复操作");
|
|||
|
|
this.basicRestore();
|
|||
|
|
} catch (restoreError) {
|
|||
|
|
console.error("❌ 基本恢复也失败:", restoreError);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
throw error;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 基本恢复操作(当标准撤销失败时使用)
|
|||
|
|
*/
|
|||
|
|
basicRestore() {
|
|||
|
|
// 重新组织所有图层的fabric对象
|
|||
|
|
this.layers.value.forEach((layer) => {
|
|||
|
|
if (layer.fabricObject) {
|
|||
|
|
try {
|
|||
|
|
// 先从所有容器中移除
|
|||
|
|
this.removeFromAllContainers(layer.fabricObject);
|
|||
|
|
|
|||
|
|
// 根据图层的parentId重新放置
|
|||
|
|
if (layer.parentId) {
|
|||
|
|
const parentLayer = this.layers.value.find(
|
|||
|
|
(l) => l.id === layer.parentId
|
|||
|
|
);
|
|||
|
|
if (
|
|||
|
|
parentLayer &&
|
|||
|
|
parentLayer.fabricObject &&
|
|||
|
|
parentLayer.fabricObject.type === "group"
|
|||
|
|
) {
|
|||
|
|
this.safeAddToContainer(
|
|||
|
|
layer.fabricObject,
|
|||
|
|
parentLayer.fabricObject,
|
|||
|
|
`父组${layer.parentId}`
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
this.safeAddToContainer(layer.fabricObject, this.canvas, "画布");
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error(`❌ 基本恢复图层 ${layer.id} 失败:`, error);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (this.canvas) {
|
|||
|
|
this.canvas.renderAll();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 重做命令
|
|||
|
|
*/
|
|||
|
|
redo() {
|
|||
|
|
if (!this.afterState) {
|
|||
|
|
throw new Error("没有保存的后置状态,无法重做");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log("🔄 重做跨层级移动命令");
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 恢复图层结构
|
|||
|
|
this.restoreLayerStructure(this.afterState.layerStructure);
|
|||
|
|
|
|||
|
|
// 恢复fabric对象状态
|
|||
|
|
this.restoreFabricObjectStates(this.afterState.fabricObjects);
|
|||
|
|
|
|||
|
|
// 刷新画布
|
|||
|
|
if (this.canvas) {
|
|||
|
|
// 使用 requestAnimationFrame 确保DOM更新完成后再渲染
|
|||
|
|
requestAnimationFrame(() => {
|
|||
|
|
this.canvas.renderAll();
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log("✅ 跨层级移动命令重做成功");
|
|||
|
|
return true;
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error("❌ 跨层级移动命令重做失败:", error);
|
|||
|
|
|
|||
|
|
// 尝试基本的恢复操作
|
|||
|
|
try {
|
|||
|
|
console.log("🔄 尝试基本恢复操作");
|
|||
|
|
this.basicRestore();
|
|||
|
|
} catch (restoreError) {
|
|||
|
|
console.error("❌ 基本恢复也失败:", restoreError);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
throw error;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 恢复图层结构
|
|||
|
|
*/
|
|||
|
|
restoreLayerStructure(layerStructure) {
|
|||
|
|
// 保存原始图层数组的引用
|
|||
|
|
const originalLayers = [...this.layers.value];
|
|||
|
|
|
|||
|
|
// 清空当前图层
|
|||
|
|
this.layers.value.splice(0);
|
|||
|
|
|
|||
|
|
// 重建图层结构
|
|||
|
|
layerStructure.forEach((layerData) => {
|
|||
|
|
// 首先从原始图层数组中查找图层
|
|||
|
|
let layer = originalLayers.find((l) => l.id === layerData.id);
|
|||
|
|
|
|||
|
|
// 如果没找到,尝试在嵌套结构中查找
|
|||
|
|
if (!layer) {
|
|||
|
|
layer = this.findLayerInOriginalStructure(layerData.id, originalLayers);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (layer) {
|
|||
|
|
// 更新图层属性
|
|||
|
|
layer.parentId = layerData.parentId;
|
|||
|
|
layer.visible = layerData.visible;
|
|||
|
|
layer.locked = layerData.locked;
|
|||
|
|
|
|||
|
|
// 重建children数组
|
|||
|
|
if (layerData.children && layerData.children.length > 0) {
|
|||
|
|
layer.children = layerData.children
|
|||
|
|
.map((childData) => {
|
|||
|
|
// 从原始图层数组中查找子图层
|
|||
|
|
let childLayer = originalLayers.find(
|
|||
|
|
(l) => l.id === childData.id
|
|||
|
|
);
|
|||
|
|
if (!childLayer) {
|
|||
|
|
childLayer = this.findLayerInOriginalStructure(
|
|||
|
|
childData.id,
|
|||
|
|
originalLayers
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
if (childLayer) {
|
|||
|
|
// 更新子图层属性
|
|||
|
|
childLayer.parentId = childData.parentId;
|
|||
|
|
childLayer.visible = childData.visible;
|
|||
|
|
childLayer.locked = childData.locked;
|
|||
|
|
return childLayer;
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
})
|
|||
|
|
.filter(Boolean);
|
|||
|
|
} else {
|
|||
|
|
layer.children = [];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.layers.value.push(layer);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 在原始结构中查找图层
|
|||
|
|
*/
|
|||
|
|
findLayerInOriginalStructure(layerId, layers = null) {
|
|||
|
|
const layersToSearch = layers || this.layers.value;
|
|||
|
|
|
|||
|
|
const findInLayers = (layersList) => {
|
|||
|
|
for (const layer of layersList) {
|
|||
|
|
if (layer.id === layerId) return layer;
|
|||
|
|
if (layer.children) {
|
|||
|
|
const found = findInLayers(layer.children);
|
|||
|
|
if (found) return found;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return findInLayers(layersToSearch);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 恢复fabric对象状态
|
|||
|
|
*/
|
|||
|
|
restoreFabricObjectStates(fabricStates) {
|
|||
|
|
if (!this.canvas || !fabricStates) return;
|
|||
|
|
|
|||
|
|
console.log("🔧 开始恢复fabric对象状态");
|
|||
|
|
|
|||
|
|
// 重新组织fabric对象的层级关系
|
|||
|
|
this.layers.value.forEach((layer) => {
|
|||
|
|
if (layer.fabricObject && fabricStates[layer.id]) {
|
|||
|
|
const targetState = fabricStates[layer.id];
|
|||
|
|
console.log(`🔍 恢复图层 ${layer.id} 的fabric对象状态:`, targetState);
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 首先从所有容器中移除对象
|
|||
|
|
this.removeFromAllContainers(layer.fabricObject);
|
|||
|
|
|
|||
|
|
// 根据目标状态放置对象
|
|||
|
|
if (targetState.parentGroupId) {
|
|||
|
|
// 应该在特定组中
|
|||
|
|
const parentLayer = this.layers.value.find(
|
|||
|
|
(l) => l.id === targetState.parentGroupId
|
|||
|
|
);
|
|||
|
|
if (
|
|||
|
|
parentLayer &&
|
|||
|
|
parentLayer.fabricObject &&
|
|||
|
|
parentLayer.fabricObject.type === "group"
|
|||
|
|
) {
|
|||
|
|
this.safeAddToContainer(
|
|||
|
|
layer.fabricObject,
|
|||
|
|
parentLayer.fabricObject,
|
|||
|
|
`父组${targetState.parentGroupId}`
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
} else if (targetState.isInCanvas) {
|
|||
|
|
// 应该在画布中
|
|||
|
|
this.safeAddToContainer(layer.fabricObject, this.canvas, "画布");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 恢复可见性
|
|||
|
|
if (layer.fabricObject.visible !== targetState.visible) {
|
|||
|
|
layer.fabricObject.visible = targetState.visible;
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error(`❌ 恢复图层 ${layer.id} 的fabric对象时出错:`, error);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 强制重新渲染画布
|
|||
|
|
if (this.canvas) {
|
|||
|
|
this.canvas.renderAll();
|
|||
|
|
console.log("✅ 画布已重新渲染");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 安全地处理fabric对象操作
|
|||
|
|
*/
|
|||
|
|
safeFabricOperation(operation, operationName = "fabric操作") {
|
|||
|
|
try {
|
|||
|
|
return operation();
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error(`❌ ${operationName}失败:`, error);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 安全地添加fabric对象到容器
|
|||
|
|
*/
|
|||
|
|
safeAddToContainer(fabricObject, container, containerName) {
|
|||
|
|
return this.safeFabricOperation(() => {
|
|||
|
|
if (container && container.add && !container.contains(fabricObject)) {
|
|||
|
|
container.add(fabricObject);
|
|||
|
|
console.log(`✅ 成功将对象添加到${containerName}`);
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
}, `添加对象到${containerName}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 安全地从容器移除fabric对象
|
|||
|
|
*/
|
|||
|
|
safeRemoveFromContainer(fabricObject, container, containerName) {
|
|||
|
|
return this.safeFabricOperation(() => {
|
|||
|
|
if (
|
|||
|
|
container &&
|
|||
|
|
container.remove &&
|
|||
|
|
container.contains &&
|
|||
|
|
container.contains(fabricObject)
|
|||
|
|
) {
|
|||
|
|
container.remove(fabricObject);
|
|||
|
|
console.log(`✅ 成功从${containerName}移除对象`);
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
}, `从${containerName}移除对象`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 从所有容器中移除fabric对象
|
|||
|
|
*/
|
|||
|
|
removeFromAllContainers(fabricObject) {
|
|||
|
|
// 从画布中移除
|
|||
|
|
this.safeRemoveFromContainer(fabricObject, this.canvas, "画布");
|
|||
|
|
|
|||
|
|
// 从所有组中移除
|
|||
|
|
this.layers.value.forEach((layer) => {
|
|||
|
|
if (layer.fabricObject && layer.fabricObject.type === "group") {
|
|||
|
|
this.safeRemoveFromContainer(
|
|||
|
|
fabricObject,
|
|||
|
|
layer.fabricObject,
|
|||
|
|
`组${layer.id}`
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 从顶级图层移动到组图层内
|
|||
|
|
*/
|
|||
|
|
moveRootToGroup(draggedLayer) {
|
|||
|
|
console.log("📥 执行顶级图层移动到组内:", {
|
|||
|
|
layerId: draggedLayer.id,
|
|||
|
|
toParentId: this.toParentId,
|
|||
|
|
newIndex: this.newIndex,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const targetParent = this.layers.value.find(
|
|||
|
|
(layer) => layer.id === this.toParentId
|
|||
|
|
);
|
|||
|
|
if (!targetParent) {
|
|||
|
|
throw new Error(`找不到目标父图层: ${this.toParentId}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 确保父图层有children数组
|
|||
|
|
if (!targetParent.children) {
|
|||
|
|
targetParent.children = [];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 从顶级图层数组中移除
|
|||
|
|
const rootIndex = this.layers.value.findIndex(
|
|||
|
|
(layer) => layer.id === draggedLayer.id
|
|||
|
|
);
|
|||
|
|
if (rootIndex !== -1) {
|
|||
|
|
this.layers.value.splice(rootIndex, 1);
|
|||
|
|
console.log(`🗑️ 从顶级图层数组中移除图层 ${draggedLayer.id}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 更新图层关系
|
|||
|
|
draggedLayer.parentId = this.toParentId;
|
|||
|
|
targetParent.children.splice(this.newIndex, 0, draggedLayer);
|
|||
|
|
console.log(
|
|||
|
|
`📂 将图层 ${draggedLayer.id} 添加到父图层 ${this.toParentId} 的children中`
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 处理fabric对象的层级关系
|
|||
|
|
if (draggedLayer.fabricObject && targetParent.fabricObject) {
|
|||
|
|
console.log(`🎨 处理fabric对象层级关系`);
|
|||
|
|
|
|||
|
|
// 从画布中移除
|
|||
|
|
this.safeRemoveFromContainer(
|
|||
|
|
draggedLayer.fabricObject,
|
|||
|
|
this.canvas,
|
|||
|
|
"画布"
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 添加到父组
|
|||
|
|
this.safeAddToContainer(
|
|||
|
|
draggedLayer.fabricObject,
|
|||
|
|
targetParent.fabricObject,
|
|||
|
|
`父组${this.toParentId}`
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log("✅ 顶级图层移动到组内完成");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 从组图层内移动到顶级图层
|
|||
|
|
*/
|
|||
|
|
moveGroupToRoot(draggedLayer) {
|
|||
|
|
console.log("📤 执行组内图层移动到顶级:", {
|
|||
|
|
layerId: draggedLayer.id,
|
|||
|
|
fromParentId: this.fromParentId,
|
|||
|
|
newIndex: this.newIndex,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const sourceParent = this.layers.value.find(
|
|||
|
|
(layer) => layer.id === this.fromParentId
|
|||
|
|
);
|
|||
|
|
if (!sourceParent || !sourceParent.children) {
|
|||
|
|
throw new Error(`找不到源父图层或其children数组: ${this.fromParentId}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 从源父图层的children中移除
|
|||
|
|
const childIndex = sourceParent.children.findIndex(
|
|||
|
|
(child) => child.id === draggedLayer.id
|
|||
|
|
);
|
|||
|
|
if (childIndex !== -1) {
|
|||
|
|
sourceParent.children.splice(childIndex, 1);
|
|||
|
|
console.log(
|
|||
|
|
`🗑️ 从父图层 ${this.fromParentId} 的children中移除图层 ${draggedLayer.id}`
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 处理fabric对象的层级关系
|
|||
|
|
if (draggedLayer.fabricObject && sourceParent.fabricObject) {
|
|||
|
|
console.log(`🎨 处理fabric对象层级关系`);
|
|||
|
|
|
|||
|
|
// 从父组中移除
|
|||
|
|
this.safeRemoveFromContainer(
|
|||
|
|
draggedLayer.fabricObject,
|
|||
|
|
sourceParent.fabricObject,
|
|||
|
|
`父组${this.fromParentId}`
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 添加到画布
|
|||
|
|
this.safeAddToContainer(draggedLayer.fabricObject, this.canvas, "画布");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清除图层的parentId
|
|||
|
|
delete draggedLayer.parentId;
|
|||
|
|
console.log(`🔗 清除图层 ${draggedLayer.id} 的parentId`);
|
|||
|
|
|
|||
|
|
// 计算在顶级图层中的插入位置
|
|||
|
|
const targetIndex = Math.min(this.newIndex, this.layers.value.length);
|
|||
|
|
this.layers.value.splice(targetIndex, 0, draggedLayer);
|
|||
|
|
console.log(
|
|||
|
|
`📂 将图层 ${draggedLayer.id} 添加到顶级图层数组位置 ${targetIndex}`
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
console.log("✅ 组内图层移动到顶级完成");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 在不同组之间移动
|
|||
|
|
*/
|
|||
|
|
moveGroupToGroup(draggedLayer) {
|
|||
|
|
console.log("🔄 执行在不同组间移动:", {
|
|||
|
|
layerId: draggedLayer.id,
|
|||
|
|
fromParentId: this.fromParentId,
|
|||
|
|
toParentId: this.toParentId,
|
|||
|
|
newIndex: this.newIndex,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const sourceParent = this.layers.value.find(
|
|||
|
|
(layer) => layer.id === this.fromParentId
|
|||
|
|
);
|
|||
|
|
const targetParent = this.layers.value.find(
|
|||
|
|
(layer) => layer.id === this.toParentId
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
if (!sourceParent || !targetParent) {
|
|||
|
|
throw new Error("找不到源父图层或目标父图层");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 从源父图层中移除
|
|||
|
|
const childIndex = sourceParent.children.findIndex(
|
|||
|
|
(child) => child.id === draggedLayer.id
|
|||
|
|
);
|
|||
|
|
if (childIndex !== -1) {
|
|||
|
|
sourceParent.children.splice(childIndex, 1);
|
|||
|
|
console.log(
|
|||
|
|
`🗑️ 从源父图层 ${this.fromParentId} 中移除图层 ${draggedLayer.id}`
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 从源父组的fabricObject中移除
|
|||
|
|
if (draggedLayer.fabricObject && sourceParent.fabricObject) {
|
|||
|
|
this.safeRemoveFromContainer(
|
|||
|
|
draggedLayer.fabricObject,
|
|||
|
|
sourceParent.fabricObject,
|
|||
|
|
`源父组${this.fromParentId}`
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 更新图层的parentId
|
|||
|
|
draggedLayer.parentId = this.toParentId;
|
|||
|
|
console.log(
|
|||
|
|
`🔗 更新图层 ${draggedLayer.id} 的parentId为 ${this.toParentId}`
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 确保目标父图层有children数组
|
|||
|
|
if (!targetParent.children) {
|
|||
|
|
targetParent.children = [];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 将图层添加到目标组
|
|||
|
|
targetParent.children.splice(this.newIndex, 0, draggedLayer);
|
|||
|
|
console.log(
|
|||
|
|
`📂 将图层 ${draggedLayer.id} 添加到目标父图层 ${this.toParentId} 的位置 ${this.newIndex}`
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 将图层的fabricObject添加到目标父组中
|
|||
|
|
if (draggedLayer.fabricObject && targetParent.fabricObject) {
|
|||
|
|
this.safeAddToContainer(
|
|||
|
|
draggedLayer.fabricObject,
|
|||
|
|
targetParent.fabricObject,
|
|||
|
|
`目标父组${this.toParentId}`
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log("✅ 不同组间移动完成");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 创建跨层级移动命令的工厂函数
|
|||
|
|
*/
|
|||
|
|
export function createCrossLevelMoveCommand(options) {
|
|||
|
|
return new CrossLevelMoveCommand(options);
|
|||
|
|
}
|