import { ref } from 'vue' import { fabric } from 'fabric-with-all' import { createId } from '../../tools/tools' import { exportObjectsToImage, exportObjectToThumbnail } from '../tools/exportMethod' import { OperationType } from '../tools/layerHelper' 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("") } setActiveID(id: string, isActive = true) { this.activeID.value = id if (isActive) { this.canvasManager.setActiveObjectById(id) this.stateManager.toolManager.setTool(OperationType.SELECT) } } getLayerById(id) { return this.layers.value.find((item: any) => item.info.id === id) } setLayerNameById(id, name: string) { const layer = this.getLayerById(id) if (layer) { layer.info.name = name } const object = this.canvasManager.getObjectById(id) if (object) { object.info.name = name this.canvasManager.renderAll() } } setLayerVisibleById(id, visible: boolean) { const layer = this.getLayerById(id) if (layer) { layer.visible = visible } const object = this.canvasManager.getObjectById(id) if (object) { object.set({ visible: visible }) this.canvasManager.renderAll() } } deleteLayerById(id, isActive = true) { this.canvasManager.deleteObjectById(id) if (id === this.activeID.value && isActive) { this.setActiveID(this.layers.value[0]?.info?.id || "") } if (isActive) this.stateManager.recordState() } // 拖拽排序 dragSort(id, newIndex) { const index = Math.abs(this.layers.value.length - newIndex - 1) this.canvasManager.dragSort(id, index) } // 更新图层列表 updateLayers() { this.layers.value = this.canvasManager.getObjects() .filter((v: any) => !!v?.info?.id) .reverse() .map(v => v.toObject()) } /** 设置图层位置-不设置默认居中 */ setLayerPosition(object, options?: any) { const width = this.canvasManager.canvasWidth const height = this.canvasManager.canvasHeight if (options && options.top !== undefined) { object.set({ top: options.top }) } else { object.set({ top: height / 2 - object.height * object.scaleY / 2 }) } if (options && options.left !== undefined) { object.set({ left: options.left }) } else { object.set({ left: width / 2 - object.width * object.scaleX / 2 }) } } /** 创建空图层 */ createEmptyLayer(isUpdate = true) { const emptyObject = new fabric.Rect({ width: 0, height: 0, fill: 'transparent', info: { id: createId("image"), name: '空图层', } }) this.setLayerPosition(emptyObject) this.canvasManager.add(emptyObject, isUpdate) return emptyObject } /** 创建文本图层 */ async createTextLayer(text: string, options?: any) { const textObject = new fabric.IText(text, { fontSize: 24, fill: '#000', ...(options || {}), info: { id: createId("text"), name: '文本图层', ...(options?.info || {}), } }) this.setLayerPosition(textObject, options) await this.canvasManager.add(textObject) return textObject } /** 创建矩形图层 */ async createRectLayer(options?: any, isActive = false) { const rectObject = new fabric.Rect({ width: 100, height: 100, fill: '#000', ...(options || {}), info: { id: createId("rect"), name: '矩形图层', ...(options?.info || {}), } }) this.setLayerPosition(rectObject, options) await this.canvasManager.add(rectObject) if (isActive) this.setActiveID(rectObject.info.id) return rectObject } /** 创建圆形图层 */ async createCircleLayer(options?: any, isActive = false) { const circleObject = new fabric.Circle({ radius: 50, fill: '#000', ...(options || {}), info: { id: createId("circle"), name: '圆形图层', ...(options?.info || {}), } }) this.setLayerPosition(circleObject, options) await this.canvasManager.add(circleObject) if (isActive) this.setActiveID(circleObject.info.id) return circleObject } /** 创建图片图层 */ async createImageLayer(imgOrUrl: string | HTMLImageElement, options?: any) { const canvasWidth = this.canvasManager.canvasWidth const canvasHeight = this.canvasManager.canvasHeight const imageObject = await new Promise((resolve) => { 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 this.setLayerPosition(imageObject, options) await this.canvasManager.add(imageObject) this.setActiveID(imageObject.info.id) return imageObject } /** 合并图层 */ 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); this.deleteLayerById(targetLayer.info.id, false) this.setActiveID(mergedImage.info.id, false) await this.canvasManager.add(mergedImage); 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 }) }) } /** 更新图层缩略图 */ async updateLayerThumbnailsById(id: string) { const object = this.canvasManager.getObjectById(id); if (!object) return; const url = await exportObjectToThumbnail(object); object.thumbnail = url this.updateLayers() } dispose() { } }