当前位置: 首页 > news >正文

理解 HTML5 Canvas 中逻辑像素与物理像素的关系

理解 HTML5 Canvas 中逻辑像素与物理像素的关系

在使用 HTML5 Canvas 时,开发者经常会遇到一个困惑:为什么鼠标的 offsetXoffsetY 和我绘制的图形坐标对不上?这通常是因为 Canvas 的逻辑像素大小和物理像素大小不一致。本文将详细解释这个问题,并给出通用解决方案。


什么是逻辑像素和物理像素?

逻辑像素

  • 是 Canvas 内部的绘图坐标系大小,由 Canvas 元素的 widthheight 属性决定。
  • 例如:
    <canvas width="400" height="400"></canvas>
    
    上面的代码定义了一个 400x400 的逻辑像素大小。绘图时坐标范围为 (0, 0)(400, 400)

物理像素

  • 是 Canvas 在网页中实际显示的尺寸,由 CSS 样式的 widthheight 控制。
  • 例如:
    <canvas width="400" height="400" style="width: 200px; height: 200px;"></canvas>
    
    上面的代码将 Canvas 的显示缩小了一半,视觉上它是一个 200x200 的区域,但绘图坐标仍然是 (0, 0)(400, 400)

为什么鼠标事件会出现问题?

当鼠标点击 Canvas 时,offsetXoffsetY 是基于 物理像素 的鼠标位置,而绘图坐标是基于 逻辑像素 的。两者之间的比例由 Canvas 的逻辑大小和 CSS 显示大小的关系决定。

例如:

<canvas width="400" height="400" style="width: 200px; height: 200px;"></canvas>
  1. 逻辑像素:绘制一个矩形,坐标为 (50, 50, 100, 100)
  2. 物理像素:鼠标点击位置为 (100, 100),但因为显示缩小了一半,offsetX 实际代表逻辑坐标的 (200, 200)

结果:鼠标事件坐标和图形坐标完全对不上!


如何解决?

解决问题的关键是计算 逻辑坐标和物理坐标之间的缩放比例,然后对鼠标事件的坐标进行调整。

通用解决方案:动态计算缩放比例

通过 Canvas 的 getBoundingClientRect() 方法,可以获取 Canvas 在页面中的物理尺寸,再结合其逻辑大小计算缩放比例。

以下是完整代码实现:

handleMouseDown(e) {const dom = this.$refs.canvasRef; // 获取 Canvas DOMconst rect = dom.getBoundingClientRect(); // 获取物理大小// 计算缩放比例const scaleX = dom.width / rect.width; // X 轴缩放比例const scaleY = dom.height / rect.height; // Y 轴缩放比例// 调整鼠标坐标const offsetX = e.offsetX * scaleX;const offsetY = e.offsetY * scaleY;console.log(`Adjusted Mouse Position: (${offsetX}, ${offsetY})`);
}

完整案例:支持高分辨率与 CSS 缩放的 Canvas 鼠标交互

以下是一个完整的 Canvas 鼠标点击交互案例,解决逻辑像素和物理像素不一致的问题。

HTML

<canvas id="myCanvas" width="800" height="800" style="width: 400px; height: 400px; border: 1px solid black;"></canvas>

JavaScript

const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");// 绘制一个矩形
ctx.fillStyle = "blue";
ctx.fillRect(200, 200, 200, 200);// 监听鼠标点击事件
canvas.addEventListener("mousedown", (e) => {// 获取物理大小const rect = canvas.getBoundingClientRect();// 计算缩放比例const scaleX = canvas.width / rect.width;const scaleY = canvas.height / rect.height;// 调整鼠标坐标const offsetX = e.offsetX * scaleX;const offsetY = e.offsetY * scaleY;console.log(`Mouse Logical Position: (${offsetX}, ${offsetY})`);// 检测点击是否在矩形内if (offsetX >= 200 && offsetX <= 400 &&offsetY >= 200 && offsetY <= 400) {alert("You clicked inside the rectangle!");}
});

适配高分辨率屏幕(Retina 屏幕)

在高分辨率屏幕上,Canvas 的默认显示分辨率可能不足,导致图形模糊。为了解决这个问题,可以在逻辑像素上增加分辨率,同时按比例调整 CSS 样式。

