import { fabric } from 'fabric-with-all' import { ref } from 'vue' import { createCanvas } from '../tools/canvasFactory' import { AnimationManager } from './AnimationManager' import { detectDeviceType } from '../tools/index' import { CanvasEventManager } from "./events/CanvasEventManager"; import { OperationType } from '../tools/layerHelper' interface CanvasInitOptions { canvasRef: any canvasViewWidth?: number canvasViewHeight?: number canvasWidth?: number canvasHeight?: number } export class CanvasManager { stateManager: any layerManager: any animationManager: any eventManager: any deviceInfo: any canvas: any canvasViewWidth: number canvasViewHeight: number canvasWidth: number canvasHeight: number currentZoom: any constructor(options) { this.stateManager = options.stateManager; this.deviceInfo = detectDeviceType(); this.currentZoom = ref(100) } setCanvasViewSize(options) { this.canvasViewWidth = options.canvasViewWidth || 1920 this.canvasViewHeight = options.canvasViewHeight || 1080 } initCanvas(options: CanvasInitOptions) { this.layerManager = this.stateManager.layerManager this.setCanvasViewSize(options) this.canvasWidth = options.canvasWidth || 750 this.canvasHeight = options.canvasHeight || 600 this.canvas = createCanvas(options.canvasRef.value, { width: this.canvasViewWidth, height: this.canvasViewHeight, preserveObjectStacking: true, enableRetinaScaling: true, stopContextMenu: true, fireRightClick: true, backgroundColor: '#fff', }) this.canvas.clipPath = new fabric.Rect({ left: 0, top: 0, width: this.canvasWidth, height: this.canvasHeight }) // 画布居中 const canvasX = this.canvasViewWidth / 2 - this.canvasWidth / 2 const canvasY = this.canvasViewHeight / 2 - this.canvasHeight / 2 this.canvas.viewportTransform = [1, 0, 0, 1, canvasX, canvasY] // 动画管理器 this.animationManager = new AnimationManager(this.canvas, { currentZoom: this.currentZoom, canvasManager: this, wheelThrottleTime: 15, // 降低滚轮事件节流时间,提高响应性 defaultEase: "power2.lin", defaultDuration: 0.3, // 缩短默认动画时间 }); this.setupCanvasEvents() this.setupBrushEvents() this.stateManager.toolManager.setTool(OperationType.SELECT) // 创建矩形 const rect = this.layerManager.createRectLayer({ left: 400, top: 100, }) //创建圆形 const circle = this.layerManager.createCircleLayer({ left: 200, top: 200, }) // 文字 const text = this.layerManager.createTextLayer('Hello World'); this.layerManager.updateLayers() this.layerManager.setActiveID(text.info.id) this.stateManager.recordState() } /** 画布添加对象 */ add(obj: any, isUpdate = true) { this.canvas.add(obj) if (isUpdate) { this.layerManager.updateLayers() this.renderAll() } } /** 设置画布事件 */ setupCanvasEvents() { // 创建画布事件管理器 this.eventManager = new CanvasEventManager(this.canvas, { canvasManager: this, animationManager: this.animationManager, toolManager: this.stateManager.toolManager, layerManager: this.stateManager.layerManager, stateManager: this.stateManager, }); // 设置动画交互效果 this.animationManager.setupInteractionAnimations(); } /** 设置激活对象 */ setActiveObjectByID(id: string) { const obj = this.getObjectById(id) if (obj) this.canvas.setActiveObject(obj) this.renderAll() } resetZoom() { this.animationManager.resetZoom() } getObjects() { return this.canvas.getObjects() || [] } getObjectById(id: string) { return this.getObjects().find((item: any) => item.info.id === id) } renderAll() { this.canvas.renderAll() } deleteObjectById(id: string) { const object = this.getObjectById(id) if (object) { this.canvas.remove(object) this.layerManager.updateLayers() this.renderAll() } } // 拖拽排序 dragSort(id, newIndex) { this.canvas.moveTo(this.getObjectById(id), newIndex) this.layerManager.updateLayers() this.renderAll() } getBitObjects() { return this.getObjects().map(v => { const object = v.toJSON("info"); return object }) } /** 画笔事件 */ setupBrushEvents() { this.canvas.onBrushImageConverted = async (fabricImage) => { const currentTool = this.stateManager.toolManager.currentTool.value; if (currentTool === OperationType.DRAW) { this.handleDrawImage(fabricImage) } return true }; } /** 处理绘制图像 */ handleDrawImage(fabricImage: fabric.Object) { const activeID = this.stateManager.layerManager.activeID.value const activeLayer = this.getObjectById(activeID) if (activeLayer) { this.layerManager.imageMergeToLayer(activeLayer, fabricImage) } else { const emptyLayer = this.layerManager.createEmptyLayer(); this.layerManager.setActiveID(emptyLayer.info.id, false) this.layerManager.imageMergeToLayer(emptyLayer, fabricImage) } return true } /** 导出画布为JSON */ getCanvasJSON() { const keys = ["top", "left", "width", "height", "scaleX", "scaleY", "info",] const json = this.canvas.toJSON(keys) return JSON.stringify(json) } /** 加载画布JSON */ loadJSON(json: string, callback?: (success: boolean) => void) { let jsonObj = null; try { jsonObj = JSON.parse(json) } catch (error) { console.error('JSON解析错误:', error) } if (!jsonObj) return callback?.(false); this.canvas.loadFromJSON(jsonObj, () => { this.layerManager.updateLayers() this.renderAll() callback?.(true) }) } dispose() { this.animationManager?.dispose() this.eventManager?.dispose() } }