Files
aida_front/src/component/Canvas/CanvasEditor/commands/FillLayerBackgroundCommand.js

227 lines
8.2 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.
import { Command } from "./Command";
import { findLayerRecursively } from "../utils/layerHelper";
import { fabric } from "fabric-with-all";
import {
findObjectById,
generateId,
insertObjectAtZIndex,
removeCanvasObjectByObject,
} from "../utils/helper";
import { restoreFabricObject } from "../utils/objectHelper";
/**
* 填充图层背景命令
*/
export class FillLayerBackgroundCommand extends Command {
constructor(options) {
super({ name: "填充图层背景", saveState: true });
this.canvas = options.canvas;
this.layers = options.layers;
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;
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
this.layer = layer;
this.group = null;
this.isGroupLayer = layer.isGroup || !!layer.children?.length || false; // 是否为组图层
this.originalfabricObjects = this._collectOriginalObjects(); // 记录所有的原始对象
// 计算所有对象的边界
this.originalInfo = this._getCurrentObjectsBoundingRect();
}
async execute() {
const layer = this.layer;
// 只允许填充背景层或普通图层
// if (!layer.isBackground && !layer.isFixed && !layer.fabricObjects?.length) return false;
// 记录原填充色
this.oldFill = layer.fill ?? null;
this.oldFillColor = layer.oldFillColor ?? null;
// 更新fabric对象填充
// 1.如果图层有遮罩则用遮罩 2.如果没有遮罩则汇总当前fabricObjects下的所有对象的边界
let clippingMaskFabricObject = null;
if (layer.clippingMask) {
// 反序列化 clippingMask
clippingMaskFabricObject = await restoreFabricObject(layer.clippingMask, this.canvas);
clippingMaskFabricObject.clipPath = null;
clippingMaskFabricObject.set({
// 设置绝对定位
// ...getOriginObjectInfo(layer.clippingMask), // 恢复原定位
absolutePositioned: true,
});
this.newFill = new fabric.Rect({
width: clippingMaskFabricObject.width,
height: clippingMaskFabricObject.height,
left: clippingMaskFabricObject.left || 0,
top: clippingMaskFabricObject.top || 0,
fill: this.fillColor,
layerId: this.layerId,
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) {
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;
// layer.fabricObjects = [this.newFill?.toObject?.(["id", "layerId"]) || this.newFill];
insertObjectAtZIndex(this.canvas, this.newFill, insertIndex, false); // 插入到画布的指定位置
// 将新填充对象添加到画布
} else if (layer.children && layer.children.length > 0) {
// 如果是组图层,直接添加到组中
let insertIndex =
this.canvas
.getObjects()
.findIndex(
(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); // 插入到画布的指定位置
}
this.canvas.renderAll();
// 实时更新的时候不生成缩略图
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?.();
}
return true;
}
async undo() {
// 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;
}
_collectOriginalObjects() {
if (this.layer.children && this.layer.children.length > 0) {
// 如果是组图层收集所有子图层的fabric对象
return this.layer.children
.flatMap((child) => child.fabricObjects || [])
.map((obj) => {
return findObjectById(this.canvas.value, obj.id)?.object || obj;
});
} else if (this.layer.fabricObjects && this.layer.fabricObjects.length > 0) {
// 如果是普通图层直接返回其fabric对象
return this.layer.fabricObjects.map((obj) => {
return findObjectById(this.canvas.value, obj.id)?.object || obj;
});
} else {
// 如果没有fabric对象返回空数组
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,
};
}
}