十八、动画与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)通过矩阵乘法直接修改上下文矩阵
m1_1m2_1dx
m1_2m2_2dy
001
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() 获取

阴影

属性值设置

属性说明
shadowColorCSS颜色值,默认黑色
shadowOffsetXx坐标偏移量
shadowOffsetYy坐标偏移量
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新绘制的形状如何与已有的上下文形状融合
source-over新图形在原图形上面,默认值
source-in只画出新图形与原图形重叠的部分,画布上其他部分全部透明
source-out只画出新图形不重叠的部分,画布上其他部分全部透明
source-atop只画出新图形重叠部分,其他部分不受影响
destination-over新图形在原图形下面,重叠部分只有原图形透明像素下可见
destination-in新图形在原图形下面,画布上只留下两者重叠部分,其他部分全部透明
destination-out新图形与原图形重叠部分透明,不重叠部分不画,画布其他部分不受影响
destination-atop新图形在原图形下面,原图形不重叠部分全部透明
lighter新图形与原图形重叠部分像素值相加,让该部分变亮
copy新图形将擦除并完全取代原图形
xor新图形与原图形在重叠部分取“异或”操作

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()方法,绘制期间反复执行,
给着色器传递数据的方式有两种attributeuniform
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); 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/522.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

昨天某读者拿到华为OD岗位offer,今天来分享一下经验,包含华为OD机试

来自读者投稿&#xff0c;已经拿到华为 OD 开发岗位 offer&#xff0c;询问了一些问题&#xff0c;下面是他的一些经验。 文章目录华为 OD 投递简历华为 OD 机试分数OD 机试通过之后&#xff0c;收到综合测评OD 技术面&#xff08;时长 1 小时左右&#xff09;主管/HR 面试&…

从参数数量视角理解深度学习神经网络算法 DNN, CNN, RNN, LSTM 以python为工具

从参数数量视角理解深度学习神经网络算法 DNN, CNN, RNN, LSTM 以python为工具 文章目录1. 神经网络数据预处理1.1 常规预测情景1.2 文本预测场景2.全连接神经网络 DNN3.卷积神经网络CNN4.循环神经网络 RNN5.长短期记忆神经网络 LSTMʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔ…

PMP-项目管理知识体系概述

文章目录前言PMP-项目管理知识体系概述1. 项目管理知识体系三个维度1.1. 时间维度1.2. 管理维度1.3. 10大知识领域2. 十大知识领域之间的关系3. 项目管理的全链路3.1. 需求 -> 目标3.2. 目标 -> 计划3.3. 计划 -> 执行3.4. 执行 -> 收尾4. 项目管理类型分类说明4.1…

【Web APls简介】

Web APls简介1 本节目标2 Web APIs 和 JS 基础关联性2.1 JS组成2.2 JS 基础阶段以及 Web APIs 阶段3 API 和 Web API3.1 API3.2 Web API3.3 API 和 Web API 总结1 本节目标 说出 Web APIs 阶段与 JavaScript 语法阶段的关联性说出什么是 API说出什么是 Web API 2 Web APIs 和…

30岁了,说几句大实话

是的&#xff0c;我 30 岁了&#xff0c;还是周岁。 就在这上个月末&#xff0c;我度过了自己 30 岁的生日。 都说三十而立&#xff0c;要对自己有一个正确的认识&#xff0c;明确自己以后想做什么&#xff0c;能做什么。 想想时间&#xff0c;过得真快。 过五关斩六将&…

2021电赛国一智能送药小车(F题)设计报告

2021电赛国一智能送药小车&#xff08;F题&#xff09;设计报告 【写在前面的话】 电赛是一个很奇妙的过程&#xff0c;可能有些人觉得电赛的门槛太高&#xff0c;那便意味着&#xff0c;当你决定要参加电赛的那一刻起&#xff0c;这一段路、这些日子就注定不会太轻松&#xf…

顺序表——“数据结构与算法”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰的内容是数据结构与算法里面的顺序表啦&#xff0c;在我看来&#xff0c;数据结构总体上是一个抽象的东西&#xff0c;关键还是要多写代码&#xff0c;下面&#xff0c;就让我们进入顺序表的世界吧 线性表 顺序表 线性表 线性表&…

【LeetCode】剑指 Offer(25)

