Files
aida_front/src/component/modules/generalCanvas.vue
2024-09-27 16:31:33 +08:00

1563 lines
45 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
<template>
<div class="generalCanvas">
<div class="generalCanvas_left">
<div class="label_item">
<div>{{ $t('exportModel.Height') }}:</div>
<input type="number" @input="setMaxInput('height', 30000)" v-model="canvasWH.height" />
</div>
<div class="generalCanvas_operation_bor_item generalCanvas_left_tool_item_column">
<div class="label_item" v-show="operation != 'move' && operation != 'eraser' && operation != 'texture'">
<div >{{ $t('exportModel.Color') }}</div>
<input type="color" @input="setPencilColor" v-model="canvasPencilColor">
<div class="labelHover_show exportCanvasBox_imgbor">
<div v-for="item in colorHistoryList" :style="{'background':item}" @click="setColorHistory(item)"></div>
</div>
</div>
<div class="label_item" v-show="operation != 'move'">
<div >{{ $t('exportModel.Size') }}:</div>
<input @change="setFontFamily" type="range" @input="setPencilWidth" min="3" max="50" v-model="canvasPencilWidth[operation]">
</div>
<div class="label_item" v-show="operation == 'pencil'">
<div >{{ $t('exportModel.Brushwork') }}:</div>
<a-select ref="select" class="label_select" size="small" v-model:value="brushworkValue"
style="flex: 1"
@change="brushworkChange"
>
<a-select-option class="label_select_item" v-for="item in brushList" :value="item.value">
<img :src="item.url" alt="">
</a-select-option>
</a-select>
</div>
<div class="label_item texture" v-show="operation == 'texture'">
<div >{{ $t('exportModel.Texture') }}:</div>
<a-select ref="select" class="label_select" size="small" v-model:value="textureValue"
style="flex: 1"
@change="textureValueChange"
>
<a-select-option class="label_select_item" v-for="item in textureList" :value="item.value">
<img :src="item.url" alt="">
</a-select-option>
</a-select>
</div>
<div class="label_item" v-show="operation != 'pencil' && operation != 'eraser'&&operation != 'move'&&operation != 'text'&&operation != 'texture'&&operation != ''">
<div >{{ $t('exportModel.FillBack') }}:</div>
<div class="generalCanvas_left_tool_item leftAlign">
<i class="icon iconfont icon-tuceng1" @click="setOperationMode('fill')" :class="{active:operationMode == 'fill'}"></i>
<i class="icon iconfont icon-tuceng" @click="setOperationMode('border')" :class="{active:operationMode == 'border'}"></i>
</div>
</div>
<div class="label_item" v-show="operation === 'move'">
<div >{{ $t('exportModel.Layer') }}:</div>
<div class="generalCanvas_left_tool_item top">
<i class="icon iconfont icon-shangyiceng" @click="setLayerIndex('Front')"></i>
<i class="icon iconfont icon-shangyiceng2" @click="setLayerIndex('Forward')"></i>
<i class="icon iconfont icon-xiayiceng" @click="setLayerIndex('Backwards')"></i>
<i class="icon iconfont icon-shangyiceng1" @click="setLayerIndex('Back')"></i>
</div>
</div>
<div class="label_item" v-show="(operation == '' || operation == 'text' || textDataShow) && operation != 'move'">
<div>Font Family</div>
<a-select ref="select" class="label_select" size="small" v-model:value="fontFamily"
style="flex: 1"
@change="setFontFamily"
>
<a-select-option class="label_select_item" v-for="item in textFontFamilyList" :style="{'font-family':item.value}" :value="item.value">
{{item.name}}
</a-select-option>
</a-select>
</div>
</div>
</div>
<div class="generalCanvas_center_box generalCanvas_left">
<div class="generalCanvas_left_tool generalCanvas_title">
<div class="generalCanvas_left_tool_item">
<i class="icon iconfont icon-chehui" @click="historyState('')"></i>
<i class="icon iconfont icon-fanchehui" @click="historyState('reverse')"></i>
<i class="icon iconfont icon-bianji" @click="setOperation('pencil')" :class="{active:operation == 'pencil'}"></i>
<i class="icon iconfont icon-caizhi" @click="setOperation('texture')" :class="{active:operation == 'texture'}"></i>
<i class="icon iconfont icon-move" @click="setOperation('move')" :class="{active:operation == 'move'}"></i>
<i class="icon iconfont icon-xiangpi_huaban1" @click="setOperation('eraser')" :class="{active:operation == 'eraser'}"></i>
<!-- <i class="icon iconfont icon-xiala" :class="closeNav.tool?'icon-rotate':''" @click.stop="setCloseNav('tool')"></i> -->
<i class="icon iconfont icon-xian" @click="setOperation('fold')" :class="{active:operation == 'fold'}"></i>
<i class="icon iconfont icon-checkbox-full" @click="setOperation('rect')" :class="{active:operation == 'rect'}"></i>
<!-- <i class="icon iconfont icon-zhixian" @click="setOperation('line')" :class="{active:operation == 'line'}"></i> -->
<!-- <i class="icon iconfont icon-circle" @click="setOperation('circle')" :class="{active:operation == 'circle'}"></i> -->
<i class="icon iconfont icon-sanjiaoxing" @click="setOperation('triangle')" :class="{active:operation == 'triangle'}"></i>
<i class="icon iconfont icon-tx-fill-tuoyuanxing" @click="setOperation('ellipse')" :class="{active:operation == 'ellipse'}"></i>
<div class="label_item uploadImage">
<i class="icon iconfont icon-shangchuantupian" ></i>
<input type="file" @change="uploadImage">
</div>
<i class="icon iconfont" @click="setOperation('text')" :class="{active:operation == 'text'}">T</i>
</div>
</div>
<div class="generalCanvas_center">
<div class="editFrontBack_pencilbtn" v-show="!isShowMark" :style="pencilbtnStyle"></div>
</div>
</div>
<div class="mark_loading" v-show="isShowMark">
<a-spin size="large" />
</div>
</div>
</template>
<script>
import {defineComponent, computed, h, ref, nextTick, onBeforeUnmount, reactive, onMounted,
} from "vue";
import { Https } from "@/tool/https";
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import scaleImage from "@/component/HomePage/scaleImage.vue";
import ExportNewCoolection from "@/component/HomePage/ExportNewCoolection.vue";
import { useStore } from "vuex";
import JSZip, { forEach } from "jszip";
// import fabric from 'fabric';
import { message, Modal } from "ant-design-vue";
import domTurnImg from '@/tool/domTurnImg'
import { openGuide,driverObj__ } from "@/tool/guide";
const FileSaver = require("file-saver");
import { JSSetPencil,JSRectUpdata,JSchangeType,JScanvasMouseDown,JScanvasMouseMove,JScreateCheck,JSSetTexture,JSSetGroup } from "@/tool/canvasDrawing";
import { useI18n } from "vue-i18n";
import {isMoible,calculateGradientCoordinate,base64ToFile} from '@/tool/util'
import publish from "@/component/WorksPage/publish.vue";
import canvasGeneral from "@/tool/canvasGeneral";
export default defineComponent({
components: {
scaleImage,
ExportNewCoolection,
publish,
},
props: ["msg", "sketchCatecoryList"],
setup(props,{emit}) {
const {t} = useI18n()
const store = useStore();
let driver__ = computed(()=>{
return store.state.Guide.guide
})
let canvas = reactive({});
// let canvasDom = ref()
let canvasWH = ref({
width: 400,
height: 100,
});
let pencilbtnStyle = ref({
background:'',
width:0+'px',
height:0+'px',
display:'none',
left:0+'px',
top:0+'px',
})
let publish = ref()
// canvasWH.value.width = [window.innerWidth/2.4]
// canvasWH.value.width = canvasWH.value.width.map(num => Math.round(num / 100) * 100)[0];
let credits = computed(() => {
return store.state.UserHabit.credits.value;
});
let allBoardData = computed(() => {
return store.state.UploadFilesModule.allBoardData;
});
let isShowMark = ref(false);
// let allImage = Object.assign(allBoardData.value,{likeDesignCollectionList:likeDesignCollectionList.value})
let position = {
//设置每个图形位置的初始值
x: 0,
y: 0,
height: 0,
};
let sketchGrouping = 3; //sketch分组
let disposeMoodboardShow = true;
let canvasState = ref()//存放canvas操作
let reverseCanvasState = ref([])//存放canvas操作
let normalCanvasState = ref([])//存放canvas操作
let isLoadCanvas = false//撤回或者反撤回false为撤回
let userlikeGroupId = 0
let imgWidth = {} //这是设置画布等宽
let submitCanvasContent = null
let init = (productData) => {
canvasWH.value.height = 100
nextTick().then(async () => {
let canvasBox = document.querySelector(".generalCanvas .generalCanvas_center");
canvas = canvasGeneral.canvasInit(canvasBox,{})
document.addEventListener("keydown", setCanvasKeyDown);
document.addEventListener("keyup", clearCanvasKeyDown);
canvasOnDrop()//开启鼠标到画布事件
canvas.on("object:modified", ()=>{
updateCanvasState()
});
canvas.preserveObjectStacking = true;
canvas.on("mouse:move", event =>setCanvasMove(event));
canvas.on("mouse:down", event=>setCanvasDown(event));
canvas.on("mouse:up", event=>setCanvasUp(event));
//双击
canvas.on("mouse:dblclick", event=>{
if(operation.value == 'fold'){
foldEnd('Enter')
}
});
pencilbtnStyle.value.background = '#fff'
fabric.Object.prototype.cornerSize = 10
fabric.Object.prototype.transparentCorners = false
isShowMark.value = true
isShowMark.value = false
updateCanvasState('')//加载完成后记录一下
setOperation('move')
submitCanvasContent = setInterval(()=>{
let data = setCanvasContent(true)
if(data.objects.length == 0){
clearTimeout(submitCanvasContent)
return
}
data.canvasHeight = canvasWH.value.height
localStorage.setItem('canvasContent',JSON.stringify(data))
localStorage.setItem('userlikeGroupId',userlikeGroupId)
},3000)
if(driver__.value.driver){
driverObj__.moveNext()
}
});
};
let deleteObject = ()=> {
if(!canvas.getActiveObjects()){
return
}
let target = canvas.getActiveObjects()
target.forEach((item)=>{
// var canvas = item.canvas;
// canvas.remove(item);
canvas.fxRemove(item, {
onComplete(){
canvas.discardActiveObject(); // 丢弃当前选中的对象
canvas.renderAll(); // 重新渲染 Canvas
}
})
canvas.FX_DURATION = 300
})
updateCanvasState('remove')
}
let setImageWidth = (key,img)=>{
let imgWidth = canvasWH.value.width; //这是设置画布等宽
if (
disposeMoodboardShow &&
key == "disposeMoodboard" &&
allBoardData.value?.[key]?.length != 0 &&
allBoardData.value?.[key]?.[0] != null
) {
//如果是mood 需要判断用户是否点击layout
disposeMoodboardShow = false;
}
if(key == 'upImgFiles'){
imgWidth = canvasWH.value.width / 4;
}
if (key == "printboardFiles") {
imgWidth = canvasWH.value.width / 8;
}
if (key == "sketchboardFiles"||key == 'moodboardFiles') {
imgWidth =
(canvasWH.value.width -
(sketchGrouping - 1) * 20) /
sketchGrouping;
}
if (key == "likeDesignCollectionList") {
if(img){
let imgObj = JSON.parse(JSON.stringify(img))
let height = imgObj.height
imgObj.height = canvasWH.value.width / 4 * 1.8
let heightScale = imgObj.height / height
imgWidth = imgObj.width * heightScale
}
// imgWidth =
// (canvasWH.value.width -
// (likeDesign - 1) * 20) /
// likeDesign;
}
return imgWidth
}
let setCanvasImage = (img,key,left,top,data)=>{
// data
let imgId = 0
let minioUrl = ''//表示收藏或者generate
let imgUrl = data.imgUrl
if (key == "likeDesignCollectionList") {
imgUrl = data.designOutfitUrl;
imgWidth[key] = setImageWidth(key,img);
}
let url = imgUrl.split('?')[0]
var match = url.match(/:(\d+)\/(.*)/);
minioUrl = match[2]
// let id =
let proportion = img.height / img.width; //计算图形宽高比例
let scaleWH = imgWidth[key] / img.width; //计算放到画布上缩小倍率
img.set({
// width: imgWidth[key]/img.width,
// height: canvasWH.value.height/img.height,
left,
top,
imgId,
minioUrl,
scaleX:
imgWidth[key] / img.width,
scaleY:(img.width * proportion * scaleWH) / img.height,
// cornerSize: 10, // 选中时角的大小为20
// transparentCorners: false, // 选中时角是被填充了。true 空心false 实心
lockRotation: true,
});
}
//关闭画布
//设置画布宽高
let setMaxInput = (str, maxNum) => {
if (str == "width") {
// maxNum = window.innerWidth < 1100 ? 400 : maxNum;
maxNum = [window.innerWidth/2.4]
maxNum = maxNum.map(num => Math.round(num / 10) * 10)[0];
}else if(str == 'height'){
if(position.y+position.height>maxNum){
maxNum = Math.floor(position.y+position.height)
}
}
if (str == "width" && canvasWH.value.width >= maxNum) {
canvasWH.value.width = maxNum;
} else if (str == "height" && canvasWH.value.height >= maxNum) {
canvasWH.value.height = maxNum;
}
canvas.setHeight(canvasWH.value.height);
canvas.setWidth(canvasWH.value.width);
};
let closeNav = ref({
nav:false,
tool:false,
move:false,
})
let setCloseNav = (key)=>{
closeNav.value[key] = !closeNav.value[key]
// for (const iterator in closeNav.value) {
// if(key != iterator){
// closeNav.value[iterator] = false
// }
// }
}
let currentType = ref({
type:'',
data:'',
})
let onDragstart = (type,imgItem)=>{
currentType.value.type = type
currentType.value.data = imgItem
}
let present = {}
let setDragstart = (type,imgItem)=>{
currentType.value.type = type
present.upScaleChecked = false
present = {}
if(imgItem.upScaleChecked){
}else{
imgItem.upScaleChecked = true
present = imgItem
}
currentType.value.data = imgItem
}
let canvasOnDrop = ()=>{
canvas.on('drop', (opt)=> {
let offset = {
left: canvas.getSelectionElement().getBoundingClientRect().left,
top: canvas.getSelectionElement().getBoundingClientRect().top
}
let point = {
x: opt.e.x - offset.left,
y: opt.e.y - offset.top,
}
let pointerVpt = canvas.restorePointerVpt(point)
switch (currentType.value.type) {
case 'colorBoards':
let rect = setGroup(currentType.value.data)
setCanvasColor(pointerVpt.y, pointerVpt.x,rect)
break
case 'moodboardFiles':
createImage(pointerVpt.y, pointerVpt.x,currentType.value.type)
break
default :
createImage(pointerVpt.y, pointerVpt.x,currentType.value.type)
break
}
// 创建完元素,把当前操作的元素类型设置回 null
currentType.value.type = null
currentType.value.data = null
})
}
let setGroup = (data)=>{
return JSSetGroup(data)
}
let setCanvasColor = (top,left,rect)=>{
let group
group = new fabric.Group([rect.color,rect.text,rect.text1],{
left,
top,
width: rect.width,
fill: "rgb(255,255,255)",
stroke: "#212121",
strokeWidth: 1,
});
canvas.add(group);
return group
}
// 创建矩形
let createImage = async (top, left,key)=> {
let itemCanvasImg = currentType.value.data.imgUrl
let data = JSON.parse(JSON.stringify(currentType.value.data))
if(key == 'likeDesignCollectionList'){
itemCanvasImg = currentType.value.data.designOutfitUrl;
}
await new Promise((resolve,reject)=>{
fabric.Image.fromURL(itemCanvasImg,(img) => {
setCanvasImage(img,key,left,top,data)//设置图片
canvas.add(img);
resolve()
},{ crossOrigin: "Anonymous" });
})
updateCanvasState()
}
//设置画布监听修改添加事件,用来做撤回功能
let updateCanvasState = (str) =>{
const canvasAsJson = JSON.stringify(canvas.toJSON());
if(str == 'loadingCompleted'){
// reverseCanvasState.value.push(canvasAsJson);
}
normalCanvasState.value.push(canvasAsJson);
if (isLoadCanvas) {
reverseCanvasState.value = []
isLoadCanvas = false;
canvasState.value = canvasAsJson
}
}
//撤回
let historyState = (str)=> {
if(str == 'reverse' && reverseCanvasState.value.length > 0){//反撤回
let obj = reverseCanvasState.value.pop()
// canvasState.value = reverseCanvasState.value[reverseCanvasState.value.length-1]
canvasState.value = obj
normalCanvasState.value.push(obj);
}else if(str == '' && normalCanvasState.value.length > 1){
let obj = normalCanvasState.value.pop()
canvasState.value = normalCanvasState.value[normalCanvasState.value.length-1]
reverseCanvasState.value.push(obj);
isLoadCanvas = true;
}else{
return
}
canvas.loadFromJSON(canvasState.value, () => {});
}
//在画布进行画画
let operation = ref('move')
let operationMode = ref('fill')
let textureValue = ref(0)//材质信息
let textureValueChange = (value)=>{
textureValue.value = value
setTexture()
}
//铅笔颜色 大小
let brushworkValue = ref('PencilBrush')
let brushworkChange = (value)=>{
brushworkValue.value = value
setPencil()
}
// let brushwork = ref('')
// 监听键盘的 keydown 和 keyup 事件
let keyDown = []
let canvasKeyDown = (event) => {
if(keyDown.indexOf(event.key)>-1){
}else{
keyDown.push(event.code)
if(event.key === 'Enter' && operation.value == 'fold'){
foldEnd('Enter')
}else if(event.key === 'Delete'){
deleteObject()
}else if(keyDown.indexOf('ControlLeft') > -1 && keyDown.indexOf('KeyZ') > -1 && keyDown.indexOf('ShiftLeft') > -1){
historyState('reverse')
}else if(keyDown.indexOf('ControlLeft') > -1 && keyDown.indexOf('KeyZ') > -1){
historyState('')
}else if(keyDown.indexOf('ControlLeft') > -1 && keyDown.indexOf('KeyC') > -1){
copy()
}else if(keyDown.indexOf('ControlLeft') > -1 && keyDown.indexOf('KeyV') > -1){
paste()
}
}
}
let canvasKeyUp = (event) =>{
keyDown = keyDown.filter(function(item) {
return event.code !== item;
})
}
let setCanvasKeyDown = (event)=>{
document.addEventListener('keydown',canvasKeyDown);
document.addEventListener('keyup', canvasKeyUp);
}
let clearCanvasKeyDown = (pointer)=>{
if(!pointer?.target){
document.removeEventListener('keydown',canvasKeyDown);
document.removeEventListener('keyup', canvasKeyUp);
}
}
let canvasPencilColor = ref('#000000')//画笔颜色
let canvasPencilWidth = ref({
})
let fontFamily = ref({})
let textFontFamilyList = ref([])
let allSelectWidth = ref(-1)//多选或单选的宽度
let allSelect = ref([])//多选或单选的宽度
let setOperation = (str)=>{
operation.value = str
canvas.discardActiveObject();//取消所有选中边框
if(createPatterningIs){
canvas.remove(currentPatterning)
}
removeSetText()
initAligningGuidelines(canvas,false)
canvas.remove(polyLineBtn)
if(str == 'pencil'){
setPencil()
pencilbtnStyle.value.display = `block`
}else if(str == 'move'){
JSchangeType(canvas,'init')
initAligningGuidelines(canvas,true)
setMove()
pencilbtnStyle.value.display = `none`
}else if(str == 'texture'){
setTexture()
pencilbtnStyle.value.display = `block`
}else if(str == 'eraser'){
setEraser()
pencilbtnStyle.value.display = `block`
}else if(str == 'text'){
setMove()
setText()
JSchangeType(canvas,'init')
pencilbtnStyle.value.display = `none`
}else if(str){
pencilbtnStyle.value.display = `none`
canvas.forEachObject((obj) =>obj.selectable = false);
canvas.isDrawingMode = false
}
setPencilWidth()
}
let _setAllSelectTime = null
let setAllSelectWidth = ()=>{
clearTimeout(_setAllSelectTime)
allSelect.value.forEach((item)=>{
// item.width = allSelectWidth.value
item.scaleX = allSelectWidth.value/item.width
item.scaleY = item.scaleX
item.setCoords()
})
_setAllSelectTime = setTimeout(() => {
updateCanvasState('')//加载完成后记录一下
}, 1500);
}
let _clipboard = null // 复制到的内容
let copy = () => {//复制
var activeObject = canvas.getActiveObject();
if(!activeObject){
return
}
activeObject.clone(function(cloned) {
_clipboard = cloned;
})
}
let paste = () => {//粘贴
if(!_clipboard){
return
}
_clipboard.clone(clonedObj => {
canvas.discardActiveObject() // 取消选择
// 设置新内容的坐标位置
clonedObj.set({
left: clonedObj.left + 10,
top: clonedObj.top + 10,
evented: true
})
if (clonedObj.type === 'activeSelection') {
// 活动选择需要一个对画布的引用
clonedObj.canvas = canvas;
clonedObj.forEachObject(function(obj) {
canvas.add(obj)
})
clonedObj.setCoords()
} else {
canvas.add(clonedObj)
}
_clipboard.top += 10
_clipboard.left += 10
canvas.setActiveObject(clonedObj)
canvas.requestRenderAll()
})
updateCanvasState()
}
let textureList = ref([])
for (let index = 0; index < 20; index++) {
textureList.value.push({value:index,url:`/image/texture/texture${index}.webp`})
}
let setTexture = async ()=>{
canvas.isDrawingMode = true//开启绘画模式
let img = await JSSetTexture(textureList.value[textureValue.value].url)
let patternBrush = new fabric.PatternBrush(canvas)
patternBrush.source = img
patternBrush.width = canvasPencilWidth.value[operation.value]?canvasPencilWidth.value[operation.value]:20; // 设置画笔大小
canvas.freeDrawingBrush = patternBrush
}
let setOperationMode = (str) =>{
operationMode.value = str
}
let uploadImage = (event)=>{
let input = document.querySelector('.uploadImage input')
const file = event.target.files[0];
setOperation('move')
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
let file = base64ToFile(e.target.result,'upload')
let formData = new FormData();
formData.append("file", file);
let config = {headers:{'Content-Type':'multipart/form-data','Accept':'*/*' }}
Https.axiosPost(Https.httpUrls.canvasElementUpload, formData,config).then((rv)=>{
rv.imgUrl = rv.minioUrl
fabric.Image.fromURL(rv.minioUrl,(img) => {
setCanvasImage(img,"upImgFiles",0,canvas.wrapperEl.parentNode.scrollTop,rv)
canvas.add(img);
},{ crossOrigin: "Anonymous" })
})
input.value = ''
};
reader.readAsDataURL(file);
}
}
let setLayerIndex = (str) =>{//设置优先级
var activeObject = canvas.getActiveObject();
switch (str) {
case 'Front':
canvas.bringToFront(activeObject)//顶层
break
case 'Back':
canvas.sendToBack(activeObject)//底层
break
case 'Forward':
canvas.bringForward(activeObject)
break
case 'Backwards':
canvas.sendBackwards(activeObject)
break
}
}
let 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})`;
}
let brushList = ref(canvasGeneral.pencilList.brushList)
let setPencil =()=>{
let pencil = JSSetPencil(brushworkValue.value,canvas)
canvas.isDrawingMode = true//开启绘画模式
canvas.freeDrawingBrush = pencil
canvas.freeDrawingBrush.width = canvasPencilWidth.value[operation.value]?canvasPencilWidth.value[operation.value]:20;
if(brushworkValue.value == 'RibbonBrush' || brushworkValue.value == 'LongfurBrush'){
canvas.freeDrawingBrush.width = 1;
}
if(brushworkValue.value == 'Marking'){
canvas.freeDrawingBrush.color = hexToRgba(canvasPencilColor.value,.5);
// }else if(brushworkValue.value == 'InkBrush'){
// canvas.freeDrawingBrush.color = hexToRgba(canvasPencilColor.value,.2);
}else{
canvas.freeDrawingBrush.color = hexToRgba(canvasPencilColor.value,1);
}
pencilbtnStyle.value.background = canvasPencilColor.value
canvas.freeDrawingBrush.isEraser = false
}
let setMove = () =>{
canvas.isDrawingMode = false
canvas.forEachObject((obj) =>obj.selectable = true);
}
let setEraser = ()=>{
canvas.isDrawingMode = true
let eraser = new fabric.EraserBrush(canvas)
canvas.freeDrawingBrush = eraser
pencilbtnStyle.value.background = '#fff'
canvas.requestRenderAll();
canvas.freeDrawingBrush.isEraser = true
canvas.freeDrawingBrush.width = canvasPencilWidth.value[operation.value]?canvasPencilWidth.value[operation.value]:20;
}
let createText = {}
let setTextFun = (e)=>{
if(operation.value != 'text'){
return
}
var clickedObject = e.target;
if (clickedObject instanceof fabric.Textbox) {
createText = clickedObject
}else{
var pointer = canvas.getPointer(e.pointer);
var x = pointer.x;
var y = pointer.y;
createText = new fabric.Textbox('', {
left: x,
top: y,
width: 150,
fontSize: canvasPencilWidth.value[operation.value]?canvasPencilWidth.value[operation.value]:20,
fontFamily:fontFamily.value,
fill:canvasPencilColor.value,
})
canvas.add(createText)
createText.enterEditing();
canvas.setActiveObject(createText).renderAll();
operation.value = ''
removeSetText()
}
}
let setText = ()=>{
canvas.on('mouse:down',setTextFun)
// if(isMoible()){
// canvas.on('mouse:down',setTextFun)
// }else{
// canvas.on('mouse:dblclick',setTextFun)
// }
}
let removeSetText = ()=>{
canvas.off('mouse:down',setTextFun)
// if(isMoible()){
// canvas.off('mouse:down',setTextFun)
// }else{
// canvas.off('mouse:dblclick',setTextFun)
// }
}
let setTimeOut = {
color:null,
width:null,
colorHistory:null,
}//给切换颜色设置防抖
let colorHistoryList = ref(['rgb(0, 0, 0)'])
let setColorHistory = (value)=>{
canvasPencilColor.value = value
pencilColor()
}
let pencilColor = ()=>{
if(createText.set){
setFontFamily()
return
}
// brushIndicator.fill = canvasPencilColor.value;
if(canvas.freeDrawingBrush.isEraser){
}else{
pencilbtnStyle.value.background = canvasPencilColor.value
}
if(brushworkValue.value == 'Marking'){
canvas.freeDrawingBrush.color = hexToRgba(canvasPencilColor.value,.5);
}else if(brushworkValue.value == 'InkBrush'){
canvas.freeDrawingBrush.color = hexToRgba(canvasPencilColor.value,.2);
}else{
canvas.freeDrawingBrush.color = hexToRgba(canvasPencilColor.value,1);
}
}
let setPencilColor = ()=>{//切换颜色给铅笔设置颜色
clearTimeout(setTimeOut.color)
clearTimeout(setTimeOut.colorHistory)
setTimeOut.color = setTimeout(()=>{
pencilColor()
},200)
setTimeOut.colorHistory = setTimeout(()=>{
colorHistoryList.value.push(canvasPencilColor.value)
},1000)
}
let setPencilWidth = ()=>{//切换颜色给铅笔设置颜色
clearTimeout(setTimeOut.width)
canvasPencilWidth.value[operation.value] = Number(canvasPencilWidth.value[operation.value]?canvasPencilWidth.value[operation.value]:20)
setTimeOut.width = setTimeout(()=>{
if(brushworkValue.value == 'LongfurBrush' || brushworkValue.value == 'RibbonBrush'){
canvas.freeDrawingBrush.width = 1;
}else{
canvas.freeDrawingBrush.width = canvasPencilWidth.value[operation.value];
}
pencilbtnStyle.value.height = canvasPencilWidth.value[operation.value]+'px'
pencilbtnStyle.value.width = canvasPencilWidth.value[operation.value]+'px'
// setPencil()
},300)
}
let downPoint = null;//鼠标按下位置
let upPoint = null;//鼠标抬起位置
let currentPatterning = null//临时图形
let polyLineBtn = null
let createPatterningIs = false
let clearPatterning = () =>{
if(createPatterningIs){
canvas.remove(currentPatterning)
}
currentPatterning = null
canvas.remove(polyLineBtn)
updateCanvasState()
}
//设置再画布上移动
let setCanvasMove = (event)=>{
var pointer = canvas.getPointer(event.e);
if(canvas.isDrawingMode){
canvas.setCursor('none');
}else{
                if(createPatterningIs){
                    JScanvasMouseMove(operation.value,event,currentPatterning,downPoint,keyDown)
                }
            }
let canvasBox = document.querySelector(".generalCanvas .canvas-container");
const rect = canvasBox.getBoundingClientRect();
const parentRect = canvasBox.parentElement.getBoundingClientRect();
let parentX = rect.left - parentRect.left
let parentY = rect.top - parentRect.top
pencilbtnStyle.value.left = parentX + pointer.x+'px'
pencilbtnStyle.value.top = parentY + canvasBox.parentElement.scrollTop + pointer.y+'px'
canvas.requestRenderAll()
}
//设置再画布上按下
let setCanvasDown = (event)=>{
//设置移动端按下添加元素
if(isMoible && present.upScaleChecked){
present.upScaleChecked = false
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
case 'moodboardFiles':
createImage(pointerVpt.y, pointerVpt.x,currentType.value.type)
break
default :
createImage(pointerVpt.y, pointerVpt.x,currentType.value.type)
break
}
// 创建完元素,把当前操作的元素类型设置回 null
currentType.value.type = null
currentType.value.data = null
}
downPoint = event.absolutePointer
let arr = ['rect','line','circle','triangle','ellipse','fold']
if(arr.indexOf(operation.value) > -1){
JSchangeType(canvas,operation.value)
createPatterningIs = true
if(currentPatterning && operation.value == 'fold'){
canvas.skipTargetFind = false
currentPatterning.points.push({
x: downPoint.x,
y: downPoint.y
})
// currentPatterning = JScanvasMouseDown(operation.value,event,canvasPencilWidth.value,currentPatterning)
}else{
currentPatterning = JScanvasMouseDown(operation.value,event,canvasPencilWidth.value[operation.value]?canvasPencilWidth.value[operation.value]:20,currentPatterning)
canvas.add(currentPatterning)
canvas.bringToFront(currentPatterning);//设置优先级最高
if(operation.value == 'fold'){
polyLineBtn = JScreateCheck(event)
polyLineBtn.on('mousedown',foldEnd)
canvas.add(polyLineBtn)
}
}
}else{
var clickedObject = event.target;
if (clickedObject instanceof fabric.Textbox && operation.value != 'text') {
textDataShow.value = true
createText = clickedObject
setTextData(clickedObject)
}else{
textDataShow.value = false
createText = {}
}
createPatterningIs = false
}
}
let foldEnd = (key)=>{
canvas.skipTargetFind = true
let points = currentPatterning.points
if(key == 'Enter'){
}else{
points.pop()
}
points.pop()
canvas.remove(currentPatterning)
let polyline = new fabric.Polyline(points, {
fill: operationMode.value == 'fill'? canvasPencilColor.value : 'transparent',
stroke: canvasPencilColor.value,
strokeWidth:canvasPencilWidth.value[operation.value]?canvasPencilWidth.value[operation.value]:20,
selection:false,
})
canvas.add(polyline)
// currentPatterning.set({stroke: canvasPencilColor.value})
createPatterningIs = false
clearPatterning()//临时图形置为空并且添加撤回对象里面
setOperation('move')
}
//设置再画布上抬起
let setCanvasUp = (event)=>{
upPoint = event.absolutePointer
if(canvas.isDrawingMode){
setTimeout(() => {
// pencilbtnStyle.value.display = `none`
updateCanvasState()
}, 100);
}else{
// event.target && (event.target.bringToFront())//设置优先级
}
var selectedObjects = canvas.getActiveObjects();//获取多选选中的内容
if (selectedObjects.length >= 1) {
allSelect.value = selectedObjects
// allSelectWidth.value = 0
allSelectWidth.value = (selectedObjects[0].width * selectedObjects[0].scaleX).toFixed(0)
}else{
allSelectWidth.value = -1
}
if(createPatterningIs){
switch (operation.value) {
case 'line':
currentPatterning.set({stroke: canvasPencilColor.value})
break
case 'fold':
// currentPatterning.set({stroke: canvasPencilColor.value})
break
default :
if(operationMode.value == 'fill'){
currentPatterning.set({fill: canvasPencilColor.value})
}else if (operationMode.value == 'border'){
currentPatterning.set({fill: 'transparent',stroke: canvasPencilColor.value,strokeWidth: canvasPencilWidth.value[operation.value]?canvasPencilWidth.value[operation.value]:20})
}
if(JSON.stringify(downPoint) == JSON.stringify(upPoint)){
canvas.remove(currentPatterning)
}
break
}
if(operation.value == 'fold'){
canvas.forEachObject((obj) =>obj.selectable = false);
canvas.bringToFront(polyLineBtn);//设置优先级最高
}else if(operation.value){
createPatterningIs = false
clearPatterning()//临时图形置为空并且添加撤回对象里面
canvas.renderAll();
setOperation('move')
}
}
}
let toSvg = ()=>{
// console.log(canvas.toSvg());
}
let setCanvasContent = (isSaveImg)=>{
var json = canvas.toJSON(['imgId','minioUrl']);
// console.log(JSON.stringify(json));
if(!isSaveImg){
json.objects.forEach(item=>{
if(item.type == 'image'){
delete item.src
}
})
}
return json
}
let textDataShow = ref(false)
let setTextData = (obj)=>{
fontFamily.value = obj.fontFamily
canvasPencilWidth.value['text'] = obj.fontSize
canvasPencilColor.value = obj.fill
}
let setFontFamily = ()=>{
if(createText.set){
createText.set({
fontFamily:fontFamily.value,
fontSize:canvasPencilWidth.value[operation.value]?canvasPencilWidth.value[operation.value]:20,
fill:canvasPencilColor.value,
})
canvas.renderAll();
}
}
onMounted(() => {
let arr = canvasGeneral.pencilList.textFontFamilyList
textFontFamilyList.value = arr
fontFamily.value = arr[0].value
init()
});
onBeforeUnmount(()=>{
canvasGeneral.canvasClear()
})
return {
toSvg,
t,
toSvg,
canvasWH,//画布初始宽高
pencilbtnStyle,//笔触按钮
publish,//发布作品广场
credits,//积分 用来判断HD导出积分是否够用
init,//首页点击导出后初始化
setMaxInput,//设置画布宽高
isShowMark,//加载遮罩
allBoardData,//选择画布所有内容
closeNav,//导航展开或者收起来状态
setCloseNav,//给图片导航或者工具收起来或者展开
onDragstart,//拖拽函数
setDragstart,//的移动端拖拽改为按下
historyState,//执行撤回或者反撤回
operation,//设置当前鼠标状态绘画或者矩形或者移动
operationMode,//设置矩形是边框还是填充
setOperation,//设置当前鼠标状态绘画或者矩形或者移动方法
setOperationMode,//设置矩形是边框还是填充方法
uploadImage,//上传图帕
setLayerIndex,//设置选中元素的层级
brushList,//笔触列表
textureList,//材质列表
canvasPencilColor,//input选择颜色
canvasPencilWidth,//input选择宽度
setAllSelectWidth,//多选设置宽度
allSelectWidth,//多选设置宽度的值
colorHistoryList,//历史颜色
setColorHistory,//设置历史颜色
setPencilColor,//切换颜色执行函数 给当前矩形或者笔触设置颜色
setPencilWidth,//切换宽度执行函数 给当前矩形或者笔触设置宽度
brushworkChange,//切换笔触的回调
textureValueChange,//切换材质信息
brushworkValue,//当前笔触
textureValue,//当前材质
textFontFamilyList,
fontFamily,
textDataShow,
setFontFamily,
};
},
data(prop) {
return {
isMoible:isMoible()
};
},
computed: {
setGradient(){
return (gradient)=>{
let gradientStr = ''
gradient.gradientList.sort((a, b) => {
let aArr = a.left.split('%')[0]
let bArr = b.left.split('%')[0]
return aArr - bArr;
});
gradient.gradientList.forEach((item,index)=>{
let str = ','
if(gradient.gradientList.length == index+1)str = ''
gradientStr += `rgba(${item.rgba.r},${item.rgba.g},${item.rgba.b},${item.rgba.a}) ${item.left}${str}`
})
return `${gradientStr}`
}
}
},
watch: {
},
mounted() {},
methods: {
},
});
</script>
<style lang="less" scoped>
.generalCanvas {
flex: 1;
overflow-x: hidden;
display: flex;
margin-top: 2rem;
justify-content: space-between;
flex-direction: column;
flex: 1;
// height: 30rem;
// overflow-x: hidden;
.icon{
transition: all .3s;
}
.icon-rotate{
transform: rotate(-180deg);
}
.generalCanvas_title {
margin-bottom: .5rem;
font-size: 1.8rem;
// font-weight: 600;
// margin-top: 2rem;
padding-top: 2rem;
display: flex;
top: -1rem;
justify-content: space-between;
cursor: pointer;
position: sticky;
background: #f9fafb;
z-index: 2;
align-items: flex-start;
margin: 0 2rem;
}
.generalCanvas_intro{
margin-bottom: 1rem;
font-size: 1.6rem;
font-weight: 600;
width: 100%;
}
.generalCanvas_right,
.generalCanvas_left {
width: 100%;
height: auto;
.generalCanvas_left_tool{
margin: 0;
}
label {
display: flex;
align-items: center;
width: 23%;
div {
width: auto;
margin-right: 2rem;
white-space: nowrap;
}
input,select {
// width: 10em;
flex: 1;
overflow: hidden;
height: 4.5rem;
width: 10rem;
}
.label_select{
img{
width: 100%;
max-height: 100%;
object-fit: contain;
}
}
}
.texture{
.label_select{
img{
max-height: none;
}
}
}
.generalCanvas_left_item.closeNav{
// max-height: 1000rem;
// height: auto;
display: block;
}
}
.generalCanvas_left::-webkit-scrollbar,
.generalCanvas_right::-webkit-scrollbar{display: none;}
.generalCanvas_left {
padding-right: 1rem;
margin-right: 2rem;
// height: 7rem;
display: flex;
flex-wrap: wrap;
align-items: flex-start;
position: relative;
flex-direction: row;
>.label_item{
width: 20%;
}
.generalCanvas_title {
// margin: 0 4rem;
position: relative;
.generalCanvas_left_tool_item{
display: flex;
flex-direction: column;
}
}
.generalCanvas_left_item{
overflow: hidden;
transition: all .3s;
// max-height: 0;
transform: translate3d(0, 0, 0);
position: absolute;
}
.generalCanvas_left_item,.generalCanvas_imgbor,.generalCanvas_operation_bor{
background: #fff;
height: auto;
max-height: 30rem;
border: 1px solid;
display: none;
top: 7rem;
position: absolute;
}
.generalCanvas_imgbor {
// height: auto;
width: 20rem;
overflow-y: auto;
padding: 1rem;
&.generalCanvas_imgbor::-webkit-scrollbar{display: none;}
.generalCanvas_allItem {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.generalCanvas_item {
text-align: center;
.generalCanvas_img{
position: relative;
margin-bottom: 2rem;
img {
max-width: 7rem;
max-height: 7rem;
object-fit: contain;
}
.generalCanvas_img_SR{
position: absolute;
bottom: 0;
height: 2rem;
background: rgba(0, 0, 0, 0.3);
color: #fff;
width: 100%;
text-align: center;
font-weight: 600;
cursor: pointer;
}
}
}
.generalCanvas_item_colorBor{
width: 100%;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.generalCanvas_item_color{
width: 8rem;
margin-bottom: 2rem;
.generalCanvas_item_BGcolor{
height: 5rem;
}
div{
// -webkit-user-select:none; /* Safari */
// -moz-user-select:none; /* Firefox */
// -ms-user-select:none; /* IE10+/Edge */
// user-select:none; /* Standard syntax */
}
}
.generalCanvas_item_dispose{
img{
max-width: 100%;
max-height: 100%;
}
}
.active{
opacity: .5;
transform: scale(.9);
}
}
}
.generalCanvas_operation_bor_item{
flex: 1;
margin-left: 8rem;
display: flex;
.label_item{
margin-right: 2rem;
position: relative;
.labelHover_show{
position: absolute;
width: 100%;
height: 10rem;
top: 100%;
z-index: 2;
flex-wrap: wrap;
div{
width: 3rem;
height: 3rem;
margin-right: 1rem;
margin-bottom: 1rem;
cursor: pointer;
}
}
}
.label_item:hover{
.labelHover_show{
display: flex;
}
}
}
.generalCanvas_left_tool_item{
display: flex;
flex: 1;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
flex-direction: row;
flex-wrap: nowrap;
&.leftAlign{
justify-content: flex-start;
}
&.leftAlign{
justify-content: flex-start;
}
i{
font-size: 2.5rem;
cursor: pointer;
width: 4rem;
height: 4rem;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
&.active{
border: 1px solid;
border-radius: .4rem;
}
}
.uploadImage{
width: 4rem;
height: 4rem;
input{
height: 0;
width: 0;
border: none;
}
}
}
}
.generalCanvas_center_box{
display: flex;
overflow: hidden;
}
.generalCanvas_center {
width: 100%;
flex: 1;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
position: relative;
.editFrontBack_pencilbtn{
position: absolute;
z-index: 1;
border-radius: 50%;
border: 1px solid #000;
pointer-events: none;
transform: translate(-50%,-50%);
}
&.generalCanvas_center::-webkit-scrollbar-button:single-button{
}
&.generalCanvas_center::-webkit-scrollbar {
/* 竖轴的宽度 */
width: 2rem;
/* 横轴的高度 */
height: 1rem;
transition: all .3s;
}
/* 进度 */
&.generalCanvas_center::-webkit-scrollbar-thumb {
border-radius: 1rem;
background: #543087;
}
/* 轨道 */
&.generalCanvas_center::-webkit-scrollbar-track {
border-radius: 1rem;
background: rgba(84, 48, 135,.2);
// background: rgba(238, 238, 244, 0);
}
}
.generalCanvas_scroll{
height: 100%;
width: 2rem;
background: #d6cfe3;
border-radius: 1rem;
div{
background: #543087;
border-radius: 1rem;
width: 100%;
height: 30rem;
}
}
.generalCanvas_new_collection_review {
position: initial;
margin: 10rem auto;
margin-bottom: 0;
}
}
</style>
<style lang="less">
.generalCanvas {
.ant-modal-content {
.ant-modal-body {
height: calc(65rem * 1.2);
}
}
}
.label_select_item{
img{
width: 100%;
max-height: 100%;
object-fit: contain;
}
}
</style>
<style lang="less">
.SRExport{
.ant-modal-body{
height: calc(35rem* 1.2);
}
.SRExport_img{
margin-bottom: 2rem;
flex: 1;
overflow-x: hidden;
display: flex;
flex-wrap: wrap;
min-height: 12rem;
.SRExport_img_item_box{
position: relative;
margin-right: 2rem;
margin-bottom: 2rem;
input{
position: absolute;
top: .5rem;
right: .5rem;
z-index: 2;
height: 2rem;
width: 2rem;
}
}
img{
width: 10rem;
max-height: 10rem;
object-fit: contain;
text-align: center;
cursor: pointer;
&.active{
transform: scale(.8);
opacity: .6;
}
}
}
.check_all_block{
display: flex;
align-items: center;
font-size: 1.6rem;
color: #64686D;
cursor: pointer;
justify-content: flex-end;
&.check_all{
color: #1A1A1A;
.check_block{
.check_block_body{
opacity: 1;
}
}
}
.check_block{
width: 2.4rem;
height: 2.4rem;
background: #EBECF4;
border: 0.1rem solid #64686D;
padding: 0.3rem;
margin-right: 0.7rem;
.check_block_body{
width: 100%;
opacity: 0;
height: 100%;
background: #343579;
}
}
}
.SRExport_operate{
display: flex;
align-items: center;
justify-content: space-between;
.SRExport_operate_box {
display: flex;
align-items: center;
margin-bottom: 1rem;
width: 100%;
>div {
width: 5rem;
}
.SRExport_operate_item_sclae{
width: 4rem;
height: 3rem;
border: .2rem solid rgba(0, 0, 0, 0.3);
display: flex;
align-items: center;
justify-content: center;
margin-right: 1rem;
cursor: pointer;
border-radius: .4rem;
font-weight: 600;
&.active{
border-color: rgba(152, 139, 247);
color: rgba(152, 139, 247);
}
}
.SRExport_operate_sclae{
max-width: 15rem;
}
// input {
// // width: 10em;
// overflow: hidden;
// }
// label{
// display: flex;
// align-items: center;
// margin-right: 2rem;
// span{
// margin-right: 1rem;
// }
// }
}
}
.generalModelOperate_endBtn{
.generalModelOperate_btn_ok{
&.active{
opacity: .6;
cursor: no-drop;
}
}
}
}
</style>