1

喜欢前端,学习前端的最原始的动机,就是因为它可以制作非常酷炫的效果。然而现在上班所用的技巧,多是在业务逻辑那一块,并非是我最初想要去做的东西。所以在下班以后,打算重新拾起自己的兴趣,去学习真正的“酷炫”的东西。
Canvas,就是能够让我实现目标的利器之一。希望通过这一个笔记,能够督促我高效完成学习,并且把学习的感悟分享出来。

学习资源来自慕课网/炫丽的倒计时效果Canvas绘图与动画基础,非常感谢@liuyubobobo 老师的课程分享!

创建标签

html5的<canvas>标签定义了一块“画布”,我们所有的绘图都是基于这一块画布。所以在页面上我们先声明一个带id的canvas标签

<canvas width="1024" height="668" style="border:1px solid #aaa; margin:0 auto;" id="canvas">
    你的浏览器版本太tm旧了
</canvas>

为什么直接在标签里面定义widthheight呢,是因为

这里面的widthheight是canvas自己的属性,并非css3的属性。如果只用css3定义宽高的话只是限制了这块画布的大小,对内容的分辨率等显示问题并无约束(这句话有待考证)。而直接在标签里定义这两个属性的好处是能够一并地解决画布大小与实际显示的问题。

标签中间的文字内容是当浏览器不支持canvas自动出现的提示性话语,在浏览器支持canvas时这句话会被省略。


在创建好页面标签以后,开始进入实际的canvas绘制。它是完全通过js控制的,所以我们有关画图的一切都是在js中进行

创建绘图上下文

在js中,我们这样定义:

var canvas = document.getElementById('canvas');
var cxt = canvas.getContext('2d');

首先获取canvas对象,然后执行它的.getContext('2d')方法,建立一个绘图上下文环境cxt。以后所有在这一块画布进行的绘制,都是调用这个cxt不同的方法来完成。环境搭建好了,就可以进行真正的操作啦!

绘制图形

教程上说得很明白,在这里就不继续赘述了,主要总结出不同方法的作用,效果,及其注意事项。

//把笔尖放在画布100, 100的位置
cxt.moveTo(100, 100)
//从100,100画到700,700
cxt.lineTo(500,500)
//继续画完它
cxt.lineTo(500,100)
cxt.lineTo(100,100)
//设置线条宽度
cxt.lineWidth = 5
//设置线条样式(颜色)
cxt.strokeStyle = 'pink'
//设置填充色
cxt.fillStyle = 'lightblue'
cxt.fill()
//告诉canvas我画完了,执行stroke()方法
cxt.stroke()

老师在教程里反复强调了一点,就是canvas是基于“状态”的绘图,也就是当我怎样定义moveTo()lineTo()之类的方法的时候,我定义的是一种“我想怎么怎么去画”的状态,是“未下笔”的,而当我已经想好了,定义好了这个状态以后,才执行“把想法画出来”的方法,即执行.fill().stroke()等方法,告诉canvas“我要画了啊!”,然后把内容画出来。

正是因为canvas是基于状态的,所以不同的状态应该有明确的起始标志。如果我们想画不同颜色的一个三角型和一条直线,我们可能会这么写

//把笔尖放在画布100, 100的位置
cxt.moveTo(100, 100)
//从100,100画到700,700
cxt.lineTo(500,500)
//继续画完这个三角形
cxt.lineTo(500,100)
cxt.lineTo(100,100)
//设置三角形线条颜色为粉红色(我特喜欢粉)
cxt.strokeStyle = 'pink'
//告诉canvas我画完了,执行stroke()方法
cxt.stroke()


//画一条新的线
cxt.moveTo(50, 100)
cxt.lineTo(450,500)
//设置这条线的颜色为浅蓝色
cxt.strokeStyle = 'lightblue'
//告诉canvas我画完了,执行stroke()方法
cxt.stroke()

看看效果如何:
图片描述
因为canvas基于状态,然而这俩的状态并没有被区分(canvas没那么智能),所以后面的cxt.strokeStyle = 'lightblue'会把前面的给覆盖掉,也就是它只有一个线条颜色的状态。那么如何给它定义不同的状态呢?有两个方法,请看代码

cxt.beginPath()
//把笔尖放在画布100, 100的位置
cxt.moveTo(100, 100)
//从100,100画到700,700
cxt.lineTo(500,500)
//继续画完这个三角形
cxt.lineTo(500,100)
cxt.lineTo(100,100)
//设置三角形线条颜色为粉红色(我特喜欢粉)
cxt.closePath()
cxt.strokeStyle = 'pink'
//告诉canvas我画完了,执行stroke()方法
cxt.stroke()

cxt.beginPath()
//画一条新的线
cxt.moveTo(50, 100)
cxt.lineTo(450,500)
cxt.closePath()
//设置这条线的颜色为浅蓝色
cxt.strokeStyle = 'lightblue'
//告诉canvas我画完了,执行stroke()方法
cxt.stroke()

其中,beginPath()告诉canvas我想会从这里开始画一段路径closePath()声明路径的结束。虽然这两个方法在包裹着.stroke()方法时也生效,但是为了语义化,path指的是路径,所以我们把这两个方法仅用于包裹路径即可。看看效果:

图片描述

未完待续……


jrainlau
12.9k 声望11.7k 粉丝

Hiphop dancer,