editImage 组件

<template><!-- v-show="$store.state.showDoodling" --><div class="editImage"><div class="optBtn"><!-- style="width: 100vw;height: 100vh;display: flex;justify-content: center;align-items: center;" --><div><canvasref="canvas":id="radom":class="{ canDraw: 'canvas' }"@mousedown="canvasDown($event)"@mouseup="canvasUp($event)"@mousemove="canvasMove($event)"@touchstart="canvasDown($event)"@touchend="canvasUp($event)"@touchmove="canvasMove($event)"></canvas></div><div class="tuyaTit"><span class="tycancel" @click="goBack">取消</span><span class="tysure" @click="toSaveImage">完成</span></div><divclass="inpContainer":style="{          left: moveX < 120 ? 0 : moveX - 120 + 'px',
          top: moveY + 'px',
        }"v-if="showTextStatus"><inputtype="text"name=""class="addTextInp"placeholder="请输入添加的文字"v-model="textValue"/><div class="addBtn" @click="drawText(moveX > 120 ? moveX - 60 : moveX, moveY - 128)">添加</div></div><div class="colorType"><div class="coloSing"><spanclass="selColor"v-for="(item, index) in colorList":key="index":style="{ backgroundColor: item }"@click="changeColor(item, index)":class="{ isChooseColor: isChooseColor == index }"></span><span class="selRevoke" @click="revokeDraw"><img src="@/assets/images/revoke.png" width="20px" height="20px" /></span><span class="text-icon" @click="showTextContainer"><imgsrc="@/assets/images/text-icon.png"width="20px"height="20px"/></span></div></div></div><!-- 点击完成选择接下的操作 --><div class="doodlingModel" v-if="isComplete"><ul><li @click="transmit">发送给朋友</li><!-- <li @click="toSaveImage">保存图片</li> --></ul></div><div class="fog" v-if="isComplete" @click="closeModel"></div></div>
