Canvas上下文详解
本部分重点讲解了Canvas中心点的内容,在Canvas中所有内容的绘制都是基于上下文变换后的新坐标系中心点来完成的,对于坐标系中心点的理解是正确完成内容绘制的前提。同时,本章节也将重点讲述Canvas绘图状态相关的两个方法save和restore。1。Canvas与CSS3坐标变换1。1CSS3matrix2D矩阵和Canvastransform2D矩阵
2D矩阵指的是元素在2D平面内发生诸如缩放、平移、旋转、拉伸四种变化,在CSS3中对应4个方法分别是scale()、translate()、rotate()和skew(),这4个方法是CSS3矩阵matrix的快捷方式,其本质都是由matrix()实现的。
类似地,在Canvas中与CSS3对应的3个方法分别是scale()、translate()、rotate(),而Canvas对象没有skew方法,CSS3中的矩阵和Canvas矩阵原理是相通的。matrix方法有六个参数matrix(a,b,c,d,x,y),六个参数默认值是:matrix(1,0,0,1,0,0)
这六个参数分别控制不同的变换
a水平缩放
b水平拉伸
c垂直拉伸
d垂直缩放
x水平位移
y垂直位移
关于matrix的各种变换在后面章节会有更加详细的说明,在这里只需知道Canvas和CSS3中矩阵变换的规则是一致的。1。2Canvas与CSS3坐标变换中心点差异
1。1部分讲过,在Canvas中也存在CSS32D变换的功能,如translate()、rotate()、scale()等。虽然两者看起来差不多,但是CSS3中元素变换中心点都是针对DOM元素,而在Canvas中并非针对DOM元素的变换,而是虚拟画布区域。
默认情况下,Canvas中心点是左上角,即坐标(0,0)。就像可以通过transformorigin来改变CSS3元素变换的中心点一样,Canvas也可以改变默认中心点,只不过需要通过translate()方法平移内部的2D绘图环境。p2{transform:rotate(45deg);transformorigin:2040;}
总之,对于中心点而言,CSS3是针对元素本身,即DOM元素,而Canvas针对的是整个Canvas绘图环境,即虚拟画布区域2。Canvas上下文变换2。1Canvas上下文变换基础
首先来看下在不改变中心点情况下,Canvas旋转前后的变化:canvasidcanvaswidth200height200canvas!真实的画布就是200x200varcanvasdocument。getElementById(canvas);ctxcanvas。getContext(2d);ctx。save();ctx。fillStyleblack;ctx。fillRect(20,20,100,100);旋转前绘制ctx。rotate((Math。PI180)30);ctx。fillStyleblue;ctx。fillRect(20,20,100,100);旋转后绘制ctx。restore();
由上面的代码可以看到,在旋转画布前,我们在坐标(20,20)处绘制了一个100100的黑色矩形,而在旋转之后,又在坐标(20,20)处绘制了一个100100的蓝色矩形。最后得到的效果如下:
需要注意的是,Canvas旋转前绘制的元素没有旋转效果,而这种旋转效果只会出现在Canvas旋转后绘制的元素。因此,如果要对Canvas里的某些图形进行旋转处理,就必须在绘图环境旋转后再进行绘制。
那么如果将Canvas旋转180后再进行绘制,最后结果如何呢?imgidtulipsrcc2021imgdataimg。jpgdatasrcimgq01。71396。combjth7c7b07d3cb9f6a74。jpgaltTheTulipcanvasidmyCanvaswidth500height300styleborder:1pxsolidd3d3d3;background:ffffff;YourbrowserdoesnotsupporttheHTML5canvastag。canvaswindow。onloadfunction(){varcdocument。getElementById(myCanvas);varctxc。getContext(2d);ctx。rotate((Math。PI180)180);varimgdocument。getElementById(tulip);ctx。drawImage(img,10,10);};
运行完上述代码,你会发现什么也看不到。因为Canvas的中心点是左上角(0,0),当将Canvas绘图环境旋转180弧度后,你会发现图形已经在Canvas可视区域外,这显然是不可行的。那需要如何做呢?2。2Canvas上下文变换原理
下面将以图解的方式进一步讲述Canvas上下文变换的原理,通过分析你也能进一步深入理解上文旋转180的例子,即绘制的元素为啥会莫名消失。
下面分步对该图进行讲解:
第一步:不做任何原点移动的绘制varcdocument。getElementById(myCanvas);varctxc。getContext(2d);varimgdocument。getElementById(tulip);ctx。drawImage(img,10,10);
此时通过X,Y轴指定了绘制的方向,整个图以O(0,0)为中心进行绘制。第二步:移动了绘制原点
ctx。translate(w2,h2);
绘制原点移动到O(12w,12h),而X和Y指定了最新绘制的方向。此时需要注意的是:整个Canvas在页面中展示区域依然是w,h指定的位置,只是绘图的原点发生了改变而已。所以,在Canvas中灰色区域是整个w,h指定的唯一有图像的区域,而其他区域都是空的,因为Context压根就没有在这些位置进行绘制。
第三步:上下文进行旋转ctx。translate(w2,h2);ctx。rotate(Math。PI);ctx。drawImage(img,0,0);
通过这一步,X轴,Y轴的方向方向再次发生了变化,分别为X和Y,但是原点依然对应于O(12w,12h),因为Context没有做类似translate方法来改变中心点位置。这一步需要注意的是绘制的方向,由X和Y的指向来看,此时的绘图方向已经转化为向上和向右绘制。和第二步分析一致,黄色区域是唯一能看到图像的区域。到这一步,你应该明白了,现在依然没有实现元素在指定位置的180旋转。请看下例:imgidtulipsrcc2021imgdataimg。jpgdatasrcimgq01。71396。combjth45b6b0800585c6cd。jpgaltTheTulipcanvasidmyCanvaswidth500height300styleborder:1pxsolidd3d3d3;background:ffffff;YourbrowserdoesnotsupporttheHTML5canvastag。canvaswindow。onloadfunction(){varcdocument。getElementById(myCanvas);varctxc。getContext(2d);ctx。translate(5002,3002);ctx。rotate(Math。PI);varimgdocument。getElementById(tulip);ctx。drawImage(img,10,10);};
原图为:
代码执行后的效果为:
图片具体表现可以通过上面的分析看出来,很显然现在绘制出来的图片只是原图的一部分,而不是完整的图片。究其原因主要是当图片尺寸超过0。5w,0。5h的时候,黄色区域没法完全容纳整张图片的绘制。而造成该问题的本质原因在于上下文移动的0。5w,0。5h距离。下面部分讲解具体的解决方法:2。3Canvas上元素旋转180的方法
通过上面2。2的分析不难看出具体的解决方法。第一种途径是在rotate后继续改变绘图环境的中心点,将中心点平移到作图区域(w2,h2)。之所以为负数,是因为X和Y指定了新的坐标方向与原点要移动的位置相反。代码有:ctx。translate(w2,h2);ctx。rotate(Math。PI);ctx。translate(w2,h2);ctx。drawImage(img,0,0);
最终效果如下:
第二种途径是改变绘制图片的坐标,将图片绘制到(w2,h2),代码有:ctx。translate(w2,h2);ctx。rotate(Math。PI);ctx。drawImage(img,w2,h2);
具体效果与上图相同。3。Canvas上下文状态保存
在上面第2部分讲过上下文变换设置只会影响到之后的内容绘制,接下来重点讲述下Canvas上下文状态相关的两个主要方法,save()和restore()。3。1save()和restore()方法详解
CanvasContext维持着绘制状态的堆栈,绘制状态主要包括以下几个维度:1。上下文矩阵变换:例如:平移translate(),缩放scale(),以及旋转rotate()等2。剪切区域:clip()3。特殊属性值设置:strokeStyle,fillStyle,globalAlpha,lineWidth,lineCap,lineJoin,miterLimit,shadowOffsetX,shadowOffsetY,shadowBlur,shadowColor,globalCompositeOperation,font,textAlign,textBaseline等
需要注意的是:当前绘制路径、画布内容本身不属于绘图状态。绘制路径是持久的,只能使用beginPath()方法重置,而画布内容是画布的属性,而非上下文。save()和restore()的出现提供了用来操作绘制状态的快捷方法。1。Context。save()方法将当前绘制状态压入堆栈2。Context。restore()弹出堆栈上的状态,将上下文恢复到该状态。3。2save()和restore()方法示例
当前示例的完整代码可以查看这里,将代码复制在任何编辑器中以。html为文件后缀,用浏览器打开即可看到完整示例效果,下面对核心代码进行说明。
第一步:首先设置了Canvas绘制的fillStyle、shadow属性,然后在(0,0)处绘制了一个15x150的矩形。接着调用了ctx。save()方法将当前绘制状态压入堆栈。ctx。fillStyleFA6900;ctx。shadowOffsetX5;ctx。shadowOffsetY5;ctx。shadowBlur4;ctx。shadowColorrgba(204,204,204,0。5);ctx。fillRect(0,0,15,150);ctx。save();
当前画布及堆栈的状态如下:
第二步:重新设置fillStyle、shadow属性,然后在坐标(30,0)处绘制一个30x150的矩阵。接着调用ctx。save()方法将当前绘制状态压入堆栈。ctx。fillStyleE0E4CD;ctx。shadowOffsetX10;ctx。shadowOffsetY10;ctx。shadowBlur4;ctx。shadowColorrgba(204,204,204,0。5);ctx。fillRect(30,0,30,150);ctx。save();
当前画布以及堆栈的完整状态如下:
第三步:再次重新设置fillStyle、shadow属性,然后在坐标(90,0)处绘制一个45x150的矩阵。接着调用ctx。save()方法将当前绘制状态压入堆栈。ctx。fillStyleA7DBD7;ctx。shadowOffsetX15;ctx。shadowOffsetY15;ctx。shadowBlur4;ctx。shadowColorrgba(204,204,204,0。5);ctx。fillRect(90,0,45,150);ctx。save();
当前画布以及堆栈的完整状态如下:
第四步:调用ctx。restore()获取堆栈的最新状态,然后使用该状态绘制一个圆形。ctx。restore();ctx。beginPath();ctx。arc(185,75,22,0,Math。PI2,true);ctx。closePath();ctx。fill();
当前画布以及堆栈的完整状态如下:
第五步:继续调用ctx。restore()获取堆栈的最新状态,然后使用该状态绘制一个圆形。ctx。restore();ctx。beginPath();ctx。arc(260,75,15,0,Math。PI2,true);ctx。closePath();ctx。fill();
当前画布以及堆栈的完整状态如下:
第六步:继续调用ctx。restore()获取堆栈的最新状态,然后使用该状态绘制一个圆形。ctx。restore();ctx。beginPath();ctx。arc(305,75,8,0,Math。PI2,true);ctx。closePath();ctx。fill();
当前画布以及堆栈的完整状态如下:
4。本章小结
本章节以图解的方式讲解了Canvas中心点在绘图中的作用,主要通过一个常见的元素180旋转的真实例子展开。同时,重点介绍了两个Canvas绘图状态设置的save()和restore()方法。通过本章节的学习,应该会对Canvas绘制的上下文相关内容有一个比较深入的理解了。参考资料
Understandingsave()andrestore()fortheCanvasContext
目前油价居高不下的原因是什么?前几个月有个段子在网上刷屏了,深入人心!内容是这么写十年前,国际原油每桶147美元,国内油价6。3元每升十年后,国际原油每桶75。56美元,国际油价7。4元每升。这难道是桶贵了吗?
东莞的房子还能不能买?房子永远不会贬值,但升值的速度如蚁速。东莞不同于其他城市,北有广州,南有深圳,东莞处在中间,因此水涨船高,广州深圳任何方向涨水,东莞这艘船高不高一点?各位自己判断。东莞的住房短期用
每周双休,每天八小时,待遇3千上下的工作你愿意做吗?很高兴回答这个问题。首先,这样的工作究竟愿不愿意做的前提是能否满足你当下的心理预期?你个人现在是处于什么样的阶段?是否能够支撑起日常的生活开销?如果是为了求一份相对稳定的工作,不想
怎么才能让自己变得自信起来?自信心是一种健康的心理表现,是一个人对自己力量的确信,深信自己一定能达到要达到的目标。与之相反的就是自卑。自卑心理是指一个人严重缺乏自信时的心理,是自信心的大敌。自卑心不是天生而来
宝宝睡觉总是要把手放被子外面,早上起来手都是冰的,有什么办法能解决吗?我家宝宝就是的,现在四个月,从出了月子天气就一天比一天冷,我早上起来发现他手是冰冷的,连手臂都是冰冷的,所以晚上我等他睡着了,轻轻的给他盖上,如果他动了不愿意盖,我就用手握着他的小
龚俊是靠什么吸粉的?我自己认为第一是他的颜值跟演技,我是让他在山河令里面的温客行圈粉,他一出场便惊艳了我,当时真不认识他,我说这个人是谁呀,我怎么没见过,怎么这么好看呀,而且演技超棒,从来没有哪个明星
刺激战场里的akm好还是m762好?我们为什么用7。62子弹的枪呢,当然是因为伤害高啦,是否能够熟练的使用AKM,一直都是高手与普通玩家之间的风水岭,所以在7。62子弹中的两把步枪中,AKM好还是M762好?AKM我
王曼昱此前东京奥运会是否被低估?王曼昱在全运会女单结束后,也谈到参加东京奥运会对她的影响非常大,对自己起到了升华的作用。那么鳗鱼实力如此之强,在全运会女单女团中对陈梦孙颖莎陈幸同王艺迪都保持了全胜,那为什么东京奥
哪个牌子的防晒霜好?个人感觉品牌的好一点防晒霜分为两种,物理防晒和化学防晒。不管是哪种防晒霜只有正确使用才能保证防晒有效!1儿童孕妇和敏感肌肤建议使用物理防晒霜2防晒霜要涂狗量,脸部大概一元钱硬币的大
宝宝两岁七个月只会喊爸爸妈妈,发育迟缓应该怎么办?宝宝讲话迟点,如不是疾病所造成的都属正常。如同事的大儿子三岁时长得健健康康,各项体检都没问题,可就是不会说话,连最起码的爸妈都不会喊,教也教不会,到了四岁时才能喷单字,更要命的是六
去掉品牌溢价,奔驰宝马和奥迪在技术上或质量上是否比别的车好?谢邀,BBA成为中国豪车市场第一梯队必然是有其必然性。超豪华市场不是一般人都能触及到的,基本不用提。楼上找出故障你给我找个没出过事的车企?装什么理客中啊,整个全球范围你都找不出来。