canvas实现图片框选-js版

由于项目中需要进行图片部分区域框选,用来做图片标注工作,之前也找过多种方案,比如徒手用div来实现,后来绕了一圈之后,还是发现canvas非常便捷,于是乎将项目中的核心代码单独提取出来,供各位学习。

核心代码如下,提供的是html + js的代码,下方的代码需要进行变动然后集成到vue中,注意部分坑即可。

<!DOCTYPE html>
<html><head><title>测试canvas</title><script src="https://cdn.bootcss.com/vue/2.4.2/vue.min.js"></script></head><body><div style="background:url('bd_logo1.png');width:540px;height:300px;"><canvas id="myCanvas" width="540" height="300"></canvas></div></body><script type="text/javascript">function draw(x, y, wid, hei){var c=document.getElementById("myCanvas");var cxt=c.getContext("2d");var img = new Image();cxt.drawImage(img, 0, 0, 340, 100);cxt.fillStyle = "rgba(255, 0, 0, 0.1)";cxt.fillRect(x, y, wid, hei);cxt.strokeStyle = "rgb(0, 0, 0)"; //"rgb(0, 0, 0)";cxt.strokeRect(x, y, wid, hei);}draw(1, 2, 100, 200);draw(50, 50, 150, 350);</script>
</html>

canvas实现图片框选-vue版

<template><div class="divbody"><div class="imgContainer" ref="imgContainer"><canvas:ref="'refmyCanvas'"class="canvasClass":width="divWidth":height="divHeight"@mousedown="canvasMouseDown"@mouseup="canvasMouseUp"@mousemove="canvasMouseMove"></canvas><img:id="'image'":src="data:imageSrc":ref="'refimage'"class="imgClass"@load="uploadImgLoad"v-show="false"/></div></div>
</template>
<script>
export default {data() {return {divWidth: 0,divHeight: 0,imageSrc: 'http://img2.imgtn.bdimg.com/it/u=3984473917,238095211&fm=26&gp=0.jpg',// canvas的配置部分c: '',cxt: '',canvasImg: '',imgWidth: 0, // img框的宽度imgHeight: 0, // img框的高度targetMarkIndex: -1, // 目标标注indexparams: {currentX: 0,currentY: 0,flag: false, // 用来判断在canvas上是否有鼠标down的事件,editFlag: false,editIndex: -1},// 目标类别listimageCategoryList: [],targetMarkArray: []}},mounted() {// 这里是进行初始化canvas的操作 myCanvasconst self = this;try {self.c = self.$refs.refmyCanvas;self.canvasImg = self.$refs.refimage;self.cxt = self.c.getContext('2d');self.divWidth = self.$refs.imgContainer.offsetWidth;self.divHeight = self.$refs.imgContainer.offsetHeight;} catch (err) {console.log(err);}try {self.canvasOnDraw(self.imgWidth, self.imgHeight);} catch (err) {console.log(err);}},methods: {// 鼠标down事件canvasMouseDown(e) {this.params.flag = true;if (!e) {e = window.event;// 防止IE文字选中this.$refs.refmyCanvas.onselectstart = function() {return false;};}// 这里先判断一下,看是否是在有效数据,并且初始化参数if ((this.params.flag === true) && (this.params.editFlag === false)) {this.params.currentX = 0;this.params.currentY = 0;this.params.currentX = e.layerX;this.params.currentY = e.layerY;const dict1 = {x1: this.params.currentX, // 开始的x坐标y1: this.params.currentY, // 开始的y坐标x2: this.params.currentX, // 结束的x坐标y2: this.params.currentY, // 结束的y坐标flag: false, // 图片区域是否高亮,targetMarkValue: '', // 目标类别值wid: 0, // 矩形宽度hei: 0, // 矩形高度// final 是最终的框选的坐标值left: this.params.currentX,top: this.params.currentY,width: 0, // 矩形宽度height: 0, // 矩形高度finalX1: this.params.currentX,finalY1: this.params.currentY,finalX2: this.params.currentX,finalY2: this.params.currentY};this.targetMarkIndex = this.targetMarkIndex + 1;this.targetMarkArray.push(dict1);}// 执行渲染操作try {this.canvasOnDraw(this.imgWidth, this.imgHeight);} catch (err) {console.log(err);}},canvasMouseUp(e) {this.params.flag = false;try {this.canvasOnDraw(this.imgWidth, this.imgHeight);} catch (err) {console.log(err);}},canvasMouseMove(e) {if (e === null) {e = window.event;}if ((this.params.flag === true) && (this.params.editFlag === false)) {this.params.currentX = e.layerX;this.params.currentY = e.layerY;this.targetMarkArray[this.targetMarkIndex].x2 = this.params.currentX; // x1 值this.targetMarkArray[this.targetMarkIndex].y2 = this.params.currentY; // y1 值this.targetMarkArray[this.targetMarkIndex].wid = this.params.currentX - this.targetMarkArray[this.targetMarkIndex].x1; // 宽度值this.targetMarkArray[this.targetMarkIndex].hei = this.params.currentY - this.targetMarkArray[this.targetMarkIndex].y1; // 高度}// 执行渲染操作try {this.canvasOnDraw(this.imgWidth, this.imgHeight);} catch (err) {console.log(err);}},uploadImgLoad(e) {try {this.imgWidth = e.path[0].naturalWidth;this.imgHeight = e.path[0].naturalHeight;this.canvasOnDraw(this.imgWidth, this.imgHeight);} catch (err) {console.log(err);}},// 输入两个坐标值,判断哪个坐标值离左上角最近,其中特殊情况需要进行坐标查找工作findWhichIsFirstPoint(x1, y1, x2, y2) {// 首先判断x轴的距离谁更近if (x1 <= x2) {// 说明x1 比较小,接下来判断y谁更近if (y1 <= y2) {// 说明第一个坐标离得更近,直接顺序return就好return [x1, y1, x2, y2];} else {// 这里遇见一个奇葩问题,需要进行顶角变换return [x1, y2, x2, y1];}} else {// 这里是x1 大于 x2 的情况if (y2 <= y1) {return [x2, y2, x1, y1];} else {// y2 大于 y1 的情况, 这里需要做顶角变换工作return [x2, y1, x1, y2];}}},// canvas绘图部分canvasOnDraw(imgW = this.imgWidth, imgH = this.imgHeight) {const imgWidth = imgW;const imgHeight = imgH;this.divWidth = this.$refs.imgContainer.offsetWidth;this.divHeight = this.$refs.imgContainer.offsetHeight;this.cxt.clearRect(0, 0, this.c.width, this.c.height);// 当前的图片和现有的canvas容器之前的一个关系,是否有必要,我们后续做讨论var resPointList = this.changeOldPointToNewPoint(imgWidth,imgHeight,this.divWidth,this.divHeight);this.cxt.drawImage(this.canvasImg,0,0,imgWidth,imgHeight,0,0,resPointList[0],resPointList[1]);for (const index in this.targetMarkArray) {const x1 = this.targetMarkArray[index].x1;const y1 = this.targetMarkArray[index].y1;const x2 = this.targetMarkArray[index].x2;const y2 = this.targetMarkArray[index].y2;const wid = this.targetMarkArray[index].wid;const hei = this.targetMarkArray[index].hei;const FinalPointList = this.findWhichIsFirstPoint((x1 * this.imgWidth) / resPointList[0],(y1 * this.imgHeight) / resPointList[1],(x2 * this.imgWidth) / resPointList[0],(y2 * this.imgHeight) / resPointList[1]);this.targetMarkArray[index].finalX1 = FinalPointList[0];this.targetMarkArray[index].finalY1 = FinalPointList[1];this.targetMarkArray[index].finalX2 = FinalPointList[2];this.targetMarkArray[index].finalY2 = FinalPointList[3];// 必须要有的字段this.targetMarkArray[index].left = this.targetMarkArray[index].finalX1;this.targetMarkArray[index].top = this.targetMarkArray[index].finalY1;this.targetMarkArray[index].width = this.targetMarkArray[index].finalX2 - this.targetMarkArray[index].finalX1;this.targetMarkArray[index].height = this.targetMarkArray[index].finalY2 - this.targetMarkArray[index].finalY1;// 调整四个顶角的函数,为了能让整体框选区域更好看const FinalPointListNow = this.findWhichIsFirstPoint(x1,y1,x2,y2);const tmpX1 = FinalPointListNow[0];const tmpY1 = FinalPointListNow[1];const tmpX2 = FinalPointListNow[2];const tmpY2 = FinalPointListNow[3];this.cxt.strokeStyle = '#FF6600';this.cxt.strokeRect(tmpX1, tmpY1, tmpX2 - tmpX1, tmpY2 - tmpY1);this.cxt.fillStyle = '#FF6600';this.cxt.font = '16px Arial';// canvas的标题部分this.cxt.fillText(parseInt(index) + 1, tmpX1, parseInt(tmpY1) - 6);// 这里是在处理高亮的地方this.cxt.fillStyle = 'rgba(255, 0, 0, 0.1)';this.cxt.fillRect(tmpX1, tmpY1, wid, hei);// 说明被点击了this.canvasDrowBorder('#FF6600',tmpX1,tmpY1,tmpX2 - tmpX1,tmpY2 - tmpY1);this.canvasDrowInnerColor('rgba(255, 0, 0, 0.3)',tmpX1,tmpY1,tmpX2 - tmpX1,tmpY2 - tmpY1);}},// canvas框选区域的内容颜色canvasDrowInnerColor(color, x, y, w, h) {this.cxt.fillStyle = color;this.cxt.fillRect(x, y, w, h);},// canvas框选区域的边框颜色canvasDrowBorder(color, x, y, w, h) {this.cxt.strokeStyle = color;this.cxt.strokeRect(x, y, w, h);},// 尺寸变换函数changeOldPointToNewPoint(imgw, imgH, canvasW, canvasH) {// 这里有个要求,先以宽度为准,然后再一步步调整高度var tmpW = canvasW;var tmpH = (tmpW * imgH) / imgw;// 如果转换之后的高度正好小于框的高度,则直接进行显示if (tmpH <= canvasH) {// 尺寸完美匹配return [tmpW, tmpH];} else {// 高度超出框了,需要重新调整高度部分tmpW = canvasW;tmpH = (tmpW * imgH) / imgw;var count = 1;var raise = 0.05;while (tmpH > canvasH || tmpW > canvasW) {tmpW = tmpW * (1 - raise * count);tmpH = (tmpW * imgH) / imgw;}return [tmpW, tmpH];}}}
}
</script>
<style lang="less" scoped>
.divbody {min-width: 640px;min-height: 480px;
}
.imgContainer {position: relative;width: 640px;height: 480px;
}
.canvasClass {position: absolute;width: auto;height: auto;max-width: 100%;max-height: 100%;
}
.imgClass {width: auto;height: auto;max-width: 100%;max-height: 100%;
}
</style>

canvas实现矩形框,用来进行图片框选相关推荐

  1. canvas换图时候会闪烁_Canvas实现图片上标注、缩放、移动和保存历史状态,纯干货(附CSS 3变化公式)...

    (给前端大学加星标,提升前端技能.) 作者:zhcxk1998 https://juejin.im/user/5d4304bdf265da03d15531dc 哈哈哈俺又来啦,这次带来的是canvas ...

  2. 用python画圆角矩形_详解微信小程序canvas圆角矩形的绘制的方法

    详解微信小程序canvas圆角矩形的绘制的方法 发布时间:2020-10-04 18:20:31 来源:脚本之家 阅读:103 作者:清夜 微信小程序允许对普通元素通过 border-radius 的 ...

  3. 小猿圈web前端简述canvas如何实现二维码和图片合成

    你经常看到活动海报什么的,上都是有各种宣传文案以及二维码形成的,你知道怎么用canvas实现二维码和图片合成,下面小猿圈Linux讲师为你详细介绍一下canvas如何实现二维码和图片合成的. 使用ur ...

  4. VC++图片框控件静态和动态加载位图

    win10,vc6:新建一个对话框工程:右击资源文件夹,插入...: 类型,Bitmap:引入:选择一个bmp图片: 插入后如下:自动给了一个id: 图片框属性:类型,下拉选中 位图: 图像属性,选中 ...

  5. css 剪辑图片_CSS clip:rect 矩形剪裁功能,截取图片某一块

    CSS clip:rect 矩形剪裁功能,截取图片某一块 2016-12-14 10:43 4715 最近我在制作一款主题的时候,在自适应css设计中,为了调整图片大小,又不愿意改变图片比例的情况下, ...

  6. android之canvas绘制矩形

    需求:想实现使用canvas绘制矩形 实现如下: @SuppressLint("AppCompatCustomView") public class MyImageView ext ...

  7. 文本框插入表情和图片

    <span style="font-size:18px;"><html><title>文本框插入表情和图片</title><s ...

  8. java word文本框_Java 读取Word文本框中的文本、图片、表格

    Word可插入文本框,文本框中可嵌入文本.图片.表格等内容.对文档中的已有文本框,也可以读取其中的内容.本文以Java程序代码来展示如何读取文本框,包括读取文本框中的文本.图片以及表格等. [程序环境 ...

  9. 用易语言制作一款图文展示软件,点击按钮切换图片和文字说明,易语言按钮、图片框、编辑框的应用

    在如今这个商业社会,产品宣传至关重要,尤其是向目标客户发送产品相册,非常有利于促进更多商品的交易.用易语言制作一款图文同时展示的小软件,通过网络发送给客户,客户很方便了解产品详情,从而提升客户体验.此 ...

最新文章

  1. MySQL 调优/优化的 101 个建议
  2. 【渝粤教育】国家开放大学2018年秋季 2322T物流信息技术 参考试题
  3. vs2010中引入boost库
  4. 年度总结 是不公平和智障的产物
  5. js实现搜索框智能提示上下移动效果
  6. Ubuntu安装完后设置root密码-转
  7. python怎么读-Python怎么读?为什么叫Python?
  8. centos7安装图形界面
  9. mPush实战笔记4安装mpush
  10. 闪迪MicroSD卡无法格式化修复经验(不一定管用)
  11. 使用gimp批量处理图片
  12. [报错]CXF动态客户端报错:No operation was found with the name
  13. 解决戴尔电脑耳机插入后无效,外放正常的问题
  14. 小程序IOS安全区域优化:safe-area-inset-bottom
  15. mysql 横向分表_mysql横向和纵向的数据库分表
  16. 开源Linux面板-1Panel
  17. Ant是什么 使用 介绍
  18. sklearn sklearn中KFold()的具体用法
  19. 浏览器数据库IndexedDB
  20. Android模仿淘宝详情页界面

热门文章

  1. Opcode 缓存介绍以及使用 Opcache
  2. 北京中医药 计算机基础,北京中医药大学远程教育学院计算机基础2008辅导资料.doc...
  3. lisp边长注记_小程序cad批量注记建筑物边长
  4. 穿山甲 groMore 配置广告位 穿山甲/优良汇
  5. 华硕 ASUS D540MC 台式计算机,华硕商用D540MC台式电脑增强校园硬实力
  6. 自动生成_一键自动生成CAD图纸目录
  7. matlab去除摩尔纹,索尼ILCE-7RM2测评——理论画质篇
  8. 关于孔明先生职称申请报告的回函
  9. CSS3开启硬件加速及利弊
  10. 如何使用docker和docker-compose在本地Testnet上开发EOS区块链