深度画布智能选区

This commit is contained in:
lzp
2026-03-23 16:43:08 +08:00
parent 73845df594
commit eccc00dc53
10 changed files with 532 additions and 374 deletions

View File

@@ -28,7 +28,18 @@ export class LayerManager {
return this.getLayerById(this.activeID.value)
}
getLayerById(id) {
return this.layers.value.find((item: any) => item.info.id === id)
function call(arr) {
for (let i = 0; i < arr.length; i++) {
let v = arr[i]
if (v.info.id === id) return v
if (v.children) {
let layer = call(v.children)
if (layer) return layer
}
}
return null
}
return call(this.layers.value)
}
setLayerNameById(id, name: string) {
const layer = this.getLayerById(id)
@@ -82,6 +93,10 @@ export class LayerManager {
/** 删除指定图层 */
deleteLayerById(id, isActive = true) {
const layer = this.getLayerById(id)
if (layer.children) {
layer.children.forEach(v => this.canvasManager.deleteObjectById(v.info.id, false))
}
this.canvasManager.deleteObjectById(id)
if (id === this.activeID.value && isActive) {
this.setActiveID(this.layers.value[0]?.info?.id || "")
@@ -106,17 +121,38 @@ export class LayerManager {
this.setActiveID(newObject.info.id)
})
}
// 拖拽排序
dragSort(id, newIndex) {
const index = Math.abs(this.layers.value.length - newIndex - 1)
this.canvasManager.dragSort(id, index)
/** 根据layers排序图层 */
async sortLayers(isRecord?: boolean) {
const ids = [];
call(this.layers.value)
await this.canvasManager.sortObjectByIds(ids.reverse(), isRecord)
function call(arr) {
arr.forEach(v => {
ids.push(v.info.id)
if (v.children) call(v.children)
})
}
}
// 更新图层列表
updateLayers() {
this.layers.value = this.canvasManager.getObjects()
.filter((v: any) => !!v?.info?.id)
.reverse()
.map(v => v.toObject())
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()
}
/** 设置图层位置-不设置默认居中 */
@@ -136,7 +172,7 @@ export class LayerManager {
}
}
/** 创建空图层 */
createEmptyLayer(isRecord = true, isActive = false) {
async createEmptyLayer(isRecord = true, isActive = false) {
const emptyObject = new fabric.Rect({
width: 0,
height: 0,
@@ -147,37 +183,28 @@ export class LayerManager {
}
})
this.setLayerPosition(emptyObject)
this.canvasManager.add(emptyObject, isRecord)
await this.canvasManager.add(emptyObject, isRecord)
if (isActive) this.setActiveID(emptyObject.info.id, false)
return emptyObject
}
/** 创建组图层 */
createGroupLayer(options?: any, isRecord = true, isActive = false) {
const child = options?.child || []
delete options.child
const groupObject = new fabric.Group(child, {
// subTargetCheck: true, // 关键:检测子对象
// interactive: true, // 启用交互
// hasControls: true,
// hasBorders: true,
// // 子对象样式
// cornerColor: 'blue',
// cornerSize: 8,
// borderColor: 'green',
// // 允许子对象独立变换
// lockScalingX: false,
// lockScalingY: false,
// lockRotation: false,
async createGroupLayer(options?: any, isRecord = true, isActive = false) {
const children = options?.children || []
delete options.children
const groupObject = new fabric.Group(children, {
...(options || {}),
hasControls: false, // 不显示控制点
hasBorders: false, // 不显示边框
selectable: false, // 不可选中(可选)
info: {
id: createId("group"),
name: '组图层',
showChildren: true,
...(options?.info || {}),
}
})
// this.setLayerPosition(groupObject)
this.canvasManager.add(groupObject, isRecord)
this.setLayerPosition(groupObject, options)
await this.canvasManager.add(groupObject, isRecord)
if (isActive) this.setActiveID(groupObject.info.id, false)
return groupObject
}
@@ -199,7 +226,7 @@ export class LayerManager {
return textObject
}
/** 创建矩形图层 */
async createRectLayer(options?: any, isActive = false) {
async createRectLayer(options?: any, isRecord = true, isActive = true) {
const rectObject = new fabric.Rect({
width: 100,
height: 100,
@@ -213,12 +240,12 @@ export class LayerManager {
}
})
this.setLayerPosition(rectObject, options)
await this.canvasManager.add(rectObject)
await this.canvasManager.add(rectObject, isRecord)
if (isActive) this.setActiveID(rectObject.info.id)
return rectObject
}
/** 创建直线图层 */
async createLineLayer(options?: any, isActive = false) {
async createLineLayer(options?: any, isRecord = true, isActive = true) {
const line = [options?.x1 || 0, options?.y1 || 0, options?.x2 || 100, options?.y2 || 0]
delete options.x1
delete options.y1
@@ -235,14 +262,13 @@ export class LayerManager {
}
})
this.setLayerPosition(lineObject, options)
await this.canvasManager.add(lineObject)
await this.canvasManager.add(lineObject, isRecord)
if (isActive) this.setActiveID(lineObject.info.id)
return lineObject
}
/** 创建椭圆图层 */
async createEllipseLayer(options?: any, isActive = false) {
async createEllipseLayer(options?: any, isRecord = true, isActive = true) {
const ellipseObject = new fabric.Ellipse({
radius: 50,
fill: '#000',
strokeWidth: 0,
...(options || {}),
@@ -258,7 +284,7 @@ export class LayerManager {
return ellipseObject
}
/** 创建三角形图层 */
async createTriangleLayer(options?: any, isActive = false) {
async createTriangleLayer(options?: any, isRecord = true, isActive = true) {
const triangleObject = new fabric.Triangle({
width: 100,
height: 100,
@@ -272,12 +298,12 @@ export class LayerManager {
}
})
this.setLayerPosition(triangleObject, options)
await this.canvasManager.add(triangleObject)
await this.canvasManager.add(triangleObject, isRecord)
if (isActive) this.setActiveID(triangleObject.info.id)
return triangleObject
}
/** 创建五角星图层 */
async createStarLayer(options?: any, isActive = false) {
async createStarLayer(options?: any, isRecord = true, isActive = true) {
const width = options?.width || 100
const height = options?.height || 100
delete options.points
@@ -292,12 +318,12 @@ export class LayerManager {
}
})
this.setLayerPosition(starObject, options)
await this.canvasManager.add(starObject)
await this.canvasManager.add(starObject, isRecord)
if (isActive) this.setActiveID(starObject.info.id)
return starObject
}
/** 创建箭头图层 */
async createArrowLayer(options?: any, isActive = false) {
async createArrowLayer(options?: any, isRecord = true, isActive = true) {
const width = options?.width || 100
const height = options?.height || 10
delete options.width
@@ -316,7 +342,7 @@ export class LayerManager {
}
});
this.setLayerPosition(arrowObject, options)
this.canvasManager.add(arrowObject)
await this.canvasManager.add(arrowObject, isRecord)
if (isActive) this.setActiveID(arrowObject.info.id)
return arrowObject
}
@@ -324,7 +350,7 @@ export class LayerManager {
/** 创建图片图层 */
async createImageLayer(imgOrUrl: string | HTMLImageElement, options?: any, isRecord = true) {
async createImageLayer(imgOrUrl: string | HTMLImageElement, options?: any, isRecord = true, isActive = true) {
const { canvasWidth, canvasHeight } = this.canvasManager.getCanvasSize();
const imageObject = await new Promise((resolve) => {
@@ -350,7 +376,7 @@ export class LayerManager {
}) as fabric.Object
this.setLayerPosition(imageObject, options)
await this.canvasManager.add(imageObject, isRecord)
this.setActiveID(imageObject.info.id)
if (isActive) this.setActiveID(imageObject.info.id)
return imageObject
}
@@ -363,6 +389,7 @@ export class LayerManager {
left: info.left,
top: info.top,
info: {
...(targetLayer?.info || {}),
id: createId("image"),
name: targetLayer?.info?.name || "合并图层",
}
@@ -370,7 +397,6 @@ export class LayerManager {
resolve(img)
}, { crossOrigin: 'anonymous' })
})
// console.log(mergedImage)
const index = this.canvasManager.getObjects().indexOf(targetLayer);
this.deleteLayerById(targetLayer.info.id, false)
this.setActiveID(mergedImage.info.id, false)
@@ -391,12 +417,12 @@ export class LayerManager {
})
}
/** 更新图层缩略图 */
async updateLayerThumbnailsById(id: string) {
async updateLayerThumbnailsById(id: string, thumbnail?: string, isUpdate = true) {
const object = this.canvasManager.getObjectById(id);
if (!object) return;
const url = await exportObjectToThumbnail(object);
const url = thumbnail || await exportObjectToThumbnail(object);
object.thumbnail = url
this.updateLayers()
if (isUpdate) this.updateLayers()
}
dispose() { }