canvas实现矩形框,用来进行图片框选
生活随笔
收集整理的這篇文章主要介紹了
canvas实现矩形框,用来进行图片框选
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
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="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实现矩形框,用来进行图片框选的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js splice的三个用法
- 下一篇: ps4仁王服务器不稳定,仁王运行流畅图文