Files
aida_front/src/component/Canvas/CanvasEditor/commands/SelectionCommands.js
X1627315083 c266967f16 接入画布
2025-06-09 10:25:54 +08:00

579 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Command, CompositeCommand } from "./Command.js";
//import { fabric } from "fabric-with-all";
import { createLayer, LayerType } from "../utils/layerHelper.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 ClearSelectionCommand extends Command {
constructor(options = {}) {
super({
name: "清除选区",
description: "清除当前选区",
saveState: false,
});
this.selectionManager = options.selectionManager;
this.originalSelection = options.selectionManager
? options.selectionManager.getSelectionPath()
: null;
}
async execute() {
if (!this.selectionManager) {
console.error("无法清除选区:参数无效");
return false;
}
// 保存原始选区
if (!this.originalSelection) {
this.originalSelection = this.selectionManager.getSelectionPath();
}
// 清除选区
this.selectionManager.clearSelection();
return true;
}
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);
}
});
}
}
/**
* 从选区中删除内容命令
*/
export class ClearSelectionContentCommand extends Command {
constructor(options = {}) {
super({
name: "清除选区内容",
description: "删除选区中的内容",
saveState: false,
});
this.canvas = options.canvas;
this.layerManager = options.layerManager;
this.selectionManager = options.selectionManager;
this.targetLayerId = options.targetLayerId;
this.removedObjects = [];
}
async execute() {
if (!this.canvas || !this.layerManager || !this.selectionManager) {
console.error("无法清除选区内容:参数无效");
return false;
}
// 获取选区
const selectionObject = this.selectionManager.getSelectionObject();
if (!selectionObject) {
console.error("无法清除选区内容:当前没有选区");
return false;
}
// 确定目标图层
const layerId = this.targetLayerId || this.layerManager.getActiveLayerId();
const layer = this.layerManager.getLayerById(layerId);
if (!layer || !layer.fabricObjects) {
console.error("无法清除选区内容:目标图层无效或为空");
return false;
}
// 找到选区内的对象
const objectsToRemove = layer.fabricObjects.filter((obj) => {
return this.selectionManager.isObjectInSelection(obj);
});
if (objectsToRemove.length === 0) {
console.warn("选区内没有对象需要清除");
return true;
}
// 备份被删除的对象
this.removedObjects = objectsToRemove.map((obj) => ({
object: this._cloneObjectSync(obj),
layerId: layerId,
}));
// 从图层中移除对象
for (const obj of objectsToRemove) {
this.layerManager.removeObjectFromLayer(layerId, obj.id);
}
return { removedCount: objectsToRemove.length };
}
async undo() {
if (!this.layerManager || this.removedObjects.length === 0) return false;
// 恢复被删除的对象
for (const item of this.removedObjects) {
if (item.object && item.layerId) {
const clonedObj = await this._cloneObject(item.object);
this.layerManager.addObjectToLayer(item.layerId, clonedObj);
}
}
return true;
}
_cloneObjectSync(obj) {
// 这是一个简单的深拷贝,不适用于所有场景
// 在实际应用中应该使用fabric.js的clone方法
if (!obj) return null;
return JSON.parse(JSON.stringify(obj));
}
async _cloneObject(obj) {
return new Promise((resolve, reject) => {
if (!obj) {
reject(new Error("对象无效,无法克隆"));
return;
}
try {
if (typeof obj.clone === "function") {
obj.clone((cloned) => {
resolve(cloned);
});
} else {
// 如果对象没有clone方法(可能是因为它已经是序列化后的对象)
// 在实际代码中需要适当处理这种情况
resolve(Object.assign({}, obj));
}
} catch (error) {
reject(error);
}
});
}
}
// 导入套索抠图命令
export { LassoCutoutCommand } from "./LassoCutoutCommand.js";