![41970dd5d41ef0d407173d350f2a8e7d.png](https://i-blog.csdnimg.cn/blog_migrate/2e73f9eb4ae73de67542c6fb78e315b4.jpeg)
Canvas基本知识
用<canvas>标签,指定width和height属性,一般还要指定id属性以供js使用。
<
默认的width是300,height是150
注意canvas的css里的width和height和标签上的width以及height是不同的,浏览器会把标签上的大小缩放到css里设置的大小上,所以一般不需要设置css里的width和height。
canvas也就三个方法
- getContext - 一般就传入'2d'参数
- toDataURL(type, quality) - type默认为image/png,也可以指定别的格式,quality是一个0~1.0的数值,用在JPEG格式上,得到的结果是一个data:image/png;base64 xxxx这样的字符串,可以直接置给<img>的src
- toBlob(callback, type, quality) - 创建canvas元素图像文件的Blob对象,type默认也是image/png,最后一个也是quality,跟上一个方法一样
getContext获得的是一个CanvasRenderingContext2D对象,以下简称context,含有如下的属性
- canvas
- fillStyle
- font
- globalAlpha
- globalCompsiteOperation
- lineCap
- lineWidth
- lineJoin
- miterLimit
- shadowBlur
- shadowColor
- shadowOffsetX
- shadowOffsetY
- strokeStyle
- textAlign
- textBaseline
context含有两个方法save( )和restore( ),用来保存和恢复绘制时设置的上述属性,它是一个栈的数据结构。绝大多数情况下,对context的设置都要包裹在save()和restore()之间。
如果想要对context进行方法功能增强,那就在CanvasRenderingContext2D.prototype上添加方法。
canvas的原点坐标在左上角。
canvas的事件处理没有什么特别的,因为往下不存在DOM了,所以事件都要挂在canvas上,以下一段代码常用来进行事件坐标和canvas坐标的转换,同时考虑了CSS设置width和height的情况。
function
下面是一个根据鼠标移动画辅助线的例子,用到上面的方法
let
![a04eb6eded518053b74eb97cc1c98493.png](https://i-blog.csdnimg.cn/blog_migrate/5d8ccc69cf8a72ef81553bbdfda8d527.jpeg)
PS:请复习一下中学数学,特别关于三角函数和向量的知识
矩形绘制
- clearRect(x, y, width, height)
- strokeRect(x, y, width, height)
- fillRect(x, y, width, height)
跟strokeRect有关的属性有
- strokeStyle
- lineWidth
- lineJoin
- miterLimit
跟fillRect有关的属性有
- fillStyle
渐变
- createLinearGradient(x0, y0, x1, y1) - 从(x0, y0)到(x1, y1)的线性渐变,用返回对象的addColorStop( )方法来增加颜色
- createRadialGradient(x0, y0, r0, x1, y1, r1) - 从(x0, y0)点周围r0宽度向(x1, y1)周围r1宽度放射渐变,也用返回对象的addColorStop( )方法来增加颜色
注意放射渐变可以不是一个矩形
var
![0bedf150dc91cfa63860a445b591312f.png](https://i-blog.csdnimg.cn/blog_migrate/65f2264c107e48810c4cb237a0e51c6e.jpeg)
渐变也可以用在stroke方法里,比如这种效果
![a431eca6b8903e7f7df03b3d19b97ed0.png](https://i-blog.csdnimg.cn/blog_migrate/609e52cc5ff1515c16f2dc92415404e6.jpeg)
图案
- createPattern(image, repeat) - repeat可以取repeat repeat-x repeat-y no-repeat
let
![553ada9a381acbfb899cf4a99d833ff9.png](https://i-blog.csdnimg.cn/blog_migrate/a7fbe4712ae88c500d1898d3b2272be9.jpeg)
阴影
指定shadowColor, shadowOffsetX, shadowOffsetY, shadowBlur这几个属性
context
效果如下图
![b6d5f40a7605cabb634e260b8808fcdb.png](https://i-blog.csdnimg.cn/blog_migrate/0878fd8999b11f6d19e8aecb711d746d.jpeg)
路径
想要画出任意图像就需要使用路径
beginPath( )用来清除之前的路径并开启新路径
closePath( )用来封闭路径
arc( )用来增加圆弧路径
![141d258070bc958636dc34bf5d1ff926.png](https://i-blog.csdnimg.cn/blog_migrate/71756e625558aab0f3aaa5acef15e1d2.jpeg)
arcTo(x1, y1, x2, y2, radius)用来增加从x点到y点相切的一条圆弧路径,一般用来做圆角矩形
fill( )用来对路径填充
stroke( )用来对路径描边
rect( )用来生成矩形路径,它自然是封闭的
moveTo( )移动路径的点
lineTo( )生成直线的路径
quadraticCurveTo(cpx, cpy, x, y)用来增加二次方贝塞尔曲线路径
![9bb5605867e0fae7957f324d87406aa1.png](https://i-blog.csdnimg.cn/blog_migrate/8b5d8a14fee4e53ae5f291370bef7ce7.jpeg)
bezierCurveTo(cpx, cpy, cp2x, cp2y, x, y)用来增加三次方贝塞尔曲线路径
![011ffd024e5fb43b9b5ee84faf72ba05.png](https://i-blog.csdnimg.cn/blog_migrate/29a3eda7e883261f43b8f010c0b23c3f.jpeg)
- 注意beginPath( )方法会清除上一次的路径,就是指从beginPath( )之后增加的路径开始画,如果不清除的话,之后的stroke( ) fill( )都会把之前的路径又画一遍。
ctx
2. 注意线段的绘制要画在0.5位置上,以一像素为例,只有画在0.5位置上才是真正的一像素宽度
![6c61a7350251c2dc0c437567a8e110a6.png](https://i-blog.csdnimg.cn/blog_migrate/43b996116b6676ee023ab58c7450f0f0.jpeg)
![f7815566ad38e9a71984b73fc722d13c.png](https://i-blog.csdnimg.cn/blog_migrate/48d43b0952a7b41b0957868c2f7cdf2f.jpeg)
for
![8dd32b968610255292be74cd384baffc.png](https://i-blog.csdnimg.cn/blog_migrate/2ada9ad3ea099cf9586b382c126f35e2.jpeg)
尝试用鼠标操作绘制线段,这个例子使用image data来保存恢复图像,还可以使用线段数据数组的方式来存储线段数据,每次重绘的时候把数组里的线段都再绘制一遍(其实我更倾向于后者)
let
3. 线段端点属性lineCap和线段连接点lineJoin属性
![4ae6022bf8e6894062b7f9ad93928574.png](https://i-blog.csdnimg.cn/blog_migrate/b6ad9ada1928dd46ea81a236eacf8662.jpeg)
![c4b93754f33a0c29a47ea25dc209b8c0.png](https://i-blog.csdnimg.cn/blog_migrate/e186512f320dce1ac033e02948e483cf.jpeg)
miterLimit是斜接线商都与二分之一线宽的比值,如果斜接线长度超过该值,浏览器以bevel方式来绘制
![241463acd026352e024f1e7956190a54.png](https://i-blog.csdnimg.cn/blog_migrate/86243f0e07d9d0836c39c2817448cc2e.jpeg)
4. context有个方法isPointInPath( )用来判断点是否在当前路径中,在使用前可以用beginPath( )等方法创建出路径来,然后进行判断。同理还有isPointInStroke( )。
5. scrollPathIntoView( )是一个实验中的方法,让给定的路径滚动到窗口
6. 通过context的lineDashOffset或者setLineDash( )方法可以设置绘制虚线的规格
坐标变换
通过rotate( ) scale( ) translate( ) transform( ) setTransform( )等方法来进行坐标轴的变换,其中transform( )和setTransform( )的区别在于transform( )会叠加效果而setTransform( )会清除之前的效果。
比如画一个左右对称图形
context
![2c44d9daf0330eda5c9e2d102992af6a.png](https://i-blog.csdnimg.cn/blog_migrate/aeb8400ac1f603934446d750c38cfb24.jpeg)
图像合成
设置context的globalCompositeOperation属性,可以取如下的值,注意一下在不同浏览器上的行为是否一致
![91787114a07e6772a0afe5cbab2a40bf.png](https://i-blog.csdnimg.cn/blog_migrate/507004b1b2da70a04e8da94ad7478079.jpeg)
下图就是一个橙色圆形和文字在合成属性设为xor的情况下的效果
![4cb1ec4a301558aca1d631d698b7832d.png](https://i-blog.csdnimg.cn/blog_migrate/21ecfc26e28c3388dd2a664d25f2afa5.jpeg)
区域剪辑
使用context的clip( )方法把当前路径与剪辑区域的交集绘制出来,记得放在save( )和restore( )之间,否则剪辑区域会越变越小。
const
![f0dbe5d1bc11fb65e98254cebacf436a.png](https://i-blog.csdnimg.cn/blog_migrate/78b88cfbd73de6cfe05cd6bf5ea7ef69.jpeg)
文本
绘制文本主要通过以下三个方法
- strokeText(text, x, y)
- fillText(text, x, y)
- measureText(text)
跟文本有关的context属性有
- font
- textAlign
- textBaseline
但其他的fillStyle等属性也是适用于文本绘制的。
font的属性是一个字符串,注意如下次序不能乱,不然canvas不认
- font-style 包含normal italic oblique
- font-variant 包含normal small-caps
- font-weight 跟css里设置该值属性一样
- font-size 跟css里一样
- line-height 只能是normal,其他值会被忽略
- font-family 字体
textAlign可以取值
- start
- center
- end
- left
- right
textBaseline可以取值
- top
- bottom
- middle
- alphabetic
- ideographic
- hanging
下图是各属性的效果,如果要将文本基于某个点居中,那就设成center middle,在坐标轴标签绘制的情况下注意设置合理的属性
![17c116b7bc2e7e472d6d071d8b0c6e0e.png](https://i-blog.csdnimg.cn/blog_migrate/0a0fcd048efe1acf7ff9fe00f32185cb.jpeg)
环形文本绘制效果可以参见之前我做的一个神盾局logo的绘制
Anli Li:用canvas画神盾局Logozhuanlan.zhihu.com![ec1c80c0412d039f622d0a6f5979b2f6.png](https://i-blog.csdnimg.cn/blog_migrate/963d7e01c99ecd2c81bc9e4129680a19.jpeg)
图像
跟图像绘制有关的方法
- drawImage(image, dx, dy) / drawImage(image, dx, dy, dw, dh) / drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh)
- getImageData( x, y, width, height)
- putImageData( )
- createImageData(width, height)
下面一个例子是通过鼠标操作缩放图像部分。
let
![0f961a7c00f7f07df6e0aeab3395c350.png](https://i-blog.csdnimg.cn/blog_migrate/d94242f3b6c981eaee1552fdc4025539.jpeg)
一个增加效率的绘图方法,创建一个canvas元素但不显示,在这个canvas进行绘制,然后把它的一部分内容复制到正在显示的canvas中,由于绘制是发生在离线情况下,用户不会感受到绘制时的变化,只注意到最后的结果,这种方式叫离线canvas。
getImageData( )会有跨域的限制,它返回的是这样一个对象
![bec72bac8e66cdd7e32c8904623f1670.png](https://i-blog.csdnimg.cn/blog_migrate/db28bad30c25c158f078ad9209729a4f.jpeg)
其中data是一个4×width×height个整数值的数组,每四个整数值代表一个像素,分别表示红、绿、蓝和透明度(最高255)。这里的宽度和高度是canvas的宽高而不是图像本身的宽高。
putImageData(ImageData imagedata, dx, dy, optional dirtyX, dirtyY, dirtyWidth, dirtyHeight )用法如下图
![16b80a9c25321940994556c771113a14.png](https://i-blog.csdnimg.cn/blog_migrate/99a8f5407276324ecd07be04fb3dcbe0.jpeg)
拿到了像素数据后就可以进行图像处理,比如取反或黑白等,如果计算量大可以考虑使用web worker。
canvas
![a10d828aa57fb6065efea886ebb5ee6b.png](https://i-blog.csdnimg.cn/blog_migrate/f6cebb2814c9970bf6a0ae4e49362da3.jpeg)
考虑优化性能,可以只重绘部分区域或者先绘制到离屏的canvas上再把部分区域绘制到屏幕上。
关于canvas的用法暂时整理到这里,其他的一些高级应用会另写文章来讨论。