feat: 添加对图层操作的支持,优化图层粘贴和变换命令,增强组图层遮罩位置更新逻辑
This commit is contained in:
@@ -971,7 +971,6 @@ export class LayerManager {
|
||||
// allObjects.push(object);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (allObjects.length) {
|
||||
// 切换到选择模式
|
||||
this?.toolManager?.setTool(OperationType.SELECT);
|
||||
@@ -1525,13 +1524,32 @@ export class LayerManager {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前图层序列化对象
|
||||
* @param {Object} layer 图层对象
|
||||
* @returns {Array} 图层中的序列化对象列表
|
||||
*/
|
||||
getCurrLayerSerializedObjects(layer) {
|
||||
if (!layer || layer?.fabricObjects?.length === 0) {
|
||||
return [];
|
||||
}
|
||||
// 序列化图层中的对象
|
||||
return layer.fabricObjects
|
||||
.map((obj) => {
|
||||
const { object } = findObjectById(this.canvas, obj.id);
|
||||
if (object) return object.toObject(["id", "layerId", "layerName"]);
|
||||
return false;
|
||||
})
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制图层数据到剪贴板
|
||||
* @param {string} layerId 要复制的图层ID
|
||||
* @returns {Object} 复制的图层数据
|
||||
*/
|
||||
copyLayer(layerId) {
|
||||
const layer = this.layers.value.find((l) => l.id === layerId);
|
||||
const { layer } = findLayerRecursively(this.layers.value, layerId);
|
||||
if (!layer) {
|
||||
console.error(`图层 ${layerId} 不存在`);
|
||||
return null;
|
||||
@@ -1548,11 +1566,18 @@ export class LayerManager {
|
||||
|
||||
// 序列化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);
|
||||
layerCopy.serializedObjects = this.getCurrLayerSerializedObjects(layer);
|
||||
}
|
||||
|
||||
// 处理子图层
|
||||
if (layer?.children?.length) {
|
||||
layerCopy.children = layer.children.map((child) => {
|
||||
const childCopy = JSON.parse(JSON.stringify(child));
|
||||
if (child.fabricObjects && child.fabricObjects.length > 0) {
|
||||
childCopy.serializedObjects = this.getCurrLayerSerializedObjects(child);
|
||||
}
|
||||
return childCopy;
|
||||
});
|
||||
}
|
||||
|
||||
// 存储到剪贴板
|
||||
@@ -1653,7 +1678,7 @@ export class LayerManager {
|
||||
* 粘贴图层
|
||||
* @returns {string} 新创建的图层ID
|
||||
*/
|
||||
pasteLayer() {
|
||||
async pasteLayer() {
|
||||
if (!this.clipboardData) {
|
||||
console.error("剪贴板中没有图层数据");
|
||||
return null;
|
||||
@@ -1668,8 +1693,20 @@ export class LayerManager {
|
||||
layerManager: this, // 传递LayerManager实例
|
||||
});
|
||||
|
||||
// 设置命令为可撤销
|
||||
command.undoable = true;
|
||||
if (this.commandManager) {
|
||||
// 使用命令管理器执行命令
|
||||
const result = await this.commandManager.execute(command);
|
||||
this.clipboardData = null; // 清空剪贴板数据 复制一次
|
||||
// 执行命令
|
||||
return result;
|
||||
}
|
||||
|
||||
const result = await command.execute();
|
||||
this.clipboardData = null; // 清空剪贴板数据 复制一次就清空,避免重复粘贴 出现 错误后也清空 总之就是清空 不用给自己找麻烦
|
||||
// 执行命令
|
||||
return command.execute();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2893,10 +2930,11 @@ export class LayerManager {
|
||||
let lastUpdateTime = 0;
|
||||
let hasMoved = false; // 追踪是否实际发生了移动
|
||||
const UPDATE_THRESHOLD = 32; // 约60fps
|
||||
|
||||
// 移动开始事件处理
|
||||
const handleMovingStart = (e) => {
|
||||
if (e.target === activeSelection) {
|
||||
// 判断活动对象是否只有一个
|
||||
const isSginleObject = e.target === activeSelection?._objects?.[0];
|
||||
if (e.target === activeSelection || isSginleObject) {
|
||||
hasMoved = false; // 重置移动状态
|
||||
console.log("🎯 开始移动组选择对象");
|
||||
// 记录遮罩初始位置
|
||||
@@ -2905,8 +2943,8 @@ export class LayerManager {
|
||||
`${layer.clippingMask.left || 0}, ${layer.clippingMask.top || 0}`
|
||||
);
|
||||
// 记录初始位置
|
||||
initialLeft = activeSelection.left;
|
||||
initialTop = activeSelection.top;
|
||||
initialLeft = isSginleObject ? e.target.left : activeSelection.left;
|
||||
initialTop = isSginleObject ? e.target.top : activeSelection.top;
|
||||
|
||||
maskInitialLeft = layer.clippingMask.left || 0;
|
||||
maskInitialTop = layer.clippingMask.top || 0;
|
||||
@@ -2914,8 +2952,10 @@ export class LayerManager {
|
||||
};
|
||||
// 移动中事件处理函数(带节流)
|
||||
const handleMoving = (e) => {
|
||||
// 判断活动对象是否只有一个
|
||||
const isSginleObject = e.target === activeSelection?._objects?.[0];
|
||||
const target = e.target;
|
||||
if (target === activeSelection) {
|
||||
if (target === activeSelection || isSginleObject) {
|
||||
hasMoved = true; // 标记发生了移动
|
||||
const now = Date.now();
|
||||
|
||||
@@ -2949,6 +2989,8 @@ export class LayerManager {
|
||||
maskInitialLeft: maskInitialLeft,
|
||||
maskInitialTop: maskInitialTop,
|
||||
isExecuteRealtime: true,
|
||||
isSginleObject,
|
||||
target,
|
||||
});
|
||||
|
||||
// 执行实时更新
|
||||
@@ -2963,7 +3005,15 @@ export class LayerManager {
|
||||
// 修改事件处理函数 - 使用 object:modified 替代 object:moved
|
||||
const handleModified = (e) => {
|
||||
const target = e.target;
|
||||
if (target === activeSelection && hasMoved) {
|
||||
// 判断活动对象是否只有一个
|
||||
const isSginleObject = e.target === activeSelection?._objects?.[0];
|
||||
if (isSginleObject) {
|
||||
// 如果是单个对象,不处理
|
||||
console.log("🚫 单个对象不处理移动完成");
|
||||
hasMoved = false; // 重置移动状态
|
||||
return;
|
||||
}
|
||||
if ((target === activeSelection || isSginleObject) && hasMoved) {
|
||||
console.log("✅ 组选择对象移动完成");
|
||||
|
||||
// 计算最终移动距离
|
||||
@@ -2982,8 +3032,12 @@ export class LayerManager {
|
||||
maskInitialLeft: maskInitialLeft,
|
||||
maskInitialTop: maskInitialTop,
|
||||
activeSelection,
|
||||
isSginleObject,
|
||||
target,
|
||||
});
|
||||
|
||||
command.undoable = isSginleObject ? false : true; // 设置为可撤销的命令
|
||||
|
||||
// 执行可撤销的命令
|
||||
if (this.commandManager) {
|
||||
this.commandManager.execute(command);
|
||||
|
||||
Reference in New Issue
Block a user