十八、动画与canvas
1.RequestAnimationFrame
早期定时动画
setTimeout和setInterval不能保证时间精度,第二个参数只能保证何时将代码添加到浏览器的任务队列
requestAnimationFrame(cb)的cb在浏览器重绘屏幕前调用
function updateProgress(){const div = document.getElementById('div');div.style.width = (parseInt(div.style.width, 10) + 5) + '%';if (div.style.width !== '100%'){requestAnimationFrame(updateProgress);}
}
requestAnimationFrame(updateProgress);
requestAnimationFrame()的函数实际上可以接受一个参数,该参数为DOMHighResTimeStamp的实例,表示下次重绘的时间点。
cancelAnimationFrame(id); // 对应clearTimeout clearInterval
requestAnimationFrame()可以用作节流
let enabled = true;
function expensiveOperation(){console.log('scroll', Date.now());
}
window.addEventListener('scroll', () => {if (enabled) {enabled = false;window.requestAnimationFrame(expensiveOperation);setTimeout(() => enabled = true, 50)}
}
2.基本的画布功能
<canvas>元素必须要指定width和height两个属性,标签之间的内容是在浏览器不支持的情况下展示的内容
getContext();// 获取绘制上下文,参数为‘2d’或者‘webgl’
toDataURL(); // 导出canvas元素上的图像,接受一个MIME类型参数
3、2D绘图上下文
原点(0,0)在左上角,width和height分别为x轴和y轴的最大值
填充和描边
fillStyle和strokeStyle两个属性,属性值可以是字符串、渐变对象和图案对象
const myCanvas = document.getElementById('myCanvas');
const ctx = myCanvas.getContext('2d');
ctx.strokeStyle = 'red';
ctx.fillStyle = '#0000ff';
绘制矩形
fillRect(x,y, width, height);
strokeRect(x, y, width, height);
clearRect(x, y, width, height);
绘制路径
必须beginPath()开始绘制新路径,closePath()绘制一条返回起点的路径。而后可以指定fillStyle属性后,使用fill()填充区域,或者指定strokeStyle属性后,使用stroke()填充路径,或者使用clip()创建一个新的剪切区域。
方法 | 说明 |
---|---|
arc(x, y, startAngle, endAngle, counterclockwise) | 以(x,y)为圆心,从起始角度到结束角度绘制弧线,最后一个参数为是否顺时针,默认为true |
arcTo(x1, y1, x2, y2, radius) | 给定半径,经过(x1, y1)从上一个点绘制到(x2,y2)的弧线 |
bezierCurveTo(c1x, c1y, c2x, c2y, x, y) | 以(c1x, c1y)(c2x, c2y)为控制点,绘制从上一点到(x,y)的三次贝塞尔曲线 |
lineTo(x,y) | 上一点到(x,y)的直线 |
moveTo(x,y) | 移动光标到(x,y) |
quadraticCurveTo(cx, cy) | 以(cx, cy)为控制点,绘制从上一点到(x,y)的二次贝塞尔曲线 |
rect(x, y, width, height) | 绘制一个矩形路径,而非图形 |
isPointInPath(x, y) | 判断(x, y)是否在当前路径 |
绘制文本
fillText(contentStr, x, y, maxWidth);
strokeText(contentStr, x, y, maxWidth);
// 相关设置属性
ctx.font; // 以css样式指定字体样式、大小、字体簇
ctx.textAlign; // 文本对齐方式 start/end/left/right/center
ctx.textBaseLine; // 文本基线, top/hanging/middle/alphabetic/ideographic/bottom
辅助确定文本大小的方法measureText(str),返回一个TextMetrics对象
变换
方法 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
rotate(angle) | 围绕原点将图像旋转angle | |||||||||
scale(scaleX, scaleY) | 在x轴和y轴上分别缩放相应倍数 | |||||||||
translate(x, y) | 将坐标原点移动到(x, y) | |||||||||
transform(m1_1, m1_2, m2_1, m2_2, dx, dy) | 通过矩阵乘法直接修改上下文矩阵
| |||||||||
setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy) | 先将上下文变换矩阵重置,然后以传入的参数调用transform |
save()可以将所有设置放入一个暂存栈,需要恢复时调用restore()
绘制图像
drawImage()可以接受三组不同的参数
//1.传入一个HTML的<img>元素
let img = document.images[0];
ctx.drawImage(img, x, y);
ctx.drawImage(img, x, y, width, height); // width和height默认为<img>的宽高
// 2.将图像的部分绘制到指定区域
ctx.drawImage(img, srcX, srcY, srcWidth, srcHeight, targetX, targetY, targetWidth, targetHeight);
// 3.第一个参数可以是另外一个canvas元素
// 操作的结果可以通过toDataURL() 获取
阴影
属性值设置
属性 | 说明 |
---|---|
shadowColor | CSS颜色值,默认黑色 |
shadowOffsetX | x坐标偏移量 |
shadowOffsetY | y坐标偏移量 |
shadowBlur | 阴影模糊量 |
渐变
线性渐变通过CanvasGradient的实例表示,createLinearGradient()创建一个CanvasGradient实例,接受起点和终点的坐标作为参数;
addColorStop()方法为gradient对象添加色标,接受两个参数(位置0-1,颜色)
const gradient = ctx.createLinearGradient(30,30,70,70);
gradient.addColorStop(0, 'white');
gradient.addColorStop(1, 'black');
// 绘制红色矩形
ctx.fillStyle = '#FF0000';
ctx.fillRect(10,10,50,50);
// 绘制渐变矩形
ctx.fillStyle = gradient;
ctx.fillRect(30,30,50,50);
径向渐变通过createRadialGradient()创建,接受六个参数,分别为起点和终点的圆心坐标、半径、
ctx.createRadialGradient(startX, startY, startR, endX, endY, endR);
图案
用于填充和描画重复图案,调用createPattern(),接受两个参数,第一个参数为<img>或者<video> 和<canvas>,第二个参数为重复模式(repeat-x, repeat-y, repeat, no-repeat)
图像数据
getImageData(startX, startY, width, height)返回一个ImageData对象,每个ImageData包含三个属性width, height, data,其中data中每四个值分别表示第i个像素点的红、绿、蓝和透明度值,取值范围为0-255
合成
属性值 | 说明 | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
globalAlpha | 全局透明度,0-1, 用于指定绘制内容的透明度 | ||||||||||||||||||||||
globalCompositionOperation | 新绘制的形状如何与已有的上下文形状融合
|
4.WebGL
webgl上下文
getContext(‘webgl’);
webgl基础
可以在调用getContext()时传入配置项,指定创建的上下文的一些选项
配置项 | 说明 | 默认值 |
---|---|---|
alpha | 是否为上下文创建透明通道缓冲区 | true |
depth | 是否使用16位深缓冲区 | true |
stencil | 是否使用8位模板缓冲区 | false |
antialias | 是否使用默认机制执行抗锯齿操作 | true |
premultipliedAlpha | 绘图缓冲区是否预乘透明度 | true |
preserveDrawingBuffer | 绘图完成后是否保留绘图缓冲区 | false |
let drawing = document.getElementById("drawing");
// 确保浏览器支持<canvas>
if (drawing.getContext) {let gl = drawing.getContext("webgl", { alpha: false });if (gl) {// 使用 WebGL}
}
1.常量
OpenGL中以GL_开头的常量大部分都被webGL支持,但不需要这个前缀
gl.COLOR_BUFFER_BIT // GL_COLOR_BUFFER_BIT
2.方法命名
参数数量(1-4)+数据类型(‘f’, ‘i’)如, gl.uniform4f()
3.准备绘图
绘图之前,需要使用clearColor(r, g, b, a) 使用一种颜色清除<canvas>元素, rgba参数值都在0-1;
也可以使用gl.clear(gl.COLOR_BUFFER_BIT)使用之前定义的颜色填充画图
4.视口与坐标
默认情况下,视口为整个canvas区域,也可以使用viewport()方法改变视口
gl.viewport(x, y, width, height)
定义视口的坐标系统是canvas像素坐标系统,而视口中,中心点是原点(0,0),左下角是(-1,-1),右上角是(1,1)。
5.缓冲区
const buffer = gl.createBuffer(); // 创建缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER, buffer); // 将缓冲区绑定到上下文中,此处是将buffer与ARRAY_BUFFER绑定,将buffer设置为当前上下文的缓冲区
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0,0.5,1]), gl.STATIC_DRAW); // 将数据写入缓冲区第三个参数可以有3个选择
/**
gl.STATIC_DRAW 数据加载一次,可以在多次绘制中使用
gl.STREAM_DRAW 数据加载一次,只能在几次绘制中使用
gl.DYNAMIC_DRAW 数据可以重复修改,在多次绘制中使用
**/
// 不再需要缓冲区
gl.deleteBuffer(buffer);
6.错误
webGL操作中通常不会抛出错误,gl.getError()方法会返回一个常量,表示发生的错误类型
gl.NO_ERROR | 没有发生错误 |
gl.INVALID_ENUM | 上一次操作没有传入webgl预定的常量 |
gl.INVALID_VALUE | 上一次操作需要无符号数值,但是传入了负数 |
gl.INVALID_OPERATION | 上一次操作在当前状态下无法完成 |
gl.OUT_OF_MEMORY | 上次操作因内存不足无法完成 |
gl.CONTEXT_LOST_WEBGL | 上次操作因外部事件而丢失了上下文 |
7.着色器
定点着色器将3D顶点绘制为2D的点;
片元着色器将计算每个像素的颜色值;
使用GLSL编程
编写着色器
每个着色器有一个main()方法,绘制期间反复执行,
给着色器传递数据的方式有两种attribute
和uniform
attribute将定点传入定点着色器,uniform将任意常量值传入任意着色器
创建着色器程序
gl.createShader(shaderType); // shaderType: gl.VERTEX_SHADER, gl.FRAGMENT_SHADER 创建着色器
gl.shaderSource(shader, shaderSource);// 将glsl代码应用于着色器
gl.compileShader(shader); // 编译着色器const program = gl.createProgram(); // 创建着色器程序
gl.attachShader(program, shader); // 将着色器添加到着色器程序,需要调用两次分别传入定点着色器和片元着色器
gl.linkProgram(program); // 将两个着色器链接到变量program
gl.useProgram(program); // 让webgl上下文使用该程序
给着色器传值
// 1.找到接受值的变量位置
let uColorLocation = gl.getUniformLocation(program, 'uColor'); // 针对uniform变量uColor
let aVertextPosLocation = gl.getAttribLocation(program, 'aVertextPosition'); // 针对attribute变量aVertexPosition
// 2.传值
// 针对uniform变量
gl.uniform4fv(uColorLocation, [0,0,0,1]);
// 针对attribte变量
gl.enableVertexAttribArray(aVertexPosLocation);
gl.vertexAttribPointer(aVertexPosLocation, itemSize, gl.FLOAT, false, 0, 0) ; // 创建一个指向bindBuffer()指定的缓冲区指针,并保存在aVertexPosLocation中,
8.绘图
webGL只能绘制3中基本图形:点、线、三角形
绘图方法有两种:
drawArrays()
使用数组缓冲区
drawElements()
操作元素数组缓冲区
drawArrays()
接受三个参数,第一个参数表示形状,第二个参数是数组缓冲区的起点索引,第三个参数是数组缓冲区顶点集合的数量
形状参数列表:
参数 | 意义 |
---|---|
gl.POINTS | 将每个顶点当做一个点 |
gl.LINES | 将数组作为一系列点,每两个点依次绘制直线,顶点数必须是偶数 |
gl.LINE_LOOP | 将数组作为一系列顶点,依次依次绘制直线连接成封闭形状 |
gl.LINE_STRIP | 类似于gl.LINE_LOOP,区别在于最后不会连接终点和起点 |
gl.TRIANGLES | 将数组作为一系列顶点,在这些顶点间绘制三角形,每个三角形都不会共享顶点 |
gl.TRIANGLES_STRIP | 类似于gl.TRIANGLES,区别在于共享点,如果有ABCD四个点,则会绘制两个三角形ABC和BCD |
gl.TRIANGLES_FAN | 如果有ABCD四个点,则会绘制ABC, ACD三角形 |
/****** 绘制一个三角形 ******/const canvas = document.querySelector('#canvas');const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');const vSource = `attribute vec4 a_position;void main(){gl_Position = a_position;}`;const fSource = `precision highp float;uniform vec4 uColor;void main(){gl_FragColor = uColor;}`;const program = gl.createProgram();const vShader = gl.createShader(gl.VERTEX_SHADER);gl.shaderSource(vShader, vSource);gl.compileShader(vShader);const fShader = gl.createShader(gl.FRAGMENT_SHADER);gl.shaderSource(fShader, fSource);gl.compileShader(fShader);gl.attachShader(program, vShader);gl.attachShader(program, fShader);gl.linkProgram(program);gl.useProgram(program);const uColorLocation = gl.getUniformLocation(program, 'uColor');gl.uniform4f(uColorLocation, 1, 0, 0, 0.5);const positionData = [0.5, 0, 0, 0, 0.5, 0, -0.5, -0.5, 0.5];const positionBuffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positionData), gl.STATIC_DRAW);const positionLocation = gl.getAttribLocation(program, 'a_position');gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);gl.enableVertexAttribArray(positionLocation);gl.clearColor(0,1,1,1);gl.clear(gl.COLOR_BUFFER_BIT)gl.drawArrays(gl.TRIANGLES, 0, 3);
纹理
纹理的来源可以是图片、<video>或者<canvas>
let image = new Image(),texture;
image.src = "smile.gif";
image.onload = function() {texture = gl.createTexture(); // 创建纹理gl.bindTexture(gl.TEXTURE_2D, texture); // 绑定缓冲区gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); // 设置存储格式gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);// 除当前纹理gl.bindTexture(gl.TEXTURE_2D, null);
}
读取像素
// 读取(0,0)到(25,25)区域的像素,并写入pixels数组,rgba四值,0-255
let pixels = new Uint8Array(25*25);
gl.readPixels(0, 0, 25, 25, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
相关文章:

十八、动画与canvas
1.RequestAnimationFrame 早期定时动画 setTimeout和setInterval不能保证时间精度,第二个参数只能保证何时将代码添加到浏览器的任务队列 requestAnimationFrame(cb)的cb在浏览器重绘屏幕前调用 function updateProgress(){const div document.getElementById(d…...

自动化测试学习-Day4-selenium的安装和8种定位方法
哈喽,大家好! 本人21年毕业,软件工程专业,毕业后一直从事金融行业的软件测试。 希望大家一起见证一名卑微测试的成长之路。 目录 一、环境准备 1.浏览器下载 2.浏览器驱动下载 3.下载selenium 二、Selenium定位元素的8种方法…...

【Kubernetes】第二十五篇 - 布署 nodejs 后端项目(下)
一,前言 上一篇,介绍了部署后端项目之前,需要的准备的相关配置信息; 本篇,创建 Deployment、Service 完成后端项目布署; 二,解决 jenkins 安全问题 构建 docker 镜像之后,登录 do…...

贪心算法之区间问题总结
一、跳跃游戏跳跃游戏类的问题,不关心每一步怎么跳,只需要关心最大覆盖范围这里注意i是在当前最大可覆盖范围内遍历,如{2,1,0,1},就是在0~2范围内遍历,千万不能0~numsSize-1范围内遍历!!&#x…...

无线WiFi安全渗透与攻防(七)之WIFI07-WEP-wifite自动化渗透WEP加密
WIFI07-WEP-wifite自动化渗透WEP加密 1.wifite介绍 wifite是一款自动化wep、wpa以及wps破解工具,不支持windows和osx。wifite的特点是可以同时攻击多个采用wep和wpa加密的网络。wifite只需简单的配置即可自动化运行,期间无需人工干预。 目前支持任何li…...

震撼,支持多模态模型的ChatGPT 4.0发布了
最近几个月,互联网和科技圈几乎ChatGPT刷屏了,各种关于ChatGPT的概念和应用的帖子也是围绕在周围。当去年年底ChatGPT发布的那几天,ChatGPT确实震撼到了所有人,原来AI还可以这么玩,并且对国内的那些所谓的人工智能公司…...

IDEA常用插件列表
一 背景 IDEA常用插件列表,用来提供工作效率。你都安装了吗 IntelliJ IDEA 默认安装并提供了非常多的工具,比如 Maven Integration、Markdown support、SSH Remote Run 等。其中有很多好用,但是不为人知的工具。 二 插件列表 阿里代码规约…...

比df更好用的命令!
大家好,我是良许。 对于分析磁盘使用情况,有两个非常好用的命令:du 和 df 。简单来说,这两个命令的作用是这样的: du 命令:它是英文单词 disk usage 的简写,主要用于查看文件与目录占用多少磁…...

【Git使用学习】记录学习过程(1)
安装就省略了,安装结果如下。 Git Bash:这是一个模拟Linux环境的命令行工具,可以使用Git的所有功能。Git GUI:这是一个图形化界面的工具,可以方便地执行Git的常用操作。Git CMD:这是一个Windows命令行工具&…...

K_A18_001 基于STM32等单片机采集MQ2传感参数串口与OLED0.96双显示
K_A18_001 基于STM32等单片机采集MQ2传感参数串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RCMQ2传感参模块1.2、STM32F103C8T6MQ2传感参模块五、基础知识学习与相关…...

【云原生·Docker】常用命令
目录 🍁1、管理命令 🍁2、帮助命令 🍁3、镜像命令 🍁4、容器命令 🍂4.1.查看容器 🍂4.2.创建容器 🍂4.3.删除容器 🍂4.4.拷贝文件 🍂4.5.查看容器IP 🍁5、部署…...
户外露营储能电源芯片CSU3AF10
户外露营的项目有很多,随着户外储能电源的发展,越来越多的电子产品可以在户外使用,也不用担心因为在户外时间过长而手机或者其他电子产品电量耗尽。户外储能电源可保证人们随时随地的用电需求,同时也可以满足家电炊具的供电需求&a…...

无线WiFi安全渗透与攻防(八)之WEP-Hirte渗透WEP加密
WEP-渗透WEP新思路–Hirte 1.Hirte介绍 Hirte是破解无线网络WEP Key的一种攻击类型 只要客户端设备(笔记本电脑,手机等)连接过的无线网络,那些WIFI即使是不在攻击者范围内也都能被破解,因为该wifi的WEP密钥和配置文…...
前端常考面试题整理
display:none与visibility:hidden的区别 这两个属性都是让元素隐藏,不可见。两者区别如下: (1)在渲染树中 display:none会让元素完全从渲染树中消失,渲染时不会占据任何空间;visibility:hidden不会让元素…...

二十二、身份验证与权限
一、 准备工作 为了讲清楚身份验证与权限,我们再创建一个应用projects,设计模型如下: class Project(models.Model):name models.CharField(项目名称, max_length20, help_text项目名称)desc models.CharField(项目描述, max_length200, help_text项目…...

k8s pod 升级与回滚
当集群中的某个服务需要升级时,我们需要停止目前与该服务相关的所有pod,然后下载新版本镜像并创建新的pod。如果集群规模比较大,则这个工作变成了一个挑战,而且先全部停止然后逐步升级的方式会导致较长时间的服务不可用。kubernet…...

【Go】Go语言开发环境安装
【Go】Go语言开发环境安装 导入 安装环境:Winowds 我现在是win7安装的,与win10整体步骤是一样的,只是部分显示的时候有点差异不影响; 【名词】 编译器:先将代码编译成可执行文件,再执行; —…...
el-switch使用
效果图: 1.表格代码,给el-waitch加上change事件 <el-table-column prop"status" label"状态" align"center" width"150"> <template slot-sc…...

【算法入门】字符串基础
目录 一.字符串引言1.字符串基础二.洛谷P5734详解1.字符串相关库函数💫(1) strcpy函数 💫💫(2) strcat函数 💫💫(3)strstr函数 💫2.题…...

前端面试题 —— 浏览器原理(二)
目录 一、有哪些可能引起前端安全的问题? 二、网络劫持有哪几种,如何防范? 三、浏览器渲染进程的线程有哪些 四、僵尸进程和孤儿进程是什么? 五、为什么需要浏览器缓存? 六、对浏览器的理解 七、CSS 如何阻塞文档解析&…...

51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...

DAY 45 超大力王爱学Python
来自超大力王的友情提示:在用tensordoard的时候一定一定要用绝对位置,例如:tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾: tensorboard的发展历史和原理tens…...