一、变形

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();

四、动画

动画的基本步骤

  1. 清空canvas

    再绘制每一帧动画之前,需要清空所有。清空所有最简单的做法就是clearRect()方法

  2. 保存canvas状态

    如果在绘制的过程中会更改canvas的状态(颜色、移动了坐标原点等),又在绘制每一帧时都是原始状态的话,则最好保存下canvas的状态

  3. 绘制动画图形

    这一步才是真正的绘制动画帧

  4. 恢复canvas状态

    如果你前面保存了canvas状态,则应该在绘制完成一帧之后恢复canvas状态。

控制动画

我们可用通过canvas的方法或者自定义的方法把图像会知道到canvas上。正常情况,我们能看到绘制的结果是在脚本执行结束之后。例如,我们不可能在一个 for 循环内部完成动画。

也就是,为了执行动画,我们需要一些可以定时执行重绘的方法。

一般用到下面三个方法:

  1. setInterval()
  2. setTimeout()
  3. 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(三)相关推荐

  1. html根据坐标画圆,Canvas三种动态画圆实现方法说明(小结)

    前言 canvas是HTML5出来的绘图API容器,对于图形的处理非常强大,下面使用canvas配合JavaScript来做一下动态画圆效果.可以用它来做圆形进度条来使用. 这里我个人总结了3种实现方 ...

  2. Flutter 36: 图解自定义 View 之 Canvas (三)

    小菜继续学习 Canvas 的相关方法: drawVertices 绘制顶点 小菜上次没有整理 drawVertices 的绘制方法,这次补上:Vertice 即顶点,通过绘制多个顶点,在进行连线,多 ...

  3. Canvas三种动态画圆实现方法说明

    前言 canvas是HTML5出来的绘图API容器,对于图形的处理非常强大,下面使用canvas配合JavaScript来做一下动态画圆效果.可以用它来做圆形进度条来使用. 这里我个人总结了3种实现方 ...

  4. Android_2D绘图的学习Paint,Canvas(三)

    前言 上一节,学习了Paint的高级用法后,这一节我们将canvas的用法.主要涉及到canvas的绘制坐标变换translate,rotate.还没看过上一节的请点击这里:Android_2D绘图的 ...

  5. javascript学习-canvas

    canvas 简介 html5中canvas标签用于绘制图像.不过canvas标签本身没有绘制能力,是图形的容器,需要用脚本完成绘制.getContext()方法可返回一个对象,该对象提供了用于在画布 ...

  6. html5绘制运动的图形,html5 canvas高级贝塞尔曲线运动动画

    canvas高级贝塞尔曲线运动动画 window.addEventListener('load',eventWindowLoaded,false);functioneventWindowLoaded( ...

  7. html5 canvas 显示文字居中,html5 canvas 文字居中对齐

    > web前端 > HTML 5 > 正文 html5 canvas 文字居中对齐 2013-07-09 我要投稿 [color=eight:25px]html部门 [color=e ...

  8. canvas练习第2天--剪纸风格海报(无动效)

    目录 参考 图例 成果 代码 参考 1.canvas二次贝塞尔曲线闭合填充图形 //二层dtx.beginPath();//一定要有开始dtx.moveTo(380,200);dtx.quadrati ...

  9. 贝赛尔曲线及其应用全面解析

    贝赛尔曲线及其应用全面解析 1.概念 贝塞尔曲线(Bezier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线.一般的矢量图形软件通过它来精确画出曲线,一条贝塞尔曲线由路径 ...

  10. Unity3D_(游戏)贪吃蛇

    Unity制作贪吃蛇小游戏 玩家通过"WASD"控制小蛇上下左右移动,蛇头撞倒食物,则食物被吃掉,蛇身体长一节,接着又出现食物,等待蛇来吃,如果蛇在移动中撞到墙或身体交叉蛇头撞倒自 ...

最新文章

  1. uniapp中qrcode生成二维码后传的参数不见了_阿虚教你制作动态二维码,超详细教程!
  2. joomla个性定制(二)
  3. Python3使用md5
  4. Linux时间子系统之(十二):periodic tick
  5. Docker容器中的Linux机器快速设置国内源
  6. 【英语学习】【Daily English】U01 Greetings / L04 Hello, this is Peter Jones speaking
  7. 活跃了 40 年的 AWK 现在怎么样了?
  8. Android Java调用ffmpeg命令
  9. 孙鑫VC学习笔记:第十五讲 (二) 线程创建方法
  10. JPA环境下使用Hibernate二级缓存
  11. 【思维导图训练2】--发散思维的秘诀
  12. 重回童年的经典系列 |《保卫萝卜》来了,你还记得它吗?复刻 源码+解析 @怀旧的你
  13. QT之qss教程- QScrollBar
  14. 第2章:Android的编译环境--build系统
  15. Linux alsa-lib c语言 播放wav音频
  16. RTA PAVIA CSD ET04控制器
  17. 使用空密码的本地帐户只允许进行控制台登陆_在群晖中运行Windows是什么样体验?教你VMM虚拟机简单使用...
  18. 普吉岛最后的黄昏,中文字幕
  19. Celery:Optimizing
  20. 安川机器人外部急停信号点不开_安川机器人示教器常见故障维修

热门文章

  1. RabbitMQ的六种工作模式(三)
  2. PHP中cURL的curl_getinfo函数返回的CURLINFO_HTTP_CODE是0
  3. LINUX环境变量environ
  4. cygwin终端中显示的中文改成英文(没成功)
  5. 管理新语:会议与问题的关系
  6. NDK编译doubango时出现错误:undefined reference to ‘stderr‘
  7. 压缩软件能否加上忽略某些目录的功能
  8. Windows下FireFox插件dll文件名,必须是np开头,不能是plugin结尾
  9. 纽微特荒唐事:都知道是找人顶罪,竟没人敢指正
  10. 百度人脸识别:即使不用,也要import,否则C调用Python会崩溃