vue2 Canvas 多边形区域绘制组件封装

效果预览:

CanvasBox组件

<!-- 区域设置canvas -->
<template><div class="all" ref="divideBox"><!-- <div><button @click="test">清空</button></div> --><img id="img" v-if="imgUrl" :src="imgUrl"><!-- width="700" height="450" --><canvas id="mycanvas" ref="mycanvas" :width="canvasWidth" :height="canvasHeight" @mousedown="canvasDown($event)"@mousemove="canvasMove($event)" @mouseup="canvasUp($event)" @dblclick="doubleclick()">浏览器不支持canvas</canvas></div>
</template><script>
export default {props: {// canvas宽度canvasWidth: {type: Number,default: 0},// canvas高度canvasHeight: {type: Number,default: 0},// 时间戳timeStamp: {type: Number,default: 0},// 图片imgUrl: {type: String,default: ""},// 是否可编辑 detail 不可编辑type: {type: String,default: ""},// 多边形区域aiDataRegionalInfoList: {type: Array,default: []},// 摄像头id// cameraId: {//     default: null// }},watch: {// 清空画布timeStamp() {this.test();},// 接收到多边形区域数据aiDataRegionalInfoList(val) {// console.log("接收到多边形区域数据", val);let newArray = []if (val && val.length > 0) {val.forEach(item => {newArray.push({"cor_x": item.x,"cor_y": item.y})})}if (newArray && newArray.length === 0) return;this.drawPolygon(newArray)// this.draw(val); // this.drawPolygon([//     {//         "cor_x": 443,//         "cor_y": 223//     },//     {//         "cor_x": 672,//         "cor_y": 197//     },//     {//         "cor_x": 562,//         "cor_y": 368//     }// ])}},data() {return {isMultiple: false, // 是否支持多个多边形绘制observer: null,x: null,y: null,isdraw: false, //是否在画图形ctx: null, //canvas对象coordinates: [], //一个多边形的坐标信息 cor_index: 0, //当前多边形的索引endtip: false, //是否结束一个多边形的绘制all_coordinates: [], //所有多边形的信息isdrag: false, //是否正在拖动drag_index: [-1, -1], //当前拖动的多边形坐标}},mounted() {// 监听画布尺寸变化// this.initObserver();setTimeout(() => {//初始化画布对象this.initDraw()}, 500)},// beforeDestroy() {//     // 销毁监听器//     this.cleanupObserver();// },methods: {// 初始化监听器// initObserver() {//     this.observer = new MutationObserver(mutations => {//         mutations.forEach(mutation => {//             if (mutation.type === 'attributes' && mutation.attributeName === 'style') {//                 this.handleResize();//             }//         });//     });//     this.observer.observe(this.$refs.divideBox, { attributes: true });//     this.handleResize(); // 初始化时也调用一次// },// 销毁监听器// cleanupObserver() {//     if (this.observer) {//         this.observer.disconnect();//     }// },// 监听到尺寸变化// handleResize() {//     const divideBox = this.$refs.divideBox;//     const canvas = this.$refs.myCanvas;//     if (divideBox && canvas) {//         const newWidth = divideBox.clientWidth;//         const newHeight = divideBox.clientHeight;//         // console.log('Divide box width:', newWidth);//         // console.log('Divide box height:', newHeight);//         // 更新 canvas 的尺寸//         canvas.width = newWidth;//         canvas.height = newHeight;//         // 进行其他初始化操作//     } else {//         console.error('未找到分割框或画布元素');//     }// },// 监听到尺寸变化// updateBoxWidth(width) {//     let widthVal = width//     let heightVal = width / 1920 * 1080//     // console.log("width", widthVal)//     // console.log("height", heightVal) //     let pointList = JSON.parse(JSON.stringify(this.oldPointList))//     pointList.forEach(item => {//         item.x = item.x / 1920 * widthVal//         item.y = item.y / 1080 * heightVal//         item.type = item.type//         item.isShow = item.isShow//     })//     this.pointList = pointList//     // console.log("更新位置", this.pointList); // },// updateCanvasSize() {//     const canvas = this.$refs.mycanvas;//     this.canvasWidth = canvas.clientWidth;//     this.canvasHeight = canvas.clientHeight;// },// 清空画布test() {this.all_coordinates = [];this.coordinates = [];this.isdraw = false;this.endtip = false;// this.ctx.clearRect(0, 0, 700, 450);this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);},// 填充区域fillarea() {this.ctx.fillStyle = 'rgba(255, 255, 0,0.4)';for (let i = 0; i < this.all_coordinates.length; i++) {let cors = this.all_coordinates[i];let x0 = cors[0].cor_x;let y0 = cors[0].cor_y;this.ctx.beginPath();this.ctx.moveTo(x0, y0);for (let j = 1; j < cors.length; j++) {let x = cors[j].cor_x;let y = cors[j].cor_y;this.ctx.lineTo(x, y);}this.ctx.fill();this.ctx.closePath();}},//初始化画布对象initDraw() {const canvas = document.querySelector("#mycanvas");this.ctx = canvas.getContext("2d");// this.ctx.strokeStyle = 'rgb(255, 255, 0)';this.ctx.strokeStyle = 'yellow';},// 判断是否是拖拽点isdragpoint(x, y) {if (this.all_coordinates.length == 0) {return false;}for (let i = 0; i < this.all_coordinates.length; i++) {for (let j = 0; j < this.all_coordinates[i].length; j++) {let px = this.all_coordinates[i][j].cor_x;let py = this.all_coordinates[i][j].cor_y;if (Math.abs(x - px) <= 5 && Math.abs(y - py) <= 5) {this.drag_index[0] = i;this.drag_index[1] = j;return true;}}}return false;},// 画布中鼠标按下canvasDown(e) {if (this.type === 'detail') return;// console.log(123, e.offsetX, e.offsetY);// const cameraId = this.cameraId// if (cameraId == "" || cameraId == undefined || cameraId == null) {//     this.$message({//         message: '请先选择摄像头',//         type: 'warning'//     });//     return;// }// console.log("鼠标按下", this.coordinates);// console.log("鼠标按下", this.all_coordinates);let x = e.offsetX;let y = e.offsetY;if (this.isdragpoint(x, y)) {this.isdrag = true;return 0;}//画布中鼠标按下if (this.endtip) {//已经结束了上个多边形的绘制,把上个多边形的坐标放入数组,同时清空单个多边形数组信息this.endtip = false;}if (this.all_coordinates && this.all_coordinates.length == 1) {this.$message({message: '最多只能绘制一个区域',type: 'warning'});this.coordinates = []return;}//获取鼠标按下的坐标,放入数组中this.coordinates.push({ cor_x: x, cor_y: y });this.isdraw = true; //正在画多边形},// 画布中鼠标移动drawlines() {//把所有多边形画出来for (let i = 0; i < this.all_coordinates.length; i++) {let cors = this.all_coordinates[i];//前后坐标连线for (let j = 0; j < cors.length - 1; j++) {this.ctx.beginPath();let x0 = cors[j].cor_x;let y0 = cors[j].cor_y;let x1 = cors[j + 1].cor_x;let y1 = cors[j + 1].cor_y;this.ctx.moveTo(x0, y0);this.ctx.lineTo(x1, y1);this.ctx.stroke();this.ctx.closePath();}//最后一个与第一个连线let begin_x = cors[0].cor_x;let begin_y = cors[0].cor_y;let end_x = cors[cors.length - 1].cor_x;let end_y = cors[cors.length - 1].cor_y;this.ctx.beginPath();this.ctx.moveTo(begin_x, begin_y);this.ctx.lineTo(end_x, end_y);this.ctx.stroke();this.ctx.closePath();}},//把当前绘制的多边形之前的坐标线段绘制出来drawline() {for (let i = 0; i < this.coordinates.length - 1; i++) {this.ctx.beginPath();let x0 = this.coordinates[i].cor_x;let y0 = this.coordinates[i].cor_y;let x1 = this.coordinates[i + 1].cor_x;let y1 = this.coordinates[i + 1].cor_y;this.ctx.moveTo(x0, y0);this.ctx.lineTo(x1, y1);this.ctx.stroke();this.ctx.closePath();}},// 针对的是单个多边形的所有顶点drawcircle() {//为当前的多边形端点画圆this.ctx.fillStyle = 'rgb(255, 255, 0)';for (let i = 0; i < this.coordinates.length; i++) {let x = this.coordinates[i].cor_x;let y = this.coordinates[i].cor_y;this.ctx.beginPath();this.ctx.moveTo(x, y);this.ctx.arc(x, y, 5, 0, Math.PI * 2);this.ctx.fill();this.ctx.closePath();}},// 用来在画布上标示出每个多边形顶点的位置,并且为这些顶点画出小圆圈drawcircles() {//为所有的多边形端点画圆this.ctx.fillStyle = 'rgb(255, 255, 0)';for (let i = 0; i < this.all_coordinates.length; i++) {let cors = this.all_coordinates[i];for (let j = 0; j < cors.length; j++) {let x = cors[j].cor_x;let y = cors[j].cor_y;this.ctx.beginPath();this.ctx.moveTo(x, y);this.ctx.arc(x, y, 5, 0, Math.PI * 2);this.ctx.fill();this.ctx.closePath();}}},// 画布中鼠标抬起canvasUp(e) {if (this.isdrag) {this.isdrag = false;// 打印所有多边形的顶点坐标this.all_coordinates.forEach((polygon, index) => {// console.log(`多边形 ${index + 1} 的顶点坐标:`);polygon.forEach((vertex, vertexIndex) => {// console.log(`  顶点 ${vertexIndex + 1}: (${vertex.cor_x}, ${vertex.cor_y})`);});});// console.log("拖拽点后抬起", this.all_coordinates);this.$emit("all_coordinates", this.all_coordinates[0]);}this.drag_index = [-1, -1];// this.drag_index = [e.layerX, e.layerY];// console.log("鼠标抬起", e);},// 画布中点击后线条鼠标移动中canvasMove(e) {//画布中鼠标移动//没开始画或者结束画之后不进行操作let x = e.offsetX;let y = e.offsetY;if (this.isdrag) {this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);// this.ctx.clearRect(0, 0, 700, 450);this.all_coordinates[this.drag_index[0]][this.drag_index[1]].cor_x = x;this.all_coordinates[this.drag_index[0]][this.drag_index[1]].cor_y = y;this.drawlines();this.drawcircles();this.fillarea();}if (this.coordinates.length == 0 || !this.isdraw || this.endtip) {return 0;}//获取上一个点let last_x = this.coordinates[this.coordinates.length - 1].cor_x;let last_y = this.coordinates[this.coordinates.length - 1].cor_y;// this.ctx.clearRect(0, 0, 700, 450); //清空画布this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);this.drawline();//把之前的点连线this.drawcircle();// 如果不止一个多边形,把多边形们画出来if (this.all_coordinates.length != 0) {this.drawlines();this.drawcircles();this.fillarea();}//获取鼠标移动时的点,画线,实现线段跟踪效果。this.ctx.beginPath();this.ctx.moveTo(last_x, last_y);this.ctx.lineTo(x, y);this.ctx.strokeStyle = 'yellow';this.ctx.stroke();this.ctx.closePath();},// 双击画布结束连线doubleclick() {if (this.type === 'detail') return;//双击画布,在最后一个点的时候双击,自动连线第一个点,同时宣告画结束let x0 = this.coordinates[0].cor_x;let y0 = this.coordinates[0].cor_y;let x1 = this.coordinates[this.coordinates.length - 1].cor_x;let y1 = this.coordinates[this.coordinates.length - 1].cor_y;this.ctx.beginPath();this.ctx.moveTo(x0, y0);this.ctx.lineTo(x1, y1);this.ctx.stroke();this.ctx.closePath();this.isdraw = false;this.endtip = truethis.drawcircle();this.coordinates.pop();this.all_coordinates.push(this.coordinates);this.ctx.fillStyle = 'rgba(255, 255, 0, 0.4)';let bx = this.coordinates[0].cor_x;let by = this.coordinates[0].cor_y;this.ctx.beginPath();this.ctx.moveTo(bx, by);for (let k = 1; k < this.coordinates.length; k++) {let x = this.coordinates[k].cor_x;let y = this.coordinates[k].cor_y;this.ctx.lineTo(x, y)}this.ctx.fill();this.ctx.closePath();// console.log("绘制完毕获得数据", this.coordinates)// console.log("绘制完毕获得全部数据", this.all_coordinates)this.$emit("all_coordinates", this.all_coordinates[0]);// console.log(666, this.all_coordinates[0]);this.coordinates = [];},// 接收多边形数据并绘制// receivePolygonData(polygonData) {//     if (Array.isArray(polygonData)) {//         // 清空画布//         this.test();//         // 绘制每个多边形//         polygonData.forEach(cors => {//             console.log(111, cors); //             this.drawPolygon(cors);//         });//     }// },// 在画布中绘制多边形并添加可拖拽的顶点drawPolygon(coordinates) {// 清空画布this.test();if (coordinates.length >= 2) {this.ctx.beginPath();let x0 = coordinates[0].cor_x;let y0 = coordinates[0].cor_y;this.ctx.moveTo(x0, y0);// 绘制多边形的边for (let j = 1; j < coordinates.length; j++) {let x = coordinates[j].cor_x;let y = coordinates[j].cor_y;this.ctx.lineTo(x, y);}// 最后一个点回到第一个点闭合多边形this.ctx.lineTo(x0, y0);this.ctx.closePath();this.ctx.stroke();// 填充多边形this.ctx.fillStyle = 'rgba(255, 255, 0, 0.4)';this.ctx.fill();// 绘制多边形顶点的小圆圈if (this.type != "detail") {this.ctx.fillStyle = 'rgb(255, 255, 0)';for (let j = 0; j < coordinates.length; j++) {let x = coordinates[j].cor_x;let y = coordinates[j].cor_y;this.ctx.beginPath();this.ctx.arc(x, y, 5, 0, Math.PI * 2);this.ctx.fill();this.ctx.closePath();}// 打印所有顶点的坐标// console.log('绘制完成的多边形顶点坐标:', coordinates);this.$emit("all_coordinates", coordinates);}let newArray = []newArray.push(coordinates)this.all_coordinates = newArray// console.log(666, this.all_coordinates, newArray);}}},
};
</script><style lang="scss" scoped>
.all {position: relative;width: 100%;height: 100%;// border: 2px solid red;border: 1px solid yellow;
}#mycanvas {// border: 1px solid red;// width: 100%;// height: 100%;// width: 700px;// height: 45px;position: absolute;top: 0;bottom: 0;left: 0;right: 0;// border: 2px solid red;
}#img {width: 100%;height: 100%;user-select: none;
}
</style>
<CanvasBox v-if="canvasIsShow" :imgUrl="imgUrl" :aiDataRegionalInfoList="aiDataRegionalInfoList":canvasWidth="canvasWidth" :canvasHeight="canvasHeight" :timeStamp="timeStamp"@all_coordinates="getCoordinates" :type="type" />
      // 默认隐藏canvascanvasIsShow: false,// 子组件背景图片imgUrl: "",// 子组件多边形区域aiDataRegionalInfoList: [],// 子组件canvas宽度canvasWidth: 0,// 子组件canvas高度canvasHeight: 0,timeStamp: 0,// 记录新增->add  修改->edit  查看->detailtype: "",// 接收到绘制后多边形数据getCoordinates(val) {// console.log("接收到canvas区域数据", val);let newArray = []if (val && val.length > 0) {val.forEach(item => {newArray.push({x: this.autoPageSizeToDefault(item.cor_x, item.cor_y).x,y: this.autoPageSizeToDefault(item.cor_x, item.cor_y).y,})})}this.form.aiDataRegionalInfoList = newArray},// 清空画布clearCanvas() {this.timeStamp = Date.now();this.aiDataRegionalInfoList = []this.form.aiDataRegionalInfoList = []},

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/56792.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu中MySQL远程登录设置

