Files
FiDA_Front/src/components/Canvas/DepthCanvas/manager/LayerManager.ts

236 lines
6.4 KiB
TypeScript
Raw Normal View History

2026-03-09 16:45:30 +08:00
import { ref } from 'vue'
2026-03-11 15:34:56 +08:00
import { fabric } from 'fabric-with-all'
import { createId } from '../../tools/tools'
2026-03-13 11:18:36 +08:00
import { exportObjectsToImage, exportObjectToThumbnail } from '../tools/exportMethod'
2026-03-12 15:51:18 +08:00
import { OperationType } from '../tools/layerHelper'
2026-03-09 16:45:30 +08:00
export class LayerManager {
stateManager: any
canvasManager: any
layers: any
activeID: any
constructor(options) {
this.stateManager = options.stateManager;
this.canvasManager = options.canvasManager;
this.layers = ref([])
this.activeID = ref("")
}
2026-03-11 15:34:56 +08:00
setActiveID(id: string, isActive = true) {
this.activeID.value = id
if (isActive) {
2026-03-13 11:18:36 +08:00
this.canvasManager.setActiveObjectById(id)
2026-03-12 15:51:18 +08:00
this.stateManager.toolManager.setTool(OperationType.SELECT)
2026-03-11 15:34:56 +08:00
}
}
2026-03-13 17:31:47 +08:00
getActiveLayer() {
return this.getLayerById(this.activeID.value)
}
2026-03-13 11:18:36 +08:00
getLayerById(id) {
2026-03-09 16:45:30 +08:00
return this.layers.value.find((item: any) => item.info.id === id)
}
2026-03-13 11:18:36 +08:00
setLayerNameById(id, name: string) {
const layer = this.getLayerById(id)
2026-03-09 16:45:30 +08:00
if (layer) {
layer.info.name = name
2026-03-13 14:08:40 +08:00
}
const object = this.canvasManager.getObjectById(id)
if (object) {
object.info.name = name
2026-03-09 16:45:30 +08:00
this.canvasManager.renderAll()
}
}
2026-03-13 11:18:36 +08:00
setLayerVisibleById(id, visible: boolean) {
const layer = this.getLayerById(id)
2026-03-09 16:45:30 +08:00
if (layer) {
2026-03-13 14:08:40 +08:00
layer.visible = visible
}
const object = this.canvasManager.getObjectById(id)
if (object) {
object.set({
2026-03-09 16:45:30 +08:00
visible: visible
})
this.canvasManager.renderAll()
}
}
2026-03-13 11:18:36 +08:00
deleteLayerById(id, isActive = true) {
2026-03-09 16:45:30 +08:00
this.canvasManager.deleteObjectById(id)
2026-03-11 15:34:56 +08:00
if (id === this.activeID.value && isActive) {
this.setActiveID(this.layers.value[0]?.info?.id || "")
}
2026-03-13 14:08:40 +08:00
if (isActive) this.stateManager.recordState()
2026-03-09 16:45:30 +08:00
}
// 拖拽排序
dragSort(id, newIndex) {
const index = Math.abs(this.layers.value.length - newIndex - 1)
this.canvasManager.dragSort(id, index)
}
// 更新图层列表
updateLayers() {
2026-03-13 11:18:36 +08:00
this.layers.value = this.canvasManager.getObjects()
.filter((v: any) => !!v?.info?.id)
.reverse()
.map(v => v.toObject())
2026-03-11 15:34:56 +08:00
}
/** 设置图层位置-不设置默认居中 */
2026-03-13 14:08:40 +08:00
setLayerPosition(object, options?: any) {
2026-03-11 15:34:56 +08:00
const width = this.canvasManager.canvasWidth
const height = this.canvasManager.canvasHeight
if (options && options.top !== undefined) {
2026-03-13 14:08:40 +08:00
object.set({ top: options.top })
2026-03-11 15:34:56 +08:00
} else {
2026-03-13 14:08:40 +08:00
object.set({ top: height / 2 - object.height * object.scaleY / 2 })
2026-03-11 15:34:56 +08:00
}
if (options && options.left !== undefined) {
2026-03-13 14:08:40 +08:00
object.set({ left: options.left })
2026-03-11 15:34:56 +08:00
} else {
2026-03-13 14:08:40 +08:00
object.set({ left: width / 2 - object.width * object.scaleX / 2 })
2026-03-11 15:34:56 +08:00
}
}
/** 创建空图层 */
2026-03-13 14:08:40 +08:00
createEmptyLayer(isUpdate = true) {
const emptyObject = new fabric.Rect({
2026-03-11 15:34:56 +08:00
width: 0,
height: 0,
fill: 'transparent',
info: {
id: createId("image"),
name: '空图层',
}
})
2026-03-13 14:08:40 +08:00
this.setLayerPosition(emptyObject)
this.canvasManager.add(emptyObject, isUpdate)
return emptyObject
2026-03-11 15:34:56 +08:00
}
/** 创建文本图层 */
2026-03-13 14:08:40 +08:00
async createTextLayer(text: string, options?: any) {
const textObject = new fabric.IText(text, {
2026-03-11 15:34:56 +08:00
fontSize: 24,
fill: '#000',
...(options || {}),
info: {
id: createId("text"),
name: '文本图层',
...(options?.info || {}),
}
})
2026-03-13 14:08:40 +08:00
this.setLayerPosition(textObject, options)
await this.canvasManager.add(textObject)
return textObject
2026-03-11 15:34:56 +08:00
}
/** 创建矩形图层 */
2026-03-13 14:08:40 +08:00
async createRectLayer(options?: any, isActive = false) {
const rectObject = new fabric.Rect({
2026-03-11 15:34:56 +08:00
width: 100,
height: 100,
fill: '#000',
...(options || {}),
info: {
id: createId("rect"),
name: '矩形图层',
...(options?.info || {}),
}
})
2026-03-13 14:08:40 +08:00
this.setLayerPosition(rectObject, options)
await this.canvasManager.add(rectObject)
if (isActive) this.setActiveID(rectObject.info.id)
return rectObject
2026-03-11 15:34:56 +08:00
}
/** 创建圆形图层 */
2026-03-13 14:08:40 +08:00
async createCircleLayer(options?: any, isActive = false) {
const circleObject = new fabric.Circle({
2026-03-11 15:34:56 +08:00
radius: 50,
fill: '#000',
...(options || {}),
info: {
id: createId("circle"),
name: '圆形图层',
...(options?.info || {}),
}
})
2026-03-13 14:08:40 +08:00
this.setLayerPosition(circleObject, options)
await this.canvasManager.add(circleObject)
if (isActive) this.setActiveID(circleObject.info.id)
return circleObject
2026-03-11 15:34:56 +08:00
}
/** 创建图片图层 */
async createImageLayer(imgOrUrl: string | HTMLImageElement, options?: any) {
const canvasWidth = this.canvasManager.canvasWidth
const canvasHeight = this.canvasManager.canvasHeight
2026-03-13 14:08:40 +08:00
const imageObject = await new Promise((resolve) => {
2026-03-11 15:34:56 +08:00
const url = typeof imgOrUrl === 'string' ? imgOrUrl : imgOrUrl.src
fabric.Image.fromURL(url, (img) => {
const width = img.width
const height = img.height
const scaleX = width > canvasWidth ? canvasWidth * 0.8 / width : 1
const scaleY = height > canvasHeight ? canvasHeight * 0.8 / height : 1
const scale = Math.min(scaleX, scaleY)
img.set({
scaleX: scale,
scaleY: scale,
...(options || {}),
info: {
id: createId("image"),
name: "图片图层",
...(options?.info || {}),
}
})
resolve(img)
})
}) as fabric.Object
2026-03-13 14:08:40 +08:00
this.setLayerPosition(imageObject, options)
await this.canvasManager.add(imageObject)
this.setActiveID(imageObject.info.id)
return imageObject
2026-03-11 15:34:56 +08:00
}
/** 合并图层 */
async imageMergeToLayer(targetLayer: fabric.Object, fabricImage: fabric.Object) {
const info = await exportObjectsToImage([targetLayer, fabricImage], true)
const mergedImage = await new Promise((resolve) => {
fabric.Image.fromURL(info.url, (img) => {
img.set({
left: info.left,
top: info.top,
info: {
id: createId("image"),
name: targetLayer?.info?.name || "合并图层",
}
})
resolve(img)
})
})
// console.log(mergedImage)
const index = this.canvasManager.getObjects().indexOf(targetLayer);
2026-03-13 11:18:36 +08:00
this.deleteLayerById(targetLayer.info.id, false)
2026-03-11 15:34:56 +08:00
this.setActiveID(mergedImage.info.id, false)
2026-03-13 14:08:40 +08:00
await this.canvasManager.add(mergedImage);
2026-03-11 15:34:56 +08:00
this.canvasManager.canvas.moveTo(mergedImage, index);
this.canvasManager.renderAll()
this.updateLayers()
return true;
}
/** 设置激活对象可擦除 */
setActiveObjectErasable() {
const objects = this.canvasManager.getObjects()
objects.forEach((item: any) => {
item.set({
erasable: item.info.id === this.activeID.value
})
})
2026-03-09 16:45:30 +08:00
}
2026-03-13 11:18:36 +08:00
/** 更新图层缩略图 */
async updateLayerThumbnailsById(id: string) {
const object = this.canvasManager.getObjectById(id);
if (!object) return;
const url = await exportObjectToThumbnail(object);
2026-03-13 14:08:40 +08:00
object.thumbnail = url
2026-03-13 11:18:36 +08:00
this.updateLayers()
}
2026-03-12 15:51:18 +08:00
dispose() { }
2026-03-11 15:34:56 +08:00
}