WebGl 如何给页面绑定点击事件

embedded/2024/10/15 15:38:25/

在WebGL中给页面绑定点击事件,可以通过为WebGL的绘图上下文所在的<canvas>元素添加事件监听器来实现点击事件的处理。

1. 画布添加点击事件

javascript">const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')ctx.onclick = function (e) {// 给canvas添加点击事件
}

2. 获取坐标位置

getBoundingClientRect的top和left,等同于offsetTop和offsetLeft,即canvas边框到屏幕的距离

javascript">const domPosition = e.target.getBoundingClientRect();

3. 将画布的宽高转换成坐标

javascript">// 1.获取鼠标相对于浏览器的坐标
const x = e.clientX;
const y = e.clientY;// 2.获取画布边框到浏览器的距离
const domPosition = e.target.getBoundingClientRect();// 3.鼠标点击位置到canvas边框的距离
const domx = x - domPosition.left;
const domy = y - domPosition.top;// 4.转换坐标的公式:
// 水平坐标=当前鼠标点击的坐标x-当前画布的一半,再除以当前画布的一半
// 垂直坐标=当前画布的一半-当前鼠标点击的坐标y,再除以当前画布的一半
const halfWidth = ctx.offsetWidth / 2;
const halfHeigth = ctx.offsetHeight / 2;const clickX = (domx - halfWidth) / halfWidth;
const clickY = (halfHeigth - domy) / halfHeigth;

4. 根据坐标在画布上绘制点

javascript">// 两个坐标点就用vertexAttrib2f
gl.vertexAttrib2f(aPosition, clickX, clickY) 
gl.drawArrays(gl.POINTS, 0, 1);

5. 完整代码

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>* {margin: 0;padding: 0;}canvas {margin: 50px auto;display: block;background: pink;}</style><title>webgl三维坐标系</title>
</head><body><canvas id="canvas" width="400" height="400">此浏览器不支持canvas</canvas><script>const ctx = document.getElementById('canvas')const gl = ctx.getContext('webgl')// 顶点着色器源码const vertexShaderSource = `attribute vec4 aPosition;void main() {gl_Position = aPosition; gl_PointSize = 5.0;}`// 片源着色器源码const fragmentShaderSource = `void main() {gl_FragColor = vec4(0.0,0.0,0.0,1.0); // r, g, b, a}`// 设置着色器封装后,直接使用const program = initShader(gl, vertexShaderSource, fragmentShaderSource)// 返回变量的存储地址const aPosition = gl.getAttribLocation(program, 'aPosition');// 着色器方法function initShader(gl, vertexShaderSource, fragmentShaderSource) {const vertexShader = gl.createShader(gl.VERTEX_SHADER);// 创建顶点着色器对象const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);// 创建片段着色器对象gl.shaderSource(vertexShader, vertexShaderSource);// 设置顶点着色器源代码gl.shaderSource(fragmentShader, fragmentShaderSource);// 设置片段着色器源代码gl.compileShader(vertexShader);// 编译顶点着色器gl.compileShader(fragmentShader);// 编译片段着色器// 创建一个程序对象const program = gl.createProgram();gl.attachShader(program, vertexShader);gl.attachShader(program, fragmentShader);gl.linkProgram(program);gl.useProgram(program);return program;}// -----------------------------本节新增代码-------------------------------------------const points = [];// 1.给canvas添加点击事件ctx.onclick = function (e) {// 2.获取坐标位置const x = e.clientX;const y = e.clientY;// getBoundingClientRect的x和y,等同于offsetTop和offsetLeft,即canvas边框到屏幕的距离const domPosition = e.target.getBoundingClientRect();console.log(domPosition, ctx.offsetTop, ctx.offsetLeft)console.log(x, y)// 鼠标点击位置到canvas边框的距离const domx = x - domPosition.left;const domy = y - domPosition.top;// 3.将获取当前画布的宽(0,200,400)转换成坐标(-1,0,1);画布的高(0,200,400)转换成坐标(1,0,-1);// 首先:获取画布宽高,除以2,得到原点到边框的距离,也就是一半的宽和高。// 其次:获取点击后得到的宽 减去 一半的宽,再除以一半的宽。// 最后:一半的高 减去 获取点击后得到的高,再除以一半的高。const halfWidth = ctx.offsetWidth / 2;const halfHeigth = ctx.offsetHeight / 2;const clickX = (domx - halfWidth) / halfWidth;const clickY = (halfHeigth - domy) / halfHeigth;console.log(clickX, clickY);// 4.使用坐标在画布上绘制点// gl.vertexAttrib2f(aPosition, clickX, clickY) // 两个坐标点就用vertexAttrib2f// gl.drawArrays(gl.POINTS, 0, 1);// 5.绘制多的点points.push({ clickX, clickY })points.forEach(element => {gl.vertexAttrib2f(aPosition, element.clickX, element.clickY) // 两个坐标点就用vertexAttrib2fgl.drawArrays(gl.POINTS, 0, 1);});}</script>
</body></html>

