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

593 lines
17 KiB
JavaScript
Raw Normal View History

2025-06-09 10:25:54 +08:00
import { Command } from "./Command";
2025-06-18 11:05:23 +08:00
import { fabric } from "fabric-with-all";
2025-06-09 10:25:54 +08:00
/**
* 创建背景图层命令
*/
export class CreateBackgroundLayerCommand extends Command {
constructor(options) {
super({
name: "创建背景图层",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.backgroundLayer = options.backgroundLayer;
this.canvasManager = options.canvasManager;
this.historyManager = options.historyManager;
this.beforeLayers = [...this.layers.value]; // 备份原图层列表
}
execute() {
// 检查是否已经存在背景图层
const existingBgLayer = this.layers.value.find(
(layer) => layer.isBackground
);
if (existingBgLayer) {
console.warn("已存在背景层,不重复创建");
return existingBgLayer.id;
}
// 创建背景矩形对象
const bgObject = this._createBackgroundObject();
// 将背景对象添加到图层中
this.backgroundLayer.fabricObject = bgObject;
// 添加图层到最底部
this.layers.value.push(this.backgroundLayer);
// 添加到画布
this.canvas.add(bgObject);
// 渲染画布
this.canvas.renderAll();
return this.backgroundLayer.id;
}
undo() {
// 从图层列表中删除背景图层
const bgLayerIndex = this.layers.value.findIndex(
(layer) => layer.isBackground
);
if (bgLayerIndex !== -1) {
this.layers.value.splice(bgLayerIndex, 1);
}
// 从画布中移除背景对象
if (this.backgroundLayer.fabricObject) {
this.canvas.remove(this.backgroundLayer.fabricObject);
}
// 渲染画布
this.canvas.renderAll();
}
/**
* 创建背景矩形对象
* @returns {Object} fabric.js 矩形对象
* @private
*/
_createBackgroundObject() {
// 计算画布尺寸
const canvasWidth = this.canvas.width;
const canvasHeight = this.canvas.height;
// 确保背景色为白色,如果没有设置或者是透明的话
const backgroundColor =
this.backgroundLayer.backgroundColor &&
this.backgroundLayer.backgroundColor !== "transparent"
? this.backgroundLayer.backgroundColor
: "#ffffff";
const rect = new fabric.Rect({
left: canvasWidth / 2,
top: canvasHeight / 2,
width: this.backgroundLayer.canvasWidth,
height: this.backgroundLayer.canvasHeight,
fill: backgroundColor,
selectable: false,
evented: false,
hoverCursor: "default",
id: `bg_object_${this.backgroundLayer.id}`,
layerId: this.backgroundLayer.id,
layerName: this.backgroundLayer.name,
originX: "center",
originY: "center",
isBackground: true, // 标记为背景对象
});
return rect;
}
getInfo() {
return {
name: this.name,
layerId: this.backgroundLayer.id,
layerName: this.backgroundLayer.name,
width: this.backgroundLayer.canvasWidth,
height: this.backgroundLayer.canvasHeight,
backgroundColor: this.backgroundLayer.backgroundColor,
};
}
}
/**
* 更新背景属性命令如背景颜色
*/
export class UpdateBackgroundCommand extends Command {
constructor(options) {
super({
name: "更新背景属性",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.backgroundColor = options.backgroundColor;
this.historyManager = options.historyManager;
// 查找背景图层
this.bgLayer = this.layers.value.find((layer) => layer.isBackground);
this.oldBackgroundColor = this.bgLayer
? this.bgLayer.backgroundColor
: "#ffffff";
}
execute() {
if (!this.bgLayer) {
console.error("未找到背景图层");
return false;
}
// 更新背景图层属性
this.bgLayer.backgroundColor = this.backgroundColor;
// 更新背景对象属性
if (this.bgLayer.fabricObject) {
this.bgLayer.fabricObject.set("fill", this.backgroundColor);
this.canvas.renderAll();
}
return true;
}
undo() {
if (!this.bgLayer) {
return false;
}
// 恢复背景图层属性
this.bgLayer.backgroundColor = this.oldBackgroundColor;
// 恢复背景对象属性
if (this.bgLayer.fabricObject) {
this.bgLayer.fabricObject.set("fill", this.oldBackgroundColor);
this.canvas.renderAll();
}
return true;
}
getInfo() {
return {
name: this.name,
layerId: this.bgLayer?.id,
oldColor: this.oldBackgroundColor,
newColor: this.backgroundColor,
};
}
}
/**
* 调整画布和背景大小命令
*/
export class BackgroundSizeCommand extends Command {
constructor(options) {
super({
name: "调整背景大小",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.canvasManager = options.canvasManager;
this.newWidth = options.newWidth;
this.newHeight = options.newHeight;
this.historyManager = options.historyManager;
2025-06-18 11:05:23 +08:00
this.isRedGreenMode = options.isRedGreenMode;
this.bgLayer = this.layers.value.find((layer) => layer.isBackground);
2025-06-09 10:25:54 +08:00
// 记录原尺寸
2025-06-18 11:05:23 +08:00
this.oldWidth = this.bgLayer.fabricObject.width;
this.oldHeight = this.bgLayer.fabricObject.height;
2025-06-09 10:25:54 +08:00
// 查找背景图层
this.bgLayer = this.layers.value.find((layer) => layer.isBackground);
}
execute() {
// 调整画布大小
this.canvas.setWidth(this.newWidth);
this.canvas.setHeight(this.newHeight);
// 如果使用 CanvasManager通知它画布大小变化
if (
this.canvasManager &&
typeof this.canvasManager.updateCanvasSize === "function"
) {
this.canvasManager.updateCanvasSize(this.newWidth, this.newHeight);
}
// 调整背景对象大小
if (this.bgLayer && this.bgLayer.fabricObject) {
// 保持原有的背景颜色,如果没有设置则使用白色
const currentFill =
this.bgLayer.fabricObject.fill ||
this.bgLayer.backgroundColor ||
"#ffffff";
this.bgLayer.fabricObject.set({
width: this.newWidth,
height: this.newHeight,
fill: currentFill, // 保持原有颜色
});
// 更新图层记录的尺寸
this.bgLayer.canvasWidth = this.newWidth;
this.bgLayer.canvasHeight = this.newHeight;
}
// 渲染画布
this.canvas.renderAll();
return true;
}
undo() {
// 恢复画布大小
this.canvas.setWidth(this.oldWidth);
this.canvas.setHeight(this.oldHeight);
// 如果使用 CanvasManager通知它画布大小恢复
if (
this.canvasManager &&
typeof this.canvasManager.updateCanvasSize === "function"
) {
this.canvasManager.updateCanvasSize(this.oldWidth, this.oldHeight);
}
// 恢复背景对象大小
if (this.bgLayer && this.bgLayer.fabricObject) {
this.bgLayer.fabricObject.set({
width: this.oldWidth,
height: this.oldHeight,
});
// 恢复图层记录的尺寸
this.bgLayer.canvasWidth = this.oldWidth;
this.bgLayer.canvasHeight = this.oldHeight;
}
// 渲染画布
this.canvas.renderAll();
return true;
}
getInfo() {
return {
name: this.name,
oldWidth: this.oldWidth,
oldHeight: this.oldHeight,
newWidth: this.newWidth,
newHeight: this.newHeight,
};
}
}
/**
* 调整背景大小并等比缩放所有其他元素的命令
*/
export class BackgroundSizeWithScaleCommand extends Command {
constructor(options) {
super({
name: "调整背景大小并缩放元素",
saveState: true,
});
this.canvas = options.canvas;
this.layers = options.layers;
this.canvasManager = options.canvasManager;
this.newWidth = options.newWidth;
this.newHeight = options.newHeight;
this.historyManager = options.historyManager;
// 缩放策略:'uniform' | 'fill' | 'fit' | 'stretch'
this.scaleStrategy = options.scaleStrategy || "uniform";
// 记录原尺寸
this.oldWidth = this.canvas.width;
this.oldHeight = this.canvas.height;
// 查找背景图层
this.bgLayer = this.layers.value.find((layer) => layer.isBackground);
// 计算缩放比例
const scaleXRatio = this.newWidth / this.oldWidth;
const scaleYRatio = this.newHeight / this.oldHeight;
// 根据策略计算缩放比例和偏移
this._calculateScaleAndOffset(scaleXRatio, scaleYRatio);
// 存储所有非背景对象的原始状态
this.objectStates = [];
this._saveOriginalStates();
}
/**
* 保存所有非背景对象的原始状态
* @private
*/
_saveOriginalStates() {
this.canvas.getObjects().forEach((obj) => {
if (!obj.isBackground) {
// 检查对象是否已经有原始状态记录
if (!obj._originalState) {
// 第一次记录原始状态
obj._originalState = {
left: obj.left,
top: obj.top,
scaleX: obj.scaleX || 1,
scaleY: obj.scaleY || 1,
width: obj.width,
height: obj.height,
// 记录基准画布尺寸
baseCanvasWidth: this.oldWidth,
baseCanvasHeight: this.oldHeight,
};
}
this.objectStates.push({
obj: obj,
// 使用原始状态而不是当前状态
left: obj._originalState.left,
top: obj._originalState.top,
scaleX: obj._originalState.scaleX,
scaleY: obj._originalState.scaleY,
width: obj._originalState.width,
height: obj._originalState.height,
});
}
});
}
/**
* 根据缩放策略计算缩放比例和偏移量
* @param {number} scaleXRatio X轴缩放比例
* @param {number} scaleYRatio Y轴缩放比例
* @private
*/
_calculateScaleAndOffset(scaleXRatio, scaleYRatio) {
switch (this.scaleStrategy) {
case "uniform":
// 统一缩放:使用平均值,保持相对比例的同时允许适度的形变
this.uniformScale = Math.sqrt(scaleXRatio * scaleYRatio);
this.offsetX = (this.newWidth - this.oldWidth * this.uniformScale) / 2;
this.offsetY =
(this.newHeight - this.oldHeight * this.uniformScale) / 2;
break;
case "fit":
// 适应模式:使用较小值,确保所有内容都在画布内,可能有留白
this.uniformScale = Math.min(scaleXRatio, scaleYRatio);
this.offsetX = (this.newWidth - this.oldWidth * this.uniformScale) / 2;
this.offsetY =
(this.newHeight - this.oldHeight * this.uniformScale) / 2;
break;
case "fill":
// 填充模式:使用较大值,填满画布,可能有部分内容被裁切
this.uniformScale = Math.max(scaleXRatio, scaleYRatio);
this.offsetX = (this.newWidth - this.oldWidth * this.uniformScale) / 2;
this.offsetY =
(this.newHeight - this.oldHeight * this.uniformScale) / 2;
break;
case "stretch":
// 拉伸模式:不保持宽高比,完全适应新尺寸
this.scaleX = scaleXRatio;
this.scaleY = scaleYRatio;
this.offsetX = 0;
this.offsetY = 0;
break;
default:
// 默认使用uniform模式
this.uniformScale = Math.sqrt(scaleXRatio * scaleYRatio);
this.offsetX = (this.newWidth - this.oldWidth * this.uniformScale) / 2;
this.offsetY =
(this.newHeight - this.oldHeight * this.uniformScale) / 2;
}
}
execute() {
// 调整画布大小
this.canvas.setWidth(this.newWidth);
this.canvas.setHeight(this.newHeight);
// 如果使用 CanvasManager通知它画布大小变化
if (
this.canvasManager &&
typeof this.canvasManager.updateCanvasSize === "function"
) {
this.canvasManager.updateCanvasSize(this.newWidth, this.newHeight);
}
// 调整背景对象大小和位置
if (this.bgLayer && this.bgLayer.fabricObject) {
// 保持原有的背景颜色,如果没有设置则使用白色
const currentFill =
this.bgLayer.fabricObject.fill ||
this.bgLayer.backgroundColor ||
"#ffffff";
this.bgLayer.fabricObject.set({
width: this.newWidth,
height: this.newHeight,
left: this.newWidth / 2,
top: this.newHeight / 2,
fill: currentFill, // 保持原有颜色
});
// 更新图层记录的尺寸
this.bgLayer.canvasWidth = this.newWidth;
this.bgLayer.canvasHeight = this.newHeight;
}
// 计算基于原始画布的缩放比例
const baseScaleX =
this.newWidth /
this.objectStates[0]?.obj._originalState?.baseCanvasWidth ||
this.newWidth / this.oldWidth;
const baseScaleY =
this.newHeight /
this.objectStates[0]?.obj._originalState?.baseCanvasHeight ||
this.newHeight / this.oldHeight;
// 根据策略缩放所有非背景对象
this.objectStates.forEach((state) => {
const obj = state.obj;
if (this.scaleStrategy === "stretch") {
// 拉伸模式使用不同的X和Y缩放比例
obj.set({
left: state.left * baseScaleX,
top: state.top * baseScaleY,
scaleX: state.scaleX * baseScaleX,
scaleY: state.scaleY * baseScaleY,
});
} else {
// 其他模式:计算基于原始状态的统一缩放比例
const baseUniformScale = Math.sqrt(baseScaleX * baseScaleY);
const baseOffsetX =
(this.newWidth -
(obj._originalState?.baseCanvasWidth || this.oldWidth) *
baseUniformScale) /
2;
const baseOffsetY =
(this.newHeight -
(obj._originalState?.baseCanvasHeight || this.oldHeight) *
baseUniformScale) /
2;
obj.set({
left: state.left * baseUniformScale + baseOffsetX,
top: state.top * baseUniformScale + baseOffsetY,
scaleX: state.scaleX * baseUniformScale,
scaleY: state.scaleY * baseUniformScale,
});
}
obj.setCoords();
});
// 渲染画布
this.canvas.renderAll();
return true;
}
undo() {
// 恢复画布大小
this.canvas.setWidth(this.oldWidth);
this.canvas.setHeight(this.oldHeight);
// 如果使用 CanvasManager通知它画布大小恢复
if (
this.canvasManager &&
typeof this.canvasManager.updateCanvasSize === "function"
) {
this.canvasManager.updateCanvasSize(this.oldWidth, this.oldHeight);
}
// 恢复背景对象大小和位置
if (this.bgLayer && this.bgLayer.fabricObject) {
this.bgLayer.fabricObject.set({
width: this.oldWidth,
height: this.oldHeight,
left: this.oldWidth / 2,
top: this.oldHeight / 2,
});
// 恢复图层记录的尺寸
this.bgLayer.canvasWidth = this.oldWidth;
this.bgLayer.canvasHeight = this.oldHeight;
}
// 恢复所有非背景对象的当前状态(而不是原始状态,因为可能有其他操作)
this.objectStates.forEach((state) => {
// 计算恢复到之前画布尺寸时的状态
const obj = state.obj;
const originalState = obj._originalState;
if (originalState) {
const baseScaleX = this.oldWidth / originalState.baseCanvasWidth;
const baseScaleY = this.oldHeight / originalState.baseCanvasHeight;
const baseUniformScale = Math.sqrt(baseScaleX * baseScaleY);
const baseOffsetX =
(this.oldWidth - originalState.baseCanvasWidth * baseUniformScale) /
2;
const baseOffsetY =
(this.oldHeight - originalState.baseCanvasHeight * baseUniformScale) /
2;
obj.set({
left: originalState.left * baseUniformScale + baseOffsetX,
top: originalState.top * baseUniformScale + baseOffsetY,
scaleX: originalState.scaleX * baseUniformScale,
scaleY: originalState.scaleY * baseUniformScale,
});
} else {
// 降级到原来的逻辑
obj.set({
left: state.left,
top: state.top,
scaleX: state.scaleX,
scaleY: state.scaleY,
});
}
obj.setCoords();
});
// 渲染画布
this.canvas.renderAll();
return true;
}
getInfo() {
const info = {
name: this.name,
oldWidth: this.oldWidth,
oldHeight: this.oldHeight,
newWidth: this.newWidth,
newHeight: this.newHeight,
scaleStrategy: this.scaleStrategy,
objectCount: this.objectStates.length,
};
if (this.scaleStrategy === "stretch") {
info.scaleX = this.scaleX;
info.scaleY = this.scaleY;
} else {
info.uniformScale = this.uniformScale;
info.offsetX = this.offsetX;
info.offsetY = this.offsetY;
}
return info;
}
}