目录 题目&#xff1a;剑指 Offer 49. 丑数 - 力扣&#xff08;Leetcode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 写在最后&#xff1a; 题目&#xff1a;剑指 Offer 49. 丑数 - 力扣&…

【云原生】Linux进程控制(创建、终止、等待)

✨个人主页&#xff1a; Yohifo &#x1f389;所属专栏&#xff1a; Linux学习之旅 &#x1f38a;每篇一句&#xff1a; 图片来源 &#x1f383;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 Good judgment comes from experience, and a lot of that comes from bad jud…

MySQL对表操作

目录 CRUD 增加(Create) 查询&#xff08;Retrieve&#xff09; 全列查询 指定列查询 查询字段为表达式 别名 去重&#xff1a;DISTINCT 排序&#xff1a;ORDER BY 条件查询&#xff1a;WHERE 逻辑运算符&#xff1a; 修改&#xff08;Update&#xff09; 删除&…

「入门指南」轻松学习嵌入式 GPIO:从原理到应用一步到位

嵌入式系统是指在其他系统中嵌入的计算机系统&#xff0c;通常由微处理器或微控制器、内存和其他支持电路组成。嵌入式系统的应用领域非常广泛&#xff0c;涉及从智能家居设备到汽车控制系统&#xff0c;再到飞机、医疗设备等各种设备。对于嵌入式系统的应用&#xff0c;GPIO是…

我在字节当主管:百次面试结果,总结一个刷掉99%求职者的问题!

我一个在大厂当主管的朋友&#xff0c;跟我说&#xff1a;“现在招性能测试太难了&#xff0c;当然不是说没人干&#xff0c;一开招聘信息就能收到一大把简历&#xff0c;其中不乏学历亮眼、背景出色、简历里各种高并发、大流量的项目经验的人才。问题在于&#xff0c;当你提出…

【C++】模板初阶

文章目录泛型编程函数模板概念格式实例化匹配原则类模板定义格式实例化泛型编程 当我们的一个函数涉及到多个类型的处理时&#xff0c;我们就需要重载函数来实现&#xff0c;但是重载函数是存在一些局限性的。   重载函数仅仅是类型不同&#xff0c;代码的复用率较低&#xf…

【AcWing】蓝桥杯备赛-深度优先搜索-dfs(2)

目录 写在前面&#xff1a; 题目&#xff1a;94. 递归实现排列型枚举 - AcWing题库 读题&#xff1a; 输入格式&#xff1a; 输出格式&#xff1a; 数据范围&#xff1a; 输入样例&#xff1a; 输出样例&#xff1a; 解题思路&#xff1a; 代码&#xff1a; AC &…

使用new bing简易教程

申请new bing 首先先申请new bing然后等待通过&#xff0c;如下图 申请完&#xff0c;用edge浏览器&#xff0c;若有科学方法&#xff0c;就能在右上角的聊天进行向AI提问 使用插件来进行直接访问New Bing 在edge浏览器中安装一个插件&#xff0c;地址为&#xff1a;Mod…

HTML樱花飘落

樱花效果 FOR YOU GIRL 以梦为马&#xff0c;不负韶华 LOVE YOU FOREVER 实现代码 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html><head><meta http-equiv"…

Windows逆向安全(一)之基础知识(二)

反汇编分析C语言 空函数反汇编 #include "stdafx.h"//空函数 void function(){}int main(int argc, char* argv[]) {//调用空函数function();return 0; }我们通过反汇编来分析这段空函数 函数外部 12: function(); 00401048 call ILT5(func…

一款丧心病狂的API测试工具:Apifox!

你好&#xff0c;我是测试开发工程师——凡哥。欢迎和我交流测试领域相关问题&#xff08;测试入门、技术、python交流都可以&#xff09; 我们平时在做接口测试的时候&#xff0c;对于一些常用的接口测试工具的使用应该都非常熟悉了&#xff1a; 接口文档&#xff1a;Swagge…

2023年网络安全比赛--attack(新)数据包分析中职组(超详细)

一、竞赛时间 180分钟 共计3小时 任务环境说明: 1 分析attack.pcapng数据包文件,通过分析数据包attack.pcapng找出恶意用户第一次访问HTTP服务的数据包是第几号,将该号数作为Flag值提交; 2.继续查看数据包文件attack.pcapng,分析出恶意用户扫描了哪些端口,将全部的端口号…

比df更好用的命令!

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