资讯专栏INFORMATION COLUMN

canvas入门里,你没注意到的那些知识

tuniutech / 2193人阅读

摘要:但需要注意的是,需在使用前调用。当然,你愿意的话也可以两者结合着用。绘制图像相信很多入门的,都看不到这个地方,不就是绘制图像的嘛,啊不准确,是绘制图形的。明确的说,是指围绕原点图像旋转弧度。

前言

本文写在七月底,进来不加班就整理了一下,一些非常基础的知识,对于canvas刚入门的人来说,值得阅读一下。

来个气势如虹的开头

与看各种文章相比,我更喜欢数学里的逻辑;与学习各种日新月异的框架相比,我更喜欢基础扎实带给人的那种踏实;与拼凑页面页面来回跳转相比,我更喜欢动画,图形在页面中表现的直观。
也许你和我一样,冲着对H5的好奇,冲着对图形的热爱,学了一下canvas,没有熟练,只是简单入了个门,或许你在入门的门槛上就绊倒了,同学不哭,站起来继续撸。我把我入门两天的积累写下来,有些门槛,绊倒了数百次,有些应该也适合你。下文的ctx指的是canvas创建的2d图形化实例,代码:

var canvas = document.querySelector("#test");  //test是Html中一个canvas元素的ID,其宽为600,高为400;
var ctx = canvas.getContext("2d");
说件重要的事

2d上下文(画布)坐标开始于元素的左上角,其顶点为坐标原点,x轴正方向指向屏幕右侧,Y轴正方向指向屏幕下方。所以x值越大越靠右,Y值越大越靠下。这和我们传统的坐标轴是有很大区别的,下面一张图,也许能看出。Y轴反向也许很好理解,但顺时针正0度在坐标轴的那个位置,就值得我们好好记住了,使用arc,熟悉这个常识很重要。

四个基本方法 描边:stroke与strokeStyle
 ctx.strokeStyle = "red";
 ctx.arc(200,200,50,0,PI*2,false);
 ctx.stroke();   
 

lineTo,moveTo方法,很基础,这里特别说一下arc(x,y,r,startAngle,endAngle,direction)画圆的方法,这个方法接受6个参数,前五个是必须的,分别是圆心位置(x坐标,y坐标),然后是圆的半径r,再然后是起始位置角和终止位置角,这两个很重要,结合前面那张图理解更,我们可知,上面这段代码绘制的第一个点是(0,50),终止位置也是(0,50)。后面direction是一个可选参数,默认为false,表示顺时针绘制,为true时,为逆时针绘制。
特别说明:

红宝书上说绘制路径,都应该以beginPath()方法开始,但实践证明,这并不需要,你只需要在stroke这个方法来结束这段路径的绘制,但加了也不坏事,所以还是加上吧;

只调用一次lineTo(0,50)方法,你是看不到一条直线绘制出来的,因为(0,0)并不是默认的起点,除非你先用moveTo()方法设置一个起点,这个简单的道理叫两点确定一条直线;

closePath()并不是一个与beginPath对照使用的方法,其作用是绘制闭合路径,比如下图所示。可以看到我们只调用了两次lineTo方法,但最后绘制除了三条线,最后这一条线就是closePath作用出来的。但需要注意的是,closePath需在stroke使用前调用。

填充:fillStyle与fill
ctx.fillStyle = "red"
ctx.arc(200,200,50,0,PI/3,false);
ctx.fill();   

与描边对应的就是填充,但这个方法很不讲究,通常来讲,只有封闭区间才有资格填充,但fill这个方法不需要,只要你的路径不是一条直线,那它就能被填充,也就是不在同一条直线上的三点,能确定一个面,这个方法真的很牛逼,我是必须服气的。

绘制文本:stokeText与fillText

以上两个方法都能写出一个字,但推荐的用法是fillText,因为其写出来的是实心字,而stokeText写出来的是描边空心字,绝大多数艺术字会采用这种写法。当然,你愿意的话也可以两者结合着用。

