场景: 已知四个点,画出矩形,并且计算出每个中垂线,并加箭头,标识符,点击四个顶点还能拖拽进行变动。

.vue

<!-- canvas -->
<template><div class="content"><div class="name-content" @click="clickName">设备一</div><!-- 背景图 --><img v-if="bgImg" :src="bgImg" alt="" class="img"><div v-else class="empty-img">暂无抓拍图片,请重新抓拍</div><!-- 画布 --><canvas ref="myCanvas" class="canvas" :width="swidth" :height="sheight"></canvas></div>
</template><script>
import {isPointInPath, calcMidLine, judgeIntersect} from './canvas.js';export default {props: {},data() {return {bgImg: 'http://snapshot/2ca59c085bf8.jpg',   //抓拍的图片(假得!)canvas: null, //canvas对象position: [],  //四边形四个点的坐标midPosition: [],  //中垂线坐标imgData: null,  //缓存四边形hasPoint: false,  //是否已经绘制了四个顶点isDragging: false,  //能否拖拽isDrawing: false,  //是否正在绘制isMoving: false,   //是否可一动四边形selectIdx: -1,  //当前选中的顶点下标point: [],  //点击四边形内部当下的点坐标swidth: 960,sheight: 540};},watch: {},mounted() {this.canvas = this.$refs.myCanvas;this.initData();this.bindEvent();},methods: {clickName() {console.log("this.position",this.position);     //拖拽以后四个顶点的坐标位置},initData() {this.getImg();this.getPc6Configuration();},/**获取抓拍图片 */getImg() {},/**获取pc6数据 */getPc6Configuration() {const arr = [{x:0.25,y:0.25},{x:0.75,y:0.25},{x:0.75,y:0.75},{x:0.25,y:0.75}];if(arr.length === 4) {this.position = arr.map(p => [p.x * this.swidth, p.y * this.sheight]);this.initDraw();}},/**初始化四边形 */initDraw(type = "",position = []) {if(type !== "draw") {position = this.position;}const ctx = this.canvas.getContext('2d');ctx.strokeStyle = "#FF0000";  //设置线颜色ctx.beginPath();  //开始路径绘制ctx.lineWidth = 3;position.forEach((p,idx)=> {if(idx === 0) {ctx.moveTo(...p);} else {ctx.lineTo(...p);}});ctx.closePath();ctx.stroke();  //进行线的着色,这时整条线才变得可见if(this.position.length < 4) {return ;}this.drawMidLine();this.imgData = ctx.getImageData(0,0,this.swidth,this.sheight);  //复制画布上指定矩形的像素数据,然后通过 putImageData() 将图像数据放回画布:======图片大小 960*540type === "drag" && this.drawPoint();},/**绘制中垂线 */drawMidLine() {this.position.forEach((p, idx) => {const mid = idx === 3 ? calcMidLine(p, this.position[0],this.position) : calcMidLine(p,this.position[idx+1],this.position);const ctx = this.canvas.getContext("2d");const headlen = 6;  //自定义箭头线的长度const theta = 45;  //自定义箭头线与直线的夹角,(45度数刚好)let arrowX,arrowY;  //箭头线终点坐标// 计算各角度和对应的箭头终点坐标const angle =(Math.atan2(mid[0][1] - mid[1][1], mid[0][0] - mid[1][0]) * 180) /Math.PI;   //返回从原点(0,0)到(x,y)点的线段与x轴正方向之间的平面角度(弧度值)const angle1 = ((angle + theta) * Math.PI) / 180;const angle2 = ((angle - theta) * Math.PI) / 180;const topX = headlen * Math.cos(angle1);const topY = headlen * Math.sin(angle1);const botX = headlen * Math.cos(angle2);const botY = headlen * Math.sin(angle2);ctx.beginPath();ctx.lineWidth = 3;ctx.strokeStyle = '#ffa51c';//画直线ctx.moveTo(...mid[0]);ctx.lineTo(...mid[1]);arrowX = mid[1][0] + topX;arrowY = mid[1][1] + topY;//画上边箭头线ctx.moveTo(arrowX,arrowY);ctx.lineTo(mid[1][0],mid[1][1]);arrowX = mid[1][0] + botX;arrowY = mid[1][1] + botY;//画下边箭头线ctx.lineTo(arrowX, arrowY);ctx.closePath();ctx.fillStyle = "#ffa51c";ctx.fill();//绘制文字const char = String.fromCharCode(65 + idx);  //将 Unicode 编码转为一个字符ctx.font = "16px Georgia";const xm = (mid[0][0] + mid[1][0]) / 2;const ym = (mid[0][1] + mid[1][1]) / 2;ctx.fillText(char, xm, ym);ctx.stroke();this.midPosition[idx] = [...mid, [xm, ym], [char]];});// console.log("this.midPosition",this.midPosition)},/**绘制四个顶点 */drawPoint() {this.hasPoint = true;const ctx = this.canvas.getContext("2d");this.position.forEach(p => {ctx.beginPath();ctx.lineWidth = 4;ctx.strokeStyle = "#FF0000";ctx.arc(...p, 4, 0, 2*Math.PI);ctx.fillStyle = '#FF0000';ctx.fill();ctx.stroke();});},/**监听鼠标事件 */bindEvent() {this.handleMouseUp();this.handleMouseDown();this.handleMouseMove();},/**停止拖拽 */handleMouseUp() {console.log("handleMouseUp-handleMouseUp-handleMouseUp");let _this = this;this.canvas.onmouseup = function() {_this.isDragging = false;_this.isMoving = false;};this.canvas.onmouseout = function() {_this.isDragging = false;_this.isMoving = false;}},/**鼠标按下事件 */handleMouseDown() {let _this = this;this.canvas.onmousedown = function(e) {e = e || event;const x = e.offsetX;const y = e.offsetY;//绘制图像if(_this.isDrawing) {  //有个按钮--绘制区域(未使用到)--有个一键清空canvas的效果_this.position.push([x,y]);_this.clearCanvas();_this.initDraw();if(_this.position.length === 4) {_this.isDrawing = false;}} else {if(_this.position.length === 0) {return ;}//判断点击的是哪个点_this.position.forEach((p,idx) => {var line = Math.abs(Math.sqrt(Math.pow(p[0] - x,2) + Math.pow(p[1] - y,2)));  //函数返回一个数的平方根if(line - 8 < 0) {_this.isDragging = true;_this.selectIdx = idx;}});//判断是否点击了四边形内部if(isPointInPath(x, y, _this.position)) {!_this.hasPoint && _this.drawPoint();if(!_this.isDragging) {_this.isMoving = true;_this.point = [x, y];}} else if(_this.hasPoint && !isPointInPath(x ,y, _this.position)) {_this.clearCanvas("cache");_this.hasPoint = false;}}}},/**拖拽重新绘制 */handleMouseMove() {let _this = this;this.canvas.onmousemove = function(e) {e = e || event;const x = e.offsetX;const y = e.offsetY;//手动绘制if(_this.isDrawing && _this.position.length > 0) {_this.clearCanvas();_this.initDraw("draw",_this.position.concat([[x,y]]));}//判断是否可以拖动顶点if(_this.isDragging) {_this.position[_this.selectIdx] = [x, y];_this.clearCanvas("drag");_this.initDraw("drag");}//移动整个四边形if(_this.isMoving) {_this.position.forEach(p => {p[0] += x - _this.point[0];p[1] += y - _this.point[1];});_this.position = [x, y];_this.clearCanvas();_this.initDraw("drag");}}},/**清空画布 */clearCanvas(type) {const ctx = this.canvas.getContext("2d");ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);type === "cache" && ctx.putImageData(this.imgData, 0, 0);if(type === "rest") {this.position = [];}}},
};
</script><style lang="scss" scoped>
.content {position: relative;
}
.name-content {height: 20px;
}
.img {width: 960px;height: 540px;
}
.empty-img {width: 960px;height: 540px;text-align: center;line-height: 540px;float: left;
}
.canvas {position: absolute;top: 20px;left: 0;
}
</style>

.config.js

// 判断点是否在四边形内
export const isPointInPath = function (testx, testy, position) {let i = 0,j = 0,c = false;const nvert = 4;const vertx = position.map(p => p[0]);const verty = position.map(p => p[1]);for (i = 0, j = nvert - 1; i < nvert; j = i++) {if (verty[i] > testy != verty[j] > testy &&testx <((vertx[j] - vertx[i]) * (testy - verty[i])) / (verty[j] - verty[i]) +vertx[i]) {c = !c;}}return c;
};// 中垂线长度
const LINE = 30;// 计算中垂线的两个点坐标
export const calcMidLine = function (p1, p2, position) {   //两两的点 (连成一条线),并把四个点传过来// console.log("calcMidLine---p1, p2, position",p1, p2, position);let xm = (p1[0] + p2[0]) / 4;if(p2[0] - 2 * xm === 0) {   p1 = [p1[0] -1,p1[1]-1];xm = (p1[0] + p2[0]) / 4;}const ym = (p1[1] + p2[1]) / 4;const e =(4 * xm * xm + 4 * ym * ym - 2 * p2[0] * xm - 2 * ym * p2[1]) /(p2[0] - 2 * xm);const d = (2 * ym - p2[1]) / (p2[0] - 2 * xm);const a = d * d + 1;const b = 2 * d * (e + 2 * xm) + 4 * ym;const c = LINE * LINE - 4 * ym * ym - (e + 2 * xm) * (e + 2 * xm);const y1 = (b + Math.sqrt(b * b + 4 * a * c)) / 2 / a;const x1 = y1 * d - e;const y2 = (b - Math.sqrt(b * b + 4 * a * c)) / 2 / a;const x2 = y2 * d - e;const x = xm + (xm + (xm + (xm + x1 / 2) / 2) / 2) / 2;const y = ym + (ym + (ym + (ym + y1 / 2) / 2) / 2) / 2;const inner = isPointInPath(x, y, position);const point = inner? [[x1, y1],[x2, y2]]: [[x2, y2],[x1, y1]];return point;
};//判断两条线段是否相交
export const judgeIntersect = function (x1, y1, x2, y2, x3, y3, x4, y4) {if (!(Math.min(x1, x2) <= Math.max(x3, x4) &&Math.min(y3, y4) <= Math.max(y1, y2) &&Math.min(x3, x4) <= Math.max(x1, x2) &&Math.min(y1, y2) <= Math.max(y3, y4))) {return false;}const u = (x3 - x1) * (y2 - y1) - (x2 - x1) * (y3 - y1);const v = (x4 - x1) * (y2 - y1) - (x2 - x1) * (y4 - y1);const w = (x1 - x3) * (y4 - y3) - (x4 - x3) * (y1 - y3);const z = (x2 - x3) * (y4 - y3) - (x4 - x3) * (y2 - y3);return u * v <= 0.00000001 && w * z <= 0.00000001;
};

canvas四个点画矩形,中垂线,以及顶点拖拽相关推荐

  1. canvas在图片上绘制标记,可拖拽、缩放,基于ZRender

    如下图所示,在图片上做标记,如圆形.矩形等. 该demo实现画布在页面布局中缩放后居中显示,可拖拽.缩放.做标记说明. 项目下载地址:https://gitlab.com/zhangcw66/draw ...

  2. js 矩形div鼠标拉扯拖拽

    实现效果图: 鼠标拖拽:                                                                鼠标拉扯:                    ...

  3. python canvas画移动物体_如何实现Canvas图像的拖拽、点击等操作

    上一篇Canvas的博文写完后,有位朋友希望能对Canvas绘制出来的图像进行点击.拖拽等操作,因为Canvas绘制出的图像能很好的美化.好像是想做炉石什么的游戏,我也没玩过. Canvas在我的理解 ...

  4. 求矩形中心点坐标编程c语言,三角函数在图形学里的应用(四) ​已知矩形的中心点、边长、phi求四个顶点的坐标...

    已经矩形的中心点.边长.phi求四个顶点的坐标 在halcon里面,类似gen_measure_rectangle2.smallest_rectangle2的算子表示任意角度的矩形. 其信息包括:矩形 ...

  5. 原生js实现canvas画布中绘制、移动、拖拽、删除矩形(如简易截图工具)

    功能描述 待图片上传并加载完成后,重新生成画布: 鼠标在画布区域内绘制,移动,拖拽,删除矩形(如截图工具一般): isboundary() 判断是否需要判断边界问题,默认false. 效果截图 实现代 ...

  6. 在Canvas中绘制圆角矩形

    问题的提出 要在Canvas中绘制一个矩形,使用strokeRect或fillRect函数即可. var canvas = document.getElementById("canvas&q ...

  7. 手游《奔跑吧?骚年!》技术分享(四):矩形碰撞检测

    手游<奔跑吧?骚年!>技术分享(四):矩形碰撞检测 今天来分享一下游戏中的碰撞处理,基本上横版2D游戏内的物体,都可以用矩形来表示(有时也需要用三角形来检测).通常就判断一下是否碰撞是不够 ...

  8. 利用Canvas制作旋转的矩形

    利用Canvas制作旋转的矩形 HTML5 Canvas API提供了强大的图形绘制功能,包括形状.颜色.线条样式等.在本文中,我将展示如何使用Canvas API创建一个旋转的矩形. 一.HTML结 ...

  9. java使用重绘实现拖动_原生JS使用Canvas实现拖拽式绘图功能

    一.实现的功能 1.基于oop思想构建,支持坐标点.线条(由坐标点组成,包含方向).多边形(由多个坐标点组成).圆形(包含圆心坐标点和半径)等实体 2.原生JavaScript实现,不依赖任何第三方j ...

最新文章

  1. 要做服务和酒店行业的“领英” ,Industry 获得230万美元种子轮融资
  2. 1、Reactive Extensions for .NET(译)
  3. MySQL 数据库命令
  4. python读取txt数据-Python读取txt数据文件,并作图
  5. P2801 教主的魔法
  6. 高斯判别分析(GDA)和朴素贝叶斯(NB)
  7. 信捷步进指令的使用_步进电机驱动器的模式
  8. spring MVC配置form支持PUT和DELETE方法
  9. 信息学奥赛C++语言:摘李子
  10. java IoT物联网server 读取javascript协议配置文件
  11. 5gh掌上云计算认证不通过_阿里云ACE高级工程师认证考试攻略、考试心得、费用及常见问题...
  12. scheme中文编程
  13. apache-cxf测试webservice添加header信息
  14. continue,return,break 在for循环中的作用
  15. unicode编码对照表
  16. PHPstorm设置字体大小
  17. 固态硬盘ssd的寿命如何计算,固态硬盘质量怎么检测?
  18. 04年学计算机,成都电子科大计算机学院04年专业?
  19. 直播预告:如何在“贵系”找到自己的发展方向?| 贵系万花筒
  20. C1——supermap获取对象的中心位置

热门文章

  1. 装了 Linux 之后就感到迷茫、不知该干什么的朋友看过来
  2. 笔记本软件页面分辨率低_笔记本分辨率降低怎么办_笔记本电脑电脑分辨率低怎么解决-win7之家...
  3. 【基于可见光定位的智能超市购物车系统】(一)概览
  4. 【343天】我爱刷题系列102(2018.01.14)
  5. 几个经典app制作网站
  6. SayLove表白墙微信小程序
  7. 2022-08-15
  8. 【大数进制转换】清华大学考研复试上机——进制转换(10—2)
  9. Java实现 LeetCode 309 最佳买卖股票时机含冷冻期
  10. c/c++控制台图片浏览