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. 效果如下

相关推荐
默_笙3 分钟前
🧀 用户访问一个网站到底经历了什么?全栈部署的"城市观光"指南
前端·javascript
aixingpan5 分钟前
aixingpan.cn API开发文档:api_docs_trichart_natal_composite_transit2接口指南
前端·php
是立不是利6 分钟前
CSS 架构——在混乱中建立秩序
前端·html
两只羊ovo21 分钟前
让 Agent 接上“万能接口”:LangChain + MCP 实战,工具不再锁死在项目里
前端
妙码生花22 分钟前
使用git更新ai-go-admin框架
前端·人工智能·git·golang·typescript·php
YUJIANYUE24 分钟前
查立得万用查分电脑版(web环境+查询系统免安装单文件一键运行包)
前端·jvm
小聪7081 小时前
基于node实现一个轻量化web引擎:elpis-core
前端
子非鱼a1 小时前
【WEB】[SWPU2019]Web1
java·服务器·前端
涛涛ing1 小时前
9 月第一周,前端圈又炸了四次
前端
葡萄城技术团队1 小时前
从自然语言到表格操作:SpreadJS 表格智能体如何执行一个任务
前端