【前端】Vue3实现图片标点

前言

公司的业务要求可以在图片的位置上面进行标点,然后在现场对汽车桌椅可以实现按照标点进行质量检测。

技术栈

  • Vue3:https://cn.vuejs.org/index.html
  • Ant Design Vue4.x:https://www.antdv.com/docs/vue/introduce-cn

图像标点

  1. 将画布覆盖在图像上;
  2. 将图像画在画布上;

目前采用的是画布覆盖在图像上,画布覆盖在图像上这种方式也有两种:

  1. 将画布的大小调整为图像渲染的大小;
  2. 将画布分解为颗粒,分散在图像上面;

图像基本概念

图像大小有两个概念:固定尺寸和渲染的大小。
固定尺寸就是图像真实的分辨率大小;
渲染的大小则是图像在网页渲染后的分辨率大小;
因此画布按照图像大小绘制的话,可能存在渲染的大小并非和图像真实的大小相同。
在这里插入图片描述

效果图

在这里插入图片描述

方式一:画布全局覆盖图像

  1. 根据图像大小绘制画布
  2. 监控图像或画布点击
  3. 绘制圆点和序号

1.编写前端显示代码

<div style="position: relative">
    <img id="img-1" src="/Img/image/1530088404487.jpg" @click="handleClickImg1"/>
    <canvas id="canvas-1" style="position: absolute; top: 0; left: 0;" @click="handleClickImg1" />
</div>

这里定义了 handleClickImg1 点击事件是用来记录鼠标在图片点击的坐标,从而在其上面做一些操作,这里分别在图片或画布上面都做点击监控,是因为第一次画布加载渲染的大小和后面展示在页面的大小不一致。

画布使用相对位置布局 position: absolute; 并且配置以图片左上角顶点为原点向右往下绘制画布 top: 0; left: 0;,是为了保证画布与图像完全重叠在一起,从而坐标可以一一对应上。

2.配置基本数据

// 图片基本信息
const image = ref();
const imageWidth = ref(0);
const imageHeight = ref(0);
// 画布
const canvas = ref();
const ctx = ref();
// 记录点击点
const proQualityList1 = ref([]);

定义一些参数来接受或后续使用,详情请看代码注释。

3.根据图像渲染大小绘制画布

/**
 * 根据图像大小绘制画布
 */
async function drawImageToCanvas() {
    // 获取图片元素
    image.value = document.getElementById('img-1');
    // 获取图片在页面渲染的大小
    imageWidth.value = image.value.clientWidth;
    imageHeight.value = image.value.clientHeight;
    // 获取画布元素
    canvas.value = document.getElementById('canvas-1');
    // 设置画布的大小于图片渲染大小一致
    canvas.value.width = imageWidth.value;
    canvas.value.height = imageHeight.value;
    // 获取二维画布
    ctx.value = canvas.value.getContext("2d");
}

**Tip:**个人喜好把独立函数定义为异步,异步函数调试可能会进不了断点。

drawImageToCanvas 异步函数主要是用来获取页面渲染的图片,并将图片渲染的大小获取到,将其值赋值给画布的宽高,从而把画布与图片的大小一致,从而进行绘画。

4.在画布绘圆

/**
 * 在画布绘制圆点
 */
const drawOriginPoint = (x, y, color) => {
    const radius = 8;
    ctx.value.beginPath();
    ctx.value.arc(x, y, radius, 0, 2 * Math.PI, false);
    ctx.value.fillStyle = color;
    ctx.value.fill();
};

5.在画布绘序号

/**
 * 在画布绘制序号
 */
const drawSnPoint = (sn, x, y, color) => {
    ctx.value.font = '14px Arial';
    ctx.value.fillStyle = color;
    ctx.value.textAlign = 'center';
    ctx.value.textBaseline = 'middle';
    ctx.value.fillText(sn, x, y);
};

6.处理图片点击

/**
 * 图片点击:处理画布全局覆盖
 */
