深度画布智能选区

This commit is contained in:
lzp
2026-03-25 11:27:24 +08:00
parent d657ca30ee
commit 2d5c02e191
10 changed files with 371 additions and 163 deletions

View File

@@ -1,6 +1,6 @@
import { fabric } from 'fabric-with-all'
import { OperationType, AI_SELECTBOX_TYPE } from '../tools/layerHelper'
import { getObjectAlphaToCanvas, traceImageContour } from '../tools/canvasMethod'
import { OperationType } from '../tools/layerHelper'
import { getObjectAlphaToCanvas, traceImageContour, cloneObjects } from '../tools/canvasMethod'
/** 智能框选工具管理器 */
export class AISelectboxToolManager {
@@ -13,7 +13,17 @@ export class AISelectboxToolManager {
isDragging: boolean = false
startX: number = 0
startY: number = 0
demoObject: any
indicatorObject: any// 指示框对象
demoObject: any// 演示框对象
tcanvas: any// 临时画布对象
tools = [
OperationType.AISELECT_ADD,
OperationType.AISELECT_REMOVE,
OperationType.AISELECT_DRAW,
OperationType.AISELECT_ERASER
]
constructor(options) {
this.canvasManager = options.canvasManager
this.stateManager = options.stateManager
@@ -22,17 +32,56 @@ export class AISelectboxToolManager {
}
/** 处理切换工具 */
handleToolChange(oldTool: string, newTool: string) {
if (newTool === OperationType.SELECTBOX) {
// 切换到智能框选工具
} else {
// 切换到普通框选工具
const oldIsAAA = this.tools.includes(oldTool)
const newIsAAA = this.tools.includes(newTool)
if (!oldIsAAA && newIsAAA) {
// 普通工具切换到智能框选工具
this.init()
} else if (oldIsAAA && !newIsAAA) {
// 智能框选工具切换到普通工具
this.clear()
}
}
mouseDownEvent(e) {
this.isDragging = true
this.startX = e.absolutePointer.x
this.startY = e.absolutePointer.y
/** 切换到橡皮擦工具 */
changeToolToEraser() {
if (!this.demoObject) return;
this.demoObject.set({ erasable: true })
}
init() {
console.log("初始化智能框选工具")
this.clear();
this.createDemoObject()
this.tcanvas = null;
}
clear() {
console.log("清除智能框选工具")
this.clearDemoObject()
this.clearIndicatorObject()
this.isDragging = false
this.canvasManager.canvas.renderAll()
}
createDemoObject() {
if (this.demoObject) this.clearDemoObject()
const { canvasWidth, canvasHeight } = this.canvasManager.getCanvasSize();
const canvas = document.createElement('canvas')
canvas.width = canvasWidth
canvas.height = canvasHeight
this.demoObject = new fabric.Image(canvas, {
left: 0,
top: 0,
evented: false,
selectable: false,
erasable: false,
})
this.canvasManager.canvas.add(this.demoObject)
this.canvasManager.canvas.renderAll()
}
clearDemoObject() {
this.canvasManager.canvas.remove(this.demoObject)
this.demoObject = null
}
createIndicatorObject() {
const rect = new fabric.Rect({
left: this.startX,
top: this.startY,
@@ -43,10 +92,44 @@ export class AISelectboxToolManager {
strokeWidth: 1,
evented: false,
})
this.demoObject = rect
this.indicatorObject = rect
this.canvasManager.canvas.add(rect)
this.canvasManager.canvas.renderAll()
}
clearIndicatorObject() {
this.canvasManager.canvas.remove(this.indicatorObject)
this.indicatorObject = null
}
// 处理画笔绘制图像
async handleBrushDrawImage(fabricImage: fabric.Object) {
if (!this.demoObject) return;
const tcanvas = new fabric.StaticCanvas(document.createElement("canvas"), {
width: this.demoObject.width,
height: this.demoObject.height,
enableRetinaScaling: false,
});
const demoObject = await cloneObjects([this.demoObject]).then(v => v[0])
tcanvas.add(demoObject)
tcanvas.add(fabricImage)
tcanvas.renderAll();
const canvas = getObjectAlphaToCanvas(tcanvas, null, 0, this.rgba);
const image = new fabric.Image(canvas);
this.canvasManager.canvas.add(image)
this.canvasManager.canvas.remove(this.demoObject);
this.demoObject = image;
this.canvasManager.canvas.renderAll()
}
mouseDownEvent(e) {
// if (true) return
const tool = this.toolManager.currentTool.value
const tools = [OperationType.AISELECT_ADD, OperationType.AISELECT_REMOVE]
if (!tools.includes(tool)) return;
this.isDragging = true
this.startX = e.absolutePointer.x
this.startY = e.absolutePointer.y
this.createIndicatorObject()
}
mouseMoveEvent(e) {
if (!this.isDragging) return;
var width = e.absolutePointer.x - this.startX
@@ -61,25 +144,23 @@ export class AISelectboxToolManager {
top += height
height = -height
}
this.demoObject.set({ width, height, left, top })
this.indicatorObject.set({ width, height, left, top })
this.canvasManager.canvas.renderAll()
}
mouseUpEvent(e) {
if (!this.isDragging) return;
this.isDragging = false;
const object = this.demoObject.toJSON("evented")
const object = this.indicatorObject.toJSON("evented")
if (object.width === 0) object.width = 100
if (object.height === 0) object.height = 100
// console.log(object)
this.canvasManager.canvas.remove(this.demoObject)
console.log(object.top, object.left, object.width, object.height)
this.clearIndicatorObject()
this.canvasManager.canvas.renderAll()
// this.createSelectbox()
}
loadImageToObject(url) {
return new Promise((resolve, reject) => {
fabric.Image.fromURL(url, (img) => {
@@ -87,7 +168,7 @@ export class AISelectboxToolManager {
}, { crossOrigin: "anonymous" });// 防止污染
});
}
rgba = { r: 0, g: 255, b: 0, a: 200 };
rgba = { r: 255, g: 0, b: 0, a: 127.5 };
selectionStyle = {
stroke: "rgba(255, 77, 71, 1)",
strokeWidth: 1.5,
@@ -99,12 +180,12 @@ export class AISelectboxToolManager {
absolutePositioned: true,
};
async createSelectbox() {
const url = "http://118.31.39.42:3000/falls/1a48ed3a-1faa-4fcd-bf07-765dba1702c5.png"
const image = await this.loadImageToObject(url)
const canvas = getObjectAlphaToCanvas(image, null, 0, this.rgba);
const fobject = this.canvasManager.canvas.clipPath
// const top = fobject.top - fobject.height * scaleY / 2;
// const left = fobject.left - fobject.width * scaleX / 2;
// const url = "http://118.31.39.42:3000/falls/1a48ed3a-1faa-4fcd-bf07-765dba1702c5.png"
// const image = await this.loadImageToObject(url)
// const fobject = this.canvasManager.canvas.clipPath
const fobject = this.demoObject
this.clearDemoObject()
const canvas = getObjectAlphaToCanvas(fobject, null, 0, { r: 255, g: 0, b: 0, a: 255 });
const scaleY = fobject.scaleY
const scaleX = fobject.scaleX
const top = fobject.top
@@ -127,6 +208,8 @@ export class AISelectboxToolManager {
});
const group = await this.layerManager.createGroupLayer({
clipPath: path,
top: path.top,
left: path.left,
}, false, false)
const rect = await this.layerManager.createRectLayer({
width: path.width,
@@ -145,5 +228,7 @@ export class AISelectboxToolManager {
dispose() { }
dispose() {
this.clear()
}
}