画布增加的新功能
This commit is contained in:
@@ -69,7 +69,7 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
||||
layer.clippingMask,
|
||||
this.canvas
|
||||
);
|
||||
clippingMaskFabricObject.clipPath = null;
|
||||
// clippingMaskFabricObject.clipPath = null;
|
||||
clippingMaskFabricObject.set({ absolutePositioned: true });
|
||||
this.newFill = new fabric.Rect({
|
||||
width: clippingMaskFabricObject.width,
|
||||
@@ -117,7 +117,7 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
||||
this.parent.clippingMask,
|
||||
this.canvas
|
||||
);
|
||||
clippingMaskFabricObject.clipPath = null;
|
||||
// clippingMaskFabricObject.clipPath = null;
|
||||
clippingMaskFabricObject.set({ absolutePositioned: true });
|
||||
this.newFill = new fabric.Rect({
|
||||
width: clippingMaskFabricObject.width,
|
||||
@@ -222,7 +222,7 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
||||
this.parent?.clippingMask,
|
||||
this.canvas
|
||||
);
|
||||
clipPath.clipPath = null;
|
||||
// clipPath.clipPath = null;
|
||||
clipPath.set({ absolutePositioned: true });
|
||||
this.group.clipPath = clipPath;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ export class FillLayerBackgroundCommand extends Command {
|
||||
layer.clippingMask,
|
||||
this.canvas
|
||||
);
|
||||
clippingMaskFabricObject.clipPath = null;
|
||||
// clippingMaskFabricObject.clipPath = null;
|
||||
|
||||
clippingMaskFabricObject.set({
|
||||
// 设置绝对定位
|
||||
|
||||
301
src/component/Canvas/CanvasEditor/commands/FillRepeatCommand.js
Normal file
301
src/component/Canvas/CanvasEditor/commands/FillRepeatCommand.js
Normal file
@@ -0,0 +1,301 @@
|
||||
import { Command } from "./Command";
|
||||
import { findLayerRecursively } from "../utils/layerHelper";
|
||||
import { fabric } from "fabric-with-all";
|
||||
import {
|
||||
findObjectById,
|
||||
generateId,
|
||||
insertObjectAtZIndex,
|
||||
removeCanvasObjectByObject,
|
||||
createPatternTransform,
|
||||
} from "../utils/helper";
|
||||
import { restoreFabricObject } from "../utils/objectHelper";
|
||||
|
||||
const scale = 0.3;// 默认缩放比例
|
||||
|
||||
export const FillSourceToBase64 = (source) => {
|
||||
if (source?.toDataURL) {
|
||||
return source.toDataURL?.();
|
||||
} else if (source?.src) {
|
||||
return source.src;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充图案平铺命令
|
||||
* 填充重复属性:repeat | repeat-x | repeat-y | no-repeat
|
||||
* 默认缩放比例:0.3
|
||||
* 默认偏移量:50%
|
||||
*/
|
||||
export class FillRepeatCommand extends Command {
|
||||
constructor(options) {
|
||||
super({ name: "填充图案平铺", saveState: true });
|
||||
this.canvas = options.canvas;
|
||||
this.layers = options.layers;
|
||||
this.canvasManager = options.canvasManager;
|
||||
this.layerManager = options.layerManager;
|
||||
this.layerId = options.layerId;
|
||||
this.fillRepeat = options.fillRepeat;
|
||||
this.oldObjects = null;
|
||||
this.oldLocked = null;
|
||||
this.oldIsDisableUnlock = null;
|
||||
}
|
||||
|
||||
async execute() {
|
||||
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
|
||||
console.warn("图层不存在或没有 fabric 对象");
|
||||
return false;
|
||||
}
|
||||
const { object } = findObjectById(this.canvas, layer?.fabricObjects?.[0]?.id);
|
||||
if (!object || (object.type !== "rect" && object.type !== "image")) {
|
||||
console.warn("当前对象不能平铺", object.type);
|
||||
return false;
|
||||
}
|
||||
this.oldObjects = object;
|
||||
const img = await new Promise((resolve, reject) => {
|
||||
if (object.type === "rect") {
|
||||
let source = object.fill.source;
|
||||
resolve(source);
|
||||
} else if (object.type === "image") {
|
||||
// resolve(object.getElement());
|
||||
// fabric.Image.fromURL(
|
||||
// object.src,
|
||||
// v => resolve(v),
|
||||
// { crossOrigin: "anonymous" }
|
||||
// );
|
||||
const imgElement = object.getElement();
|
||||
// 创建透明 Canvas
|
||||
const tcanvas = document.createElement('canvas');
|
||||
tcanvas.width = imgElement.width;
|
||||
tcanvas.height = imgElement.height;
|
||||
const ctx = tcanvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, tcanvas.width, tcanvas.height);
|
||||
ctx.drawImage(imgElement, 0, 0);
|
||||
resolve(tcanvas);
|
||||
}
|
||||
});
|
||||
const fill_ = {
|
||||
source: FillSourceToBase64(img),
|
||||
gapX: 0,
|
||||
gapY: 0,
|
||||
};
|
||||
const bgObject = this.canvasManager.getBackgroundLayerObject();
|
||||
const pattern = new fabric.Pattern({
|
||||
source: img,
|
||||
repeat: this.fillRepeat,
|
||||
patternTransform: object.fill?.hasOwnProperty("patternTransform") ? object.fill.patternTransform : createPatternTransform(scale, 0),
|
||||
offsetX: object.fill?.hasOwnProperty("offsetX") ? object.fill.offsetX : bgObject.width / 2, // 水平偏移
|
||||
offsetY: object.fill?.hasOwnProperty("offsetY") ? object.fill.offsetY : bgObject.height / 2, // 垂直偏移
|
||||
});
|
||||
const rect = new fabric.Rect({
|
||||
id: object.id,
|
||||
layerId: object.layerId,
|
||||
layerName: object.layerName,
|
||||
fill_,
|
||||
});
|
||||
layer.fabricObjects = [rect.toObject(["id", "layerId", "layerName"])];
|
||||
this.oldLocked = layer.locked;
|
||||
// this.oldIsDisableUnlock = layer.isDisableUnlock;
|
||||
// layer.isDisableUnlock = true;
|
||||
if (this.oldObjects.type === "rect") {
|
||||
rect.set({
|
||||
width: object.width,
|
||||
height: object.height,
|
||||
top: object.top,
|
||||
left: object.left,
|
||||
originX: object.originX,
|
||||
originY: object.originY,
|
||||
angle: object.angle,
|
||||
scaleX: object.scaleX,
|
||||
scaleY: object.scaleY,
|
||||
flipX: object.flipX,
|
||||
flipY: object.flipY,
|
||||
});
|
||||
} else {
|
||||
rect.set({
|
||||
width: bgObject.width,
|
||||
height: bgObject.height,
|
||||
top: bgObject.top,
|
||||
left: bgObject.left,
|
||||
originX: bgObject.originX,
|
||||
originY: bgObject.originY,
|
||||
});
|
||||
layer.locked = true;
|
||||
}
|
||||
rect.set("fill", pattern);
|
||||
this.canvas.add(rect);
|
||||
this.canvas.remove(object);
|
||||
await this.layerManager?.updateLayersObjectsInteractivity();
|
||||
await this.layerManager?.sortLayersWithTool?.();
|
||||
await this.canvasManager.thumbnailManager?.generateLayerThumbnail(
|
||||
this.layerId
|
||||
);
|
||||
await this.layerManager.selectLayerObjects(this.layerId);
|
||||
return true;
|
||||
}
|
||||
|
||||
async undo() {
|
||||
if (!this.oldObjects) {
|
||||
console.warn("没有旧对象可恢复");
|
||||
return false;
|
||||
}
|
||||
const { layer } = findLayerRecursively(this.layers.value, this.oldObjects.layerId);
|
||||
if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
|
||||
console.warn("图层不存在或没有 fabric 对象");
|
||||
return false;
|
||||
}
|
||||
const { object } = findObjectById(this.canvas, layer?.fabricObjects?.[0]?.id);
|
||||
this.canvas.remove(object);
|
||||
this.canvas.add(this.oldObjects);
|
||||
layer.fabricObjects = [this.oldObjects.toObject(["id", "layerId", "layerName"])];
|
||||
layer.locked = this.oldLocked;
|
||||
// layer.isDisableUnlock = this.oldIsDisableUnlock;
|
||||
await this.layerManager?.updateLayersObjectsInteractivity();
|
||||
await this.layerManager?.sortLayersWithTool?.();
|
||||
this.canvas.renderAll();
|
||||
this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layerId);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 填充图案更改参数
|
||||
*/
|
||||
export class FillRepeatChangeCommand extends Command {
|
||||
constructor(options) {
|
||||
super({ name: "填充图案更改参数", saveState: true });
|
||||
this.canvas = options.canvas;
|
||||
this.layers = options.layers;
|
||||
this.canvasManager = options.canvasManager;
|
||||
this.layerManager = options.layerManager;
|
||||
this.layerId = options.layerId;
|
||||
this.newPattern = options.newPattern;
|
||||
this.oldPattern = null;
|
||||
}
|
||||
|
||||
async execute() {
|
||||
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
|
||||
console.warn("图层不存在或没有 fabric 对象");
|
||||
return false;
|
||||
}
|
||||
const { object } = findObjectById(this.canvas, layer?.fabricObjects?.[0]?.id);
|
||||
if (!object || object.type !== "rect") {
|
||||
console.warn("当前对象不是矩形", object);
|
||||
return false;
|
||||
}
|
||||
this.oldPattern = object.oldPattern || object.get("fill");
|
||||
delete object.oldPattern;
|
||||
const oldPattern = { ...this.oldPattern };
|
||||
delete oldPattern.id;
|
||||
const pattern = new fabric.Pattern({
|
||||
...oldPattern,
|
||||
...this.newPattern,
|
||||
});
|
||||
object.set("fill", pattern);
|
||||
this.canvas.renderAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
async undo() {
|
||||
if (!this.oldPattern) {
|
||||
console.warn("没有旧图案可恢复");
|
||||
return false;
|
||||
}
|
||||
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
|
||||
console.warn("图层不存在或没有 fabric 对象");
|
||||
return false;
|
||||
}
|
||||
const { object } = findObjectById(this.canvas, layer?.fabricObjects?.[0]?.id);
|
||||
if (!object || object.type !== "rect") {
|
||||
console.warn("当前对象不是矩形", object);
|
||||
return false;
|
||||
}
|
||||
const pattern = new fabric.Pattern({
|
||||
...this.oldPattern
|
||||
});
|
||||
object.set("fill", pattern);
|
||||
this.canvas.renderAll();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充图案更改间隙
|
||||
*/
|
||||
export class FillRepeatGapChangeCommand extends Command {
|
||||
constructor(options) {
|
||||
super({ name: "填充图案更改间隙", saveState: true });
|
||||
this.canvas = options.canvas;
|
||||
this.layers = options.layers;
|
||||
this.canvasManager = options.canvasManager;
|
||||
this.layerManager = options.layerManager;
|
||||
this.layerId = options.layerId;
|
||||
this.newGapX = options.newGapX;
|
||||
this.newGapY = options.newGapY;
|
||||
this.record = !!options.record;
|
||||
this.oldGapX = null;
|
||||
this.oldGapY = null;
|
||||
}
|
||||
|
||||
async execute(isUndo = false) {
|
||||
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
|
||||
console.warn("图层不存在或没有 fabric 对象");
|
||||
return false;
|
||||
}
|
||||
const { object } = findObjectById(this.canvas, layer?.fabricObjects?.[0]?.id);
|
||||
if (!object || object.type !== "rect") {
|
||||
console.warn("当前对象不是矩形", object);
|
||||
return false;
|
||||
}
|
||||
if (!object.fill_) {
|
||||
object.fill_ = {
|
||||
source: FillSourceToBase64(object.fill.source),
|
||||
gapX: 0,
|
||||
gapY: 0,
|
||||
}
|
||||
}
|
||||
if (isUndo) {
|
||||
object.fill_.gapX = this.oldGapX;
|
||||
object.fill_.gapY = this.oldGapY;
|
||||
} else {
|
||||
if (!object.oldFill_ && this.record) {
|
||||
object.oldFill_ = { ...object.fill_ };
|
||||
}
|
||||
this.oldGapX = object.fill_.gapX;
|
||||
this.oldGapY = object.fill_.gapY;
|
||||
object.fill_.gapX = this.newGapX;
|
||||
object.fill_.gapY = this.newGapY;
|
||||
}
|
||||
const image = new Image();
|
||||
image.src = object.fill_.source;
|
||||
await image.decode();
|
||||
// 创建透明 Canvas
|
||||
const tcanvas = document.createElement('canvas');
|
||||
tcanvas.width = image.width + object.fill_.gapX;
|
||||
tcanvas.height = image.height + object.fill_.gapY;
|
||||
const ctx = tcanvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, tcanvas.width, tcanvas.height);
|
||||
ctx.drawImage(image, 0, 0);
|
||||
|
||||
const fill = object.get("fill");
|
||||
fill.source = tcanvas;
|
||||
object.set("fill", new fabric.Pattern(fill));
|
||||
this.canvas.renderAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
async undo() {
|
||||
if (this.oldGapX === null || this.oldGapY === null) {
|
||||
console.warn("没有旧间隙可恢复");
|
||||
return false;
|
||||
}
|
||||
await this.execute(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import { AddObjectToLayerCommand } from "./ObjectLayerCommands";
|
||||
import { ToolCommand } from "./ToolCommands";
|
||||
import {
|
||||
findObjectById,
|
||||
findObjectByLayerId,
|
||||
generateId,
|
||||
getObjectZIndex,
|
||||
insertObjectAtZIndex,
|
||||
@@ -19,7 +20,7 @@ import {
|
||||
} from "../utils/helper";
|
||||
import { fabric } from "fabric-with-all";
|
||||
import { restoreFabricObject } from "../utils/objectHelper";
|
||||
|
||||
import EventManager from "../utils/event.js";
|
||||
/**
|
||||
* 添加图层命令
|
||||
*/
|
||||
@@ -36,7 +37,7 @@ export class AddLayerCommand extends Command {
|
||||
|
||||
this.insertIndex = options.insertIndex;
|
||||
this.oldActiveLayerId = null;
|
||||
this.beforeLayers = [...this.layers.value]; // 备份原图层列表
|
||||
this.beforeLayers = JSON.stringify(this.layers.value); // 备份原图层列表
|
||||
|
||||
this.options = options.options || {};
|
||||
}
|
||||
@@ -70,7 +71,7 @@ export class AddLayerCommand extends Command {
|
||||
|
||||
undo() {
|
||||
// 从图层列表删除该图层
|
||||
this.layers.value = [...this.beforeLayers];
|
||||
this.layers.value = JSON.parse(this.beforeLayers);
|
||||
|
||||
// 恢复原活动图层
|
||||
this.activeLayerId.value = this.oldActiveLayerId;
|
||||
@@ -251,12 +252,12 @@ export class PasteLayerCommand extends Command {
|
||||
(await restoreFabricObject(groupLayer?.clippingMask, this.canvas)) ||
|
||||
null;
|
||||
|
||||
clippingMaskFabricObject.clipPath = null;
|
||||
// clippingMaskFabricObject.clipPath = null;
|
||||
clippingMaskFabricObject.set({
|
||||
absolutePositioned: true,
|
||||
});
|
||||
|
||||
clippingMaskFabricObject.dirty = true;
|
||||
// clippingMaskFabricObject.dirty = true;
|
||||
clippingMaskFabricObject.setCoords();
|
||||
// 添加所有对象到画布
|
||||
allObjects.forEach((obj) => {
|
||||
@@ -802,15 +803,23 @@ export class ToggleLayerVisibilityCommand extends Command {
|
||||
|
||||
// 切换可见性
|
||||
this.layer.visible = !this.layer.visible;
|
||||
const ids = [this.layerId];
|
||||
const childLayers = this.layer?.children || [];
|
||||
childLayers.forEach((childLayer) => {
|
||||
childLayer.visible = this.layer.visible;
|
||||
ids.push(childLayer.id);
|
||||
});
|
||||
|
||||
// 更新画布上图层对象的可见性
|
||||
if (this.canvas) {
|
||||
const layerObjects = this.canvas
|
||||
.getObjects()
|
||||
.filter((obj) => obj.layerId === this.layerId);
|
||||
layerObjects.forEach((obj) => {
|
||||
obj.visible = this.layer.visible;
|
||||
});
|
||||
this.canvas.getObjects().forEach((obj) => {
|
||||
if (ids.includes(obj.layerId)) {
|
||||
obj.getObjects?.()?.forEach((item) => {
|
||||
item.visible = this.layer.visible;
|
||||
});
|
||||
obj.visible = this.layer.visible;
|
||||
}
|
||||
});
|
||||
}
|
||||
// 更新画布上对象的可选择状态
|
||||
await this.layerManager?.updateLayersObjectsInteractivity();
|
||||
@@ -868,13 +877,14 @@ export class ToggleChildLayerVisibilityCommand extends Command {
|
||||
|
||||
// 更新画布上图层对象的可见性
|
||||
if (this.canvas) {
|
||||
const layerObjects = this.canvas
|
||||
.getObjects()
|
||||
.filter((obj) => obj.layerId === this.layerId);
|
||||
|
||||
layerObjects.forEach((obj) => {
|
||||
obj.visible = this.childLayer.visible;
|
||||
});
|
||||
this.canvas.getObjects().forEach((obj) => {
|
||||
if (obj.layerId === this.layerId) {
|
||||
obj.getObjects?.()?.forEach((item) => {
|
||||
item.visible = this.childLayer.visible;
|
||||
});
|
||||
obj.visible = this.childLayer.visible;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 更新画布上对象的可选择状态
|
||||
@@ -1007,9 +1017,8 @@ export class LayerLockCommand extends Command {
|
||||
|
||||
// 如果是组图层,递归更新所有子图层
|
||||
if (
|
||||
layer.type === "group" &&
|
||||
layer.children &&
|
||||
Array.isArray(layer.children)
|
||||
Array.isArray(layer.children) && layer.children.length > 0
|
||||
) {
|
||||
layer.children.forEach((child) => {
|
||||
this._updateLayerLockState(child, locked);
|
||||
@@ -1108,7 +1117,7 @@ export class SetLayerOpacityCommand extends Command {
|
||||
|
||||
this.canvas.renderAll();
|
||||
}
|
||||
|
||||
EventManager.emit("object:opacity:execute", this.layerId, this.opacity);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1130,6 +1139,7 @@ export class SetLayerOpacityCommand extends Command {
|
||||
this.canvas.renderAll();
|
||||
}
|
||||
}
|
||||
EventManager.emit("object:opacity:undo", this.layerId, this.opacity);
|
||||
}
|
||||
|
||||
getInfo() {
|
||||
@@ -1371,7 +1381,7 @@ export class GroupLayersCommand extends Command {
|
||||
// 备份原图层
|
||||
this.originalLayers = [...this.layers.value];
|
||||
// 新组ID
|
||||
this.groupId =
|
||||
this.groupId = options.id ||
|
||||
generateId("group_layer_") ||
|
||||
`group_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
|
||||
@@ -4434,3 +4444,87 @@ export class ChildLayerLockCommand extends Command {
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 设置图层混合模式
|
||||
*/
|
||||
export class SetLayerCompositeCommand extends Command {
|
||||
constructor(options) {
|
||||
super({
|
||||
name: "设置图层混合模式",
|
||||
saveState: false,
|
||||
});
|
||||
this.canvas = options.canvas;
|
||||
this.layers = options.layers;
|
||||
this.layerManager = options.layerManager;
|
||||
this.layerId = options.layerId;
|
||||
this.newValue = options.newValue;
|
||||
this.oldValue = options.oldValue;
|
||||
}
|
||||
|
||||
execute(isUndo = false) {
|
||||
const { layer } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
const { object } = findObjectByLayerId(this.canvas, this.layerId);
|
||||
if (!layer || !object) {
|
||||
console.error(`图层${this.layerId}不存在`);
|
||||
return false;
|
||||
}
|
||||
// console.log("==========", this.newValue, this.oldValue);
|
||||
const value = isUndo ? this.oldValue : this.newValue;
|
||||
layer.blendMode = value;
|
||||
object.set("globalCompositeOperation", value);
|
||||
this.canvas.renderAll();
|
||||
const event = isUndo ? "object:composite:undo" : "object:composite:execute";
|
||||
EventManager.emit(event, object);
|
||||
return true;
|
||||
}
|
||||
|
||||
undo() {
|
||||
return this.execute(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置颜色图层颜色
|
||||
*/
|
||||
export class SetColorLayerFillCommand extends Command {
|
||||
constructor(options) {
|
||||
super({
|
||||
name: "设置颜色图层颜色",
|
||||
saveState: false,
|
||||
});
|
||||
this.canvas = options.canvas;
|
||||
this.layerManager = options.layerManager;
|
||||
this.object = options.object;
|
||||
this.layer = this.layerManager?.getLayerById(this.object.layerId);
|
||||
this.newFill = options.newFill;
|
||||
this.oldFill = JSON.parse(JSON.stringify(this.object.fill));
|
||||
}
|
||||
|
||||
async execute(isUndo = false) {
|
||||
if (!this.object) {
|
||||
console.error(`颜色图层不存在`);
|
||||
return false;
|
||||
}
|
||||
const isVisible = this.layer?.visible;
|
||||
if(!isVisible && this.layer) this.layer.visible = true;
|
||||
const gradient = new fabric.Gradient({
|
||||
type: "linear",
|
||||
gradientUnits: "percentage",
|
||||
...(isUndo ? this.oldFill : this.newFill),
|
||||
});
|
||||
this.object.setFill(gradient);
|
||||
this.canvas.renderAll();
|
||||
await this.canvas?.thumbnailManager?.generateLayerThumbnail?.(
|
||||
this.object.id
|
||||
);
|
||||
if(!isVisible && this.layer) this.layer.visible = false;
|
||||
this.layerManager?.updateLayersObjectsInteractivity();
|
||||
return true;
|
||||
}
|
||||
|
||||
undo() {
|
||||
this.execute(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
50
src/component/Canvas/CanvasEditor/commands/ObjectCommands.js
Normal file
50
src/component/Canvas/CanvasEditor/commands/ObjectCommands.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Command } from "./Command.js";
|
||||
|
||||
/**
|
||||
* 对象移动命令
|
||||
* 轻量级命令,只记录对象的移动属性变化(位置)
|
||||
*/
|
||||
export class ObjectMoveCommand extends Command {
|
||||
constructor(options) {
|
||||
super({
|
||||
name: options.name || "对象移动",
|
||||
description: options.description || "移动对象",
|
||||
saveState: false, // 自己管理状态,避免递归
|
||||
});
|
||||
|
||||
this.canvas = options.canvas;
|
||||
this.initPos = options.initPos;
|
||||
this.finalPos = options.finalPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行命令
|
||||
*/
|
||||
async execute() {
|
||||
this.setObjectsPos(this.finalPos);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* 撤销命令
|
||||
* 应用初始状态
|
||||
*/
|
||||
async undo() {
|
||||
this.setObjectsPos(this.initPos);
|
||||
return true;
|
||||
}
|
||||
|
||||
async setObjectsPos(pos) {
|
||||
const objects = this.canvas.getObjects();
|
||||
const arr = typeof pos === "object" ? [pos] : pos;
|
||||
arr.forEach((item) => {
|
||||
const obj = objects.find((o) => o.id === item.id);
|
||||
if(obj) {
|
||||
obj.set({
|
||||
left: item.left,
|
||||
top: item.top,
|
||||
});
|
||||
}
|
||||
});
|
||||
this.canvas.renderAll();
|
||||
}
|
||||
}
|
||||
@@ -234,7 +234,7 @@ export class AddObjectToLayerCommand extends Command {
|
||||
parent.clippingMask,
|
||||
this.canvas
|
||||
);
|
||||
clippingMaskFabricObject.clipPath = null;
|
||||
// clippingMaskFabricObject.clipPath = null;
|
||||
clippingMaskFabricObject.set({ absolutePositioned: true });
|
||||
this.fabricObject.clipPath = clippingMaskFabricObject;
|
||||
// 标记为脏对象
|
||||
|
||||
@@ -46,13 +46,13 @@ export class RasterizeLayerCommand extends Command {
|
||||
this.layerId
|
||||
);
|
||||
this.layer = layer;
|
||||
this.parentLayer = parent;
|
||||
// this.parentLayer = parent;
|
||||
|
||||
// 新增:如果有父图层,则栅格化父图层及其所有子图层
|
||||
if (this.parentLayer) {
|
||||
this.layer = this.parentLayer;
|
||||
this.layerId = this.parentLayer.id;
|
||||
}
|
||||
// // 新增:如果有父图层,则栅格化父图层及其所有子图层
|
||||
// if (this.parentLayer) {
|
||||
// this.layer = this.parentLayer;
|
||||
// this.layerId = this.parentLayer.id;
|
||||
// }
|
||||
|
||||
this.isGroupLayer = this.layer?.children && this.layer.children.length > 0;
|
||||
|
||||
@@ -153,7 +153,7 @@ export class RasterizeLayerCommand extends Command {
|
||||
});
|
||||
|
||||
// 恢复原始图层结构
|
||||
this.layers.value = [...this.originalLayerStructure];
|
||||
this.layers.value = JSON.parse(this.originalLayerStructure);
|
||||
|
||||
// 恢复原活动图层
|
||||
this.activeLayerId.value = this.layerId;
|
||||
@@ -191,7 +191,7 @@ export class RasterizeLayerCommand extends Command {
|
||||
*/
|
||||
_saveOriginalLayerStructure() {
|
||||
// 只保存相关的图层结构,而不是整个图层数组
|
||||
this.originalLayerStructure = JSON.parse(JSON.stringify(this.layers.value));
|
||||
this.originalLayerStructure = JSON.stringify(this.layers.value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -517,12 +517,12 @@ export class ExportLayerToImageCommand extends Command {
|
||||
this.canvas
|
||||
);
|
||||
|
||||
clippingMaskFabricObject.clipPath = null;
|
||||
// clippingMaskFabricObject.clipPath = null;
|
||||
clippingMaskFabricObject.set({
|
||||
absolutePositioned: true,
|
||||
});
|
||||
|
||||
clippingMaskFabricObject.dirty = true;
|
||||
// clippingMaskFabricObject.dirty = true;
|
||||
clippingMaskFabricObject.setCoords();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { findObjectById } from "../utils/helper";
|
||||
import { findLayerRecursively } from "../utils/layerHelper";
|
||||
import { restoreFabricObject } from "../utils/objectHelper";
|
||||
import { Command } from "./Command";
|
||||
import EventManager from "../utils/event.js";
|
||||
|
||||
/**
|
||||
* 对象变换命令
|
||||
@@ -75,7 +76,7 @@ export class TransformCommand extends Command {
|
||||
|
||||
// 触发画布更新
|
||||
this.canvas.renderAll();
|
||||
|
||||
EventManager.emit("object:modified:execute", targetObject);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -113,7 +114,7 @@ export class TransformCommand extends Command {
|
||||
}, 300);
|
||||
// 触发画布更新
|
||||
this.canvas.renderAll();
|
||||
|
||||
EventManager.emit("object:modified:undo", targetObject);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -167,7 +168,7 @@ export class TransformCommand extends Command {
|
||||
);
|
||||
|
||||
if (clippingMaskFabricObject) {
|
||||
clippingMaskFabricObject.clipPath = null;
|
||||
// clippingMaskFabricObject.clipPath = null;
|
||||
clippingMaskFabricObject.set({
|
||||
absolutePositioned: true,
|
||||
});
|
||||
|
||||
@@ -233,7 +233,7 @@ export class UpdateGroupMaskPositionCommand extends Command {
|
||||
return;
|
||||
}
|
||||
|
||||
clippingMaskFabricObject.clipPath = null;
|
||||
// clippingMaskFabricObject.clipPath = null;
|
||||
clippingMaskFabricObject.set({
|
||||
absolutePositioned: true,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user