mysql单独放在一台Ubuntu服务器上&#xff0c;我远程连接不上。可能是安装的时候忘记设置远程登录了。事后补救措施如下&#xff1a; MySQL 绑定地址配置问题 MySQL 可能只绑定了 localhost&#xff0c;无法接受来自外部主机的连接。你需要检查 MySQL 的配置文件 /etc/mysql/…

使用Vscode配置ftp连接远程服务器(上传本地文件)

1.安装插件 扩展商店搜sftp,点击进行安装。 2.配置json文件 crtl+shift+p 输入ftp配置命令 sftp:config {"name": "My Server", //设置名字"host": "localhost"</

腐蚀膨胀预处理

腐蚀&#xff1a;通过减少前景对象&#xff08;例如白色字符&#xff09;的边缘&#xff0c;腐蚀可以用来减小或消除细小的干扰线。如果干扰线较细&#xff0c;腐蚀可以有效地“消除”这些线条&#xff0c;同时保留较粗的字符。 膨胀&#xff1a;在腐蚀之后&#xff0c;膨胀可…

TCP——Socket

应用进程只借助Socket API发和收但是不关心他是怎么进行传和收的 数据结构 图示Socket连接 捆绑属于隐式捆绑

数据驱动时代:五款免费报表工具深度解析

在当今数据驱动的时代&#xff0c;报表工具已经成为各类企业进行决策和管理的重要工具。无论是大中型企业还是小微企业&#xff0c;能够快速、高效地生成可视化报表&#xff0c;洞察业务运营情况&#xff0c;已经成为提升竞争力的关键。今天为大家挑选了5款非常优秀的报表软件&…

Autosar软件组件概述

AUTOSAR中的应用软件设计为独立的软件单元&#xff0c;即软件组件类型&#xff08;SwComponentTypes&#xff09;&#xff0c;封装了相关功能和行为的实现&#xff0c;并通过端口原型&#xff08;PortPrototypes&#xff09;&#xff0c;向外部暴露自己。 AUTOSAR 标准应用了设…

std::setw中文不能对齐的问题

从别的博主那 copy过来 记录下 #include <codecvt> #include <locale>class chs_codecvt : public std::codecvt_byname<wchar_t, char, std::mbstate_t> {public:chs_codecvt() : codecvt_byname("zh_CN.GBK") {} };int encoding_diff(string …

xtu oj 原根

文章目录 回顾杂思路c 语言代码 回顾 AB III问题 H: 三角数问题 G: 3个数等式 数组下标查询&#xff0c;降低时间复杂度1405 问题 E: 世界杯xtu 数码串xtu oj 神经网络xtu oj 1167 逆序数&#xff08;大数据&#xff09; 杂 有一些题可能是往年的程设的题&#xff0c;现在搬到…

Higress 重磅更新:AI 能力全面开源,云原生能力再升级

作者&#xff1a;澄潭、钰诚 新版本简介 Higress 最新的 1.4 版本基于为通义千问&#xff0c;以及多家云上 AGI 厂商客户提供 AI 网关的积累沉淀&#xff0c;开源了大量 AI 原生的网关能力。同时也在 Ingress、可观测、流控等云原生能力上做了全方位升级&#xff1a; AI 能力…

VS code部署Vue项目Demo

在之前已经在IDEA中部署过vue项目demo。本次在上次基础上进行。 IDEA中Vue的安装和使用【window10】_idea安装vue-CSDN博客 步骤一、安装VSCode 双击安装即可 步骤二&#xff1a;检查npm是否安装 步骤三&#xff1a;检查vue是否安装 &#xff08;vue create 项目名 只要在v…

Leetcode 单词规律

即判断给定的模式字符串&#xff08;pattern&#xff09;和单词字符串&#xff08;s&#xff09;是否遵循相同的对应规则。具体来说&#xff0c;就是要判断 pattern 中的字符与 s 中的单词是否存在一一对应的关系&#xff0c;即双射&#xff08;bijection&#xff09;。 算法思…

【解决办法】git clone报错unable to access ‘xxx‘: SSL certificate problem

git clone 是 Git 版本控制系统中的一个基本命令&#xff0c;用于从远程仓库复制一个完整的版本库到本地。这个命令不仅复制远程仓库中的所有文件&#xff0c;还复制仓库的历史记录&#xff0c;使得你可以在本地进行版本控制操作&#xff0c;如提交&#xff08;commit&#xff…

Electron+Vue实现两种方式的截屏功能

本次介绍的截屏功能一共有两种分别是在electron环境中与非electron环境中 非electron环境 这个环境下会有一些限制&#xff1a; 1.只能截浏览器中的画面 2.如果里面有iframe或者base64的图片会加载不出来&#xff08;这个会有解决办法&#xff09; yarn add -D js-web-scree…

Java爬虫:获取商品评论数据的高效工具

在电子商务的激烈竞争中&#xff0c;商品评论作为消费者购买决策的重要参考&#xff0c;对于商家来说具有极高的价值。它不仅能够帮助商家了解消费者的需求和反馈&#xff0c;还能作为改进产品和服务的依据。Java爬虫技术&#xff0c;以其稳健性和高效性&#xff0c;成为了获取…

基于Spring Cloud的电商系统设计与实现——用户与商品模块的研究(上)

操作系统&#xff1a;Windows Java开发包&#xff1a;JDK1.8 项目管理工具&#xff1a;Maven3.6.0 项目开发工具&#xff1a;IntelliJIDEA 数据库&#xff1a;MySQL Spring Cloud版本&#xff1a;Finchley.SR2 Spring Boot版本&#xff1a;2.0.6.RELEASE 目录 用户模块—user-…

YOLO系列入门:1、YOLO V11环境搭建

YOLO了解 yolo检测原理 yolo是目标检测模型&#xff0c;目标检测包含物体分类、位置预测两个内容。目前yolo的开发公司官网为&#xff1a;https://docs.ultralytics.com/zh截止到目前2024年10月&#xff0c;最新的是yolo11。关于YOLO的介绍可以参考这篇文章&#xff1a;https…

[Javase]封装、继承、多态与异常处理

文章目录 一、前言二、封装1、封装的思想2、封装代码层面的体现 三、继承1、继承的概念和好处2、继承代码层面的体现 四、多态1、多态的概念2、多态的好处和三要素2、多态代码层面的体现 五、异常处理1、try-catch-finally结构详解2、throw\throws 一、前言 本文章适合有一定面…

10.15.2024刷华为OD C题型(二)

10.15.2024刷华为OD C题型&#xff08;二&#xff09; 密码输入检测智能成绩表 如果是目标院校150分能过&#xff0c;而且这道题是两百分的话我就阿弥陀佛了。 这类简单类型的字符串处理题目一看就有思路&#xff0c;起码能做&#xff0c;遇到那种稍微加点数学的&#xff0c;感…

【从零开始的LeetCode-算法】3099. 哈沙德数

如果一个整数能够被其各个数位上的数字之和整除&#xff0c;则称之为 哈沙德数&#xff08;Harshad number&#xff09;。给你一个整数 x 。如果 x 是 哈沙德数 &#xff0c;则返回 x 各个数位上的数字之和&#xff0c;否则&#xff0c;返回 -1 。 示例 1&#xff1a; 输入&am…

MySQL增删改进阶

目录 1.数据库约束 1.1约束类型 1.2 not null约束 1.3 unique&#xff1a;唯一约束 1.4 default&#xff1a;默认约束 1.5 primary key&#xff1a;主键约束 1.6 foreign key:外键约束 1.7 check约束&#xff08;了解&#xff09; 2.表的设计 3.新增&#xff08;进阶&…