深度画布bug

This commit is contained in:
lzp
2026-03-31 13:29:46 +08:00
parent f5efaa8eaf
commit b53d15d3f2
22 changed files with 381 additions and 91 deletions

View File

@@ -1,6 +1,6 @@
import { fabric } from 'fabric-with-all'
import { OperationType } from '../tools/layerHelper'
import { getObjectAlphaToCanvas, traceImageContour, cloneObjects } from '../tools/canvasMethod'
import { getObjectAlphaToCanvas, traceImageContour, clipCanvasTransparent, cloneObjects } from '../tools/canvasMethod'
import { getSegAnythingImage } from '@/api/depth-canvas'
import { useGlobalStore, useUserInfoStore } from '@/stores'
@@ -256,28 +256,46 @@ export class AISelectboxToolManager {
if (!this.demoObject) return
const fobject = this.demoObject
this.clearDemoObject()
const tcanvas = await this.createStaticCanvas(fobject)
const canvas = getObjectAlphaToCanvas(tcanvas, null, 0, { r: 255, g: 0, b: 0, a: 255 });
const arr = traceImageContour(canvas);
const scaleY = fobject.scaleY
const scaleX = fobject.scaleX
const top = fobject.top
const left = fobject.left
let minX = fobject.width;
let minY = fobject.height;
const str = arr.map((v) => {
if (v.x < minX) minX = v.x;
if (v.y < minY) minY = v.y;
return `${v.x} ${v.y}`
}).join(" L ");
const path = new fabric.Path(`M ${str} z`);
const tcanvas = await this.createStaticCanvas(fobject)
const canvas = getObjectAlphaToCanvas(tcanvas, null, 0, { r: 255, g: 255, b: 255, a: 255 });
/** 路径裁剪法 */
// const arr = traceImageContour(canvas);
// const str = arr.map((v) => {
// if (v.x < minX) minX = v.x;
// if (v.y < minY) minY = v.y;
// return `${v.x} ${v.y}`
// }).join(" L ");
// const path = new fabric.Path(`M ${str} z`);
// path.set({
// left: left + minX,
// top: top + minY,
// scaleX: scaleX,
// scaleY: scaleY,
// ...this.selectionStyle,
// });
/** 图片裁剪法 */
const info = clipCanvasTransparent(canvas)
minX = info.minX
minY = info.minY
const path = new fabric.Image(info.canvas)
path.set({
left: left + minX,
top: top + minY,
scaleX: scaleX,
scaleY: scaleY,
...this.selectionStyle,
});
absolutePositioned: true,
})
// 创建分组层
const group = await this.layerManager.createGroupLayer({
clipPath: path,
top: path.top + path.height / 2,

View File

@@ -189,16 +189,9 @@ export class CanvasManager {
const objects = this.getObjects().filter((v: any) => v.type !== "group" && !!v.info?.id);
for (let i = 0; i < objects.length; i++) {
let object = objects[i]
if (object.clipPath) object.set({ clipPath: null })
let group = this.getObjectById(object.info.parentId)
if (!group) continue
let path = group.clipPath
let path = this.getObjectById(object.info.parentId)?.clipPath
if (!path) continue
let clipPath = await cloneObjects([path]).then((v) => v[0])
clipPath.set({
absolutePositioned: true,
})
object.set({ clipPath })
object.set({ clipPath: path })
}
this.renderAll()
}

View File

@@ -32,7 +32,30 @@ export class LayerManager {
}
}
setActiveFirstLayer() {
this.setActiveID(this.layers.value[0]?.info?.id || "")
const layer = this.layers.value[0]
const id = layer.type === "group" ? layer.children[0]?.info?.id : layer.info?.id
this.setActiveID(id || "")
}
// 更新图层列表
async updateLayers(isSort = false) {
const objects = this.canvasManager.getObjects().map(v => v.toObject()).filter(v => !!v.info?.id).reverse()
objects.forEach(v => {
if (v.type === "group") {
if (!v.children) v.children = []
return;
}
const parentId = v.info?.parentId
if (!parentId) return
objects.forEach((obj: any) => {
if (obj.info?.id !== parentId) return
if (!obj.children) obj.children = []
obj.children.push(v)
})
})
const layers = objects.filter(v => !v.info?.parentId)
this.layers.value = layers
if (isSort) await this.sortLayers()
}
getActiveLayer() {
@@ -168,26 +191,6 @@ export class LayerManager {
}
}
// 更新图层列表
async updateLayers(isSort = false) {
const objects = this.canvasManager.getObjects().map(v => v.toObject()).filter(v => !!v.info?.id).reverse()
objects.forEach(v => {
if (v.type === "group") {
if (!v.children) v.children = []
return;
}
const parentId = v.info?.parentId
if (!parentId) return
objects.forEach((obj: any) => {
if (obj.info?.id !== parentId) return
if (!obj.children) obj.children = []
obj.children.push(v)
})
})
const layers = objects.filter(v => !v.info?.parentId)
this.layers.value = layers
if (isSort) await this.sortLayers()
}
/** 设置图层位置-不设置默认居中 */
setLayerPosition(object, options?: any) {
@@ -455,7 +458,7 @@ export class LayerManager {
const objects = this.canvasManager.getObjects()
objects.forEach((item: any) => {
item.set({
erasable: (item.info.id === this.activeID.value && item.type !== "group")
erasable: (item?.info?.id === this.activeID.value && item.type !== "group")
})
})
}

View File

@@ -117,6 +117,7 @@ export class ToolManager {
setTool(value: string) {
const tool = this.tools.find((t) => t.name === value)
if (!tool) return console.warn(`工具${tool}不存在`)
this.brushManager?.handleToolChange(tool.name)
const oldTool = this.currentTool.value
this.currentTool.value = tool.name
this.canvasManager.canvas.defaultCursor = tool.cursor
@@ -124,7 +125,6 @@ export class ToolManager {
this.canvasManager.canvas.isDrawingMode = !!tool.isDrawingMode;// 绘制模式
if (!tool.isDrawingMode) this._disableBrushIndicator()// 非绘制模式,禁用笔刷指示器
if (tool.setup) tool.setup()
this.stateManager?.aiSelectboxToolManager?.handleToolChange?.(oldTool, tool.name)
@@ -160,16 +160,13 @@ export class ToolManager {
const brushStore = this.brushManager?.brushStore
if (brushStore) {
// 同步基本属性
// this.brushManager.setBrushSize(brushStore.state.size);
// this.brushManager.setBrushColor(brushStore.state.color);
// this.brushManager.setBrushOpacity(brushStore.state.opacity);
this.brushManager.setBrushSize(brushStore.state.size);
this.brushManager.setBrushColor(brushStore.state.color);
this.brushManager.setBrushOpacity(brushStore.state.opacity);
// 同步笔刷类型 - 修复方法名使用正确的setBrushType方法
this.brushManager.setBrushType("pencil");
}
this.brushManager.setBrushSize(5);
this.brushManager.setBrushColor("#000");
this.brushManager.setBrushOpacity(1);
// 更新应用到画布
this.brushManager.updateBrush();
@@ -185,11 +182,12 @@ export class ToolManager {
if (!this.canvasManager.canvas) return;
// 确保有笔刷管理器
if (this.brushManager) {
const brushStore = this.brushManager?.brushStore
if (brushStore) {
this.brushManager.createEraser();
this.brushManager.setBrushSize(brushStore.state.size);
}
this.brushManager.setBrushSize(5);
this.stateManager.layerManager.setActiveObjectErasable()
// 启用笔刷指示器
this._enableBrushIndicator();
@@ -206,10 +204,16 @@ export class ToolManager {
console.warn("画笔正在更新中,请稍候...");
return;
}
this.brushManager.setBrushSize(5);
this.brushManager.setBrushColor("rgb(255, 0, 0)");
this.brushManager.setBrushOpacity(0.5);
this.brushManager.setBrushType("pencil");
const brushStore = this.brushManager?.brushStore
if (brushStore) {
// 同步基本属性
this.brushManager.setBrushSize(brushStore.state.size);
this.brushManager.setBrushColor(brushStore.state.color);
this.brushManager.setBrushOpacity(brushStore.state.opacity);
// 同步笔刷类型 - 修复方法名使用正确的setBrushType方法
this.brushManager.setBrushType("pencil");
}
// 更新应用到画布
this.brushManager.updateBrush();
}
@@ -222,9 +226,10 @@ export class ToolManager {
if (!this.canvasManager.canvas) return;
// 确保有笔刷管理器
if (this.brushManager) {
const brushStore = this.brushManager?.brushStore
if (brushStore) {
this.brushManager.createEraser();
this.brushManager.setBrushSize(5);
this.brushManager.setBrushSize(brushStore.state.size);
}
this.stateManager.layerManager.setAllObjectsErasable(false)

View File

@@ -3,13 +3,13 @@ import { reactive, readonly } from "vue";
class texturePresetManager { }
export class BrushState {
constructor(options) {
constructor(options = {}) {
this.state = reactive({
// 笔刷基础属性
size: 5, // 笔刷大小
color: "#000000", // 笔刷颜色
opacity: 1, // 笔刷透明度
type: "pencil", // 当前笔刷类型
size: options.size || 5, // 笔刷大小
color: options.color || "#000000", // 笔刷颜色
opacity: options.opacity || 1, // 笔刷透明度
type: options.type || "pencil", // 当前笔刷类型
// 阴影相关属性
shadowEnabled: false, // 是否启用阴影

View File

@@ -21,6 +21,8 @@ import { EraserStateManager } from "../EraserStateManager.js";
import { SprayBrush } from "./types/SprayBrush";
// import { SketchyBrush } from "./types/SketchyBrush";
// import { SpraypaintBrush } from "./types/SpraypaintBrush";
import { OperationType } from '../../tools/layerHelper'
/**
* 笔刷管理器
@@ -37,7 +39,17 @@ export class BrushManager {
*/
constructor(options = {}) {
this.canvas = options.canvas;
this.brushStore = new BrushState();
this.brushStoreList = {
[OperationType.DRAW]: new BrushState(),
[OperationType.ERASER]: new BrushState(),
[OperationType.AISELECT_DRAW]: new BrushState({
color: "rgb(255, 0, 0)",
opacity: 0.5,
}),
[OperationType.AISELECT_ERASER]: new BrushState(),
}
this.brushStore = this.brushStoreList[OperationType.DRAW];
this.layerManager = options.layerManager; // 添加图层管理器引用
this.brushIndicator = options.brushIndicator; // 添加笔刷指示器引用
// this.t = options.t
@@ -55,7 +67,15 @@ export class BrushManager {
this.isErasingActive = false;
this.currentErasedObjects = []; // 当前擦除会话中被影响的对象
}
/**
* 切换工具时,更新当前活动笔刷
* @param {string} toolName 当前工具名称
*/
handleToolChange(toolName) {
const store = this.brushStoreList[toolName];
if (!store) return;
this.brushStore = store;
}
/**
* 注册默认笔刷
* @private

View File

@@ -11,7 +11,6 @@ export class KeyEventManager {
/** 处理键盘事件 */
_handleKeyDown: any
handleKeyDown(event: any) {
event.preventDefault()
const activeID = this.stateManager.layerManager.activeID.value
const ctrl = event.ctrlKey ? 'ctrl-' : "";
const shift = event.shiftKey ? 'shift-' : "";
@@ -24,6 +23,7 @@ export class KeyEventManager {
{ key: "ctrl-s", handler: () => this.onWorkbench() },
{ key: "ctrl-shift-z", handler: () => this.stateManager.redoState() },
]
if (list.some((v) => reg.test(v.key))) event.preventDefault()
list.forEach((v: any) => {
if (reg.test(v.key)) v.handler(event)
})