概念
canvas 是 HTML5 提供的一个用于展示绘图效果的标签. canvas 原意画布, 帆布. 在 HTML 页面中用于展示绘图效果. 最早 canvas 是苹果提出的一个方案, 今天已经在大多数浏览器中实现.
基本语法
1. 使用 canvas 标签, 即可在页面中开辟一格区域. 可以设置其 width 和 height 设置该区域的尺寸.
2. 默认 canvas 的宽高为 300 和 150.
3. 不要使用 CSS 的方式设置宽高, 应该使用 HTML 属性. "使用前者,可能会出现拉伸的问题"
4. 如果浏览器不支持 canvas 标签, 那么就会将其解释为 div 标签. 因此常常在 canvas 中嵌入文本, 以提示用户浏览器的能力.
5. canvas 的兼容性非常强, 只要支持该标签的, 基本功能都一样, 因此不用考虑兼容性问题.
6. canvas 本身不能绘图. 是使用 JavaScript 来完成绘图. canvas 对象提供了各种绘图用的 api.
canvas是一个用来展示绘图效果的标签,它和img类似,都是行内块元素,同一个页面可以拥有多个canvas标签
Canvas的使用领域
canvas 的使用领域很多:
- 游戏
- 可视化数据(重点)
- banner 广告
- 多媒体
- 未来
- 模拟仿真
- 远程操作
- 图形编辑
上下文工具
Canvas与上下文
"Canvas <==> 画板"
"上下文 <==> 绘图工具: 笔,填充物,涂改工具等等"
需要绘图就需要有 canvas 标签, 该标签用于展示图像.
但是 canvas 只是展示图像的标签, 它没有绘图的能力. 需要使用 canvas 的上下文工具来实现绘图.
绘图相关的所有API,都是ctx的
语法:
1. 获得 canvas 标签对象.
2. 调用 getContext 方法,
如果是绘制平面图形使用 '2d' 作为参数,返回 CanvasRenderingContext2D 类型的对象.
如果绘制立体图形使用 'webgl’,返回 WebGLRenderingContext 类型的对象
ctx = canvas.getContext2D(‘2d’)
上下文的转换
Canvas 绘图中支持矩阵变换功能.
上下文的平移、缩放、旋转
类似我们要看到纸上一个移动的图形
一、我们可以改变这个图形的位置
二、我们可以移动这张纸的位置
首先,注意:
"上下文的位置一旦改变,那么绘制的标准:x轴、y轴,也随着同步改变"
平移坐标轴:
ctx.translate( x轴平移量,y轴平移量 ) //正数向右下
备注:已绘制的图形不会受到影响,平移会累加。
旋转坐标轴:
ctx.rotate( 旋转的弧度 ) //2D的,只能在垂直Z轴的平面上旋转,水平向右为0,顺时针为正
备注:已绘制的图形不会受到影响,旋转会累加。
缩放坐标轴:
ctx.scale( x轴缩放的比值,y轴缩放的比值 )
备注:已绘制的图形不会受到影响,缩放会累加。
其他的复杂的还有
transform(六个参数) 矩阵计算
setTransform()
Canvas画图形
绘制图形
三要素:
1. 画路径
2. 设置绘图环境状态
3. stroke/fill 渲染(是描边渲染,还是实心渲染)
(12可以更换顺序,但都要在3之前)
第一步:画路径
路径绘制 — 都是上下文的方法(核心)
1、先移动钢笔到指定的位置
ctx.moveTo( x轴移动的坐标,y轴移动的坐标 )
2、开始画线条
ctx.lineTo( x轴移动的坐标,y轴移动的坐标 )
在上下文刚开启,或者用beginPath()隔绝以前路径后,第一次使用lineTo方法,起到的作用于moveTo一样
闭合路径:
从当前路径的起点到结束点连一条路径。
ctx.closePath()
如果不使用闭合路径方法来绘制闭合图形,容易出现棱角锯齿的问题
内置的API绘制一些图形
画一个矩形路径(是顺时针的):
ctx.rect( 起点x轴坐标,起点y轴坐标,宽,高 );
还有两个直接渲染的API:
绘制一个描边矩形,这个方法不会产生路径:
ctx.strokeRect( 起点x轴坐标,起点y轴坐标,宽,高 )
绘制一个填充矩形,这个方法不会产生路径:
ctx.fillRect( 起点x轴坐标,起点y轴坐标,宽,高 )
画一个弧形( 画的是路径 )
ctx.arc( 圆心x轴坐标,圆心y轴坐标,半径, angleToRadian(起点弧度),angleToRadian(结束点弧度),是否逆时针画(可选) )
水平向右,为0弧度
默认是顺时针
// 把角度转换为弧度
function angleToRadian( angle ) {
return Math.PI / 180 * angle;
}
1. 使用 arc 绘图的时候, 如果没有设置 moveTo 那么会从开始的绘弧的地方作为起始点. 如果设置了 moveTo, 那么会连线该点与圆弧的起点.
2. 如果使用 stroke 方法, 那么会从开始连线到圆弧的起始位置. 如果是 fill 方法, 会自动闭合路径填充.
actTo(x1, y1, x2, y2, radius)
用法:
ctx.moveTo( x1 , y1 ); //需要结合此方法一起使用
ctx.arcTo( x2, y2, x3, y3 , Radius );
规则:
(x1,y1)点 与 (x2, y2)点行成一条线
(x2, y2)点 与(x3, y3)点行成一条线
根据提供的radius,半径,"画出一个与这两条线都相切的,90度的弧。"
其他API
按照矩形的大小来清除画布中指定位置的内容:
ctx.clearRect( 起点x轴坐标,起点y轴坐标,宽,高 ); //注意:只是清除之前所有的渲染的样式,路径仍旧存在
"我们在绘制路径的时候,需要注意路径的顺时针、逆时针问题,因为我们在填充的时候,非零环绕原则,需要根据这个来判断"
第二步:绘图环境(状态) — 都是上下文的属性
==绘图环境的配置,一个上下文,只能有一套。也就是一个属性,如果前面设置了,后面没改动,那么在后面的路径渲染的时候,这个属性都会生效。==
描边渲染,才会生效的属性:
描边色
ctx.strokeStyle 颜色,字符串
描边的线宽
ctx.lineWidth //线宽,是在线条的里外两侧,各占一半线宽
线宽的绘制机制说明:
canvas在绘制线条的时候,线宽,是在我们初始画的细线,向左向右各偏移线宽的一半,然后进行绘制。
如果线宽为奇数,细线左右各分0.5px,但是由于像素的最小单位是1,那么左右的那0.5,都会补全,变成1px,但是左右两侧边缘上,补全的这1px的颜色值,会缩减一半。
也就是线宽为奇数,实际上是偶数,但是区别是两侧边缘各1px的颜色值,会缩减
比如:如果设置线宽为1,就会发现,实际线宽是2,但是颜色从黑色都变成灰色了
如果线宽是偶数,则没有这个顾虑
线交点样式:
ctx.lineJoin = ‘miter' 、'round'、'bevel'
miter是默认值,两边向外延伸相交为尖尖角,
round是圆头,
bevel两边相连为一个斜面。
注意:必须有ctx.stroke() 描边渲染的时候,线交点样式,才能显示出来
虚线样式:
设置画线的时候实线部分和空白部分的大小。
ctx.setLineDash([5,3,2]) //实线5、虚线3、实线2、虚线5、实线3.....等
获取线条的虚线规则
ctx.getLineDash()
// 如果我们设置的是偶数,那么获取的与我们设置的一样
// 如果我们设置的是奇数,那么获取的是我们设置的两遍加起来,凑个偶数
设置虚线绘制时的偏移量(正负表示左右偏移)
ctx.lineDashOffset = 3;
填充渲染,才会生效的属性:
填充色
ctx.fillStyle 颜色,字符串
strokeStyle、fillStyle的赋值
1. 颜色字符串
2. 一个表示颜色线性渐变的对象
3. 一个表示颜色放射渐变的对象
4. 一个表示用图片平铺填充的对象
描边渲染,只能在填充渲染的基础上,看到边上指定线宽宽度的边
其他:
线帽样式
ctx.lineCap = ‘butt' 、'round'、'square'
butt是默认值,
round线头是圆的,
square线头两段各增加线宽的一半。
注意:线帽样式,在闭合路径上是显示不出来的。
绘图状态的保存与回滚
状态保持的机制是基于状态栈实现的. 也就是说 save 一次就存储一个状态. restore 一次就将刚刚存入的恢复. 如果 save 两次, 就需要 restore 两次, 才可以恢复到最先的状态.
一般在封装绘图的时候都会采用开始绘制之前, save 一次, 然后 开启一个新路径, 然后绘制结束后 restore, 然后再开启一个新路径. 这样保持当前状态不会对其他绘图代码构成影响.
保存:ctx.save()
以上的这些属性(还有其他的),设置了之后,就组成了一副绘图环境(状态),我们可以调用ctx.save()方法,来讲当前的状态保存一份,以备用
回滚:ctx.restore()
把最近一次,保存的状态拿出来,作为覆盖替换当前状态
应用场景:
(比如:已绘制完成图形A,其绘图状态:线宽、线交点、描边样式等,过一会绘制图形C的时候还要用,但是我现在又需要改动部分属性,来去完成另外一个样式的图形B,这个时候,就可以先将该状态保存下来,等图形B完成只有,再回滚,状态回复到刚刚保存的,然后去绘制图形C)
第三步:渲染 — 上下文的方法(两者是可以共存的)
路径描边渲染
ctx.stroke(); // 默认是黑色,线宽为1,但是根据线宽绘制机制,实际是2px,颜色是灰色
路径填充渲染
ctx.fill(); //默认是黑色
填充的时候,按照非零环绕原则,进行判断该点会不会被填充
"非零环绕原则":
路径在我们绘制的时候,是有方向的,分:顺时针、逆时针(内置API绘制图形,默认都是顺时针,比如:rect()绘制矩形)
从一点向画布外,发射一条射线,遇顺时针路径 +1 ,遇逆时针路径 -1 ,如果最终结果不是为0,那么该点就会被填充
这是中空矩形绘制的原理。
ctx.beginPath()
stroke、fill渲染方法一旦调用,会将该"上下文内的所有路径",按照目前"最新的绘制环境"的配置,进行"重绘"
如果只想渲染某一条路径,不想影响到前面的路径
那么"在该条路径绘制之前,写上:ctx.beginPath() — 渲染,隔绝之前所有的路径"
描边与填充渲染的顺序:
由于,描边会占用原图形的一部分(线宽的一半)
如果,先描边,再填充,那么填充的时候,会将描边的里侧的一般给覆盖了
所以,如果想达到描边的线宽效果,先填充,再描边
其他API:写字、绘图、设置渲染为渐变色或者图片 、阴影、保存画布
写字
设置文字的属性
ctx.font = 和css语法一样。
注意:
这里设置字体大小时必须带单位,单位支持css的所有表示方式。
单独设置字体大小不会生效,必须要加一个额外属性样式。
比如:ctx.font = '2rem 微软雅黑';
绘制描边文字:
ctx.strokeText( 文字, 参考x轴坐标,参考y轴坐标,限制文字的最大长度(可选) )
ctx.strokeText( '嘻嘻嘻嘻嘻嘻', 100, 100 );
绘制填充文字:
ctx.fillText( 文字, 参考x轴坐标,参考y轴坐标,限制文字的最大长度(可选) )
ctx.fillText( '咯咯咯咯咯咯', 100, 200 );
文字的对齐方式:
我们绘制文字的时候,需要填写x,y坐标,改变文字的水平、垂直对齐方式,修改的就是"坐标点,在文字的哪个位置(坐标点是固定的,动的是文字位置)"
设置文字的水平对其方式:
ctx.textAlign = 'left || start' 、 'right || end' 、 'center'
默认值为start。
设置文字的垂直对其方式:
ctx.textBaseline = 'top' 、'bottom'、'middle'、'alphabetic'、'hanging'、'ideographic'
默认值为alphabetic。ideographic比它低一点
即:默认,坐标点,在文字的左、下角。或者说:文字在坐标点的右上方开始绘制
其他:
ctx.measureText(文本) 测量文本的尺寸
返回一个尺寸对象,TextMetrics 对象属性很多, 常用的 width 属性可以获取文字的宽度.
绘制图片
ctx.drawImage()
绘制图像,有三种使用方式。 都必须要在img图片加载完成之后才能,写在img.onload() = function(){}中
drawImage()
第一个参数,可以是image、video、context(上下文,将此上下文,绘制到另一个上下文中)
第一种,三参数版本:
把图像绘制到指定的坐标。
ctx.drawImage( img, 10, 10 );
第二种,五参数版本:
把图像绘制到指定的坐标,并指定其大小。
ctx.drawImage( img, 10, 10, 200, 200 );
第三种,九参数版本:
把裁剪到的部分图像绘制到指定的坐标,并指定其大小。
ctx.drawImage( img,
300, 100, 400, 400,
10, 10, 200, 200 );
清除痕迹,也是用clearRect()
绘制线性渐变色作为渲染色
语法: CanvasRenderingContext2D.createLinearGradient( x0, y0, x1, y1 )
描述:
1. 该方法返回一个 CanvasGradient 对象. 用于描述渐变的方式.
2. 该方法有两个参数, 用于表示线型渐变的方向与位置. "注意: 渐变点的坐标是基于坐标轴来计算的."
3. 使用的时候, 首先创建一个 CanvasGradient 对象, 然后利用 addColorStop 方法添加颜色区间.
* 方法语法: CanvasGradient.addColorStop( rate, color ).
* 该方法用于设置在某个比例位置的颜色是什么. rate 的取值是 0 到 1 之间.
* 可以添加多个渐变点.
4. 然后将该对象赋值给 *Style 属性即可.
举例:
var canvasGradient = ctx.createLinearGradient( 0, 25, 200, 25 );
canvasGradient.addColorStop( 0, 'blue' );
canvasGradient.addColorStop( 1, 'red' );
ctx.fillStyle = canvasGradient;
绘制放射渐变色作为渲染色
语法: CanvasRenderingContext2D.createRadialGradient( x0, y0, r0, x1, y1, r1 )
描述:
1. 该方法实现放射渐变, 渐变的是在两个圆之间. 一般会使用两个内含关系的圆.
2. 前三个参数分别表示其中一个圆的圆心的坐标, 以及半径.
3. 后三个参数分别表示另一个圆的圆心的坐标, 以及半径.
4. 绘制渐变效果用法与线性渐变一样.
案例
var x = cas.width / 2, y = cas.height / 2, r = 100;
var g = ctx.createRadialGradient( x + r * 2 / 3, y - r * 2 / 3, 0, x + r / 3, y - r / 3, r * 4 / 3 );
g.addColorStop( 0, '#fff' );
g.addColorStop( 1, '#f00' );
ctx.fillStyle = g;
设置上下文的背景为图片(平铺或者拉伸)
语法:CanvasRenderingContext2D.createPattern( img, repetition )
描述:
1. 该方法表示使用图片来填充的设置方法. 需要两个参数, 一个是图片, 一个是重复的方式.
2. 图片允许是 img 标签, 图片, canvas 等对象
3. 可选择的重复方式与 CSS 一致. 有: repeat, repeat-x, repeat-y, no-repeat.
4. 如果是 空或"", 但不是 undefined, 默认就是 repeat.
案例
var img = new Image();
img.src = 'imgs/04d91106ecb1ec84b6708cd9796fc772.jpg';
img.onload = function () {
var p = ctx.createPattern( img, 'repeat' );
ctx.fillStyle = p;
ctx.fillRect( 50, 50, 550, 350 );
};
阴影
在 Canvas 中还可以给绘制的内容设置阴影. 但是一般不这么用, 因为性能不高.
相关属性:
1. CanvasRenderingContext2D.shadowBlur 属性表示模糊程度.
2. CanvasRenderingContext2D.shadowColor 属性表示模糊颜色.
3. CanvasRenderingContext2D.shadowOffsetX 属性表示模糊位置 x 坐标偏移.
4. CanvasRenderingContext2D.shadowOffsetY 属性表示模糊位置 y 坐标偏移.
判断点在不在路径中:
ctx.isPointInPath( 要判断的点x轴坐标,要判断的点y轴坐标 )
画布保存
画布在绘制后实际上就是一张图片, 可以直接在浏览器中右键另存为. 同时也支持使用 js 代码将其保存为 base64 编码的字符串.
语法: Canvas.ToDataURL( type, encoderOptions ) // cavans对象的方法,不是上下文工具的
描述:
1. 该方法可以将画布转换成 base64 格式的数据
2. type 表示输出类型. 例如: image/png 或 image/jpeg 等
3. encoderOptions 表示图片输出质量, 其取值在 0 到 1 之间. 如果是 1, 表示无损压缩, 必须使用 image/jpeg 或 image/webp 才起作用
小图片少的时候可以用base64编码图片
小图片多了用精灵图
图片大了用url
图片转成base64,可以减少网络请求,但是可能会让html臃肿,也会降低加载速度,所以不要盲目