</template><script>
import { fileUpload } from '@/utils';export default {name: 'EditImage',data() {const data = {showModal: true,imageurl: '',width: 400,height: 500,canDraw: true,url: '',info: '',lineColor: 'red',lineWidth: '2',lineType: 'rec',colorList: ['#FFFFFF','#030102','#E75D58','#F6C543','#FF8500','#4FABF8','#6467E8',],// 同一页面多次渲染时,用于区分元素的idradom: 'myCanvas',// canvas对象context: {},// 是否处于绘制状态canvasMoveUse: false,// 绘制矩形和椭圆时用来保存起始点信息beginRec: {x: '',y: '',imageData: '',},moveX: '',moveY: '',// 储存坐标信息drawInfo: [],// 背景图片缓存img: new Image(),canvasHistory: [],restore: [],repeat: [],myCanvas: null,hub: 0,showImg: false,editIamgeUrl: '',isComplete: false,msgData: {},inited: false,top: 0,left: 0,isChooseColor: false,textValue: '',showTextStatus: false,};return data;},props: {propsImageurl: {type: String,default() {return '';},},},created() {const self = this;let originLink = '';originLink = this.propsImageurl;self.url = originLink;this.msgData = self.$route.query.msg;self.width = document.documentElement.clientWidth; // 可见区域宽度self.height = document.documentElement.clientHeight; // 可见区域高度if (localStorage.getItem('lineColor')) {self.lineColor = localStorage.getItem('lineColor');}},mounted() {const self = this;self.initDraw();},methods: {// 转发消息transmit() {const self = this;if (self.msgData.type === 'custom' &&self.msgData.content.type === 'imageurl') {self.msgData.content.imageurl = self.imageurl;} else if (self.msgData.type === 'image') {self.msgData.originLink = self.imageurl;}self.$router.push({path: '/forwardmsg',query: {sendMsg: self.msgData,},});},goBack() {//   this.context.clearRect(0, 0, this.width, this.height);this.$emit('hide-edit');},// canvas转base64toSaveImage() {this.imageurl = this.myCanvas.toDataURL('image/png');const blob = this.base64ToBlob(this.imageurl);const file = this.blobToFile(blob, 'newImg.png');const type = 'png';let obj = '';fileUpload(this, file, type, (url) => {obj = {image: url,content: '',};if (obj.image) {this.$emit('getNewImg', obj.image);}});},// base64转blob解决ios兼容问题base64ToBlob(base64Data) {const arr = base64Data.split(',');const fileType = arr[0].match(/:(.*?);/)[1];const bstr = atob(arr[1]);let l = bstr.length;const u8Arr = new Uint8Array(l);while (l--) {u8Arr[l] = bstr.charCodeAt(l);}return new Blob([u8Arr], {type: fileType,});},// blob转file上传blobToFile(newBlob, fileName) {const Obj = newBlob;Obj.lastModifiedDate = new Date();Obj.name = fileName;return newBlob;},// 撤销revokeDraw() {if (this.canvasHistory.length > 1) {this.context.putImageData(this.canvasHistory[this.canvasHistory.length - 2],0,0,);this.canvasHistory.length--;}},// huansechangeColor(item, index) {this.lineColor = item;this.context.strokeStyle = this.lineColor;this.isChooseColor = index;localStorage.setItem('lineColor', this.lineColor);},// 关闭窗口closeModule() {this.showModal = false;},// 操作按钮 1 涂鸦  2 编辑文字  3、确定operation(index) {if (index === 1) {this.canDraw = true;} else if (index === 2) {this.canDraw = false;} else if (index === 3) {this.canDraw = false;}this.closeModule();},// 初始化绘制信息initDraw() {// 初始化画布this.myCanvas = document.getElementById(this.radom);this.context = this.myCanvas.getContext('2d');// 初始化背景图片this.img.setAttribute('crossOrigin', 'Anonymous');this.img.src = this.url;this.img.onerror = () => {const timeStamp = +new Date();this.img.src = this.url + '?' + timeStamp;};this.img.onload = () => {this.clean();};// 初始化画笔this.context.lineWidth = this.lineWidth;this.context.strokeStyle = this.lineColor;},// 鼠标按下canvasDown(e) {this.showModal = false;if (this.canDraw) {this.repeat.length = 0;this.canvasMoveUse = true;// client是基于整个页面的坐标,offset是cavas距离pictureDetail顶部以及左边的距离const canvasX =event.changedTouches[0].clientX - e.target.parentNode.offsetLeft;const canvasY =event.changedTouches[0].clientY - e.target.parentNode.offsetTop;// 记录起始点和起始状态this.beginRec.x = canvasX;this.beginRec.y = canvasY;this.beginRec.imageData = this.context.getImageData(0,0,this.width,this.height,);// 存储本次绘制坐标信息this.drawInfo.push({x: canvasX / this.width,y: canvasY / this.height,type: this.lineType,});this.moveX = event.changedTouches[0].clientX;this.moveY = event.changedTouches[0].clientY;// console.log(this.moveX);// console.log(this.moveY);}},// 鼠标移动时绘制canvasMove() {if (this.canvasMoveUse && this.canDraw) {this.context.beginPath(); // 划线改变颜色必须用这个this.context.lineCap = 'round';this.context.lineJoin = 'round';this.context.moveTo(this.moveX - this.left, this.moveY - this.top);this.context.lineTo(event.changedTouches[0].clientX - this.left,event.changedTouches[0].clientY - this.top,);this.context.closePath();this.context.stroke();this.moveX = event.changedTouches[0].clientX;this.moveY = event.changedTouches[0].clientY;}},showTextContainer() {this.showTextStatus = true;},// 绘制文字drawText(x, y) {let handldX = x;if (x <= 0) {handldX = 40;}if (this.textValue) {this.showTextStatus = false;}this.context.font = 'bold 16px Arial';this.context.textAlign = 'center';this.context.textBaseline = 'bottom';this.context.zIndex = '99';this.context.fillStyle = '#ccc';this.context.strokeText(this.textValue, handldX, y);this.context.closePath();this.context.stroke();this.textValue = '';},// 鼠标抬起canvasUp() {if (this.canDraw) {this.canvasMoveUse = false;this.showModal = true;this.canvasHistory.push(this.context.getImageData(0, 0, this.width, this.height));}},// 保持纵横比缩放图片,使图片的长边能完全显示出来containImg(sx, sy, boxW, boxH, sourceW, sourceH) {let dx = sx;let dy = sy;let dWidth = boxW;let dHeight = boxH;if (sourceW > sourceH || (sourceW === sourceH && boxW < boxH)) {dHeight = (sourceH * dWidth) / sourceW;dy = sy + ((boxH - dHeight) / 2);} else if (sourceW < sourceH || (sourceW === sourceH && boxW > boxH)) {dWidth = (sourceW * dHeight) / sourceH;dx = sx + ((boxW - dWidth) / 2);}return {dx,dy,dWidth,dHeight,};},// 清空画布// img  规定要使用的图像、画布或视频。// sx   可选。开始剪切的 x 坐标位置。// sy   可选。开始剪切的 y 坐标位置。// swidth   可选。被剪切图像的宽度。// sheight  可选。被剪切图像的高度。// x    在画布上放置图像的 x 坐标位置。// y    在画布上放置图像的 y 坐标位置。// width    可选。把图像绘制到画布上的宽度。(伸展或缩小图像)// height   可选。把图像绘制到画布上的高度。(伸展或缩小图像)// ctx.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);clean() {// 计算宽高比const self = this;const imgRect = this.containImg(0,0,this.width,this.height,this.img.width,this.img.height,);self.width = imgRect.dWidth;self.height = imgRect.dHeight;// 给canvas赋值宽高self.$refs.canvas.width = self.width;self.$refs.canvas.height = self.height;// canvas必须有高self.$refs.canvas.style.height = self.height;// 清空canvas画布self.context.clearRect(0, 0, self.width, self.height);// 获取水平垂直偏移距离self.top = (document.documentElement.clientHeight - self.height) / 2;self.left = (document.documentElement.clientWidth - self.width) / 2;// this.context.drawImage(this.img, imgRect.dx, imgRect.dy, imgRect.dWidth, imgRect.dHeight);// 渲染图片self.context.drawImage(self.img, 0, 0, imgRect.dWidth, imgRect.dHeight);//  this.context.drawImage(this.img, imgRect.dx, imgRect.dy, imgRect.dWidth, imgRect.dHeight);// 画布垂直居中self.$refs.canvas.style.marginTop = self.top + 'px';// 初始化鼠标在画布的位置self.moveY = self.top;// 画布水平居中self.$refs.canvas.style.left = self.left + 'px';// 修改画笔颜色for (let i = 0, len = this.colorList.length; i < len; i++) {if (self.lineColor === self.colorList[i]) {self.changeColor(self.lineColor, i);break;}}// 记录第一次canvas图像(防止撤回到最后空白)self.canvasHistory.push(self.context.getImageData(0, 0, self.width, self.height));},// 关闭模态框closeModel() {self.isComplete = false;},},
};
</script><style lang="scss" scoped>
.editImage {position: fixed;z-index: 999;width: 100%;height: 100vh;background-color: #fff;.fog {position: fixed;top: 0px;left: 0px;background-color: #000;opacity: 0.5;width: 100%;height: 100%;z-index: 100;}.doodlingModel {width: 85%;position: absolute;left: 7.5%;top: 35%;background-color: #ffffff;border-radius: 5px;z-index: 1000;}.doodlingModel > ul {width: 100%;}.doodlingModel > ul > li {width: 90%;color: #000000;font-size: 16px;height: 50px;line-height: 50px;border-bottom: 1px solid #dedede;margin: 0 auto;}.doodlingModel > ul > li:last-of-type {border-bottom: none;}
}.optBtn {width: 100%;height: 100vh;position: relative;bottom: 0;left: 0;display: flex;justify-content: space-around;background-color: rgba(0, 0, 0, 0.5);z-index: 1;.inpContainer {position: absolute;display: flex;.addTextInp {width: 120px;}.addBtn {height: 20px;text-align: center;line-height: 20px;font-size: 14px;border: 2px solid #ccc;color: rgb(246, 197, 67);}}.colorType {bottom: 0px;position: absolute;padding: 0 1.8125rem;height: 3.8125rem;width: 100%;padding: 0 10px;background-image: url(../../assets/images/doodlingbg.png);.huabi {width: 1rem;height: 1rem;margin-top: 1.172rem;img {width: 100%;height: 100%;}}.coloSing {width: 100%;display: flex;justify-content: space-around;margin-top: 50px;.selColor {width: 20px;height: 20px;border-radius: 50%;border: 1px solid #fff;}.isChooseColor {border: 3px solid #fff;}}}.tuyaTit {/* width: calc(100% - 1.25rem); */width: 90%;display: flex;justify-content: space-between;align-items: center;/* margin: 3rem 0.625rem 0  0.625rem; */color: #fff;/* font-size: .5rem; */font-size: 15px;font-weight: 500;position: absolute;top: 20px;/* left: 0.625rem; */left: 5%;}.tysure {padding: 5px 15px;background-color: #ff8500;border-radius: 3px;}
}
</style>

vue基于canvas 涂鸦和文字编辑相关推荐

  1. 微信小程序-基于canvas画画涂鸦

    代码地址如下: http://www.demodashi.com/demo/14461.html 一.前期准备工作 软件环境:微信开发者工具 官方下载地址:https://mp.weixin.qq.c ...

  2. 基于canvas使用粒子拼出你想要的文字[2]——粒子的动画效果

    写在最前 本次分享一个用canvas粒子渲染文字的"完整"版实现,功能包括:随机粒子缓动动画,粒子汇聚.发散,并拼出你想要的文字.本文继续上面一节基于canvas使用粒子拼出你想要 ...

  3. 基于 Spring Boot + Vue 实现的可视化拖拽编辑的大屏项目

    大家好,今天给小伙伴们分享一个基于 SpringBoot + Vue 实现的可视化拖拽编辑的大屏项目: 简介 这个是一个开源的一个BI平台,酷炫大屏展示,能随时随地掌控业务动态,让每个决策都有数据支撑 ...

  4. VUE+Canvas实现输入文字生成对应的字体图片小功能

    你是不是经常浏览字体网站的时候,发现他们的"字体生成器"和预览功能很好奇,为什么输入框输入文字之后,点击预览,下面都会修改对应的字体内容,以便达到了没有安装字体也可以预览这个字体效 ...

  5. canvas换图时候会闪烁_基于Canvas实现的高斯模糊(上)「JS篇」

    作者:iNahoo 转发链接:https://mp.weixin.qq.com/s/5TxPjznpEBku_ybSMBdnfw 目录 基于Canvas实现的高斯模糊(上)「JS篇」本篇 基于Canv ...

  6. python之tkinter模块——基于tk得图片文字

    小编好久没更新了,最近有点事情,虽迟但到.我们补上之前的内容再加以讲解. tkinter的内置位图预览和图片预览 老样子,先看预览图 就是简易得调用计算机内部的图片位置,展示出来一个效果图,平时网页上 ...

  7. canvas路线图 vue_vue 基于canvas的编辑图片并上传至服务器。只要两碗双皮奶的时间,你上你也行...

    来,效果图 1.实现思路 先通过浏览器打开本地图片,再用canvas加载图片,然后通过getImageData把canvas的画布输出,然后用你想裁剪成多大的另一个canvas通过putImageDa ...

  8. 前端实现可绘制的canvas画布_JS前端基于canvas给图片添加水印

    前两天给个人网站添加了一个小功能,就是在文章编辑上传图片的时候自动给图片加上水印.给网页图片添加水印是个常见的功能,也是互联网内容作者保护自己版权的方法之一.本文简单记录一下借助canvas在前端实现 ...

  9. 7个华丽的基于Canvas的HTML5动画

    说起HTML5,可能让你印象更深的是其基于Canvas的动画特效,虽然Canvas在HTML5中的应用并不全都是动画制作,但其动画效果确实让人震惊.本文收集了7个最让人难忘的HTML5 Canvas动 ...

最新文章

  1. 红芯丑闻揭秘者 Touko 专访 | 关于红芯丑闻的更多内幕……
  2. 效率神器!开源快捷启动工具
  3. java数值运算后精度丢失问题
  4. SAP MM 库存初始化和批量扩充物料仓位
  5. 人工智能的炒作_解密人工智能:是炒作还是我们期望太高
  6. 阿里云Elasticsearch的X-Pack:机器学习、安全保障和可视化
  7. Dubbo使用启动时检查 check=“true“
  8. 快速排序 (Quick Sort)(Java实现)
  9. [html] 你知道著名的3像素Bug指的是什么吗?怎么解决呢?
  10. springMVC接收请求参数的几种方式
  11. java多级目录文件是否存在_Java文件夹操作,判断多级路径是否存在,不存在就创建(包括windows和linux下的路径字符分析)...
  12. 求一列数据中的波峰_pandas查看缺失数据占比(实战)
  13. C语言 数组中删除指定字符
  14. Recompile/upgrade nginx binary with no down-time
  15. 【2017CCPC哈尔滨赛区 HDU 6242】Geometry Problem【随机化】
  16. Labelimg讲解
  17. CentOS 5.5 安装 Python 2.7_老范的空间_百度空间
  18. 【这是一个还没有被证实是否有效的小白修炼手册】数据结构入门第一课基本概念
  19. wordpress插件_最好的WordPress购物车插件
  20. php实现微信公众号生成淘宝客推广海报(正则匹配淘宝联盟)

热门文章

  1. php ean13,php生成EAN_13标准条形码实例_PHP教程
  2. 深度相机Kinect2.0三维点云拼接实验(二)
  3. 真的有这么丝滑:3D头发建模新方法NeuralHDHair,浙大、ETH Zurich、CityU联合出品...
  4. Mac BERT 论文解读 Revisiting Pre-trained Models for Chinese Natural Language Processing
  5. JAVAWEB开发之——Linux命令实战、虚拟机和centos的安装以及联网、常用命令、vi编辑以及软件的安装、sftp的使用
  6. python人力成本数据测算_历史数据法进行人力成本分析
  7. hadoop文件读写示例
  8. 激荡20年,芯片产能从零起步到反超美国,中国制造的又一大成就
  9. IMPERVA - WAF syslog配置及注意事项
  10. 关于向量值函数方程变分的一点注记