Files
aida_front/src/tool/canvasGeneralCopy.js
X1627315083 42dbe8ddc4 fix
2025-05-09 16:07:47 +08:00

1998 lines
62 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
exportSele,
JSRectUpdata,
JSchangeType,
JScanvasMouseDown,
JScanvasMouseMove,
JScreateCheck,
JSSetTexture,
JSSetRemoveImage,
} from "@/tool/canvasDrawingCopy";
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'){
// 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'
){
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.custom)[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({
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
}
})
console.log(223);
MyCanvas.canvas.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.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) => {
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(/^(?: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,
minioUrl,
scaleX:scale.X,
scaleY:scale.Y,
});
MyCanvas.canvas.add(img)
this.updateCanvasState('')
}
setMove(){
MyCanvas.canvas.isDrawingMode = false
MyCanvas.canvas.forEachObject((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
}))
}
async addLayer(options){
console.log(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'){
await new Promise((resolve, reject) => {
console.log(this.clipPath.clipGroup);
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)
console.log(this.clipPath.clipGroup);
MyCanvas.canvas.remove(options.target)
resolve()
})
})
})
// 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);
}
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()