您当前的位置:首页 > 电脑百科 > 程序开发 > 移动端 > H5

Canvas从入门到实战

时间:2022-12-24 15:33:32  来源:今日头条  作者:闪念基因


 

1、什么是Canvas?

html5 提供Canvas API,其本质上是一个DOM元素,可以看成是浏览器提供一块画布供我们在上面渲染2D或者3D图形。由于3D绘制上下文(webgl)目前在很多浏览器上兼容性较差,所以我们一般用于绘制2D图形。

2、为什么使用Canvas?

canvas是HTML5引入的标签,在此之前我们通常会使用SVG来绘制一些图形,那么两者之间有什么区别呢?SVG可缩放矢量图形(Scalable Vector Graphics)是基于可扩展标记语言XML描述的2D图形的语言,两者部分区别:

 

  • SVG 图像是使用各种元素创建的,这些元素分别应用于矢量图像的结构、绘制与布局;而Canvas本身并不描述图像,而是通过JAVAscript完成绘制;
  • 如上所述,SVG本身是DOM元素,每一个描述元素也是DOM元素,浏览器在进行渲染时需要进行大量计算以处理每一个元素;而在渲染Canvas的过程中,浏览器只需要渲染一张画布,其余的是通过JavaScript引擎执行逻辑来绘制;
  • SVG(矢量图)不依赖分辨率,放大不会失真;而Canvas(位图)依赖分辨率,放大会失真;

 

由于Canvas是通过Javascript来完成绘制的,所以可控性很强,我们可以比较精确的控制图形渲染的每一帧;从另一方面来说,如果在高频率渲染中要处理过多的DOM元素就意味着性能一定不会太好,渲染速度会下降很多。Canvas的高性能能够保障复杂场景中图形的渲染效率,所以目前很多领域都会使用Canvas,例如动画、游戏图形、数据可视化、照片处理和实时视频处理等。


3、Canvas的基本使用

要使用Canvas,我们需要先获取Canvas元素的引用继而通过getContext()方法获取图形的绘制上下文。

const canvas = document.getElementById('canvas')const ctx = canvas.getContext('2d')

获取到图形绘制上下文后,我们就能使用CanvasRenderingContext2D接口上的绘图API了,接下来我们可以了解一些比较常规的使用。

3.1、画布属性:

 

  • width、height:画布的宽度以及高度,默认大小为300x150;
  • fillStyle:填充图形的样式,值可以是color string、CanvasGradient对象;
  • strokeStyle:轮廓图形的样式,值可以是color string、CanvasGradient对象;
  • lineWidth:绘制线条的宽度;
  • globalAlpha:画布的透明度,0-1的偏移值;
  • globalCompositeOperation:画布中新老图形重叠时的渲染方式,默认为source-over,新图形覆盖老图形;
  •  
ctx.width = 300ctx.height = 300ctx.fillStyle = '#fff'ctx.strokeStyle = 'blue'ctx.lineWidth = 5ctx.globalAlpha = 0.3ctx.globalCompositeOperation = 'destination-out' // 新老图形重叠部分变透明

 

3.2、绘制图形:

 

  • .fillRect(x,y,width,height):绘制一个填充的矩形,矩形左上角的坐标为(x,y),高宽分别为width、height;
  • .strokeRect(x,y,width,height):绘制一个矩形边框,矩形左上角的坐标为(x,y),高宽分别为width、height;
  • .clearRect(x,y,width,height):清除指定矩形区域,让清除部分完全透明;
ctx.fillStyle = 'red'ctx.fillRect(100,100,100,100)ctx.strokeStyle = 'blue'ctx.strokeRect(200,200,100,100)ctx.clearRect(125,125,50,50)ctx.strokeRect(130,130,40,40)

 


 

3.3、绘制路径:

 

  • .beginPath():开始一段路径的绘制;
  • .closePath():从起始点到当前点,结束路径的绘制,非必需;
  • .fill():根据路径生成填充图形;
  • .stroke():通过路径生成轮廓图形;
  • .moveTo(x,y):声明一段路径的起始点;
  • .l.NETo(x,y):绘制一条从当前坐标到(x,y)的线;