function handleClickImg(e) {
    drawImageToCanvas();
    let dataset = e.target.dataset
    proQualityList1.value.push({
        sn: proQualityList1.value.length + 1, 
        positionX: e.offsetX || e.layerX, 
        positionY: e.offsetY || e.layerY,
    });
    for(let item of proQualityList1.value) {
        drawOriginPoint(item.positionX, item.positionY, '#f00');
        drawSnPoint(item.sn, item.positionX, item.positionY, '#fff');
    }
}

方式二:画布分散覆盖图像

  1. 监控图像或画布点击
  2. 根据点击坐标创建画布
  3. 绘制圆点和序号

1.编写前端显示代码

<div style="position: relative" id="canvas-2">
    <img id="img-2" src="/Img/image/1530088404487.jpg" @click="handleClickImg2"/>
</div>

这里定义了 handleClickImg2 点击事件是用来记录鼠标在图片点击的坐标,从而在其上面做一些操作,这里只在图片上面做了点击监控,从而保证可以分散创建画布。

这里的思路是通过相对布局将画布都挂载到父元素上面,因此这里为父元素定义了唯一id id="canvas-2"

2.配置基本数据

// 图片基本信息
const image = ref();
const imageWidth = ref(0);
const imageHeight = ref(0);
// 画布
const canvas = ref();
const ctx = ref();
// 记录点击点
const proQualityList2 = ref([]);

定义一些参数来接受或后续使用,详情请看代码注释。

3.在画布绘圆

/**
 * 在画布绘制圆点
 */
const drawOriginPoint = (x, y, color) => {
    const radius = 8;
    ctx.value.beginPath();
    ctx.value.arc(x, y, radius, 0, 2 * Math.PI, false);
    ctx.value.fillStyle = color;
    ctx.value.fill();
};

4.在画布绘序号

/**
 * 在画布绘制序号
 */
const drawSnPoint = (sn, x, y, color) => {
    ctx.value.font = '14px Arial';
    ctx.value.fillStyle = color;
    ctx.value.textAlign = 'center';
    ctx.value.textBaseline = 'middle';
    ctx.value.fillText(sn, x, y);
};

5.创建画布

/**
 * 创建画布
 */
function createCanvas(sn, x, y, color) {
    let canvas = document.createElement('canvas');
    // 设置Canvas的固定宽度和高度
    canvas.width = 24;
    canvas.height = 24;
    // 设置Canvas的样式
    canvas.style.position = 'absolute';
    canvas.style.top = `${y}px`;
    canvas.style.left = `${x}px`;
    let ctx = canvas.getContext('2d');
    // 圆点半径,可以根据需要调整
    const radius = 8;
    ctx.beginPath();
    ctx.arc(canvas.width / 2, canvas.height / 2, radius, 0, 2 * Math.PI, false);
    // 设置填充颜色
    ctx.fillStyle = color[0];
    ctx.fill();
    // 文字样式设置
    ctx.font = '14px Arial';
    // 设置填充颜色
    ctx.fillStyle = color[1];
    // 设置文本对齐方式(左、中、右)
    ctx.textAlign = 'center';
    // 设置文本基线(上、中、下等)
    ctx.textBaseline = 'middle';
    // 绘制数字
    ctx.fillText(sn, canvas.width / 2, canvas.height / 2);
    // 获取要插入Canvas的容器
    let container = document.getElementById(`canvas-2`);
    // @ts-ignore 将Canvas添加到页面中
    container.appendChild(canvas);
}

这里最大的特点就是通过设置Canvas的样式来将一小块画布放在图片上面:

// 设置Canvas的样式
canvas.style.position = 'absolute';
canvas.style.top = `${y}px`;
canvas.style.left = `${x}px`;

6.处理图片点击

/**
 * 图片点击:处理画布分散覆盖
 */
