|
@@ -0,0 +1,326 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <el-dialog
|
|
|
|
|
+ :visible.sync="visible"
|
|
|
|
|
+ :append-to-body="visible"
|
|
|
|
|
+ :modal="false"
|
|
|
|
|
+ title="图片预览"
|
|
|
|
|
+ width="20%"
|
|
|
|
|
+ @opened="openCanvas"
|
|
|
|
|
+ @close="closeDialog"
|
|
|
|
|
+ style="display: flex; align-items: center;justify-content: center;"
|
|
|
|
|
+ v-if="visible">
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <div v-if="prodType === '小卡'" class="previewClass" :style="{width: previewWidth + 'px', height: previewHeight + 'px', borderWidth: previewWidth * 0.0465 + 'px'}">
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div v-if="prodType === '拍立得'" class="previewClass" :style="{width: previewWidth + 'px', height: previewHeight + 'px', borderWidth: previewWidth * 0.0465 + 'px'}">
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div v-if="prodType === '直拍封面'" class="previewClass" :style="{width: previewWidth + 'px', height: previewHeight + 'px', borderWidth: previewWidth * 0.02325 + 'px'}">
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div v-if="prodType === '票根'" class="previewClass" :style="{width: previewWidth + 'px', height: previewHeight + 'px', borderWidth: previewWidth * 0.0465 + 'px'}">
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div v-if="prodType === '书签'" class="previewClass" :style="{width: previewWidth + 'px', height: previewHeight + 'px', borderWidth: previewWidth * 0.0264 + 'px'}">
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div v-if="prodType === '明信片'" class="previewClass" :style="{width: previewWidth + 'px', height: previewHeight + 'px', borderWidth: previewWidth * 0.0261 + 'px'}">
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div v-if="prodType === '方卡'" class="previewClass" :style="{width: previewWidth + 'px', height: previewHeight + 'px', borderWidth: previewWidth * 0.0232 + 'px'}">
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div v-if="prodType === '徽章'" class="previewClass" :style="{width: previewWidth + 'px', height: previewHeight + 'px', borderWidth: previewWidth * 0.0813 + 'px', borderRadius: 100 + '%'}">
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div v-if="prodType === '手幅'" class="previewClass" :style="{width: previewWidth + 'px', height: previewHeight + 'px', borderWidth: previewWidth * 0.0255 + 'px'}">
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-image ref="previewImageRef" :src="previewPicUrl" alt="" @load="previewLoad" style="width: 100%; height: 100%"/>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <!--<div class="parent">
|
|
|
|
|
+ <canvas ref="canvas" :width="clientWidth" :height="clientHeight" id="myCanvas"></canvas>
|
|
|
|
|
+ <div class="blood" :style="{border: bloodWidth + 'px solid rgba(225,0,0, 0.3)' , width: clientWidth +'px', height: clientHeight + 'px', borderRadius: bloodRadius + '%'}"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div style="text-align: center;">
|
|
|
|
|
+ <el-button @click="cropImage">保存画布</el-button>
|
|
|
|
|
+ </div>-->
|
|
|
|
|
+
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+ const statusConfig = {IDLE:0, DRAG_START:1, DRAGGING:2};
|
|
|
|
|
+ const prodSize = {'小卡': {width: 709, height: 1087, clientScale:0.5, bloodRadio: 0.0242}, '方卡':{width: 1252, height: 1252, clientScale:0.5}, '拍立得':{width: 709, height: 1087, clientScale:0.5, bloodRadio: 0.0242},
|
|
|
|
|
+ '直拍封面':{width: 709, height: 1217, clientScale:0.5, bloodRadio: 0.02325}, '书签': {width: 638, height: 1819, clientScale:0.4, bloodRadio: 0.0264},'明信片':{width: 1252, height: 1819, clientScale:0.4, bloodRadio: 0.0261},
|
|
|
|
|
+ '徽章':{width: 839, height: 839, clientScale:0.5, bloodRadio: 0.0813, bloodRadius:100},'票根':{width: 709, height: 1489, clientScale:0.5, bloodRadio: 0.0465},'手幅':{width: 1252, height: 3614, clientScale:0.25, bloodRadio: 0.0255}}
|
|
|
|
|
+ export default {
|
|
|
|
|
+ name: "CanvasPreview",
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ visible: false,
|
|
|
|
|
+ prodType: null,
|
|
|
|
|
+ previewWidth: null,
|
|
|
|
|
+ previewHeight: null,
|
|
|
|
|
+ previewPicUrl: null,
|
|
|
|
|
+ side: null,
|
|
|
|
|
+ clientWidth: 709,
|
|
|
|
|
+ clientHeight: 1087,
|
|
|
|
|
+ clientScale: 0.5,
|
|
|
|
|
+ cardItem: null,
|
|
|
|
|
+ canvasParam:null,
|
|
|
|
|
+ bloodWidth: 20,
|
|
|
|
|
+ bloodRadius: 0,
|
|
|
|
|
+ canvasInfo:{
|
|
|
|
|
+ status: statusConfig.IDLE,
|
|
|
|
|
+ dragTarget: {x:0,y:0,w:0,h:0},
|
|
|
|
|
+ lastEvtPos: {x:null,y:null},
|
|
|
|
|
+ offsetEvtPos: {x:null,y:null},
|
|
|
|
|
+ offset: {x:0,y:0},
|
|
|
|
|
+ scale: 1,
|
|
|
|
|
+ scaleStep: 0.01,
|
|
|
|
|
+ minScale: 0.5,
|
|
|
|
|
+ maxScale: 2,
|
|
|
|
|
+ },
|
|
|
|
|
+ imgRef:null,
|
|
|
|
|
+ canvas:null,
|
|
|
|
|
+ context: null,
|
|
|
|
|
+ };
|
|
|
|
|
+ },
|
|
|
|
|
+ mounted() {
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ openCanvas(){
|
|
|
|
|
+ this.initCanvas();
|
|
|
|
|
+ this.drawImage();
|
|
|
|
|
+ this.addMouseListeners();
|
|
|
|
|
+ },
|
|
|
|
|
+ init(cardItem, previewPicUrl, prodType, side){
|
|
|
|
|
+ this.visible = true;
|
|
|
|
|
+ this.previewPicUrl = previewPicUrl;
|
|
|
|
|
+ this.prodType = prodType;
|
|
|
|
|
+ this.side = side;
|
|
|
|
|
+ this.cardItem = cardItem;
|
|
|
|
|
+ if(side === 'front'){
|
|
|
|
|
+ this.canvasParam = JSON.parse(cardItem.frontCanvasParam);
|
|
|
|
|
+ }else if(side === 'back'){
|
|
|
|
|
+ this.canvasParam = JSON.parse(cardItem.backCanvasParam);
|
|
|
|
|
+ }
|
|
|
|
|
+ let prod = prodSize[prodType];
|
|
|
|
|
+ this.clientWidth = prod.width * prod.clientScale;
|
|
|
|
|
+ this.clientHeight = prod.height * prod.clientScale;
|
|
|
|
|
+ this.bloodRadius = prod.bloodRadius ? prod.bloodRadius : this.bloodRadius;
|
|
|
|
|
+ this.bloodWidth = prod.width * prod.bloodRadio;
|
|
|
|
|
+ },
|
|
|
|
|
+ previewLoad(event){
|
|
|
|
|
+ this.previewWidth = event.srcElement.clientWidth;
|
|
|
|
|
+ this.previewHeight = event.srcElement.clientHeight;
|
|
|
|
|
+ },
|
|
|
|
|
+ cropImage() {
|
|
|
|
|
+ this.$confirm('确认要保存当前画布状态吗?', '提示', {
|
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
|
+ type: 'warning'
|
|
|
|
|
+ }).then(() => {
|
|
|
|
|
+ let canvasInfo = this.canvasInfo;
|
|
|
|
|
+ let cardItem = {cardItemId : this.cardItem.cardItemId};
|
|
|
|
|
+ let obj = {scale: canvasInfo.scale, offsetX: canvasInfo.offset.x, offsetY: canvasInfo.offset.y, targetX: canvasInfo.dragTarget.x, targetY: canvasInfo.dragTarget.y}
|
|
|
|
|
+ let canvasParam = JSON.stringify(obj);
|
|
|
|
|
+ if(this.side === 'front'){
|
|
|
|
|
+ cardItem.frontCanvasParam = canvasParam;
|
|
|
|
|
+ }else if(this.side === 'back'){
|
|
|
|
|
+ cardItem.backCanvasParam = canvasParam;
|
|
|
|
|
+ }
|
|
|
|
|
+ this.$http({
|
|
|
|
|
+ url: this.$http.adornUrl('/prod/orderCardItem/saveOrUpdateCanvasParam'),
|
|
|
|
|
+ method: 'post',
|
|
|
|
|
+ data: cardItem
|
|
|
|
|
+ }).then(({ data }) =>{
|
|
|
|
|
+ if(data){
|
|
|
|
|
+ this.$message.success("保存成功");
|
|
|
|
|
+ }else{
|
|
|
|
|
+ this.$message.error("保存失败");
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ initCanvas() {
|
|
|
|
|
+ this.canvas = this.$refs.canvas;
|
|
|
|
|
+ this.context = this.canvas.getContext('2d'); // 获取画布上下文
|
|
|
|
|
+ },
|
|
|
|
|
+ getCanvasPosition(e, offset = {x:0,y:0}){
|
|
|
|
|
+ return {
|
|
|
|
|
+ x: e.offsetX - offset.x,
|
|
|
|
|
+ y: e.offsetY - offset.y
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ render(){
|
|
|
|
|
+ this.canvas.width = this.clientWidth;
|
|
|
|
|
+ this.context.setTransform(this.canvasInfo.scale, 0, 0, this.canvasInfo.scale, this.canvasInfo.offset.x, this.canvasInfo.offset.y);
|
|
|
|
|
+ this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
|
|
|
+ this.drawImage();
|
|
|
|
|
+ },
|
|
|
|
|
+ ifInImage(pos){
|
|
|
|
|
+ let dx = this.getDistanceX(pos.x, this.imgRef.x);
|
|
|
|
|
+ let dy = this.getDistanceY(pos.y, this.imgRef.y);
|
|
|
|
|
+ if(dx <= this.imgRef.width && dy <=this.imgRef.height){
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }else{
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ getDistanceX(x1, x2){
|
|
|
|
|
+ return Math.abs((x1 - x2));
|
|
|
|
|
+ },
|
|
|
|
|
+ getDistanceY(y1, y2){
|
|
|
|
|
+ return Math.abs((y1 - y2));
|
|
|
|
|
+ },
|
|
|
|
|
+ drawImage() {
|
|
|
|
|
+ if(!this.imgRef){
|
|
|
|
|
+ this.imgRef = new Image();
|
|
|
|
|
+ this.imgRef.src = this.previewPicUrl;
|
|
|
|
|
+ if(this.canvasParam){
|
|
|
|
|
+ this.canvasInfo.scale = this.canvasParam.scale;
|
|
|
|
|
+ this.canvasInfo.offset.x = this.canvasParam.offsetX;
|
|
|
|
|
+ this.canvasInfo.offset.y = this.canvasParam.offsetY;
|
|
|
|
|
+ this.canvasInfo.dragTarget.x = this.canvasParam.targetX;
|
|
|
|
|
+ this.canvasInfo.dragTarget.y = this.canvasParam.targetY;
|
|
|
|
|
+ }else{
|
|
|
|
|
+ let scaleImgWidth = this.imgRef.width * this.canvasInfo.scale;
|
|
|
|
|
+ let scaleImgHeight = this.imgRef.height * this.canvasInfo.scale;
|
|
|
|
|
+ if (scaleImgWidth > this.canvas.width && scaleImgHeight > this.canvas.height) {
|
|
|
|
|
+ if(scaleImgWidth > scaleImgHeight){
|
|
|
|
|
+ this.canvasInfo.scale = this.canvas.height / scaleImgHeight;
|
|
|
|
|
+ }else{
|
|
|
|
|
+ this.canvasInfo.scale = this.canvas.width / scaleImgWidth;
|
|
|
|
|
+ }
|
|
|
|
|
+ }else if(scaleImgWidth < this.canvas.width && scaleImgHeight < this.canvas.height){
|
|
|
|
|
+ if(scaleImgWidth > scaleImgHeight){
|
|
|
|
|
+ this.canvasInfo.scale = this.canvas.height / scaleImgHeight;
|
|
|
|
|
+ }else{
|
|
|
|
|
+ this.canvasInfo.scale = this.canvas.width / scaleImgWidth;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ this.context.setTransform(this.canvasInfo.scale, 0,0, this.canvasInfo.scale, this.canvasInfo.offset.x,this.canvasInfo.offset.y)
|
|
|
|
|
+ this.context.drawImage(this.imgRef, this.canvasInfo.dragTarget.x, this.canvasInfo.dragTarget.y, this.imgRef.width, this.imgRef.height); // 在画布上绘制图片
|
|
|
|
|
+ }else{
|
|
|
|
|
+ this.context.drawImage(this.imgRef, this.canvasInfo.dragTarget.x, this.canvasInfo.dragTarget.y, this.imgRef.width, this.imgRef.height); // 在画布上绘制图片
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ addMouseListeners() {
|
|
|
|
|
+ let canvas = this.$refs.canvas;
|
|
|
|
|
+ // 监听鼠标按下事件
|
|
|
|
|
+ canvas.addEventListener('mousedown', e => {
|
|
|
|
|
+ let canvasPosition = this.getCanvasPosition(e, this.canvasInfo.offset);
|
|
|
|
|
+ console.log("画笔位置", canvasPosition);
|
|
|
|
|
+ if(this.ifInImage(canvasPosition)){
|
|
|
|
|
+ let scaleImgWidth = this.imgRef.width * this.canvasInfo.scale;
|
|
|
|
|
+ let scaleImgHeight = this.imgRef.height * this.canvasInfo.scale;
|
|
|
|
|
+ if(scaleImgWidth <= this.canvas.width || scaleImgHeight <= this.canvas.height){
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ this.canvasInfo.status = statusConfig.DRAG_START;
|
|
|
|
|
+ this.canvasInfo.lastEvtPos = canvasPosition;
|
|
|
|
|
+ this.canvasInfo.offsetEvtPos = canvasPosition;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ //监听鼠标移动事件
|
|
|
|
|
+ canvas.addEventListener('mousemove', e => {
|
|
|
|
|
+ let canvasPosition = this.getCanvasPosition(e, this.canvasInfo.offset);
|
|
|
|
|
+ if(this.canvasInfo.status === statusConfig.DRAG_START && (this.getDistanceX(canvasPosition.x, this.canvasInfo.lastEvtPos.x) > 5 || this.getDistanceY(canvasPosition.y, this.canvasInfo.lastEvtPos.y) > 5)){
|
|
|
|
|
+ this.canvasInfo.status = statusConfig.DRAGGING;
|
|
|
|
|
+ this.canvasInfo.offsetEvtPos = canvasPosition;
|
|
|
|
|
+ }else if(this.canvasInfo.status === statusConfig.DRAGGING){
|
|
|
|
|
+ let dragTarget = this.canvasInfo.dragTarget;
|
|
|
|
|
+ dragTarget.x += (canvasPosition.x - this.canvasInfo.offsetEvtPos.x);
|
|
|
|
|
+ dragTarget.y += (canvasPosition.y - this.canvasInfo.offsetEvtPos.y);
|
|
|
|
|
+ this.render();
|
|
|
|
|
+ this.canvasInfo.offsetEvtPos = canvasPosition;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 监听鼠标松开事件
|
|
|
|
|
+ canvas.addEventListener('mouseup', () => {
|
|
|
|
|
+ if(this.canvasInfo.status === statusConfig.DRAGGING){
|
|
|
|
|
+ this.canvasInfo.status = statusConfig.IDLE;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 监听鼠标松开事件
|
|
|
|
|
+ canvas.addEventListener('mouseout', (e) => {
|
|
|
|
|
+ this.canvasInfo.status = statusConfig.IDLE;
|
|
|
|
|
+ let canvasPosition = this.getCanvasPosition(e, this.canvasInfo.offset);
|
|
|
|
|
+ this.canvasInfo.lastEvtPos = canvasPosition;
|
|
|
|
|
+ this.canvasInfo.offsetEvtPos = canvasPosition;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 监听鼠标滚轮事件
|
|
|
|
|
+ canvas.addEventListener('wheel', (e) => {
|
|
|
|
|
+ // e.preventDefault();
|
|
|
|
|
+ let canvasPosition = this.getCanvasPosition(e, this.canvasInfo.offset);
|
|
|
|
|
+ let deltaX = canvasPosition.x / this.canvasInfo.scale * this.canvasInfo.scaleStep;
|
|
|
|
|
+ let deltaY = canvasPosition.y / this.canvasInfo.scale * this.canvasInfo.scaleStep;
|
|
|
|
|
+ let scaleImgWidth = this.imgRef.width * this.canvasInfo.scale;
|
|
|
|
|
+ let scaleImgHeight = this.imgRef.height * this.canvasInfo.scale;
|
|
|
|
|
+ if(e.wheelDelta > 0 && this.canvasInfo.scale <= this.canvasInfo.maxScale){
|
|
|
|
|
+ this.canvasInfo.offset.x -= deltaX;
|
|
|
|
|
+ this.canvasInfo.offset.y -= deltaY;
|
|
|
|
|
+ this.canvasInfo.scale += this.canvasInfo.scaleStep;
|
|
|
|
|
+ }else{
|
|
|
|
|
+ if (scaleImgWidth <= this.canvas.width || scaleImgHeight <= this.canvas.height) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }else{
|
|
|
|
|
+ this.canvasInfo.offset.x += deltaX;
|
|
|
|
|
+ this.canvasInfo.offset.y += deltaY;
|
|
|
|
|
+ this.canvasInfo.scale -= this.canvasInfo.scaleStep;
|
|
|
|
|
+ if (scaleImgWidth <= this.canvas.width || scaleImgHeight <= this.canvas.height) {
|
|
|
|
|
+ // 达到限制条件,不再缩小
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ this.render();
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ closeDialog(){
|
|
|
|
|
+ this.canvas = null;
|
|
|
|
|
+ this.context = null;
|
|
|
|
|
+ this.imgRef = null;
|
|
|
|
|
+ this.visible = false;
|
|
|
|
|
+ this.canvasInfo = {
|
|
|
|
|
+ status: statusConfig.IDLE,
|
|
|
|
|
+ dragTarget: {x:0,y:0,w:0,h:0},
|
|
|
|
|
+ lastEvtPos: {x:null,y:null},
|
|
|
|
|
+ offsetEvtPos: {x:null,y:null},
|
|
|
|
|
+ offset: {x:0,y:0},
|
|
|
|
|
+ scale: 1,
|
|
|
|
|
+ scaleStep: 0.01,
|
|
|
|
|
+ minScale: 0.5,
|
|
|
|
|
+ maxScale: 2,
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ }
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped>
|
|
|
|
|
+ .previewClass{
|
|
|
|
|
+ position:absolute;
|
|
|
|
|
+ border-style:solid;
|
|
|
|
|
+ border-color:red;
|
|
|
|
|
+ opacity:0.3;
|
|
|
|
|
+ z-index:3;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #myCanvas {
|
|
|
|
|
+ display: block;
|
|
|
|
|
+ margin: 0 auto; /* 水平居中 */
|
|
|
|
|
+ }
|
|
|
|
|
+ .parent{
|
|
|
|
|
+ position: relative; /* 设置父元素的position为relative */
|
|
|
|
|
+ background-color: white;
|
|
|
|
|
+ }
|
|
|
|
|
+ .blood {
|
|
|
|
|
+ position: absolute; /* 设置相框的position为absolute */
|
|
|
|
|
+ top: 50%; /* 距离父元素顶部50% */
|
|
|
|
|
+ left: 50%; /* 距离父元素左侧50% */
|
|
|
|
|
+ transform: translate(-50%, -50%) ; /* 将相框自身向左和向上移动50%,使其居中 */
|
|
|
|
|
+ background-color: transparent; /* 设置相框背景为透明 */
|
|
|
|
|
+ pointer-events:none;
|
|
|
|
|
+ }
|
|
|
|
|
+</style>
|