ctx.beginPath()ctx.moveTo(50,50)ctx.lineTo(100,100)ctx.lineTo(100,0)ctx.fill()ctx.beginPath()ctx.moveTo(110,100)ctx.lineTo(150,100)ctx.lineTo(150,200)ctx.lineTo(110,200)ctx.closePath() // 轮廓图形不会根据从当前坐标到起始坐标生成轮廓,所以需要闭合路径ctx.stroke()

 


 

3.4、绘制圆弧:

 

  • .arc(x,y,radius,startAngle,endAngle,anticlockwise):画一个以(x,y)为圆心的以 radius 为半径的圆弧(圆),从 startAngle 开始到 endAngle 结束,按照 anticlockwise 给定的方向(默认为顺时针,false)来生成;
  • arcTo(x1,y1,x2,y2,radius):根据给定的两条切线中的一组切点坐标生成半径为radius的圆弧;

 


 

注意:arc函数中的角度的单位是弧度而不是度,弧度=(Math.PI/180)*度

// 圆左上部分ctx.beginPath()ctx.arc(100,100,50,Math.PI,Math.PI*3/2,false)ctx.strokeStyle = '#ff6700'ctx.stroke()// 圆右上部分ctx.beginPath()ctx.arc(100,100,50,Math.PI*3/2,0,false)ctx.strokeStyle = '#6700ff'ctx.stroke()// 圆右下部分ctx.beginPath()ctx.arc(100,100,50,0,Math.PI/2,false)ctx.strokeStyle = '#00FFFF'ctx.stroke()// 圆左下部分ctx.beginPath()ctx.arc(100,100,50,Math.PI/2,Math.PI,false)ctx.strokeStyle = '#8B008B'ctx.stroke()// 两条切线的交点坐标为(0,0)ctx.beginPath()ctx.moveTo(100,0)ctx.arcTo(0,0,0,100,100)ctx.fillStyle = 'blue'ctx.fill()

3.5、渐变对象:

 

  • .createLinearGradient(x1, y1, x2, y2):创建一个沿参数坐标指定的直线的渐变,开始坐标为(x1,y1),结束坐标为(x2,y2);
  • .createRadialGradient(x1, y1, r1, x2, y2, r2):创建根据参数确定两个圆的坐标的放射性渐变,开始圆形圆心为(x1,y1),半径为r1;结束圆形圆心为(x2,y2),半径为r2;

 

创建好渐变对象之后,可以通过渐变对象上的.addColorStop(offset,color)为每一个渐变阶段填充颜色,offset为0-1的偏移值。

const gradient = ctx.createLinearGradient(50, 50, 250, 50)gradient.addColorStop(0, 'blue')gradient.addColorStop(0.5, 'green')gradient.addColorStop(1, 'red')ctx.fillStyle = gradientctx.fillRect(0, 0, 300, 90)const radialGradient = ctx.createRadialGradient(200,200,100,200,200,50);radialGradient.addColorStop(0,"yellow");radialGradient.addColorStop(1,"green");ctx.fillStyle = radialGradient;ctx.fillRect(100,100,200,200);

3.6、像素操作:

 

  • .drawImage(image,x,y,width,height):image可以是image对象、canvas元素、video元素;
  • .getImageData(x,y,width,height):获取坐标为(x,y)一定区域内图像的像素数据;