6. 效果如下


http://www.ppmy.cn/embedded/127931.html

相关文章

如何获取网页内嵌入的视频?

如何获取网页内嵌入的视频&#xff1f; 有时插件无法识别的视频资源&#xff0c;可以通过手动使用浏览器的开发者工具来抓取。你可以按照以下步骤操作&#xff1a; 步骤&#xff1a; 打开网页并按 F12&#xff1a;在视频页面按下 F12 或右键点击网页并选择“检查”或“Inspe…

Spring Boot 进阶-Spring Boot如何整合AOP实现自定义注解

通过之前的文章,我们知道在Spring Boot中使用了大量的注解,而对于注解大家应该不陌生。 Java注解是在JDK1.5的时候引入的新特性,它提供了一种类似注释的机制,用来将任何的信息或者元数据与类、方法,或者是成员变量来进行关联。在注解中附带了一些信息,这些信息可以在编译…

QT文件操作【记事本】

mainwindow.h核心函数 QFileDialog::getOpenFileName()QFileDialog::getSaveFileName() #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include<QFileDialog> #include<QMessageBox> #include<QDebug> #include<QFile> #…

PHP-FPM和FastCGI

文章目录 前言一. FastCGI1.定义2.工作方式3.协议4.架构5.工作原理&#xff08;请求生命周期&#xff09; 二. PHP-FPM1.定义&#xff1a;2.特性3.进程管理模式4.工作流程 三.关系与应用四.配置示例五.性能优化六.配置选项七.常见问题及解决方案 前言 PHP-FPM 是基于 FastCGI …

【计算机网络 - 基础问题】每日 3 题(四十)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

【原创】可用于 Android Studio 的翻译插件

在不少讲解Android 开发的老师视频中会出现一个运行在Android Studio 上的翻译插件&#xff0c;感觉挺实用的。 接下来&#xff0c;我们把它安装在我们的Android Studio 上。 设置 点击右上角齿轮按钮&#xff0c;选择Settings 安装 翻译插件 输入Tanslation&#xff0c;选…

计算机网络:数据链路层 —— 以太网(Ethernet)

文章目录 局域网局域网的主要特征 以太网以太网的发展100BASE-T 以太网物理层标准 吉比特以太网载波延伸物理层标准 10吉比特以太网汇聚层交换机物理层标准 40/100吉比特以太网传输媒体 局域网 局域网&#xff08;Local Area Network, LAN&#xff09;是一种计算机网络&#x…

Java设计模式——装饰模式

目录 模式动机 模式定义 模式结构 类图 代码分析 示例&#xff1a;动态添加功能的流 组件接口 具体组件 装饰抽象类 具体装饰类 客户端 模式分析 核心思想 动态扩展功能 组合优于继承 优点 动态扩展功能 组合优于继承 代码复用性高 符合开闭原则 缺点 增加…