水一篇水一篇
公司的大佬同事们,不好意思,这一期我又要水一篇了,最近实在是没时间排出来写这个,虽然想写点我司呼声比较高的微前端技术分享、私有化组件库(storybook)落地技术分享这些,但是近期休息时间紧张那就讲下大屏可视化的一些方案吧,那些下一次一定(等娃大点的)!
前因
我司某项目被乙方爸爸调戏讽刺,尽量多做些动画效果,没有动画效果是你们系统界面的通病!要多想想你们做的可是大屏呀,难道你们从来没做过大屏?整个页面都这么一个色调,五彩斑斓知不知道,这么low!
纳尼? 他想要五彩斑斓的黑? 我听到这话,咋办?
五彩斑斓
五彩斑斓的效果这里,我有几种不同的想法。这里我们先通过线性渐变实现其中一种。
翻一下线性渐变linear-gradient
的文档,很容易掌握它的用法。
先简单配一下参数
:root {
background-image: linear-gradient(45deg, aqua, blue, purple, red, orange, yellow, green);
}
复制代码
复制代码
得到如下背景:
这个色彩丰富度基本满足我的想象,但仅仅是这样还是差了点感觉,我需要让它动起来,让色彩无缝变幻最好。
动起来 1
想让背景动起来,自然而然会想到动画。但是怎么让这个渐变色随动画改变呢?
于是我尝试把这个渐变颜色放入动画关键帧里面去,但是关键帧技术并不能帮忙补足两种背景图片切换中间的过度并产生流动的感觉,于是只好调整动画时长让人眼分别不出来真假流动效果。
于是有了以下代码和动画:
虽然动起来了,而且连贯性似乎也有保证,但代价是我的眼睛快被闪瞎qaq,而且这个效果,一言难尽。
动起来 2
我想要的效果,是颜色能够缓慢而自然地过渡,类似这种: 而不是像第一个那样感觉自己进了迪厅。
那有没有一种办法既保留色彩的渐变,又能让它‘流动’起来呢?有的。
动起来 3
简单查了一下,我们可以通过放大背景图片,然后动画控制背景图片展示的位置来实现类似的效果。 这里有两个注意的点: 1. 如果加上倾斜角度,那起始和终止部分的动画无法完美对齐。所以只好改成90度或0度。 2. 线性渐变里每个颜色我都写了两遍,是为了让颜色宽度一致且首尾能完美过渡。
到这里,五彩斑斓基本就达到我的要求了,接下来需要把五彩斑斓和黑色结合起来。
五彩斑斓的黑
到了这一步,无论是把黑色蒙在五彩斑斓上面,给个较大的不透明度;还是把五彩斑斓蒙在黑色上面,给个较小的不透明度,效果都差不多。唯一的问题是,黑色是主体被突出了,辛苦弄出来的五彩斑斓看不太出来。
所以我们还需要开个口子,让五彩斑斓也能展示出来,同时不影响主体的黑色。
最好还能让这个五彩斑斓有一些质感。
一番调整,最后的成品就是这样啦:
大屏大屏
到这里我以为结束了,结果乙方爸爸说了,我要的是大屏大屏!这我不能忍,撸它,既然人家嫌弃咱们做的不对,那让人家提供点🌰让咱们学习学习也没得,怎么办?那就去网上看看别家怎么做,以下是大概比较主流的一些界面,我这直男审美是看不出有啥区别,而且我仔细观(查)摩(找)了一波,发现只有第一张图是人家实现了的,其他都还是概念图。。。
实现方案
- 直接切图去实现切片效果,但是乙方爸爸说了要动效啊!!!
- 那就只有根据canvas或者svg来实现了
Canvas、 SVG 和 WebGl三者之间的区别
[Canvas] 位图,是需要自己画点的白板;
[SVG] 矢量图,是给数据就可以绘制点、线、图形的,基于 XML 的标记语言;
[WebGL] 3D位图,是基于 Canvas 的 3D 框架。
如何使用canvas
什么是canvas
在 MDN 中是这样定义 <canvas>
的:
<canvas>
是 HTML5 新增的元素,可用于通过使用 JavaScript 中的脚本来绘制图形。例如,它可以用于绘制图形、制作照片、创建动画,甚至可以进行实时视频处理或渲染。
这里需要划重点的是,<canvas>
只是一个画布,本身并不具有绘图的能力,绘图必须使用 JavaScript 等脚本语言。
<canvas>
标签允许脚本语言动态渲染位图像。<canvas>
标签创建出了一个可绘制区域,JavaScript 代码可以通过一套完整的绘图功能类似于其他通用二维的 API 访问该区域,从而生成动态的图形。
我们可以认为 <canvas>
标签只是一个矩形的画布。JavaScript 就是画笔,负责在画布上画画。
例如,我的个人博客中的背景就是使用 Canvas 制作的。
我们审查元素可以看到整个背景就是一个 Canvas 元素,宽度和高度都是 100%。
Canvas 解决了什么问题
我在 MSDN(《Microsoft Developer Network》是微软一个期刊产品,专门介绍各种编程技巧)上找到了 Canvas 出现的背景,来给大家简单介绍一下。
在互联网出现的早期,Web 只不过是静态文本和链接的集合。1993 年,有人提出了 img
标签,它可以用来嵌入图像。
由于互联网的发展越来越迅猛,Web 应用已经从 Web 文档发展到 Web 应用程序。但是图像一直是静态的,人们越来越希望在其网站和应用程序中使用动态媒体(如音频、视频和交互式动画等),于是 Flash 就出现了。
但是随着 Web 应用的发展,出现了 HTML5,在 HTML5 中,浏览器中的媒体元素大受青睐。包括出现新的 Audio
和 Video
标签,可以直接将音频和视频资源放在 Web 上,而不需要其他第三方。
其次就是为了解决只能在 Web 页面中显示静态图片的问题,出现了 Canvas 标签。它是一个绘图表面,包含一组丰富的 JavaScript API,这些 API 使你能够动态创建和操作图像及动画。img 对静态图形内容起到了哪些作用,Canvas 就可能对可编写脚本的动态内容起到哪些作用。
一句话总结 Canvas 是什么
什么是 Canvas?Canvas 是为了解决 Web 页面中只能显示静态图片这个问题而提出的,一个可以使用 JavaScript 等脚本语言向其中绘制图像的 HTML 标签。
浏览器支持情况
Canvas 已经受到了主流浏览器的支持,并且支持情况良好,具体支持情况如下:
元素 | Chrome | IE | Firefox | Safari | Opera |
---|---|---|---|---|---|
Canvas | 4.0+ | 9.0+ | 2.0+ | 3.1+ | 9.0+ |
怎么在网页上画一个圆
通过上述的介绍,大家应该大体上明白了 <canvas>
是可以在 Web 页面上绘制图形的 HTML 标签。那么为什么要使用这种技术而不是其他的呢?
这里我们就要分析一下 canvas
和其他技术的区别了。
怎么在网页上画一个圆?这是笔者之前在面试的时候遇到的一个问题 (ಥ_ಥ)
我想到的方法有以下几种,当然,如果你有更(qí)好(jì)方(yín)式(qiǎo)也可以留言。
- 直接使用图片,如果需求只是显示一个圆形,那么可以直接使用图片。
- 使用 div + CSS3 的
border
+border-radius
模拟一个圆。 - 使用 svg。可能对于很多前端来说,svg 和 png、jpg 等其他图片格式是一样的,但其实还是有一定的差别。下面我们会详细介绍 svg。
- Canvas + JavaScript 动态画一个圆。
那么我们来分析一下以上几种方式的优劣性:
- 使用图片可以说是以上几种方式中排名倒数第一的了,因为直接使用图片首先会增加一次请求(制作成精灵图另说),其次是不易更改,如果想换一种颜色就需要更换图片,代价太大。
- 使用 div + CSS3 的方式适用于单个的圆,实现起来比较简单,代价也比较小,但增加了一个没有意义的 DOM 节点,不符合语义化编程规范。
- 使用 svg 和 Canvas 都可以使用脚本语言来动态写入一个圆。
那么,使用 svg 和 Canvas 又有什么区别呢?
svg 和 Canvas 的区别
什么是 svg
刚刚我们介绍了 Canvas,那么什么是 svg 呢?
svg(Scalable Vector Graphics,可缩放矢量图形)是基于 XML(可扩展标记语言,标准通用标记语言的子集),用于描述二维矢量图形的一种图形格式。它由 W3C(万维网联盟)制定,是一个开放标准。
简单的说就是,svg 可以用来定义 XML 格式的矢量图形。
因为其本质是 XML 文件,所以 svg 是使用 XML 文档描述来绘图的。和 HTML 一样,如果我们需要修改 svg 文件,可以直接使用记事本打开修改。
Canvas 和 svg 的区别
Canvas 和 svg都允许你在浏览器中创建图形,但是它们在根本上是不同的,那么 Canvas 和 svg 有什么根本区别呢?
就如刚刚介绍的那样,svg 本质上是一种使用 XML 描述 2D 图形的语言。
svg 创建的每一个元素都是一个独立的 DOM 元素,既然是独立的 DOM 元素,那么我们就可以通过 css 和 JavaScript 来操控 dom。可以对每一个 DOM 元素进行监听。
并且因为每一个元素都是一个 DOM 元素,所以修改 svg 中的 DOM 元素,系统会自动进行 DOM 重绘。
Canvas 通过 JavaScript 来绘制 2D 图形,Canvas 只是一个 HTML 元素,其中的图形不会单独创建 DOM 元素。因此我们不能通过 JavaScript 操控 Canvas 内单独的图形,不能对其中的具体图形进行监控。
在 Canvas 中,一旦图形被绘制完成,它就不会继续得到浏览器的关注。如果其位置发生变化,那么整个场景也需要重新绘制,包括任何或许已被图形覆盖的对象。
实际上 Canvas 是基于像素的即时模式图形系统,绘制完对象后不保存对象到内存中,当再次需要这个对象时,需要重新绘制;svg 是基于形状的保留模式图形系统,绘制完对象后会将其保存在内存中,当需要修改这个对象信息时,直接修改就可以了。这种根本的区别导致了很多应用场景的不同。
Canvas | svg |
---|---|
依赖分辨率(位图) | 不依赖分辨率(矢量图) |
单个 HTML 元素 | 每一个图形都是一个 DOM 元素 |
只能通过脚本语言绘制图形 | 可以通过 CSS 也可以通过脚本语言绘制 |
不支持事件处理程序 | 支持事件处理程序 |
弱的文本渲染能力 | 最适合带有大型渲染区域的应用程序(比如谷歌地图) |
图面较小,对象数量较大(>10k )时性能最佳 | 对象数量较小 (<10k )、图面更大时性能更佳 |
所以是选择 Canvas 还是 svg 还是需要看自己的需求。
本次分享主要介绍 Canvas 的相关内容,对 svg 不做过多的介绍~
Canvas 的应用场景
- Canvas 的介绍
- Canvas 提出的背景
- Canvas 和其他在 Web 中显示图像的技术的区别
你应该已经明白 Canvas 究竟是什么和 Canvas 的大致用途。(づ。◕‿‿◕。)づ
这一节将为你展示 30+ 个 Canvas 实例,让你感受下 Canvas 的强大作用。
绘制图表
绘制图表应该是 Canvas 最为实用的功能之一了吧(๑•̀ㅂ•́)و✧
因为 Canvas 通过 JavaScript 可以动态传入参数绘制图形,所以我们可以使用 Canvas 作为容器,通过 JavaScript 动态传入的参数将数据以图表的形式显示出来。
不仅显示更为方便,而且修改数据也同样的简单。同时也可以有一些简单的动画和交互效果,对于可视化的数据展示更为友好。
这些都是传统的 png/jpg 静态显示图片所不能比拟的。
现在的一些数据可视化的 js 库(如 ECharts)大部分都是使用 Canvas 实现的。
小游戏
如今人们使用手机的频率越来越高,因此用浏览器打开网址就可以玩的游戏越来越受到开发者和用户的喜爱。
而 Canvas 因其独特的性质可以说是 Web 游戏的不二之选,基本上所有的 HTML5 游戏引擎都是基于 Canvas 开发的。那么为什么会使用 Canvas 来开发游戏呢?
首先是因为 Canvas 不需要借助任何插件就可以在网页中绘图。并且其强大的绘图 API 可以操纵页面上的每一个元素。
下面我们来欣赏一下用 Canvas 制作的几款简单的小游戏~
这是一款小型的赛车游戏,可以使用键盘的方向键来控制赛车的行驶方向,没有按键操作,速度就会变成 0。
这是一款五子棋的小游戏,模拟五子棋游戏规则,游戏开始时一方先走,然后另一方再走,依次循环,直至一方有连成一条线的五个棋子,会自动判断输赢。
就连经典的俄罗斯方块游戏也可以使用 Canvas 来制作。也是需要通过键盘的方向键来控制方块,左右方向键是控制方块移动的方向,下键是加速下落,上键是翻转方块,直至某一行完全被填满就被消除。
还有前一段挺火的你画我猜小游戏也可以通过 Canvas 来实现。保存了鼠标的轨迹,还有清除屏幕和橡皮擦等功能。也可以将其保存为一张图片。
手残党,这个 gif 录制了好几遍(ಥ_ಥ)。 这是一款迷宫类的小游戏,同样是通过键盘的方向键来控制小球的移动,最终到达某个地点就会判定通过游戏。
活动页面
相信很多的营销活动大家都做过,Canvas 也可以写活动页面哦~(๑•̀ㅂ•́)و,✧这是很多公司的营销策略~
例如:
很常见的活动页面,某宝店铺的常见套路,模拟转盘抽奖。点击按钮,转盘转动,然后转盘停止,指针落在哪个区域就提示中奖的奖品。
另一个比较常见的活动页面是刮刮乐的页面,在刮刮乐的区域,鼠标会显示为硬币的形状,然后按住鼠标并拖动,经过区域就会显示出最底层的图片,同时上层图片消失。模拟刮刮乐效果,刮开一定比例面积之后“刮奖”完成,返回回调函数。
小特效
Canvas 还可以做一些小特效哦,这些小特效可以装饰你 的网站,使它变得更加精致~
这个特效也可以在活动页面中用到。逼真的模拟了纸片下落的过程,随机出现的纸片有随机生成的颜色,然后模拟重力下落过程。
这个其实是很不错的,只不过 gif 图片看得不是特别清楚。随机生成的大小随机的圆形或方形粒子组成指定的文字,粒子会自动缩放,给人闪烁的感觉。
这个特效也是由粒子组合成文字的特效,只不过文字的内容是当前的时间,因为是 gif 图,所以大家看不到和鼠标的交互,这里粒子散开是因为我鼠标进行了点击,就是点击屏幕,粒子就会散开,点击的时间越长,粒子就越分散。当松开鼠标之后,所有的粒子就又全部回到原位~
试想一下,如果你的个人网站中的当前时间使用了这样一个小特效,是不是会让访客觉得很有趣呢~٩(๑>◡<๑)۶
同样的小特效还有这个 loading,使用 canvas 制作一个这样的 loading,也会给你的网站增添亮点。
炫酷背景
上述几种应用场景都只是带大家了解一下,不做过多的介绍,当然也还有其他的应用场景,这里也不过多的介绍,下面来介绍下本小册主要给大家分析的效果:炫酷背景特效。
因为 Canvas 的特性,所以如果你的网站想要一个炫酷的背景,那么 Canvas 无疑是最好的选择,让我们一起来欣赏一下 canvas 可以做出哪些炫酷的背景。
这个特效是使用 three.js 和 Canvas 制作出的 3D 线条,随机生成的线条构建成 3D 的立体空间,还有和鼠标的交互,鼠标的移动会使得 3D 空间移动。
这个气泡背景也是很赞的,随机生成透明度不同的气泡,气泡不断移动,渐变色的背景也在不断变换,给人以梦幻的感觉。
这个的变换频率其实没有这么快,两次变换中间是有几秒钟的停留时间的,因为制作的 gif 大小有要求,所以中间的给截掉了,只保留变换的部分。
这个特效给人的感觉是和钻石表面类似的菱角感觉,然后背景也是使用的渐变的颜色。一定时间就会变换一次。QQ 的登录框就是和这个类似的特效。
这个背景是黑客帝国的代码雨特效,可能男程序员会比较喜欢,代码从上向下下落的效果。
我个人是很喜欢这个特效的,前一段时间也将其作为我的个人博客的背景,该特效的背景是一个渐变色,随机生成的“小星星”会从下向上移动,最重要的是和鼠标有互动。鼠标经过的地方会产生“星星”并自动和其他的星星连成线。
这个特效也是很不错的,模拟星空,随机生成的 “星星” 会有位移,透明度也在不断变化,会有 “流星” 随机从上向下掉落,并会有小尾巴的效果~
这个特效是以黑色为背景,彩色的随机实心 + 空心圆圈构成,所有的圈圈用直线相连,并且一直移动。
这个相交线特效其实也很简单,随机生成的线条在移动,相交的地方为小圆点。
创建 Canvas 画布
当我只在页面上写一个 Canvas 标签时,将其背景颜色设置为黑色,会是什么效果呢?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#canvas {
background: #000;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>
复制代码
我们打开浏览器来看一下:
在上面的例子中页面上只有一个 Canvas,没有设置宽高,那么会自动创建一个 300 * 150 的画布(单位默认为 px
)。
那么我们怎么改变画布的大小呢,有三种方式
- HTML 设置
width
、height
; - CSS 设置
width
、height
; - JS 动态设置
width
、height
。
我们来试一下这三种方式。有的人会问了,这不是很简单的么,还有介绍的必要吗?这就和我们听数学课是一样的,那些很简单的知识点你就不注意听,然后 10 分钟过后,一脸懵逼的不知道老师在讲什么,或者说是遇到问题了不知道错在哪,往往也都是基础的问题没有仔细听~
HTML 属性设置 width
、height
我们先来看一下直接使用 HTML 属性来设置 width
、height
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#canvas {
background: #000;
}
</style>
</head>
<body>
<canvas id="canvas" width="400" height="400">
</canvas>
<script>
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.beginPath();
context.arc(100, 100, 50, 0, Math.PI * 2, true);
context.closePath();
context.fillStyle = 'rgb(255,255,255)';
context.fill();
</script>
</body>
</html>
复制代码
我们设置 Canvas 画布的宽度为 400,高度为 400,背景颜色为黑色(在 HTML 属性中直接设置宽度和高度是可以不加单位的,默认单位是 px
)。在 Canvas 上画了一个圆心坐标为 100px、100px,半径为 50px 的白色的圆。来看一下浏览器中的显示效果:
CSS 属性设置 width
、height
还是上面那个例子,这次我们将宽度和高度使用 CSS 来设置:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#canvas {
background: #000;
width: 400px;
height: 400px;
}
</style>
</head>
<body>
<canvas id="canvas">
</canvas>
<script>
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.beginPath();
context.arc(100, 100, 50, 0, Math.PI * 2, true);
context.closePath();
context.fillStyle = 'rgb(255,255,255)';
context.fill();
</script>
</body>
</html>
复制代码
我们来看下浏览器中的显示效果:
OMG ヽ(;´Д`)ノ,怎么会是这个样子,我明明是要画一个圆啊,怎么变成椭圆了,是不是我代码写的有问题?
检查下代码,没问题呀o((⊙﹏⊙))o.那么为什么会显示成这个样子呢?
原来是因为如果使用 CSS 来设置宽高的话,画布就会按照 300 * 150
的比例进行缩放,也就是将 300 * 150
的页面显示在 400 * 400
的容器中。
JS 属性设置 width
、height
那我们再来看一下如果使用 JS 来设置宽高会是神马效果呢~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#canvas {
background: #000;
}
</style>
</head>
<body>
<canvas id="canvas">
</canvas>
<script>
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var cx = canvas.width = 400;
var cy = canvas.height = 400;
context.beginPath();
context.arc(100, 100, 50, 0, Math.PI * 2, true);
context.closePath();
context.fillStyle = 'rgb(255,255,255)';
context.fill();
</script>
</body>
</html>
复制代码
在浏览器中的效果如下:
这样就是正常的嘛~
所以我们尽量使用 HTML 的width
和 height
属性或者直接使用 JS 动态来设置宽高,不要使用 CSS 设置。
获取 Canvas 对象
在前面的例子中,我们已经创建了一个 Canvas 画布,那么第二步要做的就是获取到 Canvas 的上下文环境,对应的语法为: canvas.getContext(contextType, contextAttributes);
-
上下文类型(contextType):
- 2d(本小册所有的示例都是 2d 的):代表一个二维渲染上下文
- webgl(或"experimental-webgl"):代表一个三维渲染上下文
- webgl2(或"experimental-webgl2"):代表一个三维渲染上下文;这种情况下只能在浏览器中实现 WebGL 版本2 (OpenGL ES 3.0)。
第二个参数并不是经常用到,所以这里就不给大家介绍了,有兴趣的可以查阅 MDN 文档~
通常在创建好一个 Canvas 标签的时候,我们要做的第一步就是要先获取到这个 Canvas 的上下文对象:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
复制代码
绘制路径
使用过 PS 的应该都会知道在 PS 中有路径的概念,在 Canvas 中也有路径的概念。只不过和 PS 中的路径不同的是,PS 中的路径是矢量的,而 Canvas 中的路径不是。下面我们来看一下有哪些创建路径的方法:
方法 | 描述 |
---|---|
fill() | 填充路径 |
stroke() | 描边 |
arc() | 创建圆弧 |
rect() | 创建矩形 |
fillRect() | 绘制矩形路径区域 |
strokeRect() | 绘制矩形路径描边 |
clearRect() | 在给定的矩形内清除指定的像素 |
arcTo() | 创建两切线之间的弧/曲线 |
beginPath() | 起始一条路径,或重置当前路径 |
moveTo() | 把路径移动到画布中的指定点,不创建线条 |
lineTo() | 添加一个新点,然后在画布中创建从该点到最后指定点的线条 |
closePath() | 创建从当前点回到起始点的路径 |
clip() | 从原始画布剪切任意形状和尺寸的区域 |
quadraticCurveTo() | 创建二次方贝塞尔曲线 |
bezierCurveTo() | 创建三次方贝塞尔曲线 |
isPointInPath() | 如果指定的点位于当前路径中,则返回 true,否则返回 false |
看完了上述方法你是不是有点不知所措,一下子这么多方法(╬ ̄皿 ̄)=○
你可以把上面的表格作为一个“字典”,在下面的代码中如果遇到不认识的方法可以查找一下,一回生,二回熟。
下面我将上面的方法分为以下几部分来给大家介绍下。
使用 Canvas 画一个点
我们先从最基本的开始,使用 Canvas 画一个点。其实画一个点也就相当于画一个半径为 1 的圆,那我们就可以改造这一节开始的例子,将半径由 50 变为 1。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#canvas {
background: #000;
}
</style>
</head>
<body>
<canvas id="canvas">
</canvas>
<script>
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var cx = canvas.width = 400;
var cy = canvas.height = 400;
context.beginPath();
context.arc(100, 100, 1, 0, Math.PI * 2, true);
context.closePath();
context.fillStyle = 'rgb(255,255,255)';
context.fill();
</script>
</body>
</html>
复制代码
让我们来看一下效果:
有没有看到左上部分有一个白色的点,没有看到?没有看到的同学点开大图看一下(/_\)
细心的小伙伴可能会发现我们改动了哪里:
context.arc(100, 100, 1, 0, Math.PI * 2, true);
复制代码
将第三个参数由 50 改为了 1,聪明的你一定可以猜出来 arc()
这个方法的作用了。\( ̄︶ ̄)/,稍后我们再介绍 arc()
函数。
先来看一下在获取完 Canvas 的上下文环境之后,我们又做了哪些操作:
context.beginPath(); // 起始一条路径,或重置当前路径
context.arc(100, 100, 1, 0, Math.PI * 2, true); // 创建弧/曲线
context.closePath(); // 创建从当前点回到起始点的路径
context.fillStyle = 'rgb(255,255,255)'; // 设置或返回用于填充绘画的颜色、渐变或模式
context.fill(); // 填充当前绘图(路径)
复制代码
我们可以总结出,使用 Canvas 绘制图像的步骤:
通过使用 Canvas 绘制一个点,我们了解了在 Canvas 中绘图的大致步骤,下面我们来看一下刚刚提到的 arc()
方法。
绘制弧/曲线
arc()
方法创建弧/曲线(用于创建圆或部分圆)。
context.arc(x,y,r,sAngle,eAngle,counterclockwise);
复制代码
- x:圆心的 x 坐标
- y:圆心的 y 坐标
- r:圆的半径
- sAngle:起始角,以弧度计(弧的圆形的三点钟位置是 0 度)
- eAngle:结束角,以弧度计
- counterclockwise:可选。规定应该逆时针还是顺时针绘图。false 为顺时针,true 为逆时针
比如我们想画一个顺时针的四分之一圆,应该怎么写呢?
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var cx = canvas.width = 400;
var cy = canvas.height = 400;
context.beginPath();
context.arc(100, 100, 50, 0, Math.PI * 0.5, false);
context.strokeStyle="white";
context.stroke();
复制代码
我们先来看一下浏览器中的效果:
是不是你想要的效果呢(๑´ㅂ`๑)
其实只要找好起始角和结束角就成功一半了呢。
因为我们设置的起始角是 0,对照 w3cschool 上的截图可知弧度的 0 的位置是 3 点钟方向,然后结束角我们设置为 0.5 PI,也就是 6 点钟方向,然后我们再设置描边颜色并且进行描边,就得出上图的效果。
这里你可能会问,为什么这个不是闭合的图形呢?因为我只设置了 beginPath 并没有设置 closePath,所以这就不是一条闭合的路径。我们加上 closePath 看一下效果。
如果跟着我一起写代码的话你就会发现,这个是空心的,并没有整个路径都被填充,这是怎么回事呢?
这是因为 stroke()
和 fill()
的区别,根据上面的两个例子,我们很容易看出这两个函数的区别:一个是描边,一个是填充。
stroke()
:描边fill()
:填充
我们可以通过 strokeStyle
属性 和 fillStyle
属性来设置描边和填充的颜色。这里不仅可以设置单一的颜色,还可以设置渐变。
绘制直线
下面我们来绘制一条线。
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var cx = canvas.width = 400;
var cy = canvas.height = 400;
context.beginPath();
context.moveTo(50,50);
context.lineTo(100,100);
context.strokeStyle = '#fff';
context.stroke();
复制代码
我们来看一下浏览器中的效果:
在绘制直线的例子中,我们使用了
moveTo(x,y)
:把路径移动到画布中的指定点,不创建线条lineTo(x,y)
:添加一个新点,然后在画布中创建从该点到最后指定点的线条
这里需要注意以下几点:
- 如果没有 moveTo,那么第一次 lineTo 的就视为 moveTo
- 每次 lineTo 后如果没有 moveTo,那么下次 lineTo 的开始点为前一次 lineTo 的结束点。
也就是这种情况:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var cx = canvas.width = 400;
var cy = canvas.height = 400;
context.beginPath();
context.lineTo(200, 200);
context.lineTo(200, 100);
context.lineTo(100,50);
context.strokeStyle = '#fff';
context.stroke();
复制代码
我们没有设置 moveTo,而是设置了三个 lineTo,这也是可以的,将三个 lineTo 设置的点依次连接就好~
效果如下:
在绘制了直线之后,我们来看一下怎么给绘制的直线添加样式:
样式 | 描述 |
---|---|
lineCap | 设置或返回线条的结束端点样式 |
lineJoin | 设置或返回两条线相交时,所创建的拐角类型 |
lineWidth | 设置或返回当前的线条宽度 |
miterLimit | 设置或返回最大斜接长度 |
我们来看下这些 属性 是怎么使用的。
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var cx = canvas.width = 400;
var cy = canvas.height = 400;
context.beginPath();
context.moveTo(10,10);
context.lineTo(100,100);
context.lineWidth = 10;
context.lineCap = 'round';
context.strokeStyle = '#fff';
context.stroke()
复制代码
我绘制了一条由点 (10,10) 到点 (100,100) 的直线,然后将其宽度设置为 10,并且加上“圆角”的效果。
这里我们要注意区分哪些是方法哪些是属性,如果是方法,只需要在括号中传入参数就可以;如果是属性,那么我们就要使用等号给其赋值。有的时候你会奇怪,为什么我这么设置了但是却没有效果呢?很有可能是你将方法和属性搞混了哦 (●゚ω゚●)
绘制矩形
在了解了最基本的绘制点、线的方法之后,我们来看一下如何绘制一个矩形。
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var cx = canvas.width = 400;
var cy = canvas.height = 400;
context.beginPath();
context.fillStyle = '#fff';
context.fillRect(10, 10, 100, 100);
context.strokeStyle = '#fff';
context.strokeRect(130, 10, 100, 100);
复制代码
这里我们使用下面的方法:
fillRect(x,y,width,height)
:绘制一个实心矩形strokeRect(x,y,width,height)
:绘制一个空心矩形
同样的,我们可以通过 fillStyle()
和 strokeStyle()
来设置填充的颜色和描边的颜色。
颜色、样式和阴影
上面几个函数教大家怎么绘制点、线、以及圆形和矩形,都是通过先创建路径,然后再使用 fill()
或 stroke()
进行填充或者描边。
下面我们再具体看一下都可以给路径设置哪些属性来改变其样式。
属性 | 描述 |
---|---|
fillStyle | 设置或返回用于填充绘画的颜色、渐变或模式 |
strokeStyle | 设置或返回用于笔触的颜色、渐变或模式 |
shadowColor | 设置或返回用于阴影的颜色 |
shadowBlur | 设置或返回用于阴影的模糊级别 |
shadowOffsetX | 设置或返回阴影距形状的水平距离 |
shadowOffsetY | 设置或返回阴影距形状的垂直距离 |
fillStyle
和 strokeStyle
这两个属性我们一直在使用,所以对于它们我们不再作过多的介绍。
设置阴影
设置阴影我们用到的是 shadowBlur
这个属性。
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var cx = canvas.width = 400;
var cy = canvas.height = 400;
context.beginPath();
context.arc(100,100,50,0,2*Math.PI,false);
context.fillStyle = '#fff';
context.shadowBlur = 20;
context.shadowColor = '#fff';
context.fill()
复制代码
同样的方(tao)法(lu),我们只要在 fill()
方法之前设置模糊指数(shadowBlur
)和颜色(shadowColor
)就可以了。让我们来看一下浏览器中的效果:
在暗色背景中有一个亮色的圆并且加了阴影效果,是不是很像发光的月亮呢(●´∀`●)ノ
设置渐变
我们先来看一下怎么设置渐变:
方法 | 描述 |
---|---|
createLinearGradient() | 创建线性渐变(用在画布内容上) |
createPattern() | 在指定的方向上重复指定的元素 |
createRadialGradient() | 创建放射状/环形的渐变(用在画布内容上) |
addColorStop() | 规定渐变对象中的颜色和停止位置 |
其中绘制渐变主要用到了 createLinearGradient()
方法,我们来看一下这个方法: context.createLinearGradient(x0,y0,x1,y1);
- x0:开始渐变的 x 坐标
- y0:开始渐变的 y 坐标
- x1:结束渐变的 x 坐标
- y1:结束渐变的 y 坐标
这是设置比如说我们下一个粉色到白色的由上向下的渐变:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var cx = canvas.width = 400;
var cy = canvas.height = 400;
var grd = context.createLinearGradient(100,100,100,200);
grd.addColorStop(0,'pink');
grd.addColorStop(1,'white');
context.fillStyle = grd;
context.fillRect(100,100,200,200);
复制代码
我们看一下浏览器中的效果:
可以看出,createLinearGradient()
的参数是两个点的坐标,这两个点的连线实际上就是渐变的方向。我们可以使用 addColorStop()
方法来设置渐变的颜色。
gradient.addColorStop(stop,color);
:
stop
:介于 0.0 与 1.0 之间的值,表示渐变中开始与结束之间的位置color
:在结束位置显示的 CSS 颜色值
我们可以设置多个颜色断点,比如,要实现一个彩虹的效果,只需要多增加几个颜色断点就可以了~
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var cx = canvas.width = 400;
var cy = canvas.height = 400;
var grd = context.createLinearGradient(0,0,0,400);
grd.addColorStop(0,'rgb(255, 0, 0)');
grd.addColorStop(0.2,'rgb(255, 165, 0)');
grd.addColorStop(0.3,'rgb(255, 255, 0)');
grd.addColorStop(0.5,'rgb(0, 255, 0)');
grd.addColorStop(0.7,'rgb(0, 127, 255)');
grd.addColorStop(0.9,'rgb(0, 0, 255)');
grd.addColorStop(1,'rgb(139, 0, 255)');
context.fillStyle = grd;
context.fillRect(0,0,400,400);
复制代码
效果如下:
图形转换
在了解完了最基本的绘制路径和设置样式之后,我们来看一下怎么来进行图形的变换。
我们先来看一下图形转换都有哪些方法:
方法 | 描述 |
---|---|
scale() | 缩放当前绘图至更大或更小 |
rotate() | 旋转当前绘图 |
translate() | 重新映射画布上的 (0,0) 位置 |
transform() | 替换绘图的当前转换矩阵 |
setTransform() | 将当前转换重置为单位矩阵,然后运行 transform() |
缩放
我们来看一下怎么使用 Canvas 实现缩放的功能,绘制一个矩形;放大到 200%,再次绘制矩形;放大到 200%,然后再次绘制矩形;放大到 200%,再次绘制矩形:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var cx = canvas.width = 400;
var cy = canvas.height = 400;
context.strokeStyle = 'white';
context.strokeRect(5,5,50,25);
context.scale(2,2);
context.strokeRect(5,5,50,25);
context.scale(2,2);
context.strokeRect(5,5,50,25);
复制代码
只是使用 scale()
方法就可以实现缩放的效果,我们再来看一下浏览器中的显示情况:
可以看到,在设置 scale()
方法之后再设置的矩形,无论是线条的宽度还是坐标的位置,都被放大了。并且 scale()
的效果是可以叠加的,也就是说,我们在上面的例子中使用了两次 scale(2,2)
那么,最后一个矩形相对于第一个矩形长和宽,以及坐标的位置就放大了 4 倍。
旋转
其实在图形变换中,只要掌握了一种,其他的图形变换方式就会迎刃而解了。我们再来看一下旋转的例子吧。
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var cx = canvas.width = 400;
var cy = canvas.height = 400;
context.fillStyle = 'white';
context.rotate(20*Math.PI/180);
context.fillRect(70,30,200,100);
复制代码
我们使用的是 rotate()
方法 context.rotate(angle);
angle
: 旋转角度,以弧度计。 如需将角度转换为弧度,请使用degrees*Math.PI/180
公式进行计算。 举例:如需旋转 5 度,可规定下面的公式:5*Math.PI/180
。
在刚刚的例子中,我们将画布旋转了 20°,然后再画了一个矩形。
通过上述两个例子,我们会发现一个特点,在进行图形变换的时候,我们需要画布旋转,然后再绘制图形。
这样的结果是,我们使用的图形变换的方法都是作用在画布上的,既然对画布进行了变换,那么在接下来绘制的图形都会变换。这点是需要注意的。
比如我对画布使用了 rotate(20*Math.PI/180)
方法,就是将画布旋转了 20°,然后之后绘制的图形都会旋转 20°。
图像绘制
Canvas 还有一个经常用的方法是drawImage()
。
方法 | 描述 |
---|---|
drawImage() | 向画布上绘制图像、画布或视频 |
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
img
:规定要使用的图像、画布或视频sx
:可选。开始剪切的 x 坐标位置sy
:可选。开始剪切的 y 坐标位置swidth
:可选。被剪切图像的宽度sheight
:可选。被剪切图像的高度x
:在画布上放置图像的 x 坐标位置y
:在画布上放置图像的 y 坐标位置width
:可选。要使用的图像的宽度(伸展或缩小图像)height
:可选。要使用的图像的高度(伸展或缩小图像)
经过上面对 Canvas 常见方法的介绍,相信你也可以绘制一些基本的图形了,你看到的那些炫酷的效果都是由这些简单的图形构成的。 以上基本算是canvas入门了,怎么去实现炫酷背景特效,如粒子特效那些,手写? 不不不,百度找现成的,还有现在那么多现成库~~
网上搜集的常见特效库
动画能使我们以独特的方式讲述故事并传达情感和想法。这里有 30 个 JavaScript 动画库可供我们在今后的项目中使用。
- Greensock 地址:greensock.com/ 用于构建适用于所有主流浏览器的高性能动画的 JavaScript 库。
- Velocity.js 地址:velocityjs.org/Velocity 是一个轻量级动画引擎,其 API 与 jQuery 的 $.animate() 相同。
- Lax.js 地址:github.com/alexfoxy/la… javascript 插件,可在您滚动时创建流畅美观的动画!
- Rellax.js 地址:github.com/dixonandmoe… javascript 视差库。
- three.js 地址:github.com/mrdoob/thre… 3D 库,带有默认的 WebGL 渲染器。
- wow.js 地址:wowjs.uk/滚动时显示动画。
- Chocolat.js 地址:chocolat.insipi.de/免费灯箱插件。
- Animate on Scroll 地址:michalsnik.github.io/aos/滚动库上的动画…
- Tilt.js 地址:gijsroge.github.io/tilt.js/一个微… requestAnimationFrame 为 jQuery 提供了 60+fps 的轻量级视差悬停倾斜效果。
- Rough Notation 地址:roughnotation.com/Rough Notation 是一个小型 JavaScript 库,用于在网页上创建和动画注释。
- tsParticles 地址:particles.matteobruni.it/一个用于创建粒子的轻量…
- Particles.js 地址:vincentgarreau.com/particles.j… JavaScript 库。
- mo.js 地址:mojs.github.io/用于 Web 的动态图形工具带。
- Lightbox2 地址:lokeshdhakar.com/projects/li… JS 库,用于在当前页面顶部覆盖图像。
- Slick 地址:kenwheeler.github.io/slick/完全响应式…
- Barba.js 地址:barba.js.org/在你的网站页面之间创建…
- Locomotive Scroll 地址:locomotivemtl.github.io/locomotive-…
- Simple Parallax 地址:simpleparallax.com/使用 javascript 获得视差效果的最简单方
- Kute.js 地址:thednp.github.io/kute.js/KUT… 是一个适用于现代浏览器的 JavaScript 动画引擎。
- Granim.js 地址:sarcadass.github.io/granim.js/i… javascript 库创建流畅的交互式渐变动画。
- Popmotion 地址:popmotion.io/用于令人愉悦的用户界面…
- Vivus**地址:maxwellito.github.io/vivus/Vivus 是一个轻量级的 JavaScript 类(没有依赖项),它允许你对 SVG 进行动画处理,使它们看起来像是被绘制的。
- Typed.js 地址:mattboldt.com/demos/typed… 打字动画库。
- ProgressBar.js 地址:kimmobrunfeldt.github.io/progressbar… SVG 路径的响应式和流畅的进度条。
- Anime.js 地址:animejs.com/具有简单但功能强大的 API 的轻量级 JavaScript 动画库。
- AniJS 地址:anijs.github.io/无需编码即可提升您的网…
- Remotion 地址:www.remotion.dev/这个库本身不是一个动画… JavaScript 代码来制作视频。
正题 使用开源库data-view
DataV 此DataV非彼阿里的DataV,阿里的是收费的,这个是开源的,你甚至可以自己fork下来自己各种魔改! 具体使用方式以及需要踩的坑自行看文档吧,文档还是说的很详细