Files
aida_front/src/component/Canvas/CanvasEditor/commands/SelectionCommands.js
2025-07-14 01:00:23 +08:00

421 lines
12 KiB
JavaScript

import { Command, CompositeCommand } from "./Command.js";
import { fabric } from "fabric-with-all";
import { createLayer, LayerType } from "../utils/layerHelper.js";
import { createRasterizedImage } from "../utils/selectionToImage.js";
import { generateId } from "../utils/helper.js";
/**
* 创建选区命令
*/
export class CreateSelectionCommand extends Command {
constructor(options = {}) {
super({
name: options.name || "创建选区",
description: "在画布上创建选区",
saveState: false,
});
this.canvas = options.canvas;
this.selectionManager = options.selectionManager;
this.selectionObject = options.selectionObject;
this.selectionType = options.selectionType || "rectangle";
}
async execute() {
if (!this.canvas || !this.selectionManager || !this.selectionObject) {
console.error("无法创建选区:参数无效");
return false;
}
// 将选择对象添加到选区管理器
this.selectionManager.setSelectionObject(this.selectionObject);
return true;
}
async undo() {
if (!this.selectionManager) return false;
this.selectionManager.clearSelection();
return true;
}
}
/**
* 反转选区命令
*/
export class InvertSelectionCommand extends Command {
constructor(options = {}) {
super({
name: "反转选区",
description: "反转当前选区",
saveState: false,
});
this.canvas = options.canvas;
this.selectionManager = options.selectionManager;
this.originalSelection = options.selectionManager
? options.selectionManager.getSelectionPath()
: null;
}
async execute() {
if (!this.canvas || !this.selectionManager) {
console.error("无法反转选区:参数无效");
return false;
}
// 保存原始选区
if (!this.originalSelection) {
this.originalSelection = this.selectionManager.getSelectionPath();
}
// 反转选区
const result = await this.selectionManager.invertSelection();
return result;
}
async undo() {
if (!this.selectionManager || !this.originalSelection) return false;
// 恢复原始选区
this.selectionManager.setSelectionFromPath(this.originalSelection);
return true;
}
}
/**
* 添加到选区命令
*/
export class AddToSelectionCommand extends Command {
constructor(options = {}) {
super({
name: "添加到选区",
description: "将新的选区添加到现有选区",
saveState: false,
});
this.canvas = options.canvas;
this.selectionManager = options.selectionManager;
this.newSelection = options.newSelection;
this.originalSelection = options.selectionManager
? options.selectionManager.getSelectionPath()
: null;
}
async execute() {
if (!this.canvas || !this.selectionManager || !this.newSelection) {
console.error("无法添加到选区:参数无效");
return false;
}
// 保存原始选区
if (!this.originalSelection) {
this.originalSelection = this.selectionManager.getSelectionPath();
}
// 添加到选区
const result = await this.selectionManager.addToSelection(this.newSelection);
return result;
}
async undo() {
if (!this.selectionManager || !this.originalSelection) return false;
// 恢复原始选区
this.selectionManager.setSelectionFromPath(this.originalSelection);
return true;
}
}
/**
* 从选区中移除命令
*/
export class RemoveFromSelectionCommand extends Command {
constructor(options = {}) {
super({
name: "从选区中移除",
description: "从现有选区中移除指定区域",
saveState: false,
});
this.canvas = options.canvas;
this.selectionManager = options.selectionManager;
this.removeSelection = options.removeSelection;
this.originalSelection = options.selectionManager
? options.selectionManager.getSelectionPath()
: null;
}
async execute() {
if (!this.canvas || !this.selectionManager || !this.removeSelection) {
console.error("无法从选区中移除:参数无效");
return false;
}
// 保存原始选区
if (!this.originalSelection) {
this.originalSelection = this.selectionManager.getSelectionPath();
}
// 从选区中移除
const result = await this.selectionManager.removeFromSelection(this.removeSelection);
return result;
}
async undo() {
if (!this.selectionManager || !this.originalSelection) return false;
// 恢复原始选区
this.selectionManager.setSelectionFromPath(this.originalSelection);
return true;
}
}
/**
* 羽化选区命令
*/
export class FeatherSelectionCommand extends Command {
constructor(options = {}) {
super({
name: "羽化选区",
description: "对当前选区应用羽化效果",
saveState: false,
});
this.selectionManager = options.selectionManager;
this.featherAmount = options.featherAmount || 5;
this.originalSelection = options.selectionManager
? options.selectionManager.getSelectionPath()
: null;
this.originalFeatherAmount = options.selectionManager
? options.selectionManager.getFeatherAmount()
: 0;
}
async execute() {
if (!this.selectionManager) {
console.error("无法羽化选区:参数无效");
return false;
}
// 保存原始选区和羽化值
if (!this.originalSelection) {
this.originalSelection = this.selectionManager.getSelectionPath();
this.originalFeatherAmount = this.selectionManager.getFeatherAmount();
}
// 应用羽化
const result = await this.selectionManager.featherSelection(this.featherAmount);
return result;
}
async undo() {
if (!this.selectionManager || !this.originalSelection) return false;
// 恢复原始选区和羽化值
this.selectionManager.setSelectionFromPath(this.originalSelection);
this.selectionManager.setFeatherAmount(this.originalFeatherAmount);
return true;
}
}
/**
* 填充选区命令
*/
export class FillSelectionCommand extends Command {
constructor(options = {}) {
super({
name: "填充选区",
description: "使用指定颜色填充当前选区",
saveState: false,
});
this.canvas = options.canvas;
this.layerManager = options.layerManager;
this.selectionManager = options.selectionManager;
this.color = options.color || "#000000";
this.targetLayerId = options.targetLayerId;
this.createdObjectIds = [];
}
async execute() {
if (!this.canvas || !this.layerManager || !this.selectionManager) {
console.error("无法填充选区:参数无效");
return false;
}
// 获取选区路径
const selectionPath = this.selectionManager.getSelectionObject();
if (!selectionPath) {
console.error("无法填充选区:当前没有选区");
return false;
}
// 确定目标图层
const layerId = this.targetLayerId || this.layerManager.getActiveLayerId();
if (!layerId) {
console.error("无法填充选区:没有活动图层");
return false;
}
// 创建填充对象
const fillObject = new fabric.Path(selectionPath.path, {
fill: this.color,
stroke: null,
opacity: 1,
id: `fill_${Date.now()}_${Math.floor(Math.random() * 1000)}`,
layerId: layerId,
selectable: false,
});
// 应用羽化效果(如果有)
const featherAmount = this.selectionManager.getFeatherAmount();
if (featherAmount > 0) {
fillObject.shadow = new fabric.Shadow({
color: this.color,
blur: featherAmount,
offsetX: 0,
offsetY: 0,
});
}
// 添加到图层
this.layerManager.addObjectToLayer(layerId, fillObject);
this.createdObjectIds.push(fillObject.id);
// 清空选区
this.selectionManager.clearSelection();
return true;
}
async undo() {
if (!this.layerManager || this.createdObjectIds.length === 0) return false;
// 移除创建的填充对象
for (const id of this.createdObjectIds) {
const layerObj = this._findObjectInLayers(id);
if (layerObj) {
this.layerManager.removeObjectFromLayer(layerObj.layerId, id);
}
}
return true;
}
_findObjectInLayers(objectId) {
if (!this.layerManager) return null;
const layers = this.layerManager.layers.value;
for (const layer of layers) {
if (layer.fabricObjects) {
const obj = layer.fabricObjects.find((obj) => obj.id === objectId);
if (obj) return { object: obj, layerId: layer.id };
}
}
return null;
}
}
/**
* 复制选区内容到新图层命令
*/
export class CopySelectionToNewLayerCommand extends CompositeCommand {
constructor(options = {}) {
super([], {
name: "复制选区到新图层",
description: "将选区中的内容复制到新图层",
});
this.canvas = options.canvas;
this.layerManager = options.layerManager;
this.selectionManager = options.selectionManager;
this.sourceLayerId = options.sourceLayerId;
this.newLayerName = options.newLayerName || "选区复制";
this.newLayerId = null;
this.copiedObjectIds = [];
}
async execute() {
if (!this.canvas || !this.layerManager || !this.selectionManager) {
console.error("无法复制选区:参数无效");
return false;
}
try {
// 获取选区
const selectionObject = this.selectionManager.getSelectionObject();
if (!selectionObject) {
console.error("无法复制选区:当前没有选区");
return false;
}
// 确定源图层
const sourceId = this.sourceLayerId || this.layerManager.getActiveLayerId();
const sourceLayer = this.layerManager.getLayerById(sourceId);
if (!sourceLayer || !sourceLayer.fabricObjects) {
console.error("无法复制选区:源图层无效或为空");
return false;
}
// 创建新图层
this.newLayerId = await this.layerManager.createLayer(this.newLayerName, LayerType.EMPTY);
// 获取选区内的对象
const objectsToCopy = sourceLayer.fabricObjects.filter((obj) => {
return this.selectionManager.isObjectInSelection(obj);
});
if (objectsToCopy.length === 0) {
console.warn("选区内没有对象可复制");
return true; // 仍然返回成功,因为已创建了新图层
}
// 复制对象到新图层
for (const obj of objectsToCopy) {
// 克隆对象
const clonedObj = await this._cloneObject(obj);
// 设置新的ID和图层ID
const newId = `copy_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
clonedObj.id = newId;
clonedObj.layerId = this.newLayerId;
// 添加到新图层
await this.layerManager.addObjectToLayer(this.newLayerId, clonedObj);
this.copiedObjectIds.push(newId);
}
// 设置新图层为活动图层
this.layerManager.setActiveLayer(this.newLayerId);
// 清空选区
this.selectionManager.clearSelection();
return {
newLayerId: this.newLayerId,
copiedCount: this.copiedObjectIds.length,
};
} catch (error) {
console.error("复制选区过程中出错:", error);
// 如果已经创建了新图层,需要进行清理
if (this.newLayerId) {
try {
await this.layerManager.removeLayer(this.newLayerId);
} catch (cleanupError) {
console.warn("清理新图层失败:", cleanupError);
}
}
throw error;
}
}
async _cloneObject(obj) {
return new Promise((resolve, reject) => {
if (!obj) {
reject(new Error("对象无效,无法克隆"));
return;
}
try {
obj.clone((cloned) => {
resolve(cloned);
});
} catch (error) {
reject(error);
}
});
}
}