2025-06-29 23:29:47 +08:00
|
|
|
|
import { findObjectById } from "../utils/helper";
|
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();
|
|
|
|
|
|
|
|
|
|
|
|
// 将背景对象添加到图层中
|
2025-06-25 01:03:39 +08:00
|
|
|
|
this.backgroundLayer.fabricObject = bgObject.toObject([
|
|
|
|
|
|
"id",
|
|
|
|
|
|
"layerId",
|
|
|
|
|
|
"type",
|
|
|
|
|
|
]);
|
2025-06-09 10:25:54 +08:00
|
|
|
|
|
|
|
|
|
|
// 添加图层到最底部
|
|
|
|
|
|
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;
|
2025-06-29 23:29:47 +08:00
|
|
|
|
this.backgroundColorValue = options.backgroundColorValue; // 使用.value获取实际值
|
|
|
|
|
|
this.backgroundColor = options.backgroundColor; //
|
2025-06-09 10:25:54 +08:00
|
|
|
|
this.historyManager = options.historyManager;
|
|
|
|
|
|
|
|
|
|
|
|
// 查找背景图层
|
|
|
|
|
|
this.bgLayer = this.layers.value.find((layer) => layer.isBackground);
|
2025-06-29 23:29:47 +08:00
|
|
|
|
this.oldBackgroundColor = this.bgLayer.backgroundColor;
|
2025-06-09 10:25:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
execute() {
|
|
|
|
|
|
if (!this.bgLayer) {
|
|
|
|
|
|
console.error("未找到背景图层");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新背景图层属性
|
|
|
|
|
|
this.bgLayer.backgroundColor = this.backgroundColor;
|
|
|
|
|
|
|
|
|
|
|
|
// 更新背景对象属性
|
|
|
|
|
|
if (this.bgLayer.fabricObject) {
|
2025-06-29 23:29:47 +08:00
|
|
|
|
const { object } = findObjectById(
|
|
|
|
|
|
this.canvas,
|
|
|
|
|
|
this.bgLayer.fabricObject.id
|
|
|
|
|
|
);
|
|
|
|
|
|
object.set("fill", this.backgroundColor);
|
2025-06-09 10:25:54 +08:00
|
|
|
|
this.canvas.renderAll();
|
|
|
|
|
|
}
|
2025-06-29 23:29:47 +08:00
|
|
|
|
this.backgroundColorValue.value = this.backgroundColor; // 设置背景颜色
|
2025-06-09 10:25:54 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
undo() {
|
|
|
|
|
|
if (!this.bgLayer) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 恢复背景图层属性
|
|
|
|
|
|
this.bgLayer.backgroundColor = this.oldBackgroundColor;
|
|
|
|
|
|
|
|
|
|
|
|
// 恢复背景对象属性
|
|
|
|
|
|
if (this.bgLayer.fabricObject) {
|
2025-06-29 23:29:47 +08:00
|
|
|
|
const { object } = findObjectById(
|
|
|
|
|
|
this.canvas,
|
|
|
|
|
|
this.bgLayer.fabricObject.id
|
|
|
|
|
|
);
|
|
|
|
|
|
object.set("fill", this.oldBackgroundColor);
|
2025-06-09 10:25:54 +08:00
|
|
|
|
this.canvas.renderAll();
|
|
|
|
|
|
}
|
2025-06-29 23:29:47 +08:00
|
|
|
|
this.backgroundColorValue.value = this.oldBackgroundColor; // 恢复背景颜色
|
2025-06-09 10:25:54 +08:00
|
|
|
|
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);
|
|
|
|
|
|
|
2025-06-22 13:52:28 +08:00
|
|
|
|
console.log(
|
|
|
|
|
|
`调整画布大小:${this.oldWidth}x${this.oldHeight} -> ${this.newWidth}x${this.newHeight}`
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2025-06-09 10:25:54 +08:00
|
|
|
|
// 如果使用 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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|