Files
aida_front/src/component/modules/generalMiniCanvas.vue
2024-10-13 22:20:59 +08:00

691 lines
20 KiB
Vue
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.
<template>
<div class="generalMiniCanvas">
<div class="addDetails_canvasCenter">
<div class="generalMiniCanvas_input generalMiniCanvas_item" :class="{spread:spreadState}">
<div class="generalMiniCanvas_input_item" v-show="(canvasState != 'move' && canvasState != 'liquidation')">
<span>{{ $t('exportModel.Size') }}</span>
<input type="range" @input="setPencilWidth" min="1" max="50" v-model="canvasPencilWidth[canvasState]">
</div>
<div class="generalMiniCanvas_input_item" v-show="canvasState == 'liquidation'">
<span>{{ $t('exportModel.Size') }}</span>{{ canvasPencilWidth.routes }}
<input type="range" @change="routesChange('routes')" min="1" max="100" v-model="canvasPencilWidth.routes">
</div>
<div class="generalMiniCanvas_input_item" v-show="canvasState == 'liquidation'">
<span>{{ $t('exportModel.density') }}</span>
<input type="range" @change="routesChange('density')" min="1" max="100" v-model="canvasPencilWidth.density">
</div>
<div class="generalMiniCanvas_input_item" v-show=" canvasState == 'pencil'">
<span>{{ $t('exportModel.Color') }}</span>
<input type="color" @input="setPencilColor" v-model="canvasPencilColor">
</div>
</div>
<div class="exportCanvasBox_center_data">
<div class="generalMiniCanvas_btn generalMiniCanvas_item" :class="{spread:spreadState}">
<!-- <div @click="setOperation('')" class="generalMiniCanvas_btn_item">
<div>新增</div>
</div> -->
<i class="icon iconfont icon-chehui" @click="historyState('')"></i>
<i class="icon iconfont icon-fanchehui" @click="historyState('reverse')"></i>
<!-- <i class="icon iconfont icon-move" @click="setOperation('move')" :class="{active:canvasState == 'move'}"></i> -->
<i class="icon iconfont icon-bianji" @click="setOperation('pencil')" :class="{active:canvasState == 'pencil'}"></i>
<i class="icon iconfont icon-xiangpi_huaban1" @click="setOperation('eraser')" :class="{active:canvasState == 'eraser'}"></i>
<!-- <i class="icon iconfont icon-IC-yehua" @click="setOperation('liquidation')"></i> -->
<i class="icon iconfont icon-IC-yehua" @click="setLiquefaction()"></i>
<!-- <div class="icon iconfont icon-xiala" :class="{btnRotate:spreadState}" @click="()=>spreadState = !spreadState"></div> -->
</div>
<div class="exportCanvasBox_center_box">
<div class="exportCanvasBox_center">
</div>
<!-- <div v-show="arrows.show" class="moveDom" :style="arrows.domStyle"></div>
<div v-show="arrows.show" class="jiantouDom" :style="arrows.jiantouStyle"> </div> -->
<div class="editFrontBack_pencilbtn" v-show="loadingShow" :style="pencilbtnStyle"></div>
</div>
</div>
</div>
<div class="exportCanvasBox_submit" @click="setSubmit(false)">
<div class="started_btn">
{{ $t('addDetails.submit') }}
</div>
</div>
<liquefaction ref="liquefaction" @submitLiquefaction="submitLiquefaction"></liquefaction>
</div>
</template>
<script>
import { defineComponent, ref, reactive, watch, onMounted, onBeforeUnmount, nextTick, toRefs } from "vue";
import { Https } from "@/tool/https";
import { formatTime } from "@/tool/util";
import { setCookie, getCookie } from "@/tool/cookie";
import { Modal, message } from "ant-design-vue";
import { ExclamationCircleOutlined } from "@ant-design/icons-vue";
import allOrder from "@/component/Pay/allOrder.vue";
import creditsDetail from "@/component/Pay/creditsDetail.vue";
import { exportSele,JSRectUpdata,JSchangeType,JScanvasMouseDown,JSSetRemoveImage,JScreateCheck,JSSetTexture } from "@/tool/canvasDrawing";
import { useI18n } from "vue-i18n";
import canvasGeneral from "@/tool/canvasGeneral";
import { getMousePosition } from "@/tool/mdEvent";
import liquefaction from "@/component/modules/liquefaction.vue";
export default defineComponent({
components: {
creditsDetail,
allOrder,liquefaction
},
emits: ['submitBase64Data'],
props: {
imgUrl: {
type: String,
default: ''
},
},
// watch: {
// // imgUrl: function(newVal, oldVal) {
// // console.log(newVal);
// // // 当propertyName数据发生变化时执行相应的操作
// // }
// imgUrl(newVal, oldVal) {
// console.log(`imgUrl changed from ${oldVal} to ${newVal}`);
// },
// },
setup(props,{emit}) {
let presentState = ref('paypal');
let showPayOrder = ref(false);
let loadingShow = ref(false);
let { t } = useI18n();
let canvas = reactive({});
let scale = 2;
let ratio = [1,1]
let exportWH = 512
let pencilbtnStyle = ref({
background:'',
width:0+'px',
height:0+'px',
display:'none',
left:0+'px',
top:0+'px',
})
let canvasBtn = reactive({
canvasState:'move',
canvasPencilWidth:{
pencil:20,
eraser:20,
routes:30,
density:30,
},
canvasPencilColor:'#000000',
spreadState:false,
})
let canvasWH = ref(0);
let arrows = ref({
show:false,
domStyle:{
left:0,
top:0,
width:0,
height:0,
},
jiantouStyle:{
height:'1px',
transform:`translateY(-100%) rotate(${90}deg)`,
}
})
watch(
() => props.imgUrl,
(newValue, oldValue) => {
init()
})
onMounted(()=>{
init()
})
onBeforeUnmount(()=>{
canvasGeneral.canvasClear()
})
let reverseCanvasState = ref([])//存放canvas操作
let normalCanvasState = ref([])//存放canvas操作
let canvasState = ref()//存放canvas操作
let keyDown = []//监听键盘的 keydown 和 keyup 事件
let init = ()=>{
normalCanvasState.value = []
reverseCanvasState.value = []
showPayOrder.value = true;
ratio = [1,1]
nextTick(()=>{
let canvasBox = document.querySelector(".generalMiniCanvas .exportCanvasBox_center");
document.removeEventListener('mousemove', mouseMove);
document.removeEventListener('touchmove', touchmove);
let img = new Image();
img.onload = function(){
loadingShow.value = true
let height = canvasBox.offsetHeight;
canvasWH.value = height
// canvasBox.style.width = height+'px'
let wScale = 1
let hScale = 1
if(img.width>img.height){
hScale = img.height/img.width
exportWH = img.width
}else{
wScale = img.width/img.height
exportWH = img.height
}
ratio = [wScale,hScale]
canvas = canvasGeneral.canvasInit(canvasBox,{
width:canvasWH.value * wScale,
height:canvasWH.value * hScale,
})
canvas.selection = false;
scale = img.height/canvas.height
pencilbtnStyle.value.background = canvasBtn.canvasPencilColor
fabric.Object.prototype.cornerSize = 10
fabric.Object.prototype.transparentCorners = false
fabric.Image.fromURL(props.imgUrl, function(img) {
// 设置背景图对象的宽度和高度与 canvas 相同
img.scaleToWidth(canvas.width);
img.scaleToHeight(canvas.height);
img.set({
scaleX: canvas.width / img.width,
scaleY: canvas.height / img.height
});
// 将背景图添加到 canvas 的底层
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas));
if(!fabric.Object.prototype.controls.deleteControl){
JSSetRemoveImage(deleteObj)
}else{
fabric.Object.prototype.controls.deleteControl.mouseUpHandler = deleteObj
}
setPencilWidth()
updateCanvasState()
},{ crossOrigin: "Anonymous" });
// 鼠标抬起事件
canvas.on('mouse:up', function(event) {
if(canvasBtn.canvasState != 'move'){
updateCanvasState('mouseUp')
}
});
canvas.on('mouse:wheel', opt => {
const delta = opt.e.deltaY // 滚轮,向上滚一下是 -100向下滚一下是 100
let zoom = canvas.getZoom() // 获取画布当前缩放值
zoom *= 0.999 ** delta
if (zoom > 20) zoom = 20
if (zoom < 0.01) zoom = 0.01
// console.log(zoom);
canvas.zoomToPoint(
{ // 关键点
x: opt.e.offsetX,
y: opt.e.offsetY
},
zoom
)
opt.e.preventDefault()
opt.e.stopPropagation()
})
//画布上移动
document.addEventListener('mousemove', mouseMove);
document.addEventListener('touchmove', touchmove);
setOperation('pencil')
img.remove()
}
img.src = props.imgUrl
})
}
let canvasKeyDown = (event) => {
if(keyDown.indexOf(event.key)>-1){
}else{
keyDown.push(event.code)
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('')
}
}
}
let canvasKeyUp = (event) =>{
keyDown = keyDown.filter(function(item) {
return event.code !== item;
})
}
let clearCanvas = ()=>{
canvasBtn.canvasState = 'move'
canvasBtn.spreadState = false
document.removeEventListener("keydown", canvasKeyDown);
document.removeEventListener("keyup", canvasKeyUp);
}
let mouseMove = (event)=>{
let e = getMousePosition(event,false)
setCanvasMove(e)
}
let touchmove = (event)=>{
let e = getMousePosition(event,true)
setCanvasMove(e)
}
let setCanvasMove = (event)=>{
if(canvas.isDrawingMode){
canvas.setCursor('none');
}
let canvasCenterBox = document.querySelector(".generalMiniCanvas .exportCanvasBox_center_box");
if(!canvasCenterBox)return
let parentX = event.clientX - canvasCenterBox.getBoundingClientRect().left
let parentY = event.clientY - canvasCenterBox.getBoundingClientRect().top
pencilbtnStyle.value.left = parentX + "px"
pencilbtnStyle.value.top = parentY+'px'
}
let setOperation = (str)=>{
canvasBtn.canvasState = str
let canvasCenterBox = document.querySelector(".generalMiniCanvas .exportCanvasBox_center_box");
let classList = canvasCenterBox.className.split(' ');
if(str == 'move'){
setMove()
pencilbtnStyle.value.display = `none`
if(classList.indexOf('cursorNone')>-1) canvasCenterBox.classList.remove('cursorNone')
}else if(str == 'pencil'){
setPencil()
pencilbtnStyle.value.display = `block`
if(classList.indexOf('cursorNone') == -1) canvasCenterBox.classList.add('cursorNone')
}else if(str == 'eraser'){
setEraser()
pencilbtnStyle.value.display = `block`
if(classList.indexOf('cursorNone') == -1) canvasCenterBox.classList.add('cursorNone')
}else if(str == 'liquidation'){
canvas.isDrawingMode = false
if(classList.indexOf('cursorNone') == -1) canvasCenterBox.classList.add('cursorNone')
}
}
let setMove = ()=>{
canvas.isDrawingMode = false
canvas.forEachObject((obj) =>obj.selectable = true);
}
let setPencil = ()=>{
canvas.isDrawingMode = true//开启绘画模式
canvas.freeDrawingBrush = new fabric.PencilBrush(canvas,{});
canvas.freeDrawingBrush.width = Number(canvasBtn.canvasPencilWidth[canvasBtn.canvasState]);
canvas.freeDrawingBrush.color = canvasBtn.canvasPencilColor
pencilbtnStyle.value.background = canvasBtn.canvasPencilColor
canvas.freeDrawingBrush.isEraser = false
setPencilWidth()
}
let setEraser = ()=>{
canvas.isDrawingMode = true
let eraser = new fabric.EraserBrush(canvas)
canvas.freeDrawingBrush = eraser
canvas.requestRenderAll();
canvas.freeDrawingBrush.isEraser = true
pencilbtnStyle.value.background = `rgb(255,255,255)`
canvas.freeDrawingBrush.width = Number(canvasBtn.canvasPencilWidth[canvasBtn.canvasState]);
setPencilWidth()
}
let deleteObj = ()=> {
// if(!canvas.getActiveObjects()){
// return
// }
let target = canvas.getActiveObjects()
target.forEach((item)=>{
canvas.fxRemove(item, {
onComplete(){
canvas.discardActiveObject(); // 丢弃当前选中的对象
canvas.renderAll(); // 重新渲染 Canvas
}
})
canvas.FX_DURATION = 300
})
}
let setTimeOut = {
pencilWidth:null,
color:null,
}
let setPencilWidth = ()=>{//切换颜色给铅笔设置颜色
clearTimeout(setTimeOut.pencilWidth)
setTimeOut.pencilWidth = setTimeout(()=>{
canvas.freeDrawingBrush.width = Number(canvasBtn.canvasPencilWidth[canvasBtn.canvasState])
pencilbtnStyle.value.height = canvasBtn.canvasPencilWidth[canvasBtn.canvasState]+'px'
pencilbtnStyle.value.width = canvasBtn.canvasPencilWidth[canvasBtn.canvasState]+'px'
},300)
}
let setPencilColor = ()=>{//切换颜色给铅笔设置颜色
clearTimeout(setTimeOut.color)
// clearTimeout(setTimeOut.colorHistory)
setTimeOut.color = setTimeout(()=>{
pencilColor()
},200)
// setTimeOut.colorHistory = setTimeout(()=>{
// colorHistoryList.value.push(canvasPencilColor.value)
// },1000)
}
let pencilColor = ()=>{
if(canvas.freeDrawingBrush.isEraser){
canvas.freeDrawingBrush.color = '#FFFFFF';
}else{
pencilbtnStyle.value.background = canvasBtn.canvasPencilColor
canvas.freeDrawingBrush.color = canvasBtn.canvasPencilColor;
}
}
let routesChange = (str)=>{
canvasBtn.canvasPencilWidth[str] = Math.round(canvasBtn.canvasPencilWidth[str]/10)*10;
if (canvasBtn.canvasPencilWidth[str] < 10) {
canvasBtn.canvasPencilWidth[str] = 10; // 设置为最小值
} else if (canvasBtn.canvasPencilWidth[str] > 100) {
canvasBtn.canvasPencilWidth[str] = 100; // 设置为最大值
}
}
let updateCanvasState = (str) =>{
if(str != 'mouseUp'){
}
const canvasAsJson = JSON.stringify(canvas.toJSON());
normalCanvasState.value.push(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);
}else{
return
}
canvas.loadFromJSON(canvasState.value, () => {});
}
let setSubmit = (liquefation)=>{
return new Promise((resolve,reject)=>{
var allObjects = canvas.getObjects('path');
// if(allObjects.length == 0){
// return message.info(t('addDetails.jsContent1'))
// }
var canvasDom = document.createElement("canvas");
let exportCanvas = new fabric.Canvas(canvasDom, {
backgroundColor: "#FFFFFF",
width: exportWH * ratio[0],
height: exportWH * ratio[1],
isDrawingMode: false, // 开启绘图模式
});
canvas.backgroundImage.clone((back)=>{
back.set({
scaleX:1,
scaleY:1,
left:back.left*scale,
top:back.top*scale ,
})
exportCanvas.backgroundImage = back
allObjects.forEach((item,index)=>{
// let obj = fabric.util.object.clone(item);
if(item.type == 'circle')return
let obj
item.clone((cloned)=>{
obj = cloned
})
obj.set(
{
scaleX:(item.scaleX?item.scaleX:1)*scale,
scaleY:(item.scaleY?item.scaleY:1)*scale,
left:item.left*scale,
top:item.top*scale,
}
)
exportCanvas.add(obj)
})
console.log(canvas.toDataURL("image/png"));
let data = canvas.toDataURL("image/png");
if(liquefation){
return resolve(data)
}
cancelDsign()
clearCanvas()
emit('submitBase64Data',data)
resolve('')
})
})
}
let cancelDsign = ()=>{
document.removeEventListener('keydown',canvasKeyDown);
document.removeEventListener('keyup', canvasKeyUp);
showPayOrder.value = false
}
let liquefactionData = ref(null)
let liquefaction = ref(null)
let submitLiquefaction = (rv)=>{
// const originalWidth = liquefactionData.value.width // 保存原始宽度
// const originalHeight = liquefactionData.value.height; // 保存原始高度
fabric.Image.fromURL(rv, function(img) {
// 设置背景图对象的宽度和高度与 canvas 相同
img.scaleToWidth(canvas.width);
img.scaleToHeight(canvas.height);
img.set({
scaleX: canvas.width / img.width,
scaleY: canvas.height / img.height
});
// 将背景图添加到 canvas 的底层
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas));
if(!fabric.Object.prototype.controls.deleteControl){
JSSetRemoveImage(deleteObj)
}else{
fabric.Object.prototype.controls.deleteControl.mouseUpHandler = deleteObj
}
setPencilWidth()
updateCanvasState()
},{ crossOrigin: "Anonymous" });
}
let setLiquefaction =async ()=>{
// const activeObjects = canvas.backgroundImage // 获取选中的对象
// console.log(setSubmit(true));
let activeObjects = await setSubmit(true)
if (activeObjects) {
liquefactionData.value = activeObjects
liquefaction.value.init(activeObjects)
} else {
// message.info(useI18.t('exportModel.jsContent6'))
return null;
}
}
return {
presentState,
showPayOrder,
loadingShow,
t,
pencilbtnStyle,
...toRefs(canvasBtn),
arrows,
liquefactionData,
liquefaction,
init,
setOperation,
setPencilWidth,
setPencilColor,
historyState,
setSubmit,
cancelDsign,
submitLiquefaction,
setLiquefaction,
routesChange,
};
},
data() {
return {
};
},
mounted() {},
methods: {
},
});
</script>
<style lang="less">
.generalMiniCanvas{
position: relative;
height: 100%;
display: flex;
width: 100%;
// flex-direction: column;
margin: 0 auto;
flex-direction: row;
flex: 1;
overflow: hidden;
.generalMiniCanvas_item{
// position: relative;
background: #fff;
position: absolute;
display: flex;
// border: 0.2rem solid #c4c4c4;
width: 25rem;
border-radius: 4px; /* 设置圆角半径 */
flex-wrap: wrap;
.generalMiniCanvas_btn_item{
display: flex;
align-items: center;
padding: 1rem 0;
}
}
.generalMiniCanvas_input,.generalMiniCanvas_btn{
z-index: 2;
padding: 1rem 1.5rem;
position: relative;
width: auto;
flex-wrap: nowrap;
flex-direction: column;
}
.generalMiniCanvas_input{
flex-direction: row;
align-items: center;
margin-left: 7rem;
height: 6rem;
.generalMiniCanvas_input_item{
display: flex;
margin-right: 3rem;
align-items: center;
span{
margin-right: 1rem;
}
}
.generalMiniCanvas_input_item:last-child{
margin-right: 0;
}
}
.generalMiniCanvas_btn{
input{
// width: 100%;
width: 30rem;
// margin-top: 1rem;
flex: 1;
}
.icon-xiala{
position: absolute;
width: 2rem;
bottom: 0;
transform: translate(-50%, 90%);
left: 50%;
width: 6rem;
background: #fff;
text-align: center;
cursor: pointer;
&.icon-xiala::before{
transition: all .3s;
}
&.btnRotate::before{
transform: rotate(180deg);
display: block;
}
}
i{
font-size: 2.5rem;
cursor: pointer;
width: 4rem;
height: 4rem;
display: flex;
align-items: center;
justify-content: center;
&.active{
border: 1px solid;
border-radius: .4rem;
}
}
&.spread{
transform: translate(-50%,0);
}
}
.addDetails_canvasCenter{
flex: 1;
overflow: hidden;
display: flex;
// flex-direction: column;
// flex-direction: row;
position: relative;
margin: 0 auto;
flex-direction: column;
}
.exportCanvasBox_center_data{
flex: 1;
display: flex;
overflow: hidden;
}
.exportCanvasBox_center_box{
padding: 3rem;
height: 100%;
flex: 1;
position: relative;
overflow: hidden;
width: 100%;
background: #e6e6e6;
cursor: inherit;
&.cursorNone:hover{
cursor: none;
}
.editFrontBack_pencilbtn{
position: absolute;
z-index: 1;
border-radius: 50%;
border: 1px solid #000;
pointer-events: none;
transform: translate(-50%,-50%);
}
}
.exportCanvasBox_center{
height: 100%;
flex: 1;
position: relative;
overflow: hidden;
background: #e6e6e6;
// overflow: scroll;
.canvas-container{
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
.editFrontBack_pencilbtn{
position: absolute;
z-index: 1;
border-radius: 50%;
border: 1px solid #000;
pointer-events: none;
transform: translate(-50%,-50%);
}
}
.exportCanvasBox_center:hover{
.generalMiniCanvas_btn{
// transform: translate(-50%,-101%);
// &.spread{
// transform: translate(-50%,0);
// }
}
}
}
.exportCanvasBox_submit{
margin-top: auto;
margin-left: 1rem;
text-align: center;
}
</style>