解决方案

  1. 设置高分辨率 Canvas:

    const dpr = window.devicePixelRatio || 1;
    canvas.width = 400 * dpr; // 提高逻辑像素
    canvas.height = 400 * dpr;
    canvas.style.width = "400px"; // 设置 CSS 尺寸
    canvas.style.height = "400px";ctx.scale(dpr, dpr); // 按设备像素比缩放绘图
    
  2. 鼠标事件仍然适用缩放比例,无需额外调整。


总结

核心点

  1. 逻辑像素 vs. 物理像素

    • 逻辑像素由 widthheight 定义,用于绘图。
    • 物理像素由 CSS 控制,影响显示大小。
  2. 鼠标事件坐标映射

    • 使用 getBoundingClientRect() 获取物理大小。
    • 根据缩放比例调整 offsetXoffsetY
  3. 适配高分辨率屏幕

    • 提升逻辑像素分辨率。
    • 使用 scale 方法确保绘图清晰。

代码复用性

  • 无论是适配高分辨率屏幕,还是处理鼠标事件,计算逻辑和物理像素缩放比例是通用的解决方案。这个方法不仅适用于 Canvas,也适用于其他需要精确像素计算的场景。

希望本文能帮助你更好地理解和解决 Canvas 中的坐标问题! 🎨

相关文章:

理解 HTML5 Canvas 中逻辑像素与物理像素的关系

理解 HTML5 Canvas 中逻辑像素与物理像素的关系 在使用 HTML5 Canvas 时&#xff0c;开发者经常会遇到一个困惑&#xff1a;为什么鼠标的 offsetX 和 offsetY 和我绘制的图形坐标对不上&#xff1f;这通常是因为 Canvas 的逻辑像素大小和物理像素大小不一致。本文将详细解释这…...

7.揭秘C语言输入输出内幕:printf与scanf的深度剖析

揭秘C语言输入输出内幕&#xff1a;printf与scanf的深度剖析 C语言往期系列文章目录 往期回顾&#xff1a; VS 2022 社区版C语言的安装教程&#xff0c;不要再卡在下载0B/s啦C语言入门&#xff1a;解锁基础概念&#xff0c;动手实现首个C程序C语言概念之旅&#xff1a;解锁关…...

数据分析-系统认识数据分析

目录 数据分析的全貌 观测 实验 应用 数据分析的全貌 观测 实验 应用...

蓝桥杯介绍

赛事背景与历程 自2009年举办以来&#xff0c;蓝桥杯已经连续举行了多届&#xff0c;成为国内领先的信息技术赛事。2022年&#xff0c;蓝桥杯被教育部确定为2022—2025学年面向中小学生的全国性竞赛活动&#xff0c;并入选国家级A类学科竞赛。 参赛对象与组别 蓝桥杯的参赛对…...

鸿蒙加载网络图片并转换成PixelMap

鸿蒙加载网络图片并转换成PixelMap 参考文档 基于API12. 有一些图片功能需要使用 PixelMap 类型的参数&#xff0c;但是使用Image组件之类的时候无法获取到 PixelMap 类型数据。 因此只能是把图片下载下来然后加在并转换一下。 实现方式 一下封装了一个函数。使用的 rcp 模…...

hive搭建

1.准备环境 三台节点主机已安装hadoopmysql数据库 2.环境 2.1修改三台节点上hadoop的core-site.xml <!-- 配置 HDFS 允许代理任何主机和组 --> <property><name>hadoop.proxyuser.hadoop.hosts</name><value>*</value> </property&…...

51c扩散模型~合集1

我自己的原文哦~ https://blog.51cto.com/whaosoft/11541675 #Diffusion Forcing 无限生成视频&#xff0c;还能规划决策&#xff0c;扩散强制整合下一token预测与全序列扩散 当前&#xff0c;采用下一 token 预测范式的自回归大型语言模型已经风靡全球&#xff0c;同时互联…...

从零开始深度学习:全连接层、损失函数与梯度下降的详尽指南

引言 在深度学习的领域&#xff0c;全连接层、损失函数与梯度下降是三块重要的基石。如果你正在踏上深度学习的旅程&#xff0c;理解它们是迈向成功的第一步。这篇文章将从概念到代码、从基础到进阶&#xff0c;详细剖析这三个主题&#xff0c;帮助你从小白成长为能够解决实际…...

Liebherr利勃海尔 EDI 需求分析

