第156天:canvas(三)
一、变形
1.1 translate
translate(x, y)
用来移动 canvas
的原点到指定的位置
translate
方法接受两个参数。x
是左右偏移量,y
是上下偏移量,如右图所示。
在做变形之前先保存状态是一个良好的习惯。大多数情况下,调用 restore
方法比手动恢复原先的状态要简单得多。又如果你是在一个循环中做位移但没有保存和恢复canvas
的状态,很可能到最后会发现怎么有些东西不见了,那是因为它很可能已经超出 canvas
范围以外了。
注意:translate
移动的是canvas
的坐标原点。(坐标变换)
1 var ctx; 2 function draw(){ 3 var canvas = document.getElementById('tutorial1'); 4 if (!canvas.getContext) return; 5 var ctx = canvas.getContext("2d"); 6 ctx.save(); //保存坐原点平移之前的状态 7 ctx.translate(100, 100); 8 ctx.strokeRect(0, 0, 100, 100) 9 ctx.restore(); //恢复到最初状态 10 ctx.translate(220, 220); 11 ctx.fillRect(0, 0, 100, 100) 12 } 13 draw();
1.2 rotate
rotate(angle)
旋转坐标轴。
这个方法只接受一个参数:旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。
旋转的中心是坐标原点。
1 var ctx; 2 function draw(){ 3 var canvas = document.getElementById('tutorial1'); 4 if (!canvas.getContext) return; 5 var ctx = canvas.getContext("2d"); 6 7 ctx.fillStyle = "red"; 8 ctx.save(); 9 10 ctx.translate(100, 100); 11 ctx.rotate(Math.PI / 180 * 45); 12 ctx.fillStyle = "blue"; 13 ctx.fillRect(0, 0, 100, 100); 14 ctx.restore(); 15 16 ctx.save(); 17 ctx.translate(0, 0); 18 ctx.fillRect(0, 0, 50, 50) 19 ctx.restore(); 20 } 21 draw();
1.3 scale
scale(x, y)
我们用它来增减图形在 canvas
中的像素数目,对形状,位图进行缩小或者放大。
scale
方法接受两个参数。x,y
分别是横轴和纵轴的缩放因子,它们都必须是正值。值比 1.0 小表示缩 小,比 1.0 大则表示放大,值为 1.0 时什么效果都没有。
默认情况下,canvas
的 1 单位就是 1 个像素。举例说,如果我们设置缩放因子是 0.5,1 个单位就变成对应 0.5 个像素,这样绘制出来的形状就会是原先的一半。同理,设置为 2.0 时,1 个单位就对应变成了 2 像素,绘制的结果就是图形放大了 2 倍。
1.4 transform(变形矩阵)
transform(a, b, c, d, e, f)
a (m11)
Horizontal scaling.
b (m12)
Horizontal skewing.
c (m21)
Vertical skewing.
d (m22)
Vertical scaling.
e (dx)
Horizontal moving.
f (dy)
Vertical moving.
1 var ctx; 2 function draw(){ 3 var canvas = document.getElementById('tutorial1'); 4 if (!canvas.getContext) return; 5 var ctx = canvas.getContext("2d"); 6 ctx.transform(1, 1, 0, 1, 0, 0); 7 ctx.fillRect(0, 0, 100, 100); 8 } 9 draw();
二、合成
在前面的所有例子中、,我们总是将一个图形画在另一个之上,对于其他更多的情况,仅仅这样是远远不够的。比如,对合成的图形来说,绘制顺序会有限制。不过,我们可以利用 globalCompositeOperation
属性来改变这种状况。
globalCompositeOperation = type
1 var ctx; 2 function draw(){ 3 var canvas = document.getElementById('tutorial1'); 4 if (!canvas.getContext) return; 5 var ctx = canvas.getContext("2d"); 6 7 ctx.fillStyle = "blue"; 8 ctx.fillRect(0, 0, 200, 200); 9 10 ctx.globalCompositeOperation = "source-over"; //全局合成操作 11 ctx.fillStyle = "red"; 12 ctx.fillRect(100, 100, 200, 200); 13 } 14 draw(); 15 16 </script>
注:下面的展示中,蓝色是原有的,红色是新的。
type `是下面 13 种字符串值之一:
1. source-over(default)
这是默认设置,新图像会覆盖在原有图像。
2. source-in
仅仅会出现新图像与原来图像重叠的部分,其他区域都变成透明的。(包括其他的老图像区域也会透明)
3. source-out
仅仅显示新图像与老图像没有重叠的部分,其余部分全部透明。(老图像也不显示)
4. source-atop
新图像仅仅显示与老图像重叠区域。老图像仍然可以显示。
5. destination-over
新图像会在老图像的下面。
6. destination-in
仅仅新老图像重叠部分的老图像被显示,其他区域全部透明。
7. destination-out
仅仅老图像与新图像没有重叠的部分。 注意显示的是老图像的部分区域。
8. destination-atop
老图像仅仅仅仅显示重叠部分,新图像会显示在老图像的下面。
9. lighter
新老图像都显示,但是重叠区域的颜色做加处理
10. darken
保留重叠部分最黑的像素。(每个颜色位进行比较,得到最小的)
blue: #0000ff
red: #ff0000
所以重叠部分的颜色:#000000
11. lighten
保证重叠部分最量的像素。(每个颜色位进行比较,得到最大的)
blue: #0000ff
red: #ff0000
所以重叠部分的颜色:#ff00ff
12. xor
重叠部分会变成透明
13. copy
只有新图像会被保留,其余的全部被清除(边透明)
三、裁剪路径
clip()
把已经创建的路径转换成裁剪路径。
裁剪路径的作用是遮罩。只显示裁剪路径内的区域,裁剪路径外的区域会被隐藏。
注意:clip()
只能遮罩在这个方法调用之后绘制的图像,如果是clip()
方法调用之前绘制的图像,则无法实现遮罩。
1 var ctx; 2 function draw(){ 3 var canvas = document.getElementById('tutorial1'); 4 if (!canvas.getContext) return; 5 var ctx = canvas.getContext("2d"); 6 7 ctx.beginPath(); 8 ctx.arc(20,20, 100, 0, Math.PI * 2); 9 ctx.clip(); 10 11 ctx.fillStyle = "pink"; 12 ctx.fillRect(20, 20, 100,100); 13 } 14 draw();
四、动画
动画的基本步骤
清空
canvas
再绘制每一帧动画之前,需要清空所有。清空所有最简单的做法就是
clearRect()
方法保存
canvas
状态如果在绘制的过程中会更改
canvas
的状态(颜色、移动了坐标原点等),又在绘制每一帧时都是原始状态的话,则最好保存下canvas
的状态绘制动画图形
这一步才是真正的绘制动画帧
恢复
canvas
状态如果你前面保存了
canvas
状态,则应该在绘制完成一帧之后恢复canvas
状态。
控制动画
我们可用通过canvas
的方法或者自定义的方法把图像会知道到canvas
上。正常情况,我们能看到绘制的结果是在脚本执行结束之后。例如,我们不可能在一个 for
循环内部完成动画。
也就是,为了执行动画,我们需要一些可以定时执行重绘的方法。
一般用到下面三个方法:
setInterval()
setTimeout()
requestAnimationFrame()
案例1:太阳系
1 let sun; 2 let earth; 3 let moon; 4 let ctx; 5 function init(){ 6 sun = new Image(); 7 earth = new Image(); 8 moon = new Image(); 9 sun.src = "sun.png"; 10 earth.src = "earth.png"; 11 moon.src = "moon.png"; 12 13 let canvas = document.querySelector("#solar"); 14 ctx = canvas.getContext("2d"); 15 16 sun.onload = function (){ 17 draw() 18 } 19 20 } 21 init(); 22 function draw(){ 23 ctx.clearRect(0, 0, 300, 300); //清空所有的内容 24 /*绘制 太阳*/ 25 ctx.drawImage(sun, 0, 0, 300, 300); 26 27 ctx.save(); 28 ctx.translate(150, 150); 29 30 //绘制earth轨道 31 ctx.beginPath(); 32 ctx.strokeStyle = "rgba(255,255,0,0.5)"; 33 ctx.arc(0, 0, 100, 0, 2 * Math.PI) 34 ctx.stroke() 35 36 let time = new Date(); 37 //绘制地球 38 ctx.rotate(2 * Math.PI / 60 * time.getSeconds() + 2 * Math.PI / 60000 * time.getMilliseconds()) 39 ctx.translate(100, 0); 40 ctx.drawImage(earth, -12, -12) 41 42 //绘制月球轨道 43 ctx.beginPath(); 44 ctx.strokeStyle = "rgba(255,255,255,.3)"; 45 ctx.arc(0, 0, 40, 0, 2 * Math.PI); 46 ctx.stroke(); 47 48 //绘制月球 49 ctx.rotate(2 * Math.PI / 6 * time.getSeconds() + 2 * Math.PI / 6000 * time.getMilliseconds()); 50 ctx.translate(40, 0); 51 ctx.drawImage(moon, -3.5, -3.5); 52 ctx.restore(); 53 54 requestAnimationFrame(draw); 55 }
案例2:模拟时钟
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <style> 7 body { 8 padding: 0; 9 margin: 0; 10 background-color: rgba(0, 0, 0, 0.1) 11 } 12 13 canvas { 14 display: block; 15 margin: 200px auto; 16 } 17 </style> 18 </head> 19 <body> 20 <canvas id="solar" width="300" height="300"></canvas> 21 <script> 22 init(); 23 24 function init(){ 25 let canvas = document.querySelector("#solar"); 26 let ctx = canvas.getContext("2d"); 27 draw(ctx); 28 } 29 30 function draw(ctx){ 31 requestAnimationFrame(function step(){ 32 drawDial(ctx); //绘制表盘 33 drawAllHands(ctx); //绘制时分秒针 34 requestAnimationFrame(step); 35 }); 36 } 37 /*绘制时分秒针*/ 38 function drawAllHands(ctx){ 39 let time = new Date(); 40 41 let s = time.getSeconds(); 42 let m = time.getMinutes(); 43 let h = time.getHours(); 44 45 let pi = Math.PI; 46 let secondAngle = pi / 180 * 6 * s; //计算出来s针的弧度 47 let minuteAngle = pi / 180 * 6 * m + secondAngle / 60; //计算出来分针的弧度 48 let hourAngle = pi / 180 * 30 * h + minuteAngle / 12; //计算出来时针的弧度 49 50 drawHand(hourAngle, 60, 6, "red", ctx); //绘制时针 51 drawHand(minuteAngle, 106, 4, "green", ctx); //绘制分针 52 drawHand(secondAngle, 129, 2, "blue", ctx); //绘制秒针 53 } 54 /*绘制时针、或分针、或秒针 55 * 参数1:要绘制的针的角度 56 * 参数2:要绘制的针的长度 57 * 参数3:要绘制的针的宽度 58 * 参数4:要绘制的针的颜色 59 * 参数4:ctx 60 * */ 61 function drawHand(angle, len, width, color, ctx){ 62 ctx.save(); 63 ctx.translate(150, 150); //把坐标轴的远点平移到原来的中心 64 ctx.rotate(-Math.PI / 2 + angle); //旋转坐标轴。 x轴就是针的角度 65 ctx.beginPath(); 66 ctx.moveTo(-4, 0); 67 ctx.lineTo(len, 0); // 沿着x轴绘制针 68 ctx.lineWidth = width; 69 ctx.strokeStyle = color; 70 ctx.lineCap = "round"; 71 ctx.stroke(); 72 ctx.closePath(); 73 ctx.restore(); 74 } 75 76 /*绘制表盘*/ 77 function drawDial(ctx){ 78 let pi = Math.PI; 79 80 ctx.clearRect(0, 0, 300, 300); //清除所有内容 81 ctx.save(); 82 83 ctx.translate(150, 150); //一定坐标原点到原来的中心 84 ctx.beginPath(); 85 ctx.arc(0, 0, 148, 0, 2 * pi); //绘制圆周 86 ctx.stroke(); 87 ctx.closePath(); 88 89 for (let i = 0; i < 60; i++){//绘制刻度。 90 ctx.save(); 91 ctx.rotate(-pi / 2 + i * pi / 30); //旋转坐标轴。坐标轴x的正方形从 向上开始算起 92 ctx.beginPath(); 93 ctx.moveTo(110, 0); 94 ctx.lineTo(140, 0); 95 ctx.lineWidth = i % 5 ? 2 : 4; 96 ctx.strokeStyle = i % 5 ? "blue" : "red"; 97 ctx.stroke(); 98 ctx.closePath(); 99 ctx.restore(); 100 } 101 ctx.restore(); 102 } 103 </script> 104 </body> 105 </html>
第156天:canvas(三)相关推荐
- html根据坐标画圆,Canvas三种动态画圆实现方法说明(小结)
前言 canvas是HTML5出来的绘图API容器,对于图形的处理非常强大,下面使用canvas配合JavaScript来做一下动态画圆效果.可以用它来做圆形进度条来使用. 这里我个人总结了3种实现方 ...
- Flutter 36: 图解自定义 View 之 Canvas (三)
小菜继续学习 Canvas 的相关方法: drawVertices 绘制顶点 小菜上次没有整理 drawVertices 的绘制方法,这次补上:Vertice 即顶点,通过绘制多个顶点,在进行连线,多 ...
- Canvas三种动态画圆实现方法说明
前言 canvas是HTML5出来的绘图API容器,对于图形的处理非常强大,下面使用canvas配合JavaScript来做一下动态画圆效果.可以用它来做圆形进度条来使用. 这里我个人总结了3种实现方 ...
- Android_2D绘图的学习Paint,Canvas(三)
前言 上一节,学习了Paint的高级用法后,这一节我们将canvas的用法.主要涉及到canvas的绘制坐标变换translate,rotate.还没看过上一节的请点击这里:Android_2D绘图的 ...
- javascript学习-canvas
canvas 简介 html5中canvas标签用于绘制图像.不过canvas标签本身没有绘制能力,是图形的容器,需要用脚本完成绘制.getContext()方法可返回一个对象,该对象提供了用于在画布 ...
- html5绘制运动的图形,html5 canvas高级贝塞尔曲线运动动画
canvas高级贝塞尔曲线运动动画 window.addEventListener('load',eventWindowLoaded,false);functioneventWindowLoaded( ...
- html5 canvas 显示文字居中,html5 canvas 文字居中对齐
> web前端 > HTML 5 > 正文 html5 canvas 文字居中对齐 2013-07-09 我要投稿 [color=eight:25px]html部门 [color=e ...
- canvas练习第2天--剪纸风格海报(无动效)
目录 参考 图例 成果 代码 参考 1.canvas二次贝塞尔曲线闭合填充图形 //二层dtx.beginPath();//一定要有开始dtx.moveTo(380,200);dtx.quadrati ...
- 贝赛尔曲线及其应用全面解析
贝赛尔曲线及其应用全面解析 1.概念 贝塞尔曲线(Bezier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线.一般的矢量图形软件通过它来精确画出曲线,一条贝塞尔曲线由路径 ...
- Unity3D_(游戏)贪吃蛇
Unity制作贪吃蛇小游戏 玩家通过"WASD"控制小蛇上下左右移动,蛇头撞倒食物,则食物被吃掉,蛇身体长一节,接着又出现食物,等待蛇来吃,如果蛇在移动中撞到墙或身体交叉蛇头撞倒自 ...
最新文章
- uniapp中qrcode生成二维码后传的参数不见了_阿虚教你制作动态二维码,超详细教程!
- joomla个性定制(二)
- Python3使用md5
- Linux时间子系统之(十二):periodic tick
- Docker容器中的Linux机器快速设置国内源
- 【英语学习】【Daily English】U01 Greetings / L04 Hello, this is Peter Jones speaking
- 活跃了 40 年的 AWK 现在怎么样了?
- Android Java调用ffmpeg命令
- 孙鑫VC学习笔记:第十五讲 (二) 线程创建方法
- JPA环境下使用Hibernate二级缓存
- 【思维导图训练2】--发散思维的秘诀
- 重回童年的经典系列 |《保卫萝卜》来了,你还记得它吗?复刻 源码+解析 @怀旧的你
- QT之qss教程- QScrollBar
- 第2章:Android的编译环境--build系统
- Linux alsa-lib c语言 播放wav音频
- RTA PAVIA CSD ET04控制器
- 使用空密码的本地帐户只允许进行控制台登陆_在群晖中运行Windows是什么样体验?教你VMM虚拟机简单使用...
- 普吉岛最后的黄昏,中文字幕
- Celery:Optimizing
- 安川机器人外部急停信号点不开_安川机器人示教器常见故障维修
热门文章
- RabbitMQ的六种工作模式(三)
- PHP中cURL的curl_getinfo函数返回的CURLINFO_HTTP_CODE是0
- LINUX环境变量environ
- cygwin终端中显示的中文改成英文(没成功)
- 管理新语:会议与问题的关系
- NDK编译doubango时出现错误:undefined reference to ‘stderr‘
- 压缩软件能否加上忽略某些目录的功能
- Windows下FireFox插件dll文件名,必须是np开头,不能是plugin结尾
- 纽微特荒唐事:都知道是找人顶罪,竟没人敢指正
- 百度人脸识别:即使不用,也要import,否则C调用Python会崩溃