247 lines
8.4 KiB
JavaScript
247 lines
8.4 KiB
JavaScript
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,
|
||
});
|
||
|
||
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",
|
||
});
|
||
}
|
||
}
|
||
|
||
// 判断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,
|
||
};
|
||
}
|
||
}
|