ctx.fillStyle = "red"
ctx.font= "bold 12px Arial";
ctx.fillText("Test",300,200);

ctx.strokeStyle = "red"
ctx.font= "bold 12px Arial";
ctx.strokeText("Test",400,200);
绘制图像:drawImage

相信很多入门的,都看不到这个地方,canvas不就是绘制图像的嘛,啊,不准确,canvas是绘制图形的。具体说来就是drawImage,它不只能把图片绘制到画布上,他还能绘制canvas图形,这个在星空,雨滴等案列中应用最多,也是canvas离屏优化用的最多的,看下面这个示例。
var cache = document.createElement("canvas");
cache.width = 50;
cache.height = 50;
var cacheCtx = cache.getContext("2d"); //这是一块虚拟画布,因为未添加到dom节点中;

cacheCtx.beginPath();
cacheCtx.strokeStyle = "red";
cacheCtx.moveTo(5,5);
cacheCtx.lineTo(20,40);
cacheCtx.lineTo(40,20);
cacheCtx.closePath();
cacheCtx.stroke();

ctx.drawImage(cache,50,50);
ctx.drawImage(cache,50,100);
ctx.drawImage(cache,100,50);
ctx.drawImage(cache,100,100);


通过上例,我们就能看出drawImage在离屏优化中的应用。为什么这样可以,因为,像上面一样,我们要在一块画布上,画四个相同的三角形,这在浏览器表现上,你看不出任何卡顿,那如果你是要在屏幕上绘制一千个或万个这样的图形,且每一帧还要有规律的变换他们的位置,这时你就能明显感觉出浏览器的卡顿,因为你一直在操作dom中的元素,使浏览器一直在不停的重新绘制,渲染网页。但如果你在每一帧绘制下一个状态前,在js中,通过在虚拟的canvas中先绘制好下一帧的背景状态,然后通过drawImage这个方法,来更新浏览器中的画布状态,这样网页在一帧中就只需要渲染一次,而不是时时在渲染,这就达到了离屏优化的目的,所以这也是drawImage用的最多的场景。

过完以上知识,就算是复习一下入门知识了,至于为什么没提fillRect与strokeRect,其实那就是stroke与fill提供给绘制矩形的一个语法糖。

奇妙的变换

也许你和我一样,不习惯自己的坐标系是从左上角开始的,我们更习惯坐标原点在左下角或者正中心。

坐标原点变换 translate方法

原点变换到画布中心:ctx.translate(WIDTH/2,HEIGHT/2),WIDTH与HEIGHT分别指画布的宽与高,为了将坐标变换表现得更明显,我在同一块区域,画了两块大小相似的画布,然后让一块使用原始坐标系,一块采用translate变换后的,具体看代码,和结果图;

var ctx = document.querySelector("#test").getContext("2d"); var crx = document.querySelector("#testa").getContext("2d"); ctx.beginPath(); ctx.strokeStyle = "blue"; ctx.arc(0,0,5,0,PI*2,false); ctx.moveTo(0,0); ctx.lineTo(0,150); ctx.moveTo(0,0); ctx.lineTo(150,0); ctx.stroke(); crx.beginPath(); crx.translate(300,200); crx.arc(0,0,5,0,PI*2,false); crx.strokeStyle = "red"; crx.moveTo(0,0); crx.lineTo(0,150); crx.moveTo(0,0); crx.lineTo(150,0); crx.stroke();

坐标系旋转变换 rotate方法

也许你接触canvas很久了,但rotate方法始终没有机会用,只记得红宝书上在绘制钟表时针,分针时,提到了rotate的用法,但只要你熟悉,用法就能千奇百怪。API明确的说rotate(angle),是指围绕原点图像旋转angle弧度。所以,你需要记住两点。第一:图像是围绕原点旋转;第二:与其说是图像旋转,不如说是整个坐标系旋转了。看示例,还是和上面一样,有对比,才有说服力:

