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

在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. 完整代码

html 复制代码
<!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) // 两个坐标点就用vertexAttrib2f
                gl.drawArrays(gl.POINTS, 0, 1);
            });
        }
    </script>
</body>

</html>

6. 效果如下

相关推荐
西柚与蓝莓2 分钟前
报错:{‘csrf_token‘: [‘The CSRF token is missing.‘]}
前端·flask
NoneCoder37 分钟前
JavaScript系列(38)-- WebRTC技术详解
开发语言·javascript·webrtc
python算法(魔法师版)1 小时前
html,css,js的粒子效果
javascript·css·html
德迅云安全-小钱1 小时前
跨站脚本攻击(XSS)原理及防护方案
前端·网络·xss
ss2731 小时前
【2025小年源码免费送】
前端·后端
Amy_cx1 小时前
npm install安装缓慢或卡住不动
前端·npm·node.js
gyeolhada1 小时前
计算机组成原理(计算机系统3)--实验八:处理器结构拓展实验
java·前端·数据库·嵌入式硬件
小彭努力中1 小时前
16.在Vue3中使用Echarts实现词云图
前端·javascript·vue.js·echarts
flying robot1 小时前
React的响应式
前端·javascript·react.js
禁默1 小时前
深入探讨Web应用开发:从前端到后端的全栈实践
前端