Files
aida_front/src/tool/canvasGeneralCopy.js

2023 lines
63 KiB
JavaScript
Raw Normal View History

2024-12-11 16:26:36 +08:00
import {
exportSele,
JSRectUpdata,
JSchangeType,
JScanvasMouseDown,
JScanvasMouseMove,
JScreateCheck,
JSSetTexture,
JSSetRemoveImage,
} from "@/tool/canvasDrawing";
import { getMousePosition } from "@/tool/mdEvent";
import { file } from "jszip";
class MyCanvas {
canvas=null
constructor() {
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.canvas;
this.addPresent = {}
this.canvasWH={
width:0,
height: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,//用来获取移入前是否是绘画模式
}
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:[],
}
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 canvasInit (dom, val){//初始化
this.canvasClear()
this.canvasWH = val
this.canvasDomParent = dom;
var canvasDom = document.createElement("canvas");
this.canvasDomParent.appendChild(canvasDom);
MyCanvas.canvas = 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,
});
// MyCanvas.canvas.freeDrawingCursor= 'none'
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.canvas.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.canvas.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.canvas.add(rect1)
// // MyCanvas.canvas.add(rect1)
// let rect = new fabric.Rect({
// left: 0,
// top: 0,
// width: MyCanvas.canvas.width,
// height: MyCanvas.canvas.height,
// inverted:true,
// fill: "red",
// });
// // let rect2 = new fabric.Rect({
// // width: MyCanvas.canvas.width,
// // height: MyCanvas.canvas.height,
// // fill:'#FFF'
// // });
// // // MyCanvas.canvas.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.canvas.width/img.width,
// Y:MyCanvas.canvas.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.canvas.add(rect)
// },{ crossOrigin: "Anonymous" })
// // // MyCanvas.canvas.add(rect1)
// // // rect1.clipPath = group
// // // MyCanvas.canvas.forEachObject((item) =>{
// // // if(item.clipPath){
// // // item.clipPath.add(rect2)
// // // // item.clipPath = group
// // // }
// // // })
// return
MyCanvas.canvas.on("mouse:move", this.setCanvasMove.bind(this));
MyCanvas.canvas.on("mouse:down",this.setCanvasDown.bind(this));
MyCanvas.canvas.on("mouse:up",this.setCanvasUp.bind(this));
MyCanvas.canvas.on("mouse:wheel",this.setCanvasWheel.bind(this));
//双击
MyCanvas.canvas.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.canvas, true);
JSchangeType(MyCanvas.canvas,'init')
// await this.createBg()
await this.createLayer({str:'init'})//创建图层并且使用
MyCanvas.canvas.on("object:added", (event)=>{
this.addLayer(event)
});
this.canvas = MyCanvas.canvas;
return MyCanvas.canvas
}
initCanvasWH(str){
let scale
if(this.canvasWH.width>this.canvasWH.height)scale = this.canvasDomParent.offsetWidth / this.canvasWH.width
if(this.canvasWH.width<this.canvasWH.height)scale = this.canvasDomParent.offsetHeight / this.canvasWH.height
if(this.canvasWH.width == this.canvasWH.height)scale = this.canvasDomParent.offsetHeight / this.canvasWH.height
let x = this.canvasWH.width / 2
let y = this.canvasWH.height / 2
if(str == 'updata'){
x = 0
y = 0
const vpt = MyCanvas.canvas.viewportTransform;
vpt[4] = 0; // 更新水平偏移
vpt[5] = 0; // 更新垂直偏移
}
MyCanvas.canvas.zoomToPoint(
{ // 关键点
x: x,
y: y
},
scale
)
MyCanvas.canvas.setBackgroundColor({
source:'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC',
repeat: 'repeat',
},MyCanvas.canvas.renderAll.bind(MyCanvas.canvas),
)
}
mouseMove(event){
let e = getMousePosition(event,false)
this.setDomMove(e)
}
touchmove(event){
let e = getMousePosition(event,true)
this.setDomMove(e)
}
setDomMove(event){
let canvasCenterBox = this.canvasDomParent;
if(!canvasCenterBox)return
let parentX = event.clientX - canvasCenterBox.getBoundingClientRect().left
let parentY = event.clientY - canvasCenterBox.getBoundingClientRect().top
this.pencilbtnStyle.left = parentX + "px"
this.pencilbtnStyle.top = parentY+'px'
}
//设置操作
setOperation(str){
this.operation = str
MyCanvas.canvas.discardActiveObject();//取消所有选中边框
if(this.createPatterning.state){
MyCanvas.canvas.remove(this.createPatterning.current)
}
this.removeSetText()
initAligningGuidelines(MyCanvas.canvas,false)
MyCanvas.canvas.remove(this.createPatterning.polyLineBtn)
if(str == 'pencil'){
this.setPencil()
this.pencilbtnStyle.display = `block`
this.setCursor('none');
MyCanvas.canvas.freeDrawingCursor = 'none'
}else if(str == 'move'){
JSchangeType(MyCanvas.canvas,'')
MyCanvas.canvas.isDrawingMode = false
this.pencilbtnStyle.display = `none`
this.setCursor('grab');
}else if(str == 'movePosition'){
JSchangeType(MyCanvas.canvas,'init')
initAligningGuidelines(MyCanvas.canvas,true)
this.setMove()
this.pencilbtnStyle.display = `none`
this.setCursor('all-scroll');
MyCanvas.canvas.isDrawingMode = false
}else if(str == 'texture'){
this.setTexture()
this.pencilbtnStyle.display = `block`
MyCanvas.canvas.freeDrawingCursor = 'none'
this.setCursor('none');
}else if(str == 'eraser'){
this.setEraser()
this.pencilbtnStyle.display = `block`
MyCanvas.canvas.freeDrawingCursor = 'none'
this.setCursor('none');
}else if(str == 'text'){
this.setMove()
this.setText()
JSchangeType(MyCanvas.canvas,'init')
this.setCursor('text')
this.pencilbtnStyle.display = `none`
}else if(['zoomIn', 'zoomOut'].includes(str)){
this.pencilbtnStyle.display = `none`
if(str == 'zoomIn')this.setCursor('zoom-in');
if(str == 'zoomOut')this.setCursor('zoom-out');
MyCanvas.canvas.isDrawingMode = false
MyCanvas.canvas.forEachObject((obj) =>{
if(obj.type != 'group' && !obj.isType('path')){
obj.selectable = false
}
});
}else if(['dashedPencil', 'dashed'].includes(str)){
this.setGroupGrid('all')
MyCanvas.canvas.isDrawingMode = false
this.pencilbtnStyle.display = `none`
this.setCursor('crosshair')
MyCanvas.canvas.freeDrawingCursor = 'crosshair'
if(str == 'dashedPencil')this.setDashedPencil()
MyCanvas.canvas.forEachObject((obj) =>{
if(obj.type != 'group' && !obj.isType('path')){
obj.selectable = false
}
});
}else if(str){
this.pencilbtnStyle.display = `none`
this.setCursor('auto');
MyCanvas.canvas.isDrawingMode = false
MyCanvas.canvas.forEachObject((obj) =>{
if(obj.type != 'group' && !obj.isType('path')){
obj.selectable = false
}
});
}
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.canvas.defaultCursor = str;
MyCanvas.canvas.moveCursor = str;
MyCanvas.canvas.hoverCursor = str;
MyCanvas.canvas.upperCanvasEl.style.cursor = str;
}
setCanvasMove = (event)=>{
if(this.mouse.isMovePostion && this.operation == 'move') return this.setCanvasPosition(event)
if(MyCanvas.canvas.isDrawingMode){
}else{
let getActiveObject = MyCanvas.canvas.getActiveObject()
if(
!this.clipPath.isImg &&
this.mouse.isDown &&
getActiveObject &&
getActiveObject.custom.dashed &&
this.layer.selectLayer.group.custom?.groupType == 'Grid' &&
this.operation == 'movePosition' &&
getActiveObject._objects.length == 1
){
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.canvas.requestRenderAll()
}
}
}
setCanvasPosition(event){
const e = event;
const vpt = MyCanvas.canvas.viewportTransform;
vpt[4] += e.pointer.x - this.mouse.lastPosX; // 更新水平偏移
vpt[5] += e.pointer.y - this.mouse.lastPosY; // 更新垂直偏移
MyCanvas.canvas.requestRenderAll(); // 请求重绘画布
this.mouse.lastPosX = e.pointer.x;
this.mouse.lastPosY = e.pointer.y;
}
// setRemoveDashed(){
// MyCanvas.canvas.forEachObject((obj) =>{
// if(obj.custom.dashed && obj._objects){
// let rect = obj._objects.filter(item => item.type == 'rect')[0]
// obj.remove(rect)
// MyCanvas.canvas.renderAll();
// }
// });
// }
//设置再画布上按下
setCanvasDown(event){
if(event.target && event.target.custom?.dashed && ['dashedPencil', 'dashed'].includes(this.operation)){
// if(MyCanvas.canvas.isDrawingMode){
// MyCanvas.canvas.isDrawingMode = false;
// }
this.dashed.state = true
}else if(!event.target?.custom?.dashed){
// if(['dashedPencil'].includes(this.operation)){
// MyCanvas.canvas.isDrawingMode = true;
// }
this.dashed.state = false
}
let dashedGroup = MyCanvas.canvas.getObjects().filter(obj => obj.custom.dashed)[0];
if(this.dashed.state && (this.operation == 'dashed' || this.operation == 'dashedPencil') && dashedGroup)return
if(!this.dashed.state && (this.operation == 'dashed' || this.operation == 'dashedPencil') && !event.target?.custom?.dashed && dashedGroup){
MyCanvas.canvas.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.canvas,this.operation)
this.createPatterning.state = true
MyCanvas.canvas.forEachObject((obj) =>{
obj.set('selectable', false); // 禁用选中
});
if(this.createPatterning.current && this.operation == 'fold'){
MyCanvas.canvas.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.canvas.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.canvas.add(this.createPatterning.current)
if(this.operation == 'fold'){
this.createPatterning.polyLineBtn = JScreateCheck(event)
this.createPatterning.polyLineBtn.on('mousedown',this.foldEnd.bind(this))
MyCanvas.canvas.add(this.createPatterning.polyLineBtn)
}
}
}else{
// var clickedObject = event.target;
// if (clickedObject instanceof fabric.Textbox && this.operation != 'text') {
// this.createPatterning.textDataShow = true
// this.createText = clickedObject
// console.log(1);
// }else{
// console.log(2);
// 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.canvas.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.canvas.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.canvas.forEachObject((obj) =>{
if(this.isSelectable(obj)){
obj.selectable = true
}else{
obj.selectable = false
}
});
MyCanvas.canvas.bringToFront(this.createPatterning.polyLineBtn);//设置优先级最高
}else if(this.operation){
this.createPatterning.state = false
MyCanvas.canvas.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.type != 'image')[0]
let imgBG = MyCanvas.canvas.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.canvas.getObjects().filter(obj => this.isAddToLayer(obj));
let imgData = await this.groupToImg(elements,position,'clipPath')
let img = await this.createImage({minioUrl: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.canvas.isDrawingMode = true
let pencil = new fabric.Test(MyCanvas.canvas,{}); //普通笔
MyCanvas.canvas.freeDrawingBrush = pencil
}
async setDashed(obj){
MyCanvas.canvas.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({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.canvas.add(group)
})
// this.addLayer({target:obj})//更新参数
// for (let index = 0; index < elements.length; index++) {
// const item = elements[index];
// await new Promise((resolve, reject) => {
// if(this.isAddToLayer(item)){
// item.clone((cloned)=>{
// this.setClone(item,cloned)
// if(item.custom?.layerId != -1){
// temporar.add(cloned)
// }
// resolve()
// })
// }
// })
// }
// const {left,height,top,width} = position
// let scale = 1.2/MyCanvas.canvas.getZoom()<1?1.2:1.2/MyCanvas.canvas.getZoom()
// let data = temporar.toDataURL({left,height:height+scale,top,width:width+scale});
// let img = await this.createImage({minioUrl:data})
// img.set({scaleX:1,scaleY:1})
// MyCanvas.canvas.forEachObject((item) =>{
// if(item.custom.isSelectable)return
// if(!this.isAddToLayer(item))return
// let imgScale = {
// pX:(item.scaleX?item.scaleX:1),
// pY:(item.scaleY?item.scaleY:1),
// }
// let scaleWH = item.width / (item.width * imgScale.pX)
// let rect = new fabric.Rect({
// left:left * scaleWH - item.left - item.width / 2,
// top:top * scaleWH - item.top - item.height / 2,
// width:width * scaleWH,
// height:height * scaleWH,
// })
// let group
// if(item.clipPath){
// item.clipPath.clone(cloned =>{
// group = cloned
// })
// }else{
// group = new fabric.Group([],)
// }
// group.set({
// width:item.width * imgScale.pX,
// height:item.height * imgScale.pY,
// left: -item.width * imgScale.pX / 2,
// top: -item.height * imgScale.pY / 2,
// inverted:true,
// })
// group.add(rect)
// item.set({clipPath:group})
// MyCanvas.canvas.renderAll(); // 请求重绘画布
// })
// img.set({
// left:left,
// top:top,
// custom:{
// layerId:this.layer.selectLayer.id,
// },
// // hasControls:false,
// })
// MyCanvas.canvas.add(img)
}
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.canvas.getObjects().filter(obj => obj.custom.layerId == id)
let copyElements = []
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.canvas.add(item))
}
async setGroupGrid(str){//group变为图片
// MyCanvas.canvas.discardActiveObject();//取消所有选中边框
let elements = MyCanvas.canvas.getObjects().filter(obj => this.isAddToLayer(obj) && !obj.custom.dashed && obj.type);
if(str == 'all'){
elements = MyCanvas.canvas.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.canvas.width,
height:layerBg?.height?layerBg?.height:MyCanvas.canvas.height,
}
let imgData = await this.groupToImg(elements,{},'setGrid',scaleXY)
let img = await this.createImage({minioUrl:imgData})
elements.forEach((obj) =>{
if(obj.custom.isSelectable){
}else{
MyCanvas.canvas.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)
}else{
const rect = new fabric.Rect({
// left:0,
// top:0,
width: MyCanvas.canvas.width,
height: MyCanvas.canvas.height,
strokeWidth:0,
fill: new fabric.Pattern({
source: img.getElement(), // 传入图片元素
repeat: 'no-repeat' // 设置图片不重复
}),
custom:{
isSelectable:true,
},
hasBorders: true,
hasControls: true
});
this.setGroupStyle(rect)
MyCanvas.canvas.add(rect)
}
MyCanvas.canvas.renderAll() // 刷新画布改变group的visible属性必须通过刷新画布才能应用新属性值
}
//液化
getLiquefactionImgObj(){
return new Promise(async (resolve, reject) => {
let img,str = null
const activeObject = this.canvas.getActiveObject(); // 获取选中的对象
let dashedGroup = MyCanvas.canvas.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 = this.canvas.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) => {
console.log(liquefaction.img);
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 = this.canvas.getObjects().filter(item => item.custom?.isSelectable)[0]
let img = await this.createImage({minioUrl:data})
bg.set({
fill: new fabric.Pattern({
source: img.getElement(), // 传入图片元素
repeat: 'no-repeat' // 设置图片不重复
}),
})
}
MyCanvas.canvas.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.canvas.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(type == 'setGrid'){
cloned.set({
left: cloned.left - xy.x,
top: cloned.top - xy.y,
})
// }
if(cloned.custom?.layerId != -1){
temporar.add(cloned)
}
resolve()
})
})
}
let data = temporar.toDataURL(imgData);
this.closeTemporarilyExport(temporar)
return data
}
setCanvasWheel(opt){
const delta = opt.e.deltaY // 滚轮,向上滚一下是 -100向下滚一下是 100
let zoom = MyCanvas.canvas.getZoom() // 获取画布当前缩放值
zoom *= 0.999 ** delta
if (zoom > 20) zoom = 20
if (zoom < 0.01) zoom = 0.01
MyCanvas.canvas.zoomToPoint(
{ // 关键点
x: opt.e.offsetX,
y: opt.e.offsetY
},
zoom
)
opt.e.preventDefault()
opt.e.stopPropagation()
this.setPencilWidth()
}
foldEnd(key){
MyCanvas.canvas.skipTargetFind = true
let points = this.createPatterning.current.points
if(key == 'Enter'){
}else{
points.pop()
}
points.pop()
this.createPatterning.state = false
MyCanvas.canvas.remove(this.createPatterning.current)
MyCanvas.canvas.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.canvas.add(polyline)
this.clearPatterning()//临时图形置为空并且添加撤回对象里面
// this.layerAddElement(polyline)
}
clearPatterning(){
if(this.createPatterning.state){
MyCanvas.canvas.remove(this.createPatterning.current)
}
this.createPatterning.current = null
MyCanvas.canvas.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.canvas.getActiveObject();
switch (str) {
case 'Front':
MyCanvas.canvas.bringToFront(activeObject)//顶层
// this.layer.selectLayer.group.bringToFront(activeObject)
break
case 'Back':
MyCanvas.canvas.sendToBack(activeObject)//底层
// this.layer.selectLayer.group.sendToBack(activeObject)
break
case 'Forward':
MyCanvas.canvas.bringForward(activeObject)
// this.layer.selectLayer.group.bringForward(activeObject)
break
case 'Backwards':
MyCanvas.canvas.sendBackwards(activeObject)
// this.layer.selectLayer.group.sendBackwards(activeObject)
break
}
}
setPencil(){
let pencil
MyCanvas.canvas.isDrawingMode = true//开启绘画模式
if(this.brushwork.value == 'PencilBrush'){
pencil = new fabric.PencilBrush(MyCanvas.canvas,{}); //普通笔
}else if(this.brushwork.value == 'Marking'){
pencil = new fabric.PencilBrush(MyCanvas.canvas,); //记号笔
}else if(this.brushwork.value == 'InkBrush'){
pencil = new fabric.InkBrush(MyCanvas.canvas,{}); //油画笔
}else if(this.brushwork.value=='CrayonBrush'){
pencil = new fabric.CrayonBrush(MyCanvas.canvas,{}); //蜡笔
}else if(this.brushwork.value == 'RibbonBrush'){
pencil = new fabric.RibbonBrush(MyCanvas.canvas,{width: 1,}); //色带
}else if(this.brushwork.value == 'MarkerBrush'){
pencil = new fabric.MarkerBrush(MyCanvas.canvas,{}); //书写笔
// pencil = new fabric.PenBrush(MyCanvas.canvas,{}); //书写笔
}else if(this.brushwork.value == 'WritingBrush'){
pencil = new fabric.WritingBrush(MyCanvas.canvas,{}); //毛笔
}else if(this.brushwork.value == 'LongfurBrush'){
pencil = new fabric.LongfurBrush(MyCanvas.canvas,{width: 1,}); //色带
}else if(this.brushwork.value == 'SpraypaintBrush'){
pencil = new fabric.SpraypaintBrush(MyCanvas.canvas,{}); //长毛刷
}
MyCanvas.canvas.freeDrawingBrush = pencil
if(this.brushwork.value == 'RibbonBrush' || this.brushwork.value == 'LongfurBrush'){
MyCanvas.canvas.freeDrawingBrush.width = 1;
}
if(this.brushwork.value == 'Marking'){
MyCanvas.canvas.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.canvas.freeDrawingBrush.color = this.hexToRgba(this.brushwork.color,1);
}
this.setPencilWidth()
this.pencilbtnStyle.background = this.brushwork.color
MyCanvas.canvas.freeDrawingBrush.isEraser = false
}
setCanvasZoom(opt){
let zoom = MyCanvas.canvas.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.canvas.setDimensions(MyCanvas.canvas.width *= zoom,MyCanvas.canvas.height *= zoom)
// MyCanvas.canvas.wrapperEl.style.zoom = zoom
MyCanvas.canvas.zoomToPoint(
{ // 关键点
x: opt.pointer.x,
y: opt.pointer.y
},
zoom
)
opt.e.preventDefault()
opt.e.stopPropagation()
this.setPencilWidth()
}
async addImage (imgData){
let img = await this.createImage(imgData)
let position = {
// left: 0,
// top:MyCanvas.canvas.wrapperEl.parentNode.scrollTop,
left: MyCanvas.canvas.width/2,
top: MyCanvas.canvas.height/2,
}
img.set({
custom:{
type:'upImgFiles'
}
})
await this.createLayer({})
this.setCanvasImage(img,position,"upImgFiles",imgData)
}
createImage(imgData){
return new Promise((resolve, reject) => {
fabric.Image.fromURL(imgData.minioUrl,(img) => {
resolve(img)
},{ crossOrigin: "Anonymous" })
})
}
setImageWidth = (key,img)=>{
const CW = MyCanvas.canvas.width
const CH = MyCanvas.canvas.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.canvas.height/2) / imgObj.height
// imgWidth = imgObj.width * heightScale
// }else{
// imgWidth /= 2
// }
// }
// }
return imgWidth
}
async setCanvasImage(img,position,key,data){
let minioUrl = ''//表示收藏或者generate
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(/:(\d+)\/(.*)/);
minioUrl = match[2]
}
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,
minioUrl,
scaleX:scale.X,
scaleY:scale.Y,
});
MyCanvas.canvas.add(img)
this.updateCanvasState('')
}
setMove(){
MyCanvas.canvas.isDrawingMode = false
MyCanvas.canvas.forEachObject((obj) =>{
console.log(obj,this.isSelectable(obj));
if(this.isSelectable(obj)){
obj.selectable = true
}else{
obj.selectable = false
}
});
MyCanvas.canvas.renderAll() // 刷新画布改变group的visible属性必须通过刷新画布才能应用新属性值
}
async setTexture(){
MyCanvas.canvas.isDrawingMode = true//开启绘画模式
let img = await JSSetTexture(this.texture.list[this.texture.value].url)
let zoom = MyCanvas.canvas.getZoom() // 获取画布当前缩放值
let patternBrush = new fabric.PatternBrush(MyCanvas.canvas)
patternBrush.source = img
patternBrush.width = Number(this.brushwork.width[this.operation]) / zoom; // 设置画笔大小
this.setPencilWidth()
MyCanvas.canvas.freeDrawingBrush = patternBrush
}
setEraser(){
MyCanvas.canvas.isDrawingMode = true
let eraser = new fabric.EraserBrush(MyCanvas.canvas)
MyCanvas.canvas.freeDrawingBrush = eraser
this.pencilbtnStyle.background = '#fff'
MyCanvas.canvas.freeDrawingBrush.isEraser = true
this.setPencilWidth()
MyCanvas.canvas.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.canvas.freeDrawingBrush.isEraser){
}else{
this.pencilbtnStyle.background = this.brushwork.color
}
if(this.brushwork.value == 'Marking'){
MyCanvas.canvas.freeDrawingBrush.color = this.hexToRgba(this.brushwork.color,.5);
}else if(this.brushwork.value == 'InkBrush'){
MyCanvas.canvas.freeDrawingBrush.color = this.hexToRgba(this.brushwork.color,.2);
}else{
MyCanvas.canvas.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.canvas.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.canvas.setWidth(this.canvasWH.width);
MyCanvas.canvas.setHeight(this.canvasWH.height);
// MyCanvas.canvas.width = this.canvasWH.width
// MyCanvas.canvas.height = this.canvasWH.height
this.initCanvasWH('updata')
},1000)
}
setColorHistory = (value)=>{
this.brushwork.color = value
this.pencilColor()
}
setPencilWidth(){//切换颜色给铅笔设置颜色
let zoom = MyCanvas.canvas.getZoom() // 获取画布当前缩放值
clearTimeout(this.setTimeOut.width)
this.setTimeOut.width = setTimeout(()=>{
if(!this.brushwork.width[this.operation])this.brushwork.width[this.operation]=20
// MyCanvas.canvas.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.canvas.freeDrawingBrush.width = Number(this.brushwork.width[this.operation]) / zoom;
}else{
MyCanvas.canvas.freeDrawingBrush.width = Number(this.brushwork.width[this.operation]);
}
if((this.brushwork.value == 'LongfurBrush' || this.brushwork.value == 'RibbonBrush') && this.operation == 'pencil'){
MyCanvas.canvas.freeDrawingBrush.width = 1;
this.pencilbtnStyle.height = 1+'px'
this.pencilbtnStyle.width = 1+'px'
}
},100)
}
//关闭u或者创建文字
setTextFun(e){
if(this.operation != 'text'){
return
}
MyCanvas.canvas.forEachObject((obj) =>{
if(obj.type == 'textbox' && !obj.text){
MyCanvas.canvas.remove(obj);
}
});
var clickedObject = e.target;
if (clickedObject instanceof fabric.Textbox) {
this.createText = clickedObject
this.setTextData(this.createText)
}else{
var pointer = MyCanvas.canvas.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.canvas.add(this.createText)
// this.layer.selectLayer.group.add(this.createText)
this.createText.enterEditing();
MyCanvas.canvas.setActiveObject(this.createText).renderAll();
this.removeSetText()
}
}
setText(){
MyCanvas.canvas.on('mouse:down',(event)=>{
if(this.operation == 'zoomIn' || this.operation == 'zoomOut'){
}else{
this.setTextFun(event)
}
})
}
removeSetText(){
MyCanvas.canvas.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.canvas.width,
// height: MyCanvas.canvas.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.canvas.width,
// height: MyCanvas.canvas.height,
// erasable:false,
// selectable:false,
// });
// group.custom.layerId = -1
// MyCanvas.canvas.add(group)
// MyCanvas.canvas.clipPath = rect
// resolve()
// });
// })
// }
createLayer(data){
let {str,id} = data
let canvasData = MyCanvas.canvas.toJSON(['selectable','minioUrl','custom']);
return new Promise(async (resolve, reject) => {
MyCanvas.canvas.discardActiveObject();
if(!id)id = new Date().getTime()
let index = this.layer.currentIndex += 1
const rect = new fabric.Rect({
left: -MyCanvas.canvas.width / 2,
top: -MyCanvas.canvas.height / 2,
// left:0,
// top:0,
width: MyCanvas.canvas.width,
height: MyCanvas.canvas.height,
strokeWidth:0,
fill:'#FFF',
custom:{
layerId:id,
isSelectable:true,
},
// erasable:false,
selectable:false,
});
rect.clone((cloned)=>{
rect.clipPath = cloned
})
const group = new fabric.Group([], {
width: MyCanvas.canvas.width,
height: MyCanvas.canvas.height,
left:0,
top:0,
selectable:false,
erasable:false,
subTargetCheck:true,
evented:false,
// originX:'left',
// originY:'top',
custom:{
layerId:id,
type:'layer' ,
groupType:'Object',
layerIndex:index,
selectLayerIndex:(index) * 10000,
}
});
if(str == 'init'){
group.moveTo(group.custom.selectLayerIndex)
group.add(rect)
group.clone((cloned)=>{
cloned.set({left:0,top:0})
MyCanvas.canvas.clipPath = cloned
})
}
MyCanvas.canvas.add(group)
let img = group.toDataURL({
width: MyCanvas.canvas.width,
height: MyCanvas.canvas.height,
})
this.layer.list.unshift({
name:`Layer${index}`,
id,img,isShow:true,
groupType:'Object',
index,})
await this.selectLayer(id)
MyCanvas.canvas.renderAll();
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.canvas.remove(obj)
this.updataLayerImg(this.layer.selectLayer.id,group.toDataURL({
width: MyCanvas.canvas.width,
height: MyCanvas.canvas.height
}))
}
addLayer(options){
if(this.createPatterning.state)return
this.clipPath.clipGroup = MyCanvas.canvas.getObjects().filter(obj => obj.custom?.dashed)?.[0];
if (options.target.type === 'group' && options.target.custom?.layerId) return;
if(!options.target?.custom?.layerId){
if(options.target?.custom){
options.target.custom.layerId = this.layer.selectLayer.id
}else{
options.target.set({custom:{layerId : this.layer.selectLayer.id}})
}
}
//判断是否可以点击空白地方进行选中
if(options.target?.custom?.dashed){
options.target.set({perPixelTargetFind:false,erasable:false,hasBorders: false,hasControls: false})
// MyCanvas.canvas.setActiveObject(options.target);
MyCanvas.canvas.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.canvas.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.setGroupGrid('all')
MyCanvas.canvas.renderAll();
this.updataLayer()
}
upLayerIndex(list){
list.forEach((item,index)=>{
let arr = MyCanvas.canvas.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.canvas.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.canvas.getObjects().filter(obj => {
return this.isAddToLayer(obj)
});
const group = new fabric.Group([], {
width: this.layer.selectLayer.group.width,
height: this.layer.selectLayer.group.height,
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.left = clonedObj.left - this.layer.selectLayer.group.width/2
clonedObj.top = clonedObj.top - this.layer.selectLayer.group.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({
width: this.layer.selectLayer.group.width,
height: this.layer.selectLayer.group.height
})
)
},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.canvas.remove(this.layer.selectLayer.group)
MyCanvas.canvas.forEachObject((obj) =>{
if(obj.type != 'group' && obj.custom?.layerId == id){
MyCanvas.canvas.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.canvas.remove(group)
}
this.updateCanvasState()
}
async selectLayer(id){
await new Promise(async (resolve, reject) => {
if(this.layer.selectLayer.id != -1){
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.canvas.renderAll() // 刷新画布改变group的visible属性必须通过刷新画布才能应用新属性值
this.setOperation('movePosition')
resolve('')
})
}
async mergeGroup(){
const elements = MyCanvas.canvas.getObjects().filter(obj => this.isAddToLayer(obj));
let isClipPath = MyCanvas.canvas.getObjects().filter(obj => obj.custom.dashed);
if(isClipPath.length>0)await this.setGroupGrid('all')
let group = await this.lookingLayer(this.layer.selectLayer.id,'setlayerIndex')
group.set({visible: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 - group.width/2
v.top = v.top - group.height/2
if(v.custom?.dashed){
// MyCanvas.canvas.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.canvas.remove(v))
}
async expandGroup(){
const elements = this.layer.selectLayer.group._objects.filter(obj => this.isAddToLayer(obj));
// fabric.util.enlivenObjects(elements, (clonedObjects) => {
this.layer.selectLayer.group.set({visible: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 + this.layer.selectLayer.group.width/2
v.top = v.top + this.layer.selectLayer.group.height/2
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.canvas.add(img)
// }
}else{
MyCanvas.canvas.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.canvas.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){
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){
// console.log(id);
item.isShow = !item.isShow
MyCanvas.canvas.forEachObject((obj)=>{
if(obj.custom.layerId == id)obj.visible = item.isShow
})
MyCanvas.canvas.renderAll() // 刷新画布改变group的visible属性必须通过刷新画布才能应用新属性值
}
canvasKeyDown(event){
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')
}
}
}
canvasClear(){
if(MyCanvas.canvas?.dispose)MyCanvas.canvas.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=[];//反撤回
MyCanvas.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'
document.removeEventListener("keydown", this.canvasKeyDown);
document.removeEventListener("keyup", this.canvasKeyUp);
document.removeEventListener('mousemove', this.mouseMove);
document.removeEventListener('touchmove', this.touchmove);
}
//删除选中元素
deleteObject(){
if(!MyCanvas.canvas.getActiveObjects()){
return
}
let target = MyCanvas.canvas.getActiveObjects()
target.forEach((item)=>{
MyCanvas.canvas.fxRemove(item, {
onComplete:()=>{
MyCanvas.canvas.discardActiveObject(); // 丢弃当前选中的对象
MyCanvas.canvas.renderAll(); // 重新渲染 Canvas
}
})
MyCanvas.canvas.FX_DURATION = 200
// MyCanvas.canvas.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.canvas.getObjects().filter(obj => this.isAddToLayer(obj));
let imgData = await this.groupToImg(elements,position,'clipPath')//矩形裁剪图片
let img = await this.createImage({minioUrl: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.canvas.getActiveObject()){
activeObject = MyCanvas.canvas.getActiveObject()
}else{
activeObject = MyCanvas.canvas.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;
}
async paste(){//粘贴
if(!this._clipboard){
return
}
await this.createLayer({})
this._clipboard.clone(clonedObj => {
// this.setClone(this._clipboard,clonedObj)
MyCanvas.canvas.discardActiveObject() // 取消选择
clonedObj.set({
left: clonedObj.left,
top: clonedObj.top,
selectable: true
})
if (clonedObj.type === 'activeSelection') {
// 活动选择需要一个对画布的引用
clonedObj.forEachObject((obj)=>{
MyCanvas.canvas.add(obj)
})
clonedObj.setCoords()
} else {
MyCanvas.canvas.add(clonedObj)
// this.layer.selectLayer.group.add(clonedObj)
}
MyCanvas.canvas.setActiveObject(clonedObj)
MyCanvas.canvas.requestRenderAll()
})
this._clipboard = null
this.updateCanvasState()
}
isSelectable(obj){//判断元素是否允许选中
return (obj.custom?.type != 'layer' && (!obj.custom?.isSelectable || this.layer.selectLayer.group.custom.groupType == 'Grid') && !obj.isType('path'))
//isSelectable已废弃现在isSelectable作为判断是否是背景来使用
return (obj.custom?.type != 'layer' && !obj.isType('path'))
}
isAddToLayer(obj){//判断元素是否允许添加
return(obj.custom?.type != 'layer' && obj.custom?.layerId == this.layer.selectLayer.id)
}
//撤回反撤回
//设置画布监听修改添加事件,用来做撤回功能
updateCanvasState(str){
let canvasData = MyCanvas.canvas.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);
}
console.log(JSON.parse(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.canvas.loadFromJSON(this.canvasState, () => {});
MyCanvas.canvas.setBackgroundColor({
source:'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC',
repeat: 'repeat',
},MyCanvas.canvas.renderAll.bind(MyCanvas.canvas),
)
}
temporarilyExport(data){
let scaleXY = {
scaleX:data?.scaleX?data?.scaleX:1,
scaleY:data?.scaleY?data?.scaleY:1,
}
let width = data?.width || MyCanvas.canvas.width
let height = data?.height || MyCanvas.canvas.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
}
//导出
selectExport(){
let layer = this.layer.list.filter(item=>item.id == this.layer.selectLayer.id)[0]
return layer.img
}
allExport(){
let exportCanvas = this.temporarilyExport()
MyCanvas.canvas.forEachObject((obj) =>{
if(obj.custom?.layerId != -1){
obj.clone((cloned)=>{
this.setClone(obj,cloned)
exportCanvas.add(cloned)
})
}
});
let data = exportCanvas.toDataURL("image/png");
this.closeTemporarilyExport(exportCanvas)
return data
}
}
export default new MyCanvas()