Liebherr 使用 EDI 技术来提高业务流程的效率、降低错误率、加快数据交换速度&#xff0c;并优化与供应商、客户和其他合作伙伴之间的业务沟通。通过 EDI&#xff0c;Liebherr 实现了与全球交易伙伴的自动化数据交换&#xff0c;提升了供应链管理和订单处理的透明度。 Liebher…...

java小练习

小练1.用while语句计算11/2!1/3!1/4!...1/20!的和 public class test_11_17_2 {public static void main(String[] args) {double sum 0;double item 1;int n 20;int i 1;while(i<n){sum item;i i1;item item*(1.0/i);}System.out.println(sum);} } 小练2.计算88888…...

go语言中的占位符有哪些

在Go语言中&#xff0c;占位符主要用于格式化字符串输出&#xff0c;特别是在使用fmt包中的Printf系列函数时。以下是Go语言中常用的占位符&#xff1a; %v&#xff1a;代表值的默认格式&#xff0c;对于字符串是直接输出&#xff0c;对于整型是十进制形式。%v&#xff1a;扩展…...

基于Windows安装opus python库

项目中需要用到一些opus格式的编解码功能&#xff0c;找到网上有opus的开源库。网址&#xff1a;Opus Codec 想着人生苦短&#xff0c;没想到遇上了错误&#xff01;在这里记录一下过程 过程 安装python库 pip3 install opuslib验证 >>> import opuslib Tracebac…...

【设计模式】行为型模式(五):解释器模式、访问者模式、依赖注入

《设计模式之行为型模式》系列&#xff0c;共包含以下文章&#xff1a; 行为型模式&#xff08;一&#xff09;&#xff1a;模板方法模式、观察者模式行为型模式&#xff08;二&#xff09;&#xff1a;策略模式、命令模式行为型模式&#xff08;三&#xff09;&#xff1a;责…...

使用nossl模式连接MySQL数据库详解

使用nossl模式连接MySQL数据库详解 摘要一、引言二、nossl模式概述2.1 SSL与nossl模式的区别2.2 选择nossl模式的场景三、在nossl模式下连接MySQL数据库3.1 准备工作3.2 C++代码示例3.3 代码详解3.3.1 初始化MySQL连接对象3.3.2 连接到MySQL数据库3.3.3 执行查询操作3.3.4 处理…...

【MySQL】ubantu 系统 MySQL的安装与免密码登录的配置

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;MySQL初阶探索&#xff1a;构建数据库基础 欢迎大家点赞收藏评论&#x1f60a; 目录 &#x1f4da;mysql的安装&#x1f4d5;MySQL的登录&#x1f30f;MySQL配置免密码登录 &#x1f4da;mysql的…...

高级 SQL 技巧讲解

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; SQL&#xff08;结构化查询语言&#xff09;是管理和操作数据库的核心工具。从基本的查询语句到复杂的数据处理&#xff0c;掌握高级 SQL 技巧不仅能显著提高数据分析的效率&#xff0c;还能解决业务中的复…...

浅论AI大模型在电商行业的发展未来

随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;AI大模型在电商行业中扮演着越来越重要的角色。本文旨在探讨AI大模型如何赋能电商行业&#xff0c;包括提升销售效率、优化用户体验、增强供应链管理等方面。通过分析AI大模型在电商领域的应用案例和技术进展…...

【python笔记03】《类》

文章目录 面向对象基本概念对象的概念类的概念 类的定义类的创建&#xff08;实例的模板&#xff09;类的实例化--获取对象对象方法中的self关键字面试题请描述什么是对象&#xff0c;什么是类。请观阅读如下代码&#xff0c;判断是否能正常运行&#xff0c;如果不能正常运行&a…...

Flutter 应用在真机上调试的流程

在真机上调试 Flutter 应用的方法有很多&#xff0c;可以使用 USB 数据线连接设备到电脑进行调试&#xff0c;也可以通过无线方式进行 Flutter 真机调试。 1. 有线调试 设备准备 启用开发者模式&#xff1a; Android&#xff1a;进入 设置 > 关于手机&#xff0c;连续点击…...

以太坊基础知识结构详解

以太坊的历史和发展 初创阶段 2013年&#xff1a;Vitalik Buterin 发表了以太坊白皮书&#xff0c;提出了一个通用的区块链平台&#xff0c;不仅支持比特币的货币功能&#xff0c;还能支持更复杂的智能合约。2014年&#xff1a;以太坊项目启动&#xff0c;进行了首次ICO&…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...