function handleClickImg2(e) {
    let dataset = e.target.dataset
    proQualityList2.value.push({
        sn: proQualityList.value.length + 1, 
        positionX: e.offsetX || e.layerX, 
        positionY: e.offsetY || e.layerY,
    });
    createCanvas(proQualityList2.value.length, e.offsetX || e.layerX, e.offsetY || e.layerY, ['#f00', '#fff'])
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FP7209M太阳能升压恒流一体测试板,带短路保护功能,软启动时间可调,应用于太阳能吸塑灯箱 商场便利店户外门头侧挂招牌广告牌led灯箱

太阳能灯箱用于城市主要街道、停车场、宾馆、旅游区、等夜间人群活动较多的公共场所照明的设备 太阳能广告灯箱凭借独特的设计理念为广告行业开辟一个全新的领域。不仅具有广告原有的宣传作用&#xff0c;还点亮了都市&#xff0c;小区的景观环境。在不需要架电线&#xff0c;电…

JS渗透(安全)

JS逆向 基本了解 作用域&#xff1a; 相关数据值 调用堆栈&#xff1a; 由下到上就是代码的执行顺序 常见分析调试流程&#xff1a; 1、代码全局搜索 2、文件流程断点 3、代码标签断点 4、XHR提交断点 某通js逆向结合burp插件jsEncrypter 申通快递会员中心-登录 查看登录包…

Imperva 数据库与安全解决方案

Imperva是网络安全解决方案的专业提供商&#xff0c;能够在云端和本地对业务关键数据和应用程序提供保护。公司成立于 2002 年&#xff0c;拥有稳定的发展和成功历史并于 2014 年实现产值1.64亿美元&#xff0c;公司的3700多位客户及300个合作伙伴分布于全球各地的90多个国家。…

工业网络监控中的IP保护与软件授权革新

未来的智能工厂离不开稳定而高效的通信网络&#xff0c;这些网络在支撑生产流程的同时&#xff0c;也面临着复杂的管理与安全挑战。PROCENTEC推出了一系列硬件和软件产品&#xff0c;如Atlas、Mercury和Osiris&#xff0c;以提供全面的网络监控和故障排除能力。然而&#xff0c…

基于springboot+vue实现的网上预约挂号管理系统 (源码+L文+ppt)4-104

结合现有六和医院网上预约挂号管理系统的特点&#xff0c;应用新技术&#xff0c;构建了六和医院网上预约挂号管理系统。首先从需求出发&#xff0c;对目前传统的六和医院网上预约挂号管理进行了详细的了解和分析。根据需求分析结果&#xff0c;对系统进行了设计&#xff0c;并…

QT for android 问题总结(QT 5.15.2)

1.配置好的sdk&#xff0c;显示设置失败 Android SDK Command-line Tools run. Android Platform-Tools installed. Command-line Tools (latest) 版本过高导致报错 &#xff0c;下载一个低版本的latest &#xff0c;替换掉之前latest中的文件。即可&#xff0c;latest 路径如…

NAS端最强音乐库,多平台服务支持。海康存储部署『Navidrome』

NAS端最强音乐库&#xff0c;多平台服务支持。海康存储部署『Navidrome』 哈喽小伙伴们好&#xff0c;我是Stark-C~ 对于我们NAS用户&#xff0c;我们总是喜欢将自己喜欢的音乐资源通过下载的方式保存在本地&#xff0c;不过海康存储目前对因音乐的支持和管理实在过于薄弱&am…

【论文阅读笔记】Wavelet Convolutions for Large Receptive Fields

1.论文介绍 Wavelet Convolutions for Large Receptive Fields 大感受野的小波卷积 2024 EECV Paper Code 2.摘要 近年来&#xff0c;人们试图通过增加卷积神经网络&#xff08;ConvolutionalNeuralNets&#xff0c;CNNs&#xff09;的核尺寸来模拟视觉变换器&#xff08;V…

2024年最新10款顶级项目管理软件排行

项目管理软件在现代项目管理中扮演着至关重要的角色&#xff0c;它不仅仅是一个工具&#xff0c;更是一种高效、系统化的方法来管理和优化项目流程&#xff0c;帮助项目经理和团队成员快速了解项目状态&#xff0c;加速项目进展。 进度猫 进度猫是一款以甘特图为向导的轻量级…

SAP ABAP开发学习——RFC

目录 RFC接口 定义 调用过程 RFC的通信 RFC通信情况 RFC接口系统 RFC的通信模式 RFC版本 RFC调用方式 Web Service接口 SAP创建Web Service示例 远程目标的维护 创建远程目标 外部系统访问设置 RFC的调用 RFC接口 定义 调用过程 RFC的通信 RFC通信情况 RFC接…

gps数据对接G7易流平台

之前伙伴对接G7物流平台获取温度、轨迹数据&#xff0c;写的一塌糊涂&#xff0c;今天来重新对接下。 G7易流 G7物联和易流科技合并后正式发布的品牌&#xff0c;主要面向生产制造与消费物流行业的货主及货运经营者提供软硬一体、全链贯通的SaaS服务。这包括订阅服务&#xff…

【网络】传输层协议TCP(下)

目录 四次挥手状态变化 流量控制 PSH标记位 URG标记位 滑动窗口 快重传 拥塞控制 延迟应答 mtu TCP异常情况 四次挥手状态变化 之前我们讲了四次挥手的具体过程以及为什么要进行四次挥手&#xff0c;下面是四次挥手的状态变化 那么我们下面可以来验证一下CLOSE_WAIT这…

高效新闻管理:SpringBoot框架应用

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理新闻稿件管理系统的相关信息成为必然。开发…

【已解决】C# NPOI如何设置单元格格式

前言 设置单元格格式我们做表格必须要的一步&#xff0c;那么如何对单元格进行设置呢&#xff1f;直接上图看看效果图先&#xff0c;我做的是一个居中然后字体变化的操作&#xff0c;其他的查他的手册即可。 解决方法 直接上代码 IWorkbook excelDoc new XSSFWorkbook();…

通过微调 Embedding 优化 RAG

大型语言模型 (LLM) 向用户和组织展示了巨大的潜力&#xff1b;它们的强大功能和生成能力使它们最近广受欢迎并被广泛接受。LLM 面临的一些缺点是无法以上下文感知的方式生成或响应用户给出的提示&#xff0c;听起来非常通用和开放&#xff0c;或者有时响应的信息已经过时。如果…

微信小程序生成二维码

目前是在开发小程序端 --> 微信小程序。然后接到需求&#xff1a;根据 form 表单填写内容生成二维码&#xff08;第一版&#xff1a;表单目前需要客户进行自己输入&#xff0c;然后点击生成按钮实时生成二维码&#xff0c;不需要向后端请求&#xff0c;不存如数据库&#xf…

用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门(二)

概述 从 WWDC 24 开始&#xff0c;苹果推出了全新的测试机制&#xff1a;Swift Testing。利用它我们可以大幅度简化之前“老态龙钟”的 XCTest 编码范式&#xff0c;并且使得单元测试更加灵动自由&#xff0c;更符合 Swift 语言的优雅品味。 在这里我们会和大家一起初涉并领略…

Python的自然语言生成与对话系统介绍

1. 背景介绍 自然语言生成(Natural Language Generation&#xff0c;NLG)和对话系统是人工智能领域的重要研究方向。NLG 涉及将计算机理解的信息转换为自然语言文本&#xff0c;而对话系统则涉及计算机与用户之间的自然语言交互。Python 作为一种易于学习、易于使用的编程语言…

HarmonyOS NEXT 应用开发实战(十、从零设计一款个人中心页面详细示例)

随着HarmonyOS的不断发展&#xff0c;越来越多的开发者开始关注这个平台上的应用开发。本篇文章将详细讲解如何从零开始设计一款个人中心页&#xff0c;并在代码中实现其相关功能。 1. 项目结构设计 首先&#xff0c;我们需要设计一个合理的项目结构。我们将个人中心页面分为几…

Node.js 入门指南:从零开始构建全栈应用

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;node.js篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来node.js篇专栏内容:node.js-入门指南&#xff1a;从零开始构建全栈应用 前言 大家好&#xff0c;我是青山。作…