import { exportSele, JSRectUpdata, JSchangeType, JScanvasMouseDown, JScanvasMouseMove, JScreateCheck, JSSetTexture, JSSetRemoveImage, } from "@/tool/canvasDrawingCopy"; import { getMousePosition } from "@/tool/mdEvent"; import { getMinioUrl } from "@/tool/util"; import { file } from "jszip"; class MyCanvas { constructor(id) { this.id = id || Date.now(); this.pencilList = { textFontFamilyList:[ { value: 'Arial', name: 'select font' }, { value: 'EN_slogan_art1', name: 'select font' }, { value: 'EN_slogan_art2', name: 'select font' }, { value: 'EN_slogan_art3', name: 'select font' }, { value: 'EN_slogan_art4', name: 'select font' }, { value: 'EN_slogan_art5', name: 'select font' }, { value: 'EN_slogan_art6', name: 'select font' }, { value: 'EN_slogan_art7', name: 'select font' }, { value: '微软雅黑', name: '请选择字体' }, { value: 'CN_slogan_art1', name: '请选择字体' }, { value: 'CN_slogan_art2', name: '请选择字体' }, { value: 'CN_slogan_art3', name: '请选择字体' }, { value: 'CN_slogan_art4', name: '请选择字体' }, { value: '华文行楷', name: '请选择字体' }, { value: '隶书', name: '请选择字体' }, ], brushList:[ { value:'PencilBrush', url:'/image/brush/PencilBrush.jpg' },{ value:'Marking', url:'/image/brush/PencilBrush-2.jpg' },{ value:'InkBrush', url:'/image/brush/InkBrush.jpg' },{ value:'CrayonBrush', url:'/image/brush/CrayonBrush.jpg' },{ value:'RibbonBrush', url:'/image/brush/RibbonBrush.jpg' },{ value:'MarkerBrush', url:'/image/brush/MarkerBrush.jpg' },{ value:'WritingBrush', url:'/image/brush/WritingBrush.jpg' },{ value:'LongfurBrush', url:'/image/brush/LongfurBrush.jpg' },{ value:'SpraypaintBrush', url:'/image/brush/SpraypaintBrush.jpg' }, ] } this.canvasDomParent = null; this.canvas = MyCanvas?.[this.id]; this.addPresent = {} this.canvasWH={ width:0, height:0, layerWidth:0, layerHeight:0, } this.createPatterning = {//创建图形 state:false, content:null, current:null, //临时图形 polyLineBtn:null, textDataShow:false, } this.mouse = { point:null, upPoint:null, isMovePostion:false, isDown:false, lastPosX:0, lastPosY:0, } this.keyboard={ down:[] } this.pencilbtnStyle ={//笔触图形 background:'', width:0+'px', height:0+'px', display:'none', left:0+'px', top:0+'px', } this.layer = { list:[], selectLayer:{ group:null, id:-1, }, currentIndex:0, } this.liquefaction = { img:null, type:'', dashed:null, } this.clipPath = { isImg:false, img:null, clipGroup:null } this.dashed = { state:false,//用来判断鼠标是否移入dashed 如果移入就变为可拖拽 isDrawingMode:false,//用来获取移入前是否是绘画模式 isDetail:false,//判断裁剪或者局部添加内容,为true是添加内容 isDashedShow:false,//判断选区是否存在 } this.currentOperation = true //表示是否可以使用快捷键 this.fontFamily = this.pencilList.textFontFamilyList[0].value this.createText=null this.pencilBtn = null; this.pencilType = null; this.canvasPencilColor = '#000000' this.colorHistoryList = ['rgb(0, 0, 0)'] this.keyDown = [];//键盘按下 this.oldOperation = '' //笔触 this.brushwork = { value:'PencilBrush', width:{}, color:'#000000', texture:0, } this.texture={ value:0, list:[], } this.exportData = { width:-1, } for (let index = 0; index < 20; index++) { this.texture.list.push({value:index,url:`/image/texture/texture${index}.webp`}) } this._clipboard = null; //剪切板 this.isLoadCanvas = false//撤回或者反撤回false为撤回 this.reverseCanvasState=[];//撤回 this.normalCanvasState=[];//反撤回 this.canvasState = {}//当前内容 this.operation = 'movePosition' this.operationMode = 'fill' this.setTimeOut = {//定时器 color:null, width:null, colorHistory:null, canvasWH:null, updataLayer:null, }//给切换颜色设置防抖 } async createCanvas(dom,val,exportWidth = -1){ this.exportData.width = exportWidth this.canvasWH={ width:val.width, height:val.height, layerWidth:val.width, layerHeight:val.height, } this.canvasDomParent = dom; var canvasDom = document.createElement("canvas"); this.canvasDomParent.appendChild(canvasDom); MyCanvas[this.id] = await new fabric.Canvas(canvasDom, { backgroundColor: "rgba(230, 230, 230)", width: this.canvasWH.width, height: this.canvasWH.height, isDrawingMode: val.isDrawingMode, // 开启绘图模式 selectionFullyContained: true, selectionKey:'ctrlKey', includeDefaultValues: false,//尚未测试 精简导出JSON // freeDrawingCursor: 'none', preserveObjectStacking:true, hoverCursor: 'pointer', }); this.initCanvasWH('init') fabric.Object.prototype.cornerSize = 10//选中后的操作按钮大小 fabric.Object.prototype.transparentCorners = false //实心 if(!fabric.Object.prototype.controls.deleteControl){//设置元素删除 JSSetRemoveImage(this.deleteObject.bind(this)) }else{ fabric.Object.prototype.controls.deleteControl.mouseUpHandler = this.deleteObject.bind(this) } initAligningGuidelines(MyCanvas?.[this.id], true); JSchangeType(MyCanvas?.[this.id],'init') this.canvas = MyCanvas?.[this.id]; // console.log(this.layer) return MyCanvas?.[this.id] } addEvent(){ MyCanvas?.[this.id].on("object:modified", (event)=>{ this.updateCanvasState('') this.updataLayer() }); this.canvasKeyDown = this.canvasKeyDown.bind(this); this.canvasKeyUp = this.canvasKeyUp.bind(this); MyCanvas?.[this.id].on("mouse:move", this.setCanvasMove.bind(this)); MyCanvas?.[this.id].on("mouse:down",this.setCanvasDown.bind(this)); MyCanvas?.[this.id].on("mouse:up",this.setCanvasUp.bind(this)); MyCanvas?.[this.id].on("mouse:wheel",this.setCanvasWheel.bind(this)); //双击 MyCanvas?.[this.id].on("mouse:dblclick", event=>{ if(this.operation == 'fold'){ this.foldEnd('Enter') } }); document.addEventListener('mousemove', this.mouseMove.bind(this)); document.addEventListener('touchmove', this.touchmove.bind(this)); document.addEventListener("keydown", this.canvasKeyDown); document.addEventListener("keyup", this.canvasKeyUp); MyCanvas?.[this.id].on("object:added", this.addLayer.bind(this)); } async canvasInit (dom, val,img,editGroupImg,data,exportWidth = -1){//初始化 // let {erasable} = data // this.canvasClear() this.exportData.width = exportWidth this.canvasWH={ width:val.width, height:val.height, layerWidth:val.width, layerHeight:val.height, } this.canvasDomParent = dom; var canvasDom = document.createElement("canvas"); this.canvasDomParent.appendChild(canvasDom); MyCanvas[this.id] = await new fabric.Canvas(canvasDom, { backgroundColor: "rgba(230, 230, 230)", width: this.canvasWH.width, height: this.canvasWH.height, isDrawingMode: val.isDrawingMode, // 开启绘图模式 selectionFullyContained: true, selectionKey:'ctrlKey', includeDefaultValues: false,//尚未测试 精简导出JSON // freeDrawingCursor: 'none', preserveObjectStacking:true, hoverCursor: 'pointer', }); // await new Promise((resolve, reject) => { // canvas.clone(cloned=>{ // cloned.set({ // }) // this.canvas = cloned // resolve() // }) // }) // MyCanvas?.[this.id].freeDrawingCursor= 'none' // let imgage = await this.createImage({minioUrl:img}) // let rect1 = new fabric.Rect({ // left: 0, // top: 0, // width: 500, // height: 500, // fill: "red", // }); // canvas.add(rect1) this.initCanvasWH('init') fabric.Object.prototype.cornerSize = 10//选中后的操作按钮大小 fabric.Object.prototype.transparentCorners = false //实心 if(!fabric.Object.prototype.controls.deleteControl){//设置元素删除 JSSetRemoveImage(this.deleteObject.bind(this)) }else{ fabric.Object.prototype.controls.deleteControl.mouseUpHandler = this.deleteObject.bind(this) } MyCanvas?.[this.id].on("object:modified", (event)=>{ this.updateCanvasState('') this.updataLayer() }); this.canvasKeyDown = this.canvasKeyDown.bind(this); this.canvasKeyUp = this.canvasKeyUp.bind(this); // let rect1 = new fabric.Rect({ // left: 0, // top: 0, // width: 500, // height: 500, // fill: "red", // }); // MyCanvas?.[this.id].add(rect1) // rect1.on('mouseover', function() { // // rect1.set({ fill: 'green' }); // 鼠标移入时改变颜色为绿色 // // canvas.renderAll(); // 重新渲染画布 // }); // // 为矩形添加 mouseleave 事件 // rect1.on('mouseout', function() { // // rect1.set({ fill: 'blue' }); // 鼠标移出时恢复颜色为蓝色 // // canvas.renderAll(); // 重新渲染画布 // }); // return // rect1.filters.push(new fabric.Image.filters.Grayscale()) // MyCanvas?.[this.id].add(rect1) // // MyCanvas?.[this.id].add(rect1) // let rect = new fabric.Rect({ // left: 0, // top: 0, // width: MyCanvas?.[this.id].width, // height: MyCanvas?.[this.id].height, // inverted:true, // fill: "red", // }); // // let rect2 = new fabric.Rect({ // // width: MyCanvas?.[this.id].width, // // height: MyCanvas?.[this.id].height, // // fill:'#FFF' // // }); // // // MyCanvas?.[this.id].add(rect2) // fabric.Image.fromURL('https://www.minio.aida.com.hk:12024/aida-collection-element/83/Moodboard/7a5fec0f-5a8c-4f1e-80c0-c4cda335d7c5.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=admin%2F20241112%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20241112T060752Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=25c5fa23dc447d1d06b4efeeec23454c797219df9c45d2cec231d0c8372754ce',(img)=>{ // let scale = { // X:MyCanvas?.[this.id].width/img.width, // Y:MyCanvas?.[this.id].height/img.height // } // rect.set({ // fill: new fabric.Pattern({ // source: img.getElement(), // 传入图片元素 // repeat: 'no-repeat' // 设置图片不重复 // }), // clipPath : rect1 // }) // img.set({ // scaleX:scale.X, // scaleY:scale.Y, // left:0, // top:0, // }) // MyCanvas?.[this.id].add(rect) // },{ crossOrigin: "Anonymous" }) // // // MyCanvas?.[this.id].add(rect1) // // // rect1.clipPath = group // // // MyCanvas?.[this.id].forEachObject((item) =>{ // // // if(item.clipPath){ // // // item.clipPath.add(rect2) // // // // item.clipPath = group // // // } // // // }) // return MyCanvas?.[this.id].on("mouse:move", this.setCanvasMove.bind(this)); MyCanvas?.[this.id].on("mouse:down",this.setCanvasDown.bind(this)); MyCanvas?.[this.id].on("mouse:up",this.setCanvasUp.bind(this)); if(!data?.noWheel){ MyCanvas?.[this.id].on("mouse:wheel",this.setCanvasWheel.bind(this)); } //双击 MyCanvas?.[this.id].on("mouse:dblclick", event=>{ if(this.operation == 'fold'){ this.foldEnd('Enter') } }); document.addEventListener('mousemove', this.mouseMove.bind(this)); document.addEventListener('touchmove', this.touchmove.bind(this)); document.addEventListener("keydown", this.canvasKeyDown); document.addEventListener("keyup", this.canvasKeyUp); initAligningGuidelines(MyCanvas?.[this.id], true); JSchangeType(MyCanvas?.[this.id],'init') // await this.createBg() await this.createLayer({str:'init',img:img,noErasable:data?.noErasable || false})//创建图层并且使用 if(img && data.dashedIsDetail){ this.dashed.isDetail = true await this.createLayer({editImg:editGroupImg,noErasable:data?.noErasable || false})//创建图层并且使用 } MyCanvas?.[this.id].on("object:added", this.addLayer.bind(this)); this.canvas = MyCanvas?.[this.id]; return MyCanvas?.[this.id] } initCanvasWH(str){ let scale if(this.canvasWH.width>this.canvasWH.height)scale = this.canvasDomParent.offsetWidth / this.canvasWH.width if(this.canvasWH.width{ if(obj.type != 'group' && !obj.isType('path')){ obj.selectable = false } }); }else if(['dashedPencil', 'dashed'].includes(str)){ this.dashed.isDashedShow = false this.setGroupGrid('all') MyCanvas[this.id].isDrawingMode = false this.pencilbtnStyle.display = `none` this.setCursor('crosshair') MyCanvas[this.id].freeDrawingCursor = 'crosshair' if(str == 'dashedPencil')this.setDashedPencil() MyCanvas?.[this.id].forEachObject((obj) =>{ if(obj.type != 'group' && !obj.isType('path')){ obj.selectable = false } }); }else if(str){ this.pencilbtnStyle.display = `none` this.setCursor('auto'); MyCanvas[this.id].isDrawingMode = false MyCanvas?.[this.id].forEachObject((obj) =>{ if(obj.type != 'group' && !obj.isType('path')){ obj.selectable = false } }); } if(str == 'dashed' || str == 'dashedPencil'){ // if(str == 'dashed' || str == 'dashedPencil' || str != 'movePosition'){ if(this.layer.selectLayer.group.custom.groupType == 'Grid')this.setGroupGrid('all') this.clipPath = { isImg:false, clipGroup:null, img:null, } } } setCursor(str){ MyCanvas[this.id].defaultCursor = str; MyCanvas[this.id].moveCursor = str; MyCanvas[this.id].hoverCursor = str; MyCanvas[this.id].upperCanvasEl.style.cursor = str; } setCanvasMove = (event)=>{ if(this.mouse.isMovePostion && this.operation == 'move') return this.setCanvasPosition(event) if(MyCanvas?.[this.id].isDrawingMode){ }else{ let getActiveObject = MyCanvas?.[this.id].getActiveObject() // console.log(getActiveObject) // console.log(!this.clipPath.isImg , // this.mouse.isDown , // getActiveObject?.custom?.dashed , // this.layer.selectLayer.group.custom?.groupType == 'Grid') if( !this.clipPath.isImg && this.mouse.isDown && getActiveObject && getActiveObject.custom?.dashed && this.layer.selectLayer.group.custom?.groupType == 'Grid' && this.operation == 'movePosition' ){ this.setclipPathImg() } if(this.createPatterning.state){ let str = this.operation if(this.operation == 'dashed')str = 'rect' JScanvasMouseMove(str,event,this.createPatterning.current,this.mouse.point,this.keyboard.down) MyCanvas?.[this.id].requestRenderAll() } } } setCanvasPosition(event){ const e = event; const vpt = MyCanvas?.[this.id].viewportTransform; vpt[4] += e.pointer.x - this.mouse.lastPosX; // 更新水平偏移 vpt[5] += e.pointer.y - this.mouse.lastPosY; // 更新垂直偏移 MyCanvas?.[this.id].requestRenderAll(); // 请求重绘画布 this.mouse.lastPosX = e.pointer.x; this.mouse.lastPosY = e.pointer.y; } // setRemoveDashed(){ // MyCanvas?.[this.id].forEachObject((obj) =>{ // if(obj.custom.dashed && obj._objects){ // let rect = obj._objects.filter(item => item.type == 'rect')[0] // obj.remove(rect) // MyCanvas?.[this.id].renderAll(); // } // }); // } //设置再画布上按下 setCanvasDown(event){ if(event.target && event.target.custom?.dashed && ['dashedPencil', 'dashed'].includes(this.operation) && !this.dashed.isDetail){ // if(MyCanvas?.[this.id].isDrawingMode){ // MyCanvas[this.id].isDrawingMode = false; // } this.dashed.state = true }else if(!event.target?.custom?.dashed){ // if(['dashedPencil'].includes(this.operation)){ // MyCanvas[this.id].isDrawingMode = true; // } this.dashed.state = false } let dashedGroup = MyCanvas?.[this.id].getObjects().filter(obj => obj?.custom?.dashed)[0]; if(this.dashed.state && (this.operation == 'dashed' || this.operation == 'dashedPencil') && dashedGroup)return if(!this.dashed.state && (!event.target?.custom?.dashed || this.dashed.isDetail) && (this.operation == 'dashed' || this.operation == 'dashedPencil') && dashedGroup){ MyCanvas?.[this.id].remove(dashedGroup) } if(this.operation == 'movePosition' && !event?.target?.custom?.dashed && this.layer.selectLayer.group?.custom?.groupType == 'Grid')this.setGroupGrid('all'); //设置移动端按下添加元素 this.mouse.isDown = true this.mouse.lastPosX = event.pointer.x; this.mouse.lastPosY = event.pointer.y; if(this.operation == 'move'){ this.mouse.isMovePostion = true; this.setCursor('grabbing'); return } if(this.operation == 'zoomIn' || this.operation == 'zoomOut'){ this.setCanvasZoom(event) return } // this.setRemoveDashed() if(this.addPresent.upScaleChecked){//创建元素 this.present.upScaleChecked = false this.present = {} let pointerVpt = canvas.restorePointerVpt(event.pointer) switch (currentType.value.type) { case 'colorBoards': let rect = setGroup(currentType.value.data) setCanvasColor(pointerVpt.y, pointerVpt.x,rect) break default : createImage(pointerVpt.y, pointerVpt.x,currentType.value.type) break } // 创建完元素,把当前操作的元素类型设置回 null currentType.value.type = null currentType.value.data = null } this.mouse.point = event.absolutePointer let arr = ['rect','line','circle','triangle','ellipse','fold','dashed'] if(arr.indexOf(this.operation) > -1){ JSchangeType(MyCanvas?.[this.id],this.operation) this.createPatterning.state = true MyCanvas?.[this.id].forEachObject((obj) =>{ obj.set('selectable', false); // 禁用选中 }); if(this.createPatterning.current && this.operation == 'fold'){ MyCanvas[this.id].skipTargetFind = false this.createPatterning.current.points.push({ x: this.mouse.point.x, y: this.mouse.point.y }) }else{ let width = this.brushwork.width[this.operation]?this.brushwork.width[this.operation]:20 let data = { str:this.operation, width, selectable:true, } if(this.operation == 'dashed'){ width = 1 / MyCanvas?.[this.id].getZoom() data = { fill:'transparent', strokeDashArray: [width*3, width*3], width, radius:0, str:'rect', selectable:true, } }else if(this.operation == 'rect'){ data.width = 0 } this.createPatterning.current = JScanvasMouseDown(event,data) if(this.operation == 'dashed')this.createPatterning.current.set({custom:{dashed:true}}) MyCanvas?.[this.id].add(this.createPatterning.current) if(this.operation == 'fold'){ this.createPatterning.polyLineBtn = JScreateCheck(event) this.createPatterning.polyLineBtn.on('mousedown',this.foldEnd.bind(this)) MyCanvas?.[this.id].add(this.createPatterning.polyLineBtn) } } }else{ // var clickedObject = event.target; // if (clickedObject instanceof fabric.Textbox && this.operation != 'text') { // this.createPatterning.textDataShow = true // this.createText = clickedObject // }else{ // this.createPatterning.textDataShow = false // this.createText = {} // } // this.createPatterning.state = false } } setTextData(obj){ this.fontFamily = obj.fontFamily this.brushwork.width['text'] = obj.fontSize this.brushwork.color = obj.fill } async setCanvasUp(event){ this.mouse.isDown = false if(this.mouse.isMovePostion){ this.mouse.isMovePostion = false this.setCursor('grab'); return } if(this.operation == 'eraser')return this.updataLayer() this.mouse.upPoint = event.absolutePointer if(MyCanvas?.[this.id].isDrawingMode){ setTimeout(() => { // pencilbtnStyle.value.display = `none` this.updateCanvasState() }, 100); }else{ // event.target && (event.target.bringToFront())//设置优先级 } if(this.createPatterning.state){ switch (this.operation) { case 'line': this.createPatterning.current.set({stroke: this.brushwork.color}) break case 'fold': // this.createPatterning.current.set({stroke: this.brushwork.color}) break default : if(JSON.stringify(this.mouse.point) == JSON.stringify(this.mouse.upPoint)){ MyCanvas?.[this.id].remove(this.createPatterning.current) return } if(this.operation == 'dashed'){ this.createPatterning.current.set({fill: 'transparent'}) }else if(this.operationMode == 'fill'){ this.createPatterning.current.set({fill: this.brushwork.color}) }else if (this.operationMode == 'border'){ this.createPatterning.current.set({fill: 'transparent',stroke: this.brushwork.color,strokeWidth: this.brushwork.width[this.operation]?this.brushwork.width[this.operation]:20}) } break } if(this.operation == 'fold'){ MyCanvas?.[this.id].forEachObject((obj) =>{ if(this.isSelectable(obj.target)){ obj.selectable = true }else{ obj.selectable = false } }); MyCanvas?.[this.id].bringToFront(this.createPatterning.polyLineBtn);//设置优先级最高 }else if(this.operation){ this.createPatterning.state = false MyCanvas?.[this.id].renderAll(); if(this.operation == 'dashed'){ await this.setDashed(this.createPatterning.current) }else{ this.addLayer({target:this.createPatterning?.current}) this.setOperation('movePosition') } this.clearPatterning()//临时图形置为空并且添加撤回对象里面 } } } async setclipPathImg(){//裁剪图片 if(!this.clipPath.clipGroup)return this.clipPath.isImg = true let clipPathElement = this.clipPath.clipGroup._objects.filter(obj => obj.custom)[0] let imgBG = MyCanvas?.[this.id].getObjects().filter(obj => obj.custom.isSelectable && obj.type == 'rect')[0]; let position = { left:this.clipPath.clipGroup?.left - (imgBG.left?imgBG.left:0), top:this.clipPath.clipGroup?.top - (imgBG.top?imgBG.top:0), width:this.clipPath.clipGroup?.width, height:this.clipPath.clipGroup?.height, } // await this.setGroupGrid() //添加裁剪后的图片 let elements = MyCanvas?.[this.id].getObjects().filter(obj => this.isAddToLayer(obj)); let imgData = await this.groupToImg(elements,position,'clipPath') let img = await this.createImage({imgUrl:imgData}) img.set({ scaleX:1, scaleY:1, left:0 - position.width/2, top:0 - position.height/2, }) img.clipPath = clipPathElement this.clipPath.clipGroup.insertAt(img) //裁剪 this.layer.selectLayer.group.custom.groupType = 'Grid' clipPathElement.clone(cloned=>{ cloned.set({left:position.left,top:position.top,strokeWidth:0}) if(imgBG?.custom?.state != 'success')this.setClipPath(imgBG,cloned) }) } setDashedPencil(){ MyCanvas[this.id].isDrawingMode = true let pencil = new fabric.Test(MyCanvas?.[this.id],{}); //普通笔 MyCanvas[this.id].freeDrawingBrush = pencil } async setDashed(obj){ MyCanvas?.[this.id].remove(obj) let position = { left:obj.left, top:obj.top, width:obj.width, height:obj.height, } await obj.clone((cloned)=>{ let {width,height,left,top} = position cloned.set({ custom:{ dashed:true } }) // cloned.set({left:cloned.strokeWidth/2,top:cloned.strokeWidth/2}) let group = new fabric.Group([cloned],{ left:left + cloned.strokeWidth/2, top:top + cloned.strokeWidth/2, width,height, custom:{ dashed:true } }) MyCanvas?.[this.id].add(group) }) } async setGridOrObject(id,str){ this.layer.list.forEach((item) => { if(item.id == id)item.groupType = str }) await this.lookingLayer(id).then(rv=>{ rv.custom.groupType = str }) if(str == 'Grid'){ await this.setGroupGrid() }else{ await this.setGroupGrid('all') } this.setOperation('movePosition') } // 复制图层 async copyLayer(id){ // let createId = new Date().getTime() let elements = MyCanvas?.[this.id].getObjects().filter(obj => obj.custom.layerId == id) for (let i = 0; i < elements.length; i++) { await new Promise((resolve, reject) => { let item = elements[i] item.clone((clonedObj)=>{ this.setClone(item,clonedObj) clonedObj.custom.layerId = createId copyElements.push(clonedObj) resolve('') }) }) } // await this.createLayer({id:createId}) copyElements.forEach( item=>MyCanvas?.[this.id].add(item)) } async setGroupGrid(str){//group变为图片 let dashed = MyCanvas?.[this.id].getObjects().filter(obj => obj.custom?.dashed)?.[0]; if(this.layer.selectLayer.group.custom.groupType == 'Object' && !dashed)return MyCanvas?.[this.id].discardActiveObject();//取消所有选中边框 return await new Promise(async (resolve, reject) => { let elements = MyCanvas?.[this.id].getObjects().filter(obj => this.isAddToLayer(obj) && !obj.custom.dashed && obj.type); if(str == 'all'){ elements = MyCanvas?.[this.id].getObjects().filter(obj => this.isAddToLayer(obj) && obj.type); } let layerBg = elements.filter(obj => obj.custom.isSelectable)[0] let scaleXY = { scaleX:layerBg?.scaleX?layerBg?.scaleX:1, scaleY:layerBg?.scaleY?layerBg?.scaleY:1, width:layerBg?.width?layerBg?.width:MyCanvas?.[this.id].width, height:layerBg?.height?layerBg?.height:MyCanvas?.[this.id].height, } let imgData = await this.groupToImg(elements,{},'setGrid',scaleXY) let img = await this.createImage({imgUrl:imgData}) elements.forEach((obj) =>{ if(obj.custom.isSelectable){ }else{ MyCanvas?.[this.id].remove(obj) } }); if(layerBg){ layerBg.custom.state = '' delete layerBg.eraser layerBg.set({ scaleX:1, scaleY:1, width: scaleXY.width * scaleXY.scaleX, height: scaleXY.height * scaleXY.scaleY, clipPath:null, fill: new fabric.Pattern({ source: img.getElement(), // 传入图片元素 repeat: 'no-repeat' // 设置图片不重复 }), hasBorders: true, hasControls: true }) this.setGroupStyle(layerBg) resolve('') }else{ const rect = new fabric.Rect({ // left:0, // top:0, width: MyCanvas?.[this.id].width, height: MyCanvas?.[this.id].height, strokeWidth:0, fill: new fabric.Pattern({ source: img.getElement(), // 传入图片元素 repeat: 'no-repeat' // 设置图片不重复 }), custom:{ isSelectable:true, }, hasBorders: true, hasControls: true }); this.setGroupStyle(rect) MyCanvas?.[this.id].add(rect) resolve('') } MyCanvas?.[this.id].renderAll() // 刷新画布,改变group的visible属性,必须通过刷新画布,才能应用新属性值 }) } //液化 getLiquefactionImgObj(){ return new Promise(async (resolve, reject) => { let img,str = null const activeObject = MyCanvas?.[this.id].getActiveObject(); // 获取选中的对象 let dashedGroup = MyCanvas?.[this.id].getObjects().filter(obj => obj.custom.dashed)[0]; if (activeObject && activeObject.type === 'image' && activeObject.custom.type == 'upImgFiles' ){ img = activeObject this.liquefaction.type = 'upImgFiles' }else if(dashedGroup){//判断选取是否存在 if( dashedGroup._objects.filter(item => item.type == 'image').length == 0 && this.layer.selectLayer.group.custom.groupType == 'Grid' ){ await this.setclipPathImg() }else if(dashedGroup._objects.filter(item => item.type == 'image').length == 0){ resolve() return } await new Promise((resolve, reject) => { dashedGroup.clone(async (cloned)=>{ this.setClone(dashedGroup,cloned) this.liquefaction.dashed = dashedGroup this.liquefaction.type = 'dashed' cloned._objects = cloned._objects.filter(item => item.type == 'image') img = await cloned.toDataURL() resolve() }) }) }else if(this.layer.selectLayer.group.custom.groupType == 'Grid'){//判断当前图层是否可以做为液化图片 let bg = MyCanvas?.[this.id].getObjects().filter(item => item.custom?.isSelectable)[0] img = bg.fill.source.src this.liquefaction.type = 'layer' } this.liquefaction.img = img resolve(this.liquefaction) }) } async setLiquefactionImgObj(liquefaction,data){ if(liquefaction.type == 'upImgFiles'){ await new Promise((resolve, reject) => { liquefaction.img.setSrc(data, (value)=>{ delete liquefaction.img.minioUrl resolve() }) }) }else if(liquefaction.type == 'dashed'){ if(liquefaction.dashed){ await new Promise((resolve, reject) => { liquefaction.dashed._objects = liquefaction.dashed._objects.filter(item => item.type != 'image') fabric.Image.fromURL(data, (value)=>{ value.set({ left:-liquefaction.dashed.width/2, top:-liquefaction.dashed.height/2, }) liquefaction.dashed.insertAt(value) resolve() }) }) // canvasObj.addDashedImg(value) } }else if(liquefaction.type == 'layer'){ let bg = MyCanvas?.[this.id].getObjects().filter(item => item.custom?.isSelectable)[0] let img = await this.createImage({imgUrl:data}) bg.set({ fill: new fabric.Pattern({ source: img.getElement(), // 传入图片元素 repeat: 'no-repeat' // 设置图片不重复 }), }) } MyCanvas?.[this.id].renderAll(); this.updateCanvasState() } //end液化 setGroupStyle(obj){ obj.set({ borderColor:'#4584ff', cornerStrokeColor :'#4584ff', cornerStyle:'circle' }) obj.setControlsVisibility({ mtr:false, deleteControl:false }) // obj.controls.deleteControl.mouseUpHandler = null } setClipPath(img,clipPath){ let imgScale = { pX:(img?.scaleX?img.scaleX:1), pY:(img?.scaleY?img.scaleY:1), } clipPath.set({ left: clipPath.left - img.width*imgScale.pX/2, top: clipPath.top - img.height*imgScale.pY/2, inverted:true, }) img.set({clipPath:clipPath}) img.custom.state = 'success' MyCanvas?.[this.id].renderAll() // 刷新画布,改变group的visible属性,必须通过刷新画布,才能应用新属性值 } async groupToImg(elements,imgData,type,scaleXY){ let temporar = this.temporarilyExport(scaleXY) let bg = elements.filter(item => item.custom?.isSelectable)[0] let xy = { x:bg?.left?bg?.left:0, y:bg?.top?bg?.top:0, } for (let index = 0; index < elements.length; index++) { const item = elements[index]; await new Promise((resolve, reject) => { item.clone((cloned)=>{ this.setClone(item,cloned) if(item.custom?.dashed && item._objects){ cloned._objects = cloned._objects.filter(item => item.type == 'image') } if(this.exportData.width != -1){ if (cloned.type !== 'image' || cloned.type !== 'group') { cloned.set({ left: scaleXY?.scale?cloned.left * scaleXY?.scale:cloned.left - xy.x, top: scaleXY?.scale?cloned.top * scaleXY?.scale:cloned.top - xy.y, scaleX: cloned.scaleX * (scaleXY?.scale?scaleXY?.scale:1), scaleY: cloned.scaleY * (scaleXY?.scale?scaleXY?.scale:1) }); } else { // 对图片对象单独处理:重新计算图片的缩放 cloned.set({ left: scaleXY?.scale?cloned.left * scaleXY?.scale:cloned.left - xy.x, top: scaleXY?.scale?cloned.top * scaleXY?.scale:cloned.top - xy.y, scaleX: cloned.scaleX * (scaleXY?.scale?scaleXY?.scale:1), // 根据原有 scaleX 进行缩放 scaleY: cloned.scaleY * (scaleXY?.scale?scaleXY?.scale:1) // 根据原有 scaleY 进行缩放 }); // 确保图片的尺寸缩放是基于原始宽高和当前缩放 var originalWidth = cloned.width * cloned.scaleX; // 原始宽度 * 当前缩放 var originalHeight = cloned.height * cloned.scaleY; // 原始高度 * 当前缩放 cloned.set({ width: originalWidth * (scaleXY?.scale?scaleXY?.scale:1), // 调整后的宽度 height: originalHeight * (scaleXY?.scale?scaleXY?.scale:1) // 调整后的高度 }); } }else{ cloned.set({ left: (cloned.left - xy.x), top: (cloned.top - xy.y), }) } if(cloned.custom?.layerId != -1){ temporar.add(cloned) } resolve() }) }) } let data = await temporar.toDataURL(imgData); this.closeTemporarilyExport(temporar) return data } setCanvasWheel(opt){ const delta = opt.e.deltaY // 滚轮,向上滚一下是 -100,向下滚一下是 100 let zoom = MyCanvas?.[this.id].getZoom() // 获取画布当前缩放值 zoom *= 0.999 ** delta if (zoom > 20) zoom = 20 if (zoom < 0.01) zoom = 0.01 MyCanvas?.[this.id].zoomToPoint( { // 关键点 x: opt.e.offsetX, y: opt.e.offsetY }, zoom ) opt.e.preventDefault() opt.e.stopPropagation() this.setPencilWidth() } foldEnd(key){ MyCanvas[this.id].skipTargetFind = true let points = this.createPatterning.current.points if(key == 'Enter'){ }else{ points.pop() } points.pop() this.createPatterning.state = false MyCanvas?.[this.id].remove(this.createPatterning.current) MyCanvas?.[this.id].remove(this.createPatterning.polyLineBtn) let polyline = new fabric.Polyline(points, { fill: this.operationMode == 'fill'? this.brushwork.color : 'transparent', stroke: this.brushwork.color, strokeWidth:this.brushwork.width[this.operation]?this.brushwork.width[this.operation]:20, // selection:false, }) polyline.set({ left:polyline.left+polyline.strokeWidth / 2, top:polyline.top+polyline.strokeWidth / 2, }) MyCanvas?.[this.id].add(polyline) this.clearPatterning()//临时图形置为空并且添加撤回对象里面 // this.layerAddElement(polyline) } clearPatterning(){ if(this.createPatterning.state){ MyCanvas?.[this.id].remove(this.createPatterning.current) } this.createPatterning.current = null MyCanvas?.[this.id].remove(this.createPatterning.polyLineBtn) this.updateCanvasState() } textureValueChange = (value)=>{ this.texture.value = value this.setTexture() } setOperationMode(str){ this.operationMode = str } brushworkChange = (value)=>{ this.brushwork.value = value this.setPencil() } setLayerIndex(str){//设置优先级 var activeObject = MyCanvas?.[this.id].getActiveObject(); switch (str) { case 'Front': MyCanvas?.[this.id].bringToFront(activeObject)//顶层 // this.layer.selectLayer.group.bringToFront(activeObject) break case 'Back': MyCanvas?.[this.id].sendToBack(activeObject)//底层 // this.layer.selectLayer.group.sendToBack(activeObject) break case 'Forward': MyCanvas?.[this.id].bringForward(activeObject) // this.layer.selectLayer.group.bringForward(activeObject) break case 'Backwards': MyCanvas?.[this.id].sendBackwards(activeObject) // this.layer.selectLayer.group.sendBackwards(activeObject) break } } setPencil(){ let pencil MyCanvas[this.id].isDrawingMode = true//开启绘画模式 if(this.brushwork.value == 'PencilBrush'){ pencil = new fabric.PencilBrush(MyCanvas?.[this.id],{}); //普通笔 }else if(this.brushwork.value == 'Marking'){ pencil = new fabric.PencilBrush(MyCanvas?.[this.id],); //记号笔 }else if(this.brushwork.value == 'InkBrush'){ pencil = new fabric.InkBrush(MyCanvas?.[this.id],{}); //油画笔 }else if(this.brushwork.value=='CrayonBrush'){ pencil = new fabric.CrayonBrush(MyCanvas?.[this.id],{}); //蜡笔 }else if(this.brushwork.value == 'RibbonBrush'){ pencil = new fabric.RibbonBrush(MyCanvas?.[this.id],{width: 1,}); //色带 }else if(this.brushwork.value == 'MarkerBrush'){ pencil = new fabric.MarkerBrush(MyCanvas?.[this.id],{}); //书写笔 // pencil = new fabric.PenBrush(MyCanvas?.[this.id],{}); //书写笔 }else if(this.brushwork.value == 'WritingBrush'){ pencil = new fabric.WritingBrush(MyCanvas?.[this.id],{}); //毛笔 }else if(this.brushwork.value == 'LongfurBrush'){ pencil = new fabric.LongfurBrush(MyCanvas?.[this.id],{width: 1,}); //色带 }else if(this.brushwork.value == 'SpraypaintBrush'){ pencil = new fabric.SpraypaintBrush(MyCanvas?.[this.id],{}); //长毛刷 } MyCanvas[this.id].freeDrawingBrush = pencil if(this.brushwork.value == 'RibbonBrush' || this.brushwork.value == 'LongfurBrush'){ MyCanvas[this.id].freeDrawingBrush.width = 1; } if(this.brushwork.value == 'Marking'){ MyCanvas[this.id].freeDrawingBrush.color = this.hexToRgba(this.brushwork.color,.5); // }else if(this.brushwork.value == 'InkBrush'){ // canvas.freeDrawingBrush.color = this.hexToRgba(this.brushwork.color,.2); }else{ MyCanvas[this.id].freeDrawingBrush.color = this.hexToRgba(this.brushwork.color,1); } this.setPencilWidth() this.pencilbtnStyle.background = this.brushwork.color MyCanvas[this.id].freeDrawingBrush.isEraser = false } setCanvasZoom(opt){ let zoom = MyCanvas?.[this.id].getZoom() // 获取画布当前缩放值 let num = -100 if(this.operation == 'zoomOut') num = 100 zoom *= 0.999 ** num if (zoom > 20) zoom = 20 if (zoom < 0.01) zoom = 0.01 // MyCanvas?.[this.id].setDimensions(MyCanvas?.[this.id].width *= zoom,MyCanvas?.[this.id].height *= zoom) // MyCanvas?.[this.id].wrapperEl.style.zoom = zoom MyCanvas?.[this.id].zoomToPoint( { // 关键点 x: opt.pointer.x, y: opt.pointer.y }, zoom ) opt.e.preventDefault() opt.e.stopPropagation() this.setPencilWidth() } async addImage (imgData){ if(!imgData.imgUrl)imgData.imgUrl = imgData.url let img = await this.createImage(imgData) let position = { // left: 0, // top:MyCanvas?.[this.id].wrapperEl.parentNode.scrollTop, left: MyCanvas?.[this.id].width/2, top: MyCanvas?.[this.id].height/2, } img.set({ custom:{ type:'upImgFiles', // minioUrl:getMinioUrl(imgData.url) }, }) if(this.exportData.width != -1)await this.createLayer({}) // if(this.dashed.isDetail)await this.createLayer({}) this.setCanvasImage(img,position,"upImgFiles",imgData) } createImage(imgData){ return new Promise((resolve, reject) => { fabric.Image.fromURL(imgData.imgUrl,(img) => { img.set({ hasControls: true, }) let url = imgData.imgUrl || imgData.minioUrl img.minioUrl=getMinioUrl(url) resolve(img) },{ crossOrigin: "Anonymous" }) }) } setImageWidth = (key,img)=>{ const CW = MyCanvas?.[this.id].width const CH = MyCanvas?.[this.id].height let WH = CW>CH?'H':'W' let imgWidth; //这是设置画布等宽 if(WH == 'W'){ imgWidth = CW / 2; }else{ let heightScale = (CH/2) / img.height imgWidth = img.width * heightScale } // let sketchGrouping = 6 // if(key == 'upImgFiles'){ // imgWidth = imgWidth / 8; // }else if (key == "printboardFiles") { // imgWidth = imgWidth / 14; // }else if (key == "sketchboardFiles"||key == 'moodboardFiles'||key == 'FinalizeImage') { // imgWidth = // (imgWidth - // (sketchGrouping - 1) * 20) / // sketchGrouping; // }else if (key == "likeDesignCollectionList") { // if(img){ // let imgObj = JSON.parse(JSON.stringify(img)) // let height = imgObj.height // imgObj.height = imgWidth / 8 * 1.8 // let heightScale = imgObj.height / height // imgWidth = imgObj.width * heightScale // } // }else { // if(img){ // let imgObj = JSON.parse(JSON.stringify(img)) // if(imgObj.height > imgObj.width){ // let heightScale = (MyCanvas?.[this.id].height/2) / imgObj.height // imgWidth = imgObj.width * heightScale // }else{ // imgWidth /= 2 // } // } // } return imgWidth } async setCanvasImage(img,position,key,data){ let imgUrl = data.imgUrl if (key == "likeDesignCollectionList") { imgUrl = data.designOutfitUrl; } let imgWidth = await this.setImageWidth(key,img); if(imgUrl?.split('?')){ // let url = imgUrl.split('?')[0] // var match = url.match(/^(?:https?:\/\/[^\/]+)\/(.*)/); // minioUrl = match[1] const { pathname } = new URL(imgUrl); const result = pathname.slice(1); minioUrl = result } let proportion = img.height / img.width; //计算图形宽高比例 let scaleWH = imgWidth / img.width; //计算放到画布上缩小倍率 let scale = { X: imgWidth / img.width, Y: (img.width * proportion * scaleWH) / img.height, } img.set({ left:position.left - img.width*scale.X/2, top:position.top - img.height*scale.Y / 2, scaleX:scale.X, scaleY:scale.Y, }); MyCanvas?.[this.id].add(img) this.updateCanvasState('') } setMove(){ MyCanvas[this.id].isDrawingMode = false MyCanvas?.[this.id].forEachObject((obj) =>{ if(this.isSelectable(obj)){ obj.selectable = true }else{ obj.selectable = false } }); MyCanvas?.[this.id].renderAll() // 刷新画布,改变group的visible属性,必须通过刷新画布,才能应用新属性值 } async setTexture(){ MyCanvas[this.id].isDrawingMode = true//开启绘画模式 let img = await JSSetTexture(this.texture.list[this.texture.value].url) let zoom = MyCanvas?.[this.id].getZoom() // 获取画布当前缩放值 let patternBrush = new fabric.PatternBrush(MyCanvas?.[this.id]) patternBrush.source = img patternBrush.width = Number(this.brushwork.width[this.operation]) / zoom; // 设置画笔大小 this.setPencilWidth() MyCanvas[this.id].freeDrawingBrush = patternBrush } setEraser(){ MyCanvas[this.id].isDrawingMode = true let eraser = new fabric.EraserBrush(MyCanvas?.[this.id]) MyCanvas[this.id].freeDrawingBrush = eraser this.pencilbtnStyle.background = '#fff' MyCanvas[this.id].freeDrawingBrush.isEraser = true this.setPencilWidth() MyCanvas?.[this.id].requestRenderAll(); } hexToRgba(hex, alpha){ const r = parseInt(hex.slice(1, 3), 16); const g = parseInt(hex.slice(3, 5), 16); const b = parseInt(hex.slice(5, 7), 16); return `rgba(${r}, ${g}, ${b}, ${alpha})`; } pencilColor(){ if(this.createText?.set){ this.setFontFamily() return } if(MyCanvas[this.id].freeDrawingBrush.isEraser){ }else{ this.pencilbtnStyle.background = this.brushwork.color } if(this.brushwork.value == 'Marking'){ MyCanvas[this.id].freeDrawingBrush.color = this.hexToRgba(this.brushwork.color,.5); }else if(this.brushwork.value == 'InkBrush'){ MyCanvas[this.id].freeDrawingBrush.color = this.hexToRgba(this.brushwork.color,.2); }else{ MyCanvas[this.id].freeDrawingBrush.color = this.hexToRgba(this.brushwork.color,1); } } setFontFamily=()=>{ if(this.createText?.set){ this.createText.set({ fontFamily:this.fontFamily, fontSize:this.brushwork.width[this.operation]?this.brushwork.width[this.operation]:20, fill:this.brushwork.color, }) MyCanvas?.[this.id].renderAll(); } } setPencilColor(){//切换颜色给铅笔设置颜色 clearTimeout(this.setTimeOut.color) clearTimeout(this.setTimeOut.colorHistory) this.setTimeOut.color = setTimeout(()=>{ this.pencilColor() },200) this.setTimeOut.colorHistory = setTimeout(()=>{ this.colorHistoryList.push(this.brushwork.color) },1000) } setCanvasWH = (str)=>{ clearTimeout(this.setTimeOut.canvasWH) this.setTimeOut.canvasWH = setTimeout(()=>{ // MyCanvas?.[this.id].setWidth(this.canvasWH.width); // MyCanvas?.[this.id].setHeight(this.canvasWH.height); var allObjects = MyCanvas?.[this.id].getObjects(); allObjects.forEach((obj)=>{ if((obj?.custom?.type == 'layer' && obj.type == 'group')||(obj.type == 'rect' && obj.custom.isSelectable)){ if((obj?.custom?.type == 'layer' && obj.type == 'group')){ // if(obj.custom.layerId == this.layer.selectLayer.id){ obj.set({ // left: -MyCanvas?.[this.id].width / 2, // top: -MyCanvas?.[this.id].height / 2, left: MyCanvas?.[this.id].width / 2 - this.canvasWH.layerWidth / 2, top: MyCanvas?.[this.id].height / 2 - this.canvasWH.layerHeight / 2, width:this.canvasWH.layerWidth, height:this.canvasWH.layerHeight, }) // } // if(obj._objects.length > 1){ // obj._objects.forEach((item)=>{ // item.set({ // left: item.left + this.canvasWH.layerWidth / 2, // top: item.top + this.canvasWH.layerHeight / 2, // }) // }) // } }else{ obj.set({ left: MyCanvas?.[this.id].width / 2 - this.canvasWH.layerWidth / 2, top: MyCanvas?.[this.id].height / 2 - this.canvasWH.layerHeight / 2, }) } obj.set({ width:this.canvasWH.layerWidth, height:this.canvasWH.layerHeight, }) } }); MyCanvas?.[this.id].renderAll(); // this.initCanvasWH('updata') this.updataLayer() },1000) } setColorHistory = (value)=>{ this.brushwork.color = value this.pencilColor() } setPencilWidth(){//切换颜色给铅笔设置颜色 let zoom = MyCanvas?.[this.id].getZoom() // 获取画布当前缩放值 clearTimeout(this.setTimeOut.width) this.setTimeOut.width = setTimeout(()=>{ if(!this.brushwork.width[this.operation])this.brushwork.width[this.operation]=20 // MyCanvas[this.id].freeDrawingBrush.width = Number(this.brushwork.width[this.operation]); let arr = ['PencilBrush','Marking'] this.pencilbtnStyle.height = this.brushwork.width[this.operation]+'px' this.pencilbtnStyle.width = this.brushwork.width[this.operation]+'px' if(arr.indexOf(this.brushwork.value) > -1){ MyCanvas[this.id].freeDrawingBrush.width = Number(this.brushwork.width[this.operation]) / zoom; }else{ MyCanvas[this.id].freeDrawingBrush.width = Number(this.brushwork.width[this.operation]); } if((this.brushwork.value == 'LongfurBrush' || this.brushwork.value == 'RibbonBrush') && this.operation == 'pencil'){ MyCanvas[this.id].freeDrawingBrush.width = 1; this.pencilbtnStyle.height = 1+'px' this.pencilbtnStyle.width = 1+'px' } },100) } uploadImg(){ const input = document.createElement('input'); input.type = 'file'; input.accept = 'image/*'; // 将文件输入框和图片预览元素添加到页面中 document.body.appendChild(input); // 监听文件输入框的变化事件 input.addEventListener('change', (event)=> { event.preventDefault() const file = event.target.files[0]; // 获取用户选择的文件 if (file) { const reader = new FileReader(); // 创建 FileReader 对象读取文件 reader.onload = (e)=> { const base64Image = e.target.result; this.addPartImg({minioUrl:base64Image},'print') input.remove() }; reader.readAsDataURL(file); } }); input.click() } //关闭u或者创建文字 setTextFun(e){ if(this.operation != 'text'){ return } MyCanvas?.[this.id].forEachObject((obj) =>{ if(obj.type == 'textbox' && !obj.text){ MyCanvas?.[this.id].remove(obj); } }); var clickedObject = e.target; if (clickedObject instanceof fabric.Textbox) { this.createText = clickedObject this.setTextData(this.createText) }else{ var pointer = MyCanvas?.[this.id].getPointer(e.pointer); var x = pointer.x; var y = pointer.y; this.createText = new fabric.Textbox('', { left: x, top: y, width: 50, fontSize: this.brushwork.width[this.operation]?this.brushwork.width[this.operation]:20, fontFamily:this.fontFamily, fill:this.canvasPencilColor, }) MyCanvas?.[this.id].add(this.createText) // this.layer.selectLayer.group.add(this.createText) this.createText.enterEditing(); MyCanvas?.[this.id].setActiveObject(this.createText).renderAll(); this.removeSetText() } } setText(){ MyCanvas?.[this.id].on('mouse:down',(event)=>{ if(this.operation == 'zoomIn' || this.operation == 'zoomOut'){ }else{ this.setTextFun(event) } }) } removeSetText(){ MyCanvas?.[this.id].off('mouse:down',this.setTextFun.bind(this)) } // async createBg(){// // await new Promise((resolve, reject) => { // let url = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC' // fabric.Image.fromURL(url, (backgroundImage)=>{ // backgroundImage.set({ // }) // const rect = new fabric.Rect({ // left: 0, // top: 0, // width: MyCanvas?.[this.id].width, // height: MyCanvas?.[this.id].height, // fill:'#FFF', // // fill: new fabric.Pattern({ // // source: backgroundImage.getElement(), // 使用图像元素作为填充 // // repeat: 'repeat', // 设置为重复 // // patternTransform: [this.canvasWH.width/this.canvasDomParent.offsetWidth, 0, 0, this.canvasWH.width/this.canvasDomParent.offsetWidth, 0, 0] // // }), // }); // const group = new fabric.Group([rect], { // width: MyCanvas?.[this.id].width, // height: MyCanvas?.[this.id].height, // erasable:false, // selectable:false, // }); // group.custom.layerId = -1 // MyCanvas?.[this.id].add(group) // MyCanvas?.[this.id].clipPath = rect // resolve() // }); // }) // } getBGRect(){ let rect if(!MyCanvas?.[this.id]?.getObjects)return '' MyCanvas?.[this.id].getObjects().forEach((element)=>{ if(element?.custom?.type == 'layer' && element.type == 'group'){ element._objects.forEach((item)=>{ if(item?.custom?.isSelectable && item.type == 'rect'){ rect = item } }) }else if(element?.custom?.isSelectable && element.type == 'rect'){ rect = element } }) return rect } async upDataRectBGImg(image){ let rect = this.getBGRect() if(!rect)return let img = await this.createImage({imgUrl:image}) const scaleX = this.canvasWH.layerWidth / img.width; // 横向比例 const scaleY = this.canvasWH.layerWidth / img.height; // 纵向比例 // 选择较大的比例来保持完整图片显示,避免裁剪 const scale = Math.min(scaleX, scaleY); const patternTransform = [ scale, 0, 0, scale, (this.canvasWH.layerWidth - img.width * scale) / 2, (this.canvasWH.layerWidth - img.height * scale) / 2 ]; rect.set({ fill: new fabric.Pattern({ source: img.getElement(), // 传入图片元素 repeat: 'no-repeat', // 设置图片不重复 patternTransform: patternTransform // patternTransform: [group.width / img.width, 0, 0, group.height / img.height, 0, 0] }), }) rect.minioUrl = getMinioUrl(image) MyCanvas?.[this.id].requestRenderAll() } createLayer(data){ let {str,id,editImg,noErasable} = data let image = data.img let canvasData = MyCanvas?.[this.id].toJSON(['selectable','minioUrl','custom']); return new Promise(async (resolve, reject) => { MyCanvas?.[this.id].discardActiveObject(); if(!id)id = new Date().getTime() let index = this.layer.currentIndex += 1 const rect = new fabric.Rect({ left: -MyCanvas?.[this.id].width / 2, top: -MyCanvas?.[this.id].height / 2, // left:0, // top:0, // width: this.canvasWH.layerWidth, // height: this.canvasWH.layerHeight, width: this.canvasWH.width, height: this.canvasWH.height, strokeWidth:0, fill:'#FFF', custom:{ layerId:id, isSelectable:true, type:str, }, // erasable:false, selectable:false, }); rect.clone((cloned)=>{ rect.clipPath = cloned }) const group = new fabric.Group([], { width: this.canvasWH.width, height: this.canvasWH.height, left:(this.canvasWH.width - this.canvasWH.layerWidth)/2, top:(this.canvasWH.height - this.canvasWH.layerHeight)/2, erasable:false, subTargetCheck:true, evented:false, // originX:'left', // originY:'top', custom:{ noErasable:noErasable, layerId:id, type:'layer' , groupType:'Object', layerIndex:index, selectLayerIndex:(index) * 10000, } }); if(str == 'init'){ group.moveTo(group.custom.selectLayerIndex) if(image){ let img = await this.createImage({imgUrl:image}) const scaleX = group.width / img.width; // 横向比例 const scaleY = group.height / img.height; // 纵向比例 // 选择较大的比例来保持完整图片显示,避免裁剪 const scale = Math.min(scaleX, scaleY); const patternTransform = [ scale, 0, 0, scale, (group.width - img.width * scale) / 2, (group.height - img.height * scale) / 2 ]; rect.set({ fill: new fabric.Pattern({ source: img.getElement(), // 传入图片元素 repeat: 'no-repeat', // 设置图片不重复 patternTransform: patternTransform // patternTransform: [group.width / img.width, 0, 0, group.height / img.height, 0, 0] }), }) rect.minioUrl = getMinioUrl(image) } group.add(rect) group.clone((cloned)=>{ cloned.set({left:0,top:0}) // MyCanvas?.[this.id].clipPath = cloned }) }else if(editImg){ group.moveTo(group.custom.selectLayerIndex) let img = await this.createImage({imgUrl:editImg}) rect.set({ fill: new fabric.Pattern({ source: img.getElement(), // 传入图片元素 repeat: 'no-repeat', // 设置图片不重复 patternTransform: [group.width / img.width, 0, 0, group.height / img.height, 0, 0] }), }) group.add(rect) group.clone((cloned)=>{ cloned.set({left:0,top:0}) // MyCanvas?.[this.id].clipPath = cloned }) } MyCanvas?.[this.id].add(group) let img = group.toDataURL({ // width: this.canvasWH.layerWidth, // height: this.canvasWH.layerHeight, width: this.canvasWH.width, height: this.canvasWH.height, }) this.layer.list.unshift({ name:`Layer${index}`, id,img,isShow:true, groupType:'Object', index,}) if(this.layer.selectLayer.group && this.layer.selectLayer.group?.custom.groupType == 'Grid'){ await this.setGroupGrid('all') } MyCanvas?.[this.id].renderAll(); await this.selectLayer(id) this.updateCanvasState() resolve(group) }) } layerAddElement(obj){ let group = this.layer.selectLayer.group obj.left = obj.left - group.width/2 obj.top = obj.top - group.height/2 group.add(obj) MyCanvas?.[this.id].remove(obj) this.updataLayerImg(this.layer.selectLayer.id,group.toDataURL({ width: MyCanvas?.[this.id].width, height: MyCanvas?.[this.id].height })) } showBg(boolen){ let rect = this.getBGRect() if(!rect)return rect.set({visible:boolen}) // if(Bg.visible){ // Bg.set({visible:false}) // }else{ // Bg.set({visible:true}) // } MyCanvas?.[this.id].renderAll() // 刷新画布,改变group的visible属性,必须通过刷新画布,才能应用新属性值 } async addPartImg(file,str,data){ // let {erasable} = data let img = await this.createImage(file) if(str){ img.set({ custom:{ type:str } }) } // let dashedGroup = MyCanvas?.[this.id].getObjects().filter(obj => obj?.custom?.dashed)[0]; // dashedGroup.clone(cloned=>{ // this.setClone(img,cloned) // img.set({ // left:0, // top:0 // }) // }) MyCanvas?.[this.id].add(img) img.bringToFront(); MyCanvas?.[this.id].renderAll(); } async addLayer(options){ if(this.createPatterning.state)return this.clipPath.clipGroup = MyCanvas?.[this.id].getObjects().filter(obj => obj.custom?.dashed)?.[0]; if (options.target.type === 'group' && options.target.custom?.layerId) return; if(!options.target?.custom?.layerId,this.layer.selectLayer.id){ if(options.target?.custom){ options.target.custom.layerId = this.layer.selectLayer.id }else{ options.target.set({custom:{layerId : this.layer.selectLayer.id}}) } } if(this.clipPath.clipGroup && this.dashed.isDetail && !options.target?.custom?.dashed){ let clipPathElement = this.clipPath.clipGroup._objects.filter(obj => obj.custom)[0] clipPathElement.clone(cloned=>{ cloned.set({ left:this.clipPath.clipGroup.left, top:this.clipPath.clipGroup.top, absolutePositioned:true, inverted:false, }) if(options.target.type == 'image' && options.target.custom?.type != 'pencil'){ options.target.set({ scaleX:this.clipPath.clipGroup.width / options.target.width, scaleY:this.clipPath.clipGroup.height / options.target.height, left:this.clipPath.clipGroup.left, top:this.clipPath.clipGroup.top, // width:cloned.width, // height:options.cloned.width / target.width * options.target.height, }) } options.target.clipPath = cloned }) }else if(options.target.type == 'image' && options.target.custom?.type != 'pencil' && this.dashed.isDetail ){ let scale = 1 if(options.target?.custom?.type == 'print')scale = 2 options.target.set({ scaleX:MyCanvas?.[this.id].width / scale / options.target.width, scaleY:MyCanvas?.[this.id].height / scale / options.target.height, left:MyCanvas?.[this.id].width / scale - (options.target.width / scale * MyCanvas?.[this.id].width / scale / options.target.width), top:MyCanvas?.[this.id].height / scale - (options.target.height / scale * MyCanvas?.[this.id].height / scale / options.target.height), // width:cloned.width, // height:options.cloned.width / target.width * options.target.height, }) } //判断是否可以点击空白地方进行选中 if(options.target?.custom?.dashed){ this.dashed.isDashedShow = true options.target.set({perPixelTargetFind:false,erasable:false,hasBorders: false,hasControls: false,selectable:true}) if(this.dashed.isDetail){//判断是裁剪还是局部添加 options.target.set({selectable:false,perPixelTargetFind:true}) }else{ // MyCanvas?.[this.id].setActiveObject(options.target); MyCanvas[this.id].skipTargetFind = false } this.setOperation('movePosition') }else if(options.target.type == 'textbox' || options.target?.custom.type == 'layer'){ options.target.set({perPixelTargetFind:false}) }else{ options.target.set({perPixelTargetFind:true}) } //设置优先级 if(options.target?.custom?.isSelectable && (options.target?.type == 'rect')){ options.target.custom.selectLayerIndex = this.layer.selectLayer.group.custom.layerIndex * 10000 }else{ options.target.custom.selectLayerIndex = this.layer.selectLayer.group.custom.selectLayerIndex += 1 if(this.clipPath.clipGroup){ this.clipPath.clipGroup.custom.selectLayerIndex = this.layer.selectLayer.group.custom.selectLayerIndex + 1 } } if(options.target.isType('path'))options.target.selectable=false let arr = MyCanvas?.[this.id].getObjects().sort((a, b) =>{ return a.custom.selectLayerIndex - b.custom.selectLayerIndex; }); arr.forEach((item,index)=>{ item.moveTo(index) }) if(!options?.target?.custom?.dashed && this.layer.selectLayer.group.custom.groupType == 'Grid' && this.clipPath.clipGroup && this.dashed.isDetail){ await new Promise((resolve, reject) => { let clipPathElement = this.clipPath.clipGroup._objects.filter(obj => obj.custom?.dashed)[0] let clipPathLect = this.clipPath.clipGroup.left let clipPathTop = this.clipPath.clipGroup.top clipPathElement.clone((clipPathElementCloned)=>{ clipPathElementCloned.set({ // left:this.clipPath.clipGroup.left, // top:this.clipPath.clipGroup.top, left:clipPathLect, top:clipPathTop, absolutePositioned:true, }) let optionLect = (options.target.left - this.clipPath.clipGroup.left) - this.clipPath.clipGroup.width/2 let optionTop = (options.target.top - this.clipPath.clipGroup.top) - this.clipPath.clipGroup.height/2 options.target.clone((cloned)=>{ cloned.set({ left:optionLect, top:optionTop, clipPath:clipPathElementCloned, }) this.clipPath.clipGroup.add(cloned) MyCanvas?.[this.id].remove(options.target) resolve() }) }) }) // this.setGroupGrid('all') } MyCanvas?.[this.id].renderAll(); this.updataLayer() } upLayerIndex(list){ list.forEach((item,index)=>{ let arr = MyCanvas?.[this.id].getObjects().filter(obj => obj.custom.layerId == item.id) arr.forEach((obj)=>{ if(obj.custom.type == 'layer')obj.custom.layerIndex = item.index let selectLayerIndex = obj.custom.selectLayerIndex+'' selectLayerIndex = selectLayerIndex.replace(/^\d/, item.index); obj.custom.selectLayerIndex = Number(selectLayerIndex) }) // arrList.unshift(obj) }) // this.layer.list = arrList let arr = MyCanvas?.[this.id].getObjects().sort((a, b) =>{ return a.custom.selectLayerIndex - b.custom.selectLayerIndex; }); arr.forEach((item,index)=>item.moveTo(index)) } updataLayer(){ clearTimeout(this.setTimeOut.updataLayer) this.setTimeOut.updataLayer = setTimeout(async()=>{ let elements elements = MyCanvas?.[this.id].getObjects().filter(obj => { return this.isAddToLayer(obj) }); const group = new fabric.Group([], { // width: this.layer.selectLayer.group.width, // height: this.layer.selectLayer.group.height, width:this.canvasWH.layerWidth, height:this.canvasWH.layerHeight, erasable:false, selectable:false, }); for (let i = 0; i < elements.length; i++) { await new Promise((resolve, reject) => { let item = elements[i] item.clone((clonedObj)=>{ this.setClone(item,clonedObj) // clonedObj.height = this.layer.selectLayer.group.height // clonedObj.width = this.layer.selectLayer.group.width clonedObj.left = clonedObj.left - this.canvasWH.width/2 clonedObj.top = clonedObj.top - this.canvasWH.height/2 if(clonedObj.custom?.dashed){ let clipPath = clonedObj._objects.filter(item => item.type != 'image')[0] clonedObj.remove(clipPath) } group.add(clonedObj) resolve('') }) }) } this.updataLayerImg(this.layer.selectLayer.id,group.toDataURL({ // left:this.canvasWH.width / 2 - this.canvasWH.layerWidth/2, // top:this.canvasWH.height / 2 - this.canvasWH.layerWidth/2, width:this.canvasWH.layerWidth, height:this.canvasWH.layerHeight, }) ) },500) } updataLayerImg(id,img){ this.layer.list.forEach(v => { if (v.id === id) { v.img = img } }) } async layerDelete(index,id){ if(this.layer.list.length == 1)return for (let i = index; i < this.layer.list.length; i++) { this.layer.list[this.layer.list.length - i-1].index-- } this.layer.list.splice(index,1) if(id == this.layer.selectLayer.id){ MyCanvas?.[this.id].remove(this.layer.selectLayer.group) MyCanvas?.[this.id].forEachObject((obj) =>{ if(obj.type != 'group' && obj.custom?.layerId == id){ MyCanvas?.[this.id].remove(obj) } }); this.layer.selectLayer.id = -1 this.selectLayer(this.layer.list[this.layer.list.length - 1].id) }else{ let group = await this.lookingLayer(id,'setLayerIndex') MyCanvas?.[this.id].remove(group) } this.updateCanvasState() } async selectLayer(id){ await new Promise(async (resolve, reject) => { if(this.layer.selectLayer.id != -1 && this.layer.selectLayer.group){ await this.mergeGroup() } let group = await this.lookingLayer(id,'setRubber') group.custom.selectLayerIndex = group.custom.layerIndex*10000 this.layer.selectLayer.group = group this.layer.selectLayer.id = id await this.expandGroup() MyCanvas?.[this.id].renderAll() // 刷新画布,改变group的visible属性,必须通过刷新画布,才能应用新属性值 this.setOperation('movePosition') resolve('') }) } async mergeGroup(){ const elements = MyCanvas?.[this.id].getObjects().filter(obj => this.isAddToLayer(obj)); let group = await this.lookingLayer(this.layer.selectLayer.id,'setlayerIndex') group.set({visible:true,evented:false}) for (let index = 0; index < elements.length; index++) { const item = elements[index]; await new Promise((resolve, reject) => { item.clone((v)=>{ this.setClone(item,v) // v.left = v.left - MyCanvas?.[this.id].width / 2 // v.top = v.top - MyCanvas?.[this.id].height / 2 v.left = v.left - (this.canvasWH.width - this.canvasWH.layerWidth)/2 - this.layer.selectLayer.group.width/2 v.top = v.top - (this.canvasWH.height - this.canvasWH.layerHeight)/2 - this.layer.selectLayer.group.height/2 if(v.custom?.dashed){ // MyCanvas?.[this.id].remove(item) // let img = v._objects.filter(item => item.type == 'image')[0] // if(img){ // img.set({ // left:v.left, // top:v.top, // custom:{ // layerId:v.custom.layerId // } // }) // group.add(img) // } }else{ group.add(v) } resolve('') }) }) } elements.forEach(v => MyCanvas?.[this.id].remove(v)) } async expandGroup(){ const elements = this.layer.selectLayer.group._objects.filter(obj => this.isAddToLayer(obj)); // fabric.util.enlivenObjects(elements, (clonedObjects) => { let isClipPath = MyCanvas?.[this.id].getObjects().filter(obj => obj.custom?.dashed); if(isClipPath.length>0)await this.setGroupGrid('all') this.layer.selectLayer.group.set({evented:true}) for (let index = 0; index < elements.length; index++) { const item = elements[index]; await new Promise((resolve, reject) => { item.clone((v)=>{ this.setClone(item,v) // v.left = v.left + this.layer.selectLayer.group.width/2 // v.top = v.top + this.layer.selectLayer.group.height/2 v.left = v.left + (this.canvasWH.width - this.canvasWH.layerWidth)/2 + this.layer.selectLayer.group.width/2 v.top = v.top + (this.canvasWH.height - this.canvasWH.layerHeight)/2 + this.layer.selectLayer.group.height/2 if(v.custom?.isSelectable && this.layer.selectLayer.group.custom.noErasable){ v.set({ erasable:false }) } if(v.custom?.dashed){ // this.layer.selectLayer.group._objects.remove(item) // let img = v._objects.filter(item => item.type == 'image')[0] // if(img){ // img.set({ // left:v.left, // top:v.top, // custom:{ // layerId:v.custom.layerId // } // }) // MyCanvas?.[this.id].add(img) // } }else{ MyCanvas?.[this.id].add(v) } if(index == elements.length - 1){ elements.forEach(v => this.layer.selectLayer.group.remove(v)) } resolve() }) }) } } lookingLayer(id,str){ return new Promise((resolve, reject) => { const groups = MyCanvas?.[this.id].getObjects() let group = null groups.forEach(v => { if(str && v?.custom?.type === 'layer' && (str == 'setlayerIndex' || str == 'setRubber')){ let layerIndex = v?.custom?.layerIndex * 10000 v.moveTo(layerIndex) } if(v?.custom?.layerId == id && !v?.custom?.noErasable){ if(str && str == 'setRubber'){ v.set({erasable:'deep'}) } }else if(v?.custom?.type === 'layer'){ v.set({erasable:false}) } if (v?.custom?.layerId === id && v?.custom?.type === 'layer') { group = v } }) resolve(group) }) } canvasKeyUp(event){ this.keyDown = this.keyDown.filter((item) => { if(item.code !== 'AltLeft'){ if(this.oldOperation)this.setOperation(this.oldOperation) } return event.code !== item; }) } async layerShowHide(id,item){ item.isShow = !item.isShow MyCanvas?.[this.id].forEachObject((obj)=>{ if(obj.custom.layerId == id)obj.visible = item.isShow }) MyCanvas?.[this.id].renderAll() // 刷新画布,改变group的visible属性,必须通过刷新画布,才能应用新属性值 } canvasKeyDown(event){ if(!this.currentOperation)return let keys = ['Enter','Delete','ControlLeft','ShiftLeft','BracketLeft','BracketRight','MetaLeft'] var activeObject = MyCanvas?.[this.id].getActiveObject(); let state = (activeObject && activeObject.type == 'textbox'&&activeObject.isEditing) if(keys.indexOf(event.code) > -1){ event.preventDefault(); } if(this.keyDown.indexOf(event.code)>-1 || state){ }else{ this.keyDown.push(event.code) // console.log(this.keyDown.indexOf('ControlLeft') > -1 , this.keyDown.indexOf('MetaLeft') > -1, event.code == 'KeyC') if(event.code === 'Enter' && operation.value == 'fold'){ this.foldEnd('Enter') }else if(event.key === 'Delete'){ this.deleteObject() }else if((this.keyDown.indexOf('ControlLeft') > -1 || this.keyDown.indexOf('MetaLeft') > -1) && event.code == 'KeyZ' && this.keyDown.indexOf('ShiftLeft') > -1){ this.historyState('reverse') }else if((this.keyDown.indexOf('ControlLeft') > -1 || this.keyDown.indexOf('MetaLeft') > -1) && event.code == 'KeyZ'){ this.historyState('') }else if((this.keyDown.indexOf('ControlLeft') > -1 || this.keyDown.indexOf('MetaLeft') > -1) && event.code == 'KeyC'){ this.copy() }else if((this.keyDown.indexOf('ControlLeft') > -1 || this.keyDown.indexOf('MetaLeft') > -1) && event.code == 'KeyV'){ this.paste() }else if(this.keyDown.indexOf('BracketLeft') > -1){ let width = this.brushwork.width[this.operation] this.brushwork.width[this.operation] = (width - 5) < 3?3:(width - 5) this.setPencilWidth() }else if(this.keyDown.indexOf('BracketRight') > -1){ let width = this.brushwork.width[this.operation] this.brushwork.width[this.operation] = (width + 5) > 50?50:(width + 5) this.setPencilWidth() }else if(this.keyDown.indexOf('KeyI') > -1){ this.getColor()//吸色 }else if(this.keyDown.indexOf('KeyM') > -1){ this.setOperation('move') }else if((this.keyDown.indexOf('ControlLeft') > -1 || this.keyDown.indexOf('MetaLeft') > -1) && event.code == 'KeyD'){ MyCanvas?.[this.id].discardActiveObject().renderAll(); }else if((this.keyDown.indexOf('ControlLeft') > -1 || this.keyDown.indexOf('MetaLeft') > -1) && event.code == 'KeyO'){ event.preventDefault(); this.uploadImg() }else if(this.keyDown.indexOf('KeyB') > -1){ // if(operation.value == 'pencil' || operation.value == 'texture'){ this.setOperation('pencil') // } }else if(this.keyDown.indexOf('KeyE') > -1){ // if(operation.value == 'pencil' || operation.value == 'texture'){ this.setOperation('eraser') // } } } // if(this.keyDown.indexOf(event.key)>-1){ // }else{ // this.keyDown.push(event.code) // if(event.key === 'Enter' && this.operation == 'fold'){ // this.foldEnd('Enter') // }else if(event.key === 'Delete'){ // this.deleteObject() // }else if(this.keyDown.indexOf('ControlLeft') > -1 && this.keyDown.indexOf('KeyZ') > -1 && this.keyDown.indexOf('ShiftLeft') > -1){ // this.historyState('reverse') // }else if(this.keyDown.indexOf('ControlLeft') > -1 && this.keyDown.indexOf('KeyZ') > -1){ // this.historyState('') // }else if(this.keyDown.indexOf('ControlLeft') > -1 && this.keyDown.indexOf('KeyC') > -1){ // this.copy() // }else if(this.keyDown.indexOf('ControlLeft') > -1 && this.keyDown.indexOf('KeyV') > -1){ // this.paste() // }else if(this.keyDown.indexOf('AltLeft') > -1 && this.keyDown.length == 1 && this.operation != 'move'){ // this.oldOperation = this.operation // this.setOperation('move') // } // } } getColor = async ()=>{ try { const dropper = new EyeDropper(); const result = await dropper.open(); let hex = result.sRGBHex.replace("#", ""); // 将十六进制颜色码拆分成红、绿、蓝三个部分 // const r = parseInt(hex.substring(0, 2), 16); // const g = parseInt(hex.substring(2, 4), 16); // const b = parseInt(hex.substring(4, 6), 16); this.brushwork.color = result.sRGBHex; // canvasPencilColor.value = setPencilColor() } catch (e) { // message.info(this.t('ColorboardUpload.jsContent1')) } } canvasClear(){ // if(this.canvas?.dispose)MyCanvas?.[this.id].dispose() let oldCanvasDom = this.canvasDomParent?.querySelector('.canvas-container') let oldCanvasDom1 = this.canvasDomParent?.querySelector('canvas') if(oldCanvasDom)oldCanvasDom.remove() if(oldCanvasDom1)oldCanvasDom1.remove() this.reverseCanvasState=[];//撤回 this.normalCanvasState=[];//反撤回 this.canvas = null this.canvas = null this.layer = { list:[], selectLayer:{ group:null, id:-1, }, currentIndex: 0, } this.mouse = { point:null, upPoint:null, isMovePostion:false, lastPosX:0, lastPosY:0, } this.brushwork = { value:'PencilBrush', width:{}, color:'#000000', texture:0, } this.operation = 'movePosition' this.clearEvent() delete MyCanvas[this.id] // MyCanvas[this.id] = null } clearEvent(){ document.removeEventListener("keydown", this.canvasKeyDown); document.removeEventListener("keyup", this.canvasKeyUp); document.removeEventListener('mousemove', this.mouseMove); document.removeEventListener('touchmove', this.touchmove); } //删除选中元素 deleteObject(){ if(!MyCanvas?.[this.id].getActiveObjects()){ return } let target = MyCanvas?.[this.id].getActiveObjects() target.forEach((item)=>{ MyCanvas?.[this.id].fxRemove(item, { onComplete:()=>{ MyCanvas?.[this.id].discardActiveObject(); // 丢弃当前选中的对象 MyCanvas?.[this.id].renderAll(); // 重新渲染 Canvas } }) MyCanvas[this.id].FX_DURATION = 200 // MyCanvas[this.id].remove(item) }) this.updataLayer() this.updateCanvasState('remove') } async getDashedImg(cloned){ let position = { left:cloned?.left, top:cloned?.top, width:cloned?.width + cloned?.strokeWidth*2, height:cloned?.height + cloned?.strokeWidth*2, } let elements = MyCanvas[this.id].getObjects().filter(obj => this.isAddToLayer(obj)); let imgData = await this.groupToImg(elements,position,'clipPath')//矩形裁剪图片 let img = await this.createImage({imgUrl:imgData}) // cloned._objects = cloned._objects.filter(item => item.type == 'image') let clipPathElement = cloned._objects.filter(obj => obj.type != 'image')[0] cloned.set({ left:0, top:0, visible:true }) img.set({ left:position.left, top:position.top, clipPath:clipPathElement, }) return img } //复制粘贴 async copy(canvas){ var activeObject=null; if(MyCanvas?.[this.id].getActiveObject()){ activeObject = MyCanvas?.[this.id].getActiveObject() }else{ activeObject = MyCanvas?.[this.id].getObjects().filter(obj => obj.custom.dashed)[0]; } if(!activeObject){ return } let copyObj = null await new Promise((resolve, reject) => { activeObject.clone(async (cloned)=>{ this.setClone(activeObject,cloned) if(cloned.custom.dashed){ copyObj = await this.getDashedImg(cloned) }else{ copyObj = cloned } resolve() }) }) this._clipboard = copyObj; } paste(){//粘贴 if(!this._clipboard){ return } this._clipboard.clone(async clonedObj => { MyCanvas?.[this.id].discardActiveObject() // 取消选择 clonedObj.set({ selectable: true }) if(this.exportData.width != -1)await this.createLayer({}) if (clonedObj.type === 'activeSelection') { // 活动选择需要一个对画布的引用 clonedObj.forEachObject((obj)=>{ MyCanvas?.[this.id].add(obj) }) clonedObj.setCoords() } else { MyCanvas?.[this.id].add(clonedObj) } MyCanvas?.[this.id].setActiveObject(clonedObj) MyCanvas?.[this.id].requestRenderAll() }) this._clipboard = null this.updateCanvasState() } isSelectable(obj){//判断元素是否允许选中 if(!this.dashed.isDetail){ return (obj.custom?.type != 'layer' && (!obj.custom?.isSelectable || this.layer.selectLayer.group.custom.groupType == 'Grid') && !obj.isType('path')) }else{ return (obj.custom?.type != 'layer' && (!obj.custom?.isSelectable || this.layer.selectLayer.group.custom.groupType == 'Grid') && !obj.isType('path') && (this.dashed.isDetail || !obj.custom?.dashed)) } } isAddToLayer(obj){//判断元素是否允许添加 return(obj.custom?.type != 'layer' && obj.custom?.layerId == this.layer.selectLayer.id) } //撤回反撤回 //设置画布监听修改添加事件,用来做撤回功能 updateCanvasState(str){ let canvasData = MyCanvas?.[this.id].toJSON(['custom','selectable','MINIOURL','perPixelTargetFind','subTargetCheck','evented']); if(canvasData.clipPath){ canvasData.clipPath.left = 0 canvasData.clipPath.top = 0 } let canvasAsJson = JSON.stringify(canvasData) let layerList = JSON.stringify(this.layer.list) let layerId = this.layer.selectLayer.id if(str == 'loadingCompleted'){ // this.reverseCanvasState.push(canvasAsJson); } this.normalCanvasState.push({canvasAsJson,layerList,layerId}); if (this.isLoadCanvas) { this.reverseCanvasState = [] this.isLoadCanvas = false; this.canvasState = canvasAsJson } } //撤回 async historyState(str){ if(str == 'reverse' && this.reverseCanvasState.length > 0){//反撤回 let obj = this.reverseCanvasState.pop() let layerList = JSON.parse(obj.layerList) this.layer.list = layerList this.layer.selectLayer.id = obj.layerId this.canvasState = obj.canvasAsJson this.normalCanvasState.push(obj); }else if(str == '' && this.normalCanvasState.length > 1){ let obj = this.normalCanvasState.pop() let select = this.normalCanvasState[this.normalCanvasState.length-1] this.canvasState = select.canvasAsJson this.layer.list = JSON.parse(select.layerList) this.layer.selectLayer.id = select.layerId this.reverseCanvasState.push(obj); this.isLoadCanvas = true; }else{ return } MyCanvas?.[this.id].loadFromJSON(this.canvasState, () => {}); MyCanvas?.[this.id].setBackgroundColor({ source:'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC', repeat: 'repeat', },MyCanvas?.[this.id].renderAll.bind(MyCanvas?.[this.id]), ) } setLoadFromJSON(data,fun){ MyCanvas?.[this.id].loadFromJSON(data.canvas, async ()=>{ fun() if(data.groupList.length == 0){ }else{ data.groupList.sort((a, b) => a.index - b.index); data.groupList.forEach((item, i) => { item.index = i + 1; // 从1开始 }); this.layer.currentIndex = data.groupList.length this.layer.list = data.groupList this.layer.selectLayer.id = data.groupList[0].id await this.selectLayer(this.layer.list[this.layer.list.length-1].id) let arr = MyCanvas?.[this.id].getObjects().sort((a, b) =>{ return a.custom.selectLayerIndex - b.custom.selectLayerIndex; }); arr.forEach((item,index)=>{ item.moveTo(index) }) this.addEvent() } }); } temporarilyExport(data){ let scaleXY = { scaleX:data?.scaleX?data?.scaleX:1, scaleY:data?.scaleY?data?.scaleY:1, } let width = data?.width || MyCanvas?.[this.id].width let height = data?.height || MyCanvas?.[this.id].height var canvasDom = document.createElement("canvas"); let exportCanvas = new fabric.Canvas(canvasDom, { width:width*scaleXY.scaleX, height:height*scaleXY.scaleY, scaleX:scaleXY.scaleX, scaleY:scaleXY.scaleY, isDrawingMode: false, // 开启绘图模式 }); return exportCanvas } closeTemporarilyExport(temporar){ if(temporar){ temporar.wrapperEl.remove() temporar.dispose() } } setClone(obj,goal){ if(obj.custom){ goal.set({custom:JSON.parse(JSON.stringify(obj.custom))}) } goal.perPixelTargetFind = obj.perPixelTargetFind goal.hasBorders = obj.hasBorders goal.hasControls = obj.hasControls goal.selectable = obj.selectable goal.erasable = obj.erasable if(obj.minioUrl)goal.minioUrl = obj.minioUrl } getElement(){ let list = [] if(MyCanvas?.[this.id]?.getObjects){ list = MyCanvas?.[this.id].getObjects().filter(obj => this.isAddToLayer(obj) && !obj.custom.dashed && obj.type && obj.erasable); } return list } //导出除了底图 async detailSubmit(){ return await new Promise(async (resolve, reject) => { let list if(this.exportData.width == -1){ list = MyCanvas?.[this.id].getObjects().filter(obj => this.isAddToLayer(obj) && !obj.custom.dashed && obj.type && obj.erasable); }else{ list = MyCanvas?.[this.id].getObjects().filter(obj => !obj.custom.dashed && obj.type); } let layerBg = list.filter(obj => obj.custom.isSelectable)[0] let canvasWidth = layerBg?.width?layerBg?.width:MyCanvas?.[this.id].width let canvasHeight = layerBg?.height?layerBg?.height:MyCanvas?.[this.id].height let exportWidth = this.exportData.width == -1?canvasWidth:this.exportData.width let exportHeight = canvasHeight / canvasWidth * exportWidth let scaleXY = { scaleX:layerBg?.scaleX?layerBg?.scaleX:1, scaleY:layerBg?.scaleY?layerBg?.scaleY:1, width:exportWidth, height:exportHeight, scale:exportWidth / canvasWidth, } let imgData = await this.groupToImg(list,{},'setGrid',scaleXY) resolve(imgData) }) // return imgData } //导出 selectExport(){ let layer = this.layer.list.filter(item=>item.id == this.layer.selectLayer.id)[0] return layer.img } async allExport(){ let list = MyCanvas?.[this.id].getObjects() let layerBg = list.filter(obj => obj.custom.isSelectable)[0] let scaleXY = { scaleX:layerBg?.scaleX?layerBg?.scaleX:1, scaleY:layerBg?.scaleY?layerBg?.scaleY:1, width:layerBg?.width?layerBg?.width:MyCanvas?.[this.id].width, height:layerBg?.height?layerBg?.height:MyCanvas?.[this.id].height, } let imgData = await this.groupToImg(list,{},'setGrid',scaleXY) // let exportCanvas = this.temporarilyExport() // let list = MyCanvas?.[this.id].getObjects() // for (let index = 0; index < list.length; index++) { // let item = list[index] // new Promise((resolve, reject) => { // item.clone((cloned)=>{ // this.setClone(item,cloned) // exportCanvas.add(cloned) // resolve() // }) // }) // } // let data = exportCanvas.toDataURL("image/png"); // this.closeTemporarilyExport(exportCanvas) return imgData } } export default MyCanvas