ctx.beginPath();
ctx.strokeStyle = "blue";
ctx.translate(300,200);
ctx.arc(0,0,5,0,PI*2,false);
ctx.moveTo(0,0);
ctx.lineTo(0,150);
ctx.moveTo(0,0);
ctx.lineTo(150,0);
ctx.stroke();
ctx.moveTo(0,0);
ctx.lineTo(0,-150);
ctx.stroke();

crx.beginPath();
crx.strokeStyle = "red";
crx.translate(300,200);
crx.rotate(PI/3); //旋转60*
crx.arc(0,0,5,0,PI*2,false);
crx.moveTo(0,0);
crx.lineTo(0,150);
crx.moveTo(0,0);
crx.lineTo(150,0);
crx.stroke();
crx.moveTo(0,0);
crx.lineTo(0,-150);
crx.stroke();


与上个图相比,我将两块画布的中心都先变换到了画布的中心,作为对比,红色画笔的做了旋转变换,在分别绘制了正x,正y轴以后,在stoke方法结束一段绘制以后,又绘制了负y轴,可以看到,上一段绘制路径的rotate仍然起作用,所以rotate是对画布坐标系做了变换,而不是狭义上的绘制图像,这个区别很重要。后面在上一段代码,不用sin,cos计算,就能绘制一个正多边形,这里以6边形为例。

ctx.beginPath();
ctx.translate(300,200);
ctx.strokeStyle = "red";
var a=0;
for(var i=1;i<7;i++){
    ctx.lineTo(0,150);
    ctx.rotate(PI/3);
    a =a + PI/3 ;
}
ctx.closePath();
ctx.stroke();
ctx.lineTo(0,0);
ctx.stroke();

不重要,但很点题的API

绘制一个普通的图形,也许上面的API也已足够,但要让你的图形有亮点,你可能还需要多了解一些,我个人觉得非常有用的两个就是阴影的绘制(shadow)与渐变色的添加(createLinearGradient)。在用canvas做星星背景时,或者飞行的流星周围的闪光,这些都是用shadow做出来的特效。而消逝的流星,头部亮,尾部暗的效果就是用渐变色做的,在以后的系列中,会结合实例多讲一些。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92281.html

相关文章

  • 个人分享--web前端学习资源分享

    摘要:前言月份开始出没社区,现在差不多月了,按照工作的说法,就是差不多过了三个月的试用期,准备转正了一般来说,差不多到了转正的时候,会进行总结或者分享会议那么今天我就把看过的一些学习资源主要是博客,博文推荐分享给大家。 1.前言 6月份开始出没社区,现在差不多9月了,按照工作的说法,就是差不多过了三个月的试用期,准备转正了!一般来说,差不多到了转正的时候,会进行总结或者分享会议!那么今天我就...

    sherlock221 评论0 收藏0
  • 编程界也有修仙秘籍?程序员码字3年终得《JavaScript 百炼成仙》

    摘要:百炼成仙走红该书于年月出版,作者杨逸飞是一名从事开发六年的程序员,写过诸多技术博客。作者在博客上对粉丝提出关于百炼成仙的问题进行了统一回复,该博文持续占据热榜第二,热度达。 刚接触编程的小伙伴,估计都想过把枯燥无聊的编程教材变成小说读的念头,这不,说曹操曹操就来了,真的有程序员用写修仙小说的...

    zzbo 评论0 收藏0
  • 滴滴一下,小程序专车来了

    摘要:功能三滴滴费用计算古人云细节决定成败,一个良好的微信小程序往往就是一些细节打动人心,居然是模仿,虽做不到百分百,至少还是很希望一模一样。 最近时常感叹道:时间总是那么的快,转瞬即逝。对于像我这种刚入门的小生来讲,技术每天都在更新,框架也层出不穷,有时候还没弄懂这个知识大牛们又推出了更好的技术。当然学习好的技术也是十分重要的。但是在学习之后怎样才能够得到自己想要的呢,一个好的建议便是静...

    SwordFly 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<