feat: 优化填充组图层背景命令,支持实时更新和撤销功能,改进填充对象的处理逻辑

This commit is contained in:
bighuixiang
2025-07-16 11:35:52 +08:00
parent e31a619bd6
commit 5f29e488ed
9 changed files with 372 additions and 201 deletions

View File

@@ -20,6 +20,7 @@ export class FillLayerBackgroundCommand extends Command {
this.canvasManager = options.canvasManager;
this.layerId = options.layerId;
this.fillColor = options.fillColor;
this.isRetimeUpdate = options.isRetimeUpdate; // 是否实时更新
this.oldFill = null;
this.oldFillColor = null;
this.newFill = null;
@@ -33,6 +34,8 @@ export class FillLayerBackgroundCommand extends Command {
this.isGroupLayer = layer.isGroup || !!layer.children?.length || false; // 是否为组图层
this.originalfabricObjects = this._collectOriginalObjects(); // 记录所有的原始对象
// 计算所有对象的边界
this.originalInfo = this._getCurrentObjectsBoundingRect();
}
async execute() {
@@ -45,31 +48,11 @@ export class FillLayerBackgroundCommand extends Command {
this.oldFillColor = layer.oldFillColor ?? null;
// 更新fabric对象填充
// 判断是否有遮罩层 有遮罩使用遮罩层大小 否则使用第一个大小
const { object } = findObjectById(this.canvas, layer.fabricObjects?.[0]?.id);
if (object) {
const originalInfo = object?.getBoundingRect?.(true, true);
this.newFill = new fabric.Rect({
width: originalInfo.width,
height: originalInfo.height,
left: originalInfo.left || 0,
top: originalInfo.top || 0,
fill: this.fillColor,
layerId: this.layerId,
id: generateId("fill-"),
selectable: false,
evented: false,
originX: object.originX || "center",
originY: object.originY || "center",
scaleX: object.scaleX || 1,
scaleY: object.scaleY || 1,
});
}
// 1.如果图层有遮罩则用遮罩 2.如果没有遮罩则汇总当前fabricObjects下的所有对象的边界
let clippingMaskFabricObject = null;
if (layer.clippingMask) {
// 反序列化 clippingMask
const clippingMaskFabricObject = await restoreFabricObject(layer.clippingMask, this.canvas);
clippingMaskFabricObject = await restoreFabricObject(layer.clippingMask, this.canvas);
clippingMaskFabricObject.clipPath = null;
clippingMaskFabricObject.set({
@@ -85,40 +68,51 @@ export class FillLayerBackgroundCommand extends Command {
top: clippingMaskFabricObject.top || 0,
fill: this.fillColor,
layerId: this.layerId,
id: generateId("fill-"),
id: this.oldFill?.id || generateId("fill-"),
selectable: false,
evented: false,
originX: clippingMaskFabricObject.originX || "center",
originY: clippingMaskFabricObject.originY || "center",
scaleX: clippingMaskFabricObject.scaleX || 1,
scaleY: clippingMaskFabricObject.scaleY || 1,
type: "fill",
});
this.newFill.clipPath = clippingMaskFabricObject; // 设置填充的遮罩
this.newFill.dirty = true; // 标记为脏,以便重新渲染
this.newFill.setCoords();
} else {
const originalInfo = this.originalInfo;
if (originalInfo) {
this.newFill = new fabric.Rect({
width: originalInfo.width,
height: originalInfo.height,
left: originalInfo.left + originalInfo.width / 2 || 0,
top: originalInfo.top + originalInfo.height / 2 || 0,
fill: this.fillColor,
layerId: this.layerId,
id: this.oldFill?.id || generateId("fill-"),
selectable: false,
evented: false,
originX: "center",
originY: "center",
type: "fill",
});
}
}
// 判断fabricObjects是否是组是组则添加填充到最前面否则创建组
if (layer.fabricObjects && layer.fabricObjects.length > 0) {
// 如果是组,直接添加到组中
// 否则创建一个新的组 插入到原本的图层对象前面
// const layerObjects = this.canvas
// .getObjects()
// .reverse()
// .filter((obj) => obj.layerId === this.layerId);
let insertIndex =
this.canvas.getObjects()?.findIndex((obj) => obj.id === layer.fabricObjects?.[0]?.id) || 0;
if (this.oldFill) {
// 如果有旧填充,先获取旧的索引再移除旧填充
insertIndex =
this.canvas.getObjects()?.findIndex((obj) => obj.id === this.oldFill?.id) || 0;
removeCanvasObjectByObject(this.canvas, this.oldFill);
}
insertIndex = insertIndex == -1 ? 0 : insertIndex;
// this.group = new fabric.Group([this.newFill, ...layerObjects]);
// this.group.set({
// id: layerObjects[0]?.id || generateId("group-"),
// layerId: layerObjects[0]?.layerId,
// });
// this.group.setCoords();
layer.fabricObjects = [this.newFill?.toObject?.(["id", "layerId"]) || this.newFill];
// removeCanvasObjectByObject(this.canvas, layer.fabricObjects[0]);
// layer.fabricObjects = [this.newFill?.toObject?.(["id", "layerId"]) || this.newFill];
insertObjectAtZIndex(this.canvas, this.newFill, insertIndex, false); // 插入到画布的指定位置
// 将新填充对象添加到画布
} else if (layer.children && layer.children.length > 0) {
@@ -130,6 +124,13 @@ export class FillLayerBackgroundCommand extends Command {
(obj) =>
obj.id === this.originalfabricObjects[this.originalfabricObjects.length - 1]?.id
) || 0;
if (this.oldFill) {
// 如果有旧填充,先获取旧的索引再移除旧填充
insertIndex =
this.canvas.getObjects()?.findIndex((obj) => obj.id === this.oldFill?.id) || 0;
removeCanvasObjectByObject(this.canvas, this.oldFill);
}
insertIndex = insertIndex == -1 ? 0 : insertIndex;
insertObjectAtZIndex(this.canvas, this.newFill, insertIndex, false); // 插入到画布的指定位置
@@ -137,25 +138,43 @@ export class FillLayerBackgroundCommand extends Command {
this.canvas.renderAll();
layer.fill = this.newFill.toObject(["id", "layerId"]);
layer.fillColor = this.fillColor;
// 实时更新的时候不生成缩略图
if (!this.isRetimeUpdate) {
layer.fill = this.newFill.toObject(["id", "layerId"]);
layer.fillColor = this.fillColor;
this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layer.id);
// 重新排序
// 使用LayerSort工具重新排列画布对象如果可用
await this?.canvasManager?.layerManager?.layerSort?.rearrangeObjects?.();
this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layer.id);
// 重新排序
// 使用LayerSort工具重新排列画布对象如果可用
// await this?.canvasManager?.layerManager?.layerSort?.rearrangeObjects?.();
}
return true;
}
async undo() {
this.layer.fillColor = this.oldFillColor;
this.layer.fill = this.oldFill;
this.group.removeWithUpdate(this.newFill);
this.canvas.remove(this.newFill);
// this.group.removeWithUpdate(this.newFill);
// this.canvas.remove(this.newFill);
if (this.oldFill) {
// 如果有旧填充,恢复旧填充
const { object } = findObjectById(this.canvas, this.oldFill.id);
if (object) {
this.newFill.set({
fill: this.oldFill.fill,
left: this.oldFill.left,
top: this.oldFill.top,
width: this.oldFill.width,
height: this.oldFill.height,
});
this.newFill.setCoords();
}
} else {
// 如果没有旧填充,移除新填充
removeCanvasObjectByObject(this.canvas, this.layer.fill);
}
this.canvas.renderAll();
this.layer.fillColor = this.oldFillColor;
this.layer.fill = this.oldFill;
this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layer.id);
return true;
}
@@ -178,4 +197,30 @@ export class FillLayerBackgroundCommand extends Command {
return [];
}
}
// 获取当前所有对象的边界信息
_getCurrentObjectsBoundingRect() {
// this.originalfabricObjects = this._collectOriginalObjects();
let minLeft = Infinity,
minTop = Infinity,
maxRight = -Infinity,
maxBottom = -Infinity;
console.log("计算当前所有对象的边界信息:===>", this.originalfabricObjects.length);
this.originalfabricObjects?.forEach((obj) => {
const { object } = findObjectById(this.canvas, obj.id) || {};
if (object) {
const rect = object.getBoundingRect({ absolute: true, includeStroke: false });
minLeft = Math.min(minLeft, rect.left);
minTop = Math.min(minTop, rect.top);
maxRight = Math.max(maxRight, rect.left + rect.width);
maxBottom = Math.max(maxBottom, rect.top + rect.height);
}
});
if (minLeft === Infinity || minTop === Infinity) return null;
return {
left: minLeft,
top: minTop,
width: maxRight - minLeft,
height: maxBottom - minTop,
};
}
}