const div = document.querySelector('div')let mousedown = false;function getRandom() {return Math.round(255 * Math.random());function getColor() {return `rgb(${getRandom()},${getRandom()},${getRandom()})`;const gradient = ctx.createLinearGradient(0, 0, 300, 300);gradient.addColorStop(0, getColor());gradient.addColorStop(0.6, getColor());gradient.addColorStop(1, getColor());function clear() {ctx.fillStyle = gradient;ctx.fillRect(0, 0, canvas.width, canvas.height);ctx.beginPath();ctx.fillStyle = gradient;ctx.fillRect(0, 0, 300, 300);function selector(x = 150, y = 150) {clear();ctx.beginPath();ctx.arc(x, y, 5, 0, Math.PI * 2);ctx.strokeStyle = "#fff";ctx.stroke();const { data } = ctx.getImageData(x, y, 1, 1); // 获取(x,y)点对应的imageDataconst color = `rgba(${data[0]},${data[1]},${data[2]},${data[3] / 255})`div.innerText = `color: ${color}`;div.style.backgroundColor = colorfunction handleSelector(e) {const x = e.offsetX;const y = e.offsetY;selector(x, y);canvas.addEventListener("mousedown", (e) => {mousedown = true;handleSelector(e)canvas.addEventListener("mouseup", () => {mousedown = false;canvas.addEventListener("mousemove", (e) => {if (mousedown) {handleSelector(e)selector();

 

3.7、画布状态:

 

  • .save():将当前画布的状态推入到栈中,例如fillStyle、2D转换等;
  • .restore():将栈顶元素弹出,恢复上一次推入栈中画布的状态;

 

当我们需要通过空间转换来绘制图形时,保存与恢复画布的状态是很关键的,因为我们是在同一块画布上绘制图形,而变换都是基于画布的,这与我们平时使用到的css 2D转换截然不同,所以我们在下一步绘制时要确认此时画布的状态是否是我们的理想状态。

ctx.save() // 保存画布初始状态ctx.translate(100,100) // 将画布原点转移至(100,100)ctx.fillStyle = 'red'ctx.fillRect(0,0,50,50)ctx.restore() // 恢复画布状态,此时画布原点为(0,0)ctx.fillStyle = 'blue'ctx.fillRect(0,0,50,50)

3.8、几何变化:

 

  • .translate(x,y):画布默认的原点是(0,0),此方法可以切换原点到(x,y)而不需要手动更改绘制图形的坐标;
  • .rotate(angle):将画布旋转一定的角度,angle单位为弧度;
  • .scale(sx,sy):sx为水平方向的缩放比例,sy为竖直方向的缩放比例;
  • .transform(a,b,c,d,e,f):依次为水平缩放、垂直倾斜、水平倾斜、垂直缩放、水平移动、垂直移动;

 

const colors = ['red','orange','yellow','green','blue','purple'];ctx.translate(150,150)for(let i = 0; i < 6; i++) {ctx.beginPath()ctx.fillStyle = colors[i]ctx.moveTo(0,0)ctx.lineTo(100,0)ctx.lineTo(100,50)ctx.rotate(Math.PI/3)ctx.fill()


 

4、综合实战

const p = Math.PI;function clock() {const date = new Date();const hour = date.getHours()const s = date.getSeconds();const m = date.getMinutes();const h = !!(hour % 12) ? hour % 12 : 12;ctx.clearRect(0, 0, canvas.width, canvas.height);ctx.save(); // 保存画布初始状态ctx.translate(150, 150);ctx.rotate(-p / 2);// 轮廓ctx.beginPath();ctx.lineWidth = 5;ctx.strokeStyle = "#76b2ff";ctx.arc(0, 0, 80, 0, p * 2);ctx.stroke();// 圆心ctx.beginPath();ctx.arc(0, 0, 2, 0, p * 2);ctx.fill();// 分针、秒针刻度for (let i = 0; i < 60; i++) {ctx.beginPath();ctx.rotate(p / 30);ctx.moveTo(75, 0);ctx.lineWidth = 4;ctx.strokeStyle = "#89f086";ctx.lineTo(80, 0);ctx.stroke();// 时针刻度for (let i = 0; i < 12; i++) {ctx.beginPath()ctx.rotate(p / 6)ctx.moveTo(70, 0)ctx.lineTo(80, 0)ctx.stroke()ctx.save(); // 保存画布变换之后的状态// 秒针ctx.beginPath();ctx.rotate(s * (p / 30));ctx.lineWidth = 2ctx.strokeStyle = '#ff6700'ctx.moveTo(0, 0);ctx.lineTo(80, 0);ctx.stroke();// 恢复之前的状态再保存,时针、分针、秒针都是基于原点以及画布方向变换后绘制ctx.restore();ctx.save();// 分针ctx.beginPath();ctx.rotate(m * (p / 30));ctx.lineWidth = 3;ctx.strokeStyle = '#6700ff'ctx.moveTo(0, 0);ctx.lineTo(70, 0);ctx.stroke();ctx.restore();// 时针ctx.beginPath();ctx.rotate(h * (p / 6));ctx.lineWidth = 4;ctx.moveTo(0, 0);ctx.lineTo(60, 0);ctx.stroke();ctx.restore(); // 恢复画布最初状态document.querySelector('div').innerText = `Now:${h} : ${m} : ${s} ${hour > 12 ? 'pm' : 'am'}`window.requestAnimationFrame(clock);clock();


 

5、小结

随着互联网的高速发展,用户对页面的视觉和交互有着越来越高的要求,传统的web开发无法得到满足,利用Canvas强大的绘图能力,可以让网页显示的内容更加的丰富多彩,也能给用户带来更好的视觉体验。

作者:LLS-FE团队

出处:https://mp.weixin.qq.com/s/bvkx3wOeMvIUU64cktX6iA



Tags:Canvas   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
浅谈 Canvas 渲染引擎设计
当渲染层 JS 资源加载完成后,直接省略反序列化、初始化 Model、计算排版数据等阶段,将 FVG 转换成 Widget 进行 Canvas 渲染,这一步非常接近于 React 的 hydrate,很巧妙。用过 C...【详细内容】
2023-02-28  Search: Canvas  点击:(120)  评论:(0)  加入收藏
Canvas从入门到实战
1、什么是Canvas?HTML5 提供Canvas API,其本质上是一个DOM元素,可以看成是浏览器提供一块画布供我们在上面渲染2D或者3D图形。由于3D绘制上下文(webgl)目前在很多浏览器上兼...【详细内容】
2022-12-24  Search: Canvas  点击:(223)  评论:(0)  加入收藏
使用 JavaScript 和 HTML5 Canvas 绘制图表
你将要创造什么在本教程中,我将向您展示如何使用 JavaScript 和画布以饼图和圆环图的形式显示数字信息。什么是饼图?图表是一种统计工具,用于以图形方式表示数值数据。饼图将...【详细内容】
2022-08-31  Search: Canvas  点击:(505)  评论:(0)  加入收藏
Zerker 一个简单又灵活的 flutter canvas 图形动画库
《开源精选》是我们分享Github、Gitee等开源社区中优质项目的栏目,包括技术、学习、实用与各种有趣的内容。本期推荐的是一个简单又灵活的 flutter canvas 图形动画库Zerker...【详细内容】
2022-02-11  Search: Canvas  点击:(1216)  评论:(0)  加入收藏
HTML5 绘图技术 「Canvas」和「SVG」
本文重点还是要介绍Canvas,但每次提起Canvas,脑海总会想起SVG,因此先做个简单的对比。 &emsp;*Canvas 和 SVG 对比&emsp;Canvas 和 SVG 都是 HTML5 中推荐的也是主要的2D图形绘...【详细内容】
2020-08-10  Search: Canvas  点击:(393)  评论:(0)  加入收藏
基于canvas的JavaScript 二维码生成工具——QRCanvas
介绍在我们日常的开发中,特别是在现代的社会环境下,二维码的应用可谓是丰富多彩,各种各样让人眼花缭乱的二维码,可见二维码已经渗透进我们生活的方方面面,也可以说目二维码确确实...【详细内容】
2020-07-27  Search: Canvas  点击:(445)  评论:(0)  加入收藏
▌简易百科推荐
京东快递H5项目接入vite实战
本文介绍了如何在开发阶段将vite应用于vue 2.x 工程,从而提高研发的开发体验与效率。主要涉及如何兼容process变量,如何处理 node-sass 与 dart-sass冲突,以及路径别名的兼容处...【详细内容】
2023-03-17  东东程序猿  今日头条  Tags:H5   点击:(234)  评论:(0)  加入收藏
什么是HTML5?HTML5的含义、元素和好处
译者 | 李睿审校 | 孙淑娟HTML5是超文本标记语言(HTML)的第五版,网络浏览器使用它来可视化代码。它在网站功能、网页内容开发等方面有一些改进。 ​HTML的发展 ​在万维网的...【详细内容】
2023-03-16  李睿  51CTO  Tags:HTML5   点击:(262)  评论:(0)  加入收藏
H5直播技术起航
作者:京东科技 吴磊音视频基本概念视频格式就是通常所说的.mp4,.flv,.ogv,.webm等。简单来说,它其实就是一个盒子,用来将实际的视频流以一定的顺序放入,确保播放的有序和完整性...【详细内容】
2023-01-10  京东云开发者  今日头条  Tags:H5   点击:(241)  评论:(0)  加入收藏
Canvas从入门到实战
1、什么是Canvas?HTML5 提供Canvas API,其本质上是一个DOM元素,可以看成是浏览器提供一块画布供我们在上面渲染2D或者3D图形。由于3D绘制上下文(webgl)目前在很多浏览器上兼...【详细内容】
2022-12-24  闪念基因  今日头条  Tags:Canvas   点击:(223)  评论:(0)  加入收藏
网站程序开发使用的html5你了解吗
首先可以肯定,html5(简称h5)将在很多年内成为互联网的主流。那到底什么是h5呢?想了解h5,先要了解它的前身html和被它终结的flash:2000年左右的前端静态网页格式是html的,仅支持ie,n...【详细内容】
2022-09-26  易企优     Tags:html5   点击:(499)  评论:(0)  加入收藏
使用 JavaScript 和 HTML5 Canvas 绘制图表
你将要创造什么在本教程中,我将向您展示如何使用 JavaScript 和画布以饼图和圆环图的形式显示数字信息。什么是饼图?图表是一种统计工具,用于以图形方式表示数值数据。饼图将...【详细内容】
2022-08-31  兴趣编程网  今日头条  Tags:   点击:(505)  评论:(0)  加入收藏
一看就能学会的H5视频推流方案
环境部署1、 配置、安装 Nginx;# ./configure --sbin-path=/usr/local/nginx/nginx --conf-path=/usr/local/nginx/nginx.pid --with-http_ssl_module --with-pcre=/usr/loca...【详细内容】
2022-08-27  音视频开发老舅    Tags:H5   点击:(619)  评论:(0)  加入收藏
H5实时解码音频并播放
音视频的格式是一个有歧义的说法。我们熟知的诸如Flv、Mp4、Mov啥的都是包装格式,可以理解为一种容器,就像一个盒子。里面放到是经过编码的音视频数据,而这些音视频数据都有自...【详细内容】
2022-08-17  音视频开发老舅    Tags:音频   点击:(686)  评论:(0)  加入收藏
实战演示 H5 性能分析
W3C标准是浏览器标准,一般浏览器都支持W3C标准,它规定使用者可以通过api查询性能信息,可借用W3C协议完成自动化H5性能测试。 W3C官网: https://www.w3.org/TR/navigation-timing...【详细内容】
2022-06-06  CeshirenTester    Tags: H5   点击:(329)  评论:(0)  加入收藏
HTML5新特性
①语义化标签,可以让页面有更加完善的结构,让页面的元素有含义,同时利于被搜索引擎解析,有利于SEO,主要标签包括下面的标签:html5新的常用标签②增强型表单可以通过input的type属...【详细内容】
2022-05-07  Celinf    Tags:HTML5   点击:(415)  评论:(0)  加入收藏
站内最新
站内热门
站内头条