一、变形

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. Flutter 36: 图解自定义 View 之 Canvas (三)

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

  2. [js高手之路] html5 canvas系列教程 - arcTo(弧度与二次,三次贝塞尔曲线以及在线工具)

    之前,我写了一个arc函数的用法:[js高手之路] html5 canvas系列教程 - arc绘制曲线图形(曲线,弧线,圆形). arcTo: cxt.arcTo( cx, cy, x2, y2, ...

  3. canvas学习和面向对象(二)

    Canvas 学习(二) 上一篇Canvas 学习(一)中我是用canvas绘制了一些基本和组合的图形. 现在开始绘制图片和动画帧,以及面向对象的升级版本. 还是一样,看代码,所有的代码都托管在git ...

  4. HTML5 Canvas 画布

    一.Canvas是什么? canvas,是一个画布,canvas元素用于在网页上绘制图形. canvas 拥有多种绘制路径.矩形.圆形.字符以及添加图像的方法. 二.创建Canvas元素 加上基本的属 ...

  5. 中国地图 xaml Canvas

    <Canvas x:Name="LayoutRoot"  Height="560" Width="700" Background=&q ...

  6. 【javascript】谈谈HTML5: Web-Worker、canvas、indexedDB、拖拽事件

    前言:作为一名Web开发者,可能你并没有对这个“H5”这个字眼投入太多的关注,但实际上它早已不知不觉进入到你的开发中,并且总有一天会让你不得不正视它,了解它并运用它   打个比方:<海贼王> ...

  7. HTML5的新标签之一的Canvas

    一. <canvas>简介(了解) 1. 什么是canvas: 是HTML5提供的一种新标签 <canvas></canvas>  英 ['kænvəs]  美 [ ...

  8. html5 canvas高级贝塞尔曲线运动动画(好吧这一篇被批的体无完肤!都说看不懂了!没办法加注释了!当然数学不好的我也没办法了,当然这还涉及到一门叫做计算机图形学的学科)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. H5如何用Canvas画布生成并保存带图片文字的新年快乐的海报

    摘要:初略算了算大概有20天没有写博客了,原本是打算1月1号元旦那天写一个年终总结的,博客园里大佬们都在总结过去,迎接将来,看得我热血沸腾,想想自己也工作快2年了,去年都没有去总结一下,今年势必要总结 ...

  10. 安卓自己定义View进阶-Canvas之绘制基本形状

    Canvas之绘制基本形状 作者微博: @GcsSloop [本系列相关文章] 在上一篇自己定义View分类与流程中我们了解自己定义View相关的基本知识,只是,这些东西依然还是理论,并不能拿来(zh ...

随机推荐

  1. 20155305 2016-2017-2 《Java程序设计》实验二 Java面向对象程序设计

    实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验步骤 单元测试 1. ...

  2. 20155315 2016-2017-2 《Java程序设计》第一周学习总结

    教材学习内容总结 第一章中提到了Java的前世今生和三大平台,我了解到Java SE包括JVM,JRE,JDK和Java语言.java最基本的特性之一是"跨平台",这使得Java语 ...

  3. 20155327 嵌入式C语言课堂补交

    嵌入式C语言 题目要求 在作业本上完成附图作业,要认真看题目要求. 提交作业截图 作弊本学期成绩清零(有雷同的,不管是给别人传答案,还是找别人要答案都清零) 题目分析 分析一:提取插入时间 根据老师上 ...

  4. week8课上实践

    课上练习. 第一题: 参考 http://www.cnblogs.com/rocedu/p/6766748.html#SECCLA 在Linux下完成"求命令行传入整数参数的和" ...

  5. 【MongoDB】NoSQL Manager for MongoDB 教程(进阶篇)

    项目做完,有点时间,接着写下第二篇吧.回顾戳这里  基础篇:安装.连接mongodb.使用shell.增删改查.表复制 本文属于进阶篇,为什么叫进阶篇,仅仅是因为这些功能属于DB范畴,一般使用的不多, ...

  6. equals和==方法比较(二)--Long中equals源码分析

    接上篇,分析equals方法在Long包装类中的重写,其他类及我们自定义的类,同样可以根据需要重新equals方法. equals方法定义 equals方法是Object类中的方法,java中所有的对 ...

  7. 一个web应用的诞生(2)--使用模板

    经过了第一章的内容,已经可以做出一些简单的页面,首先用这种方式做一个登录页面,首先要创建一个login的路由方法: @app.route("/login",methods=[&qu ...

  8. Linux环境配置备忘

    1.Ubuntu服务器版本装scipy 预装版本可能fortran包版本过旧或者不全,安装scipy之前需要更新环境. sudo apt-get install gfortran libopenbla ...

  9. Django——多网页网站及网页互联

    在helloapp文件夹下添加名为templates的文件夹(此文件夹名称是固定的),并在其下添加html文件,文件内容根据自己网页想呈现的内容而定 在views文件内添加新的函数 在urls文件内添 ...

  10. KRKR基础篇(二)

    这里介绍一些krkr的语法规范,具体的命令含义及用法以后再叙述 一:kag语法及基本概念 KAG使用的剧本语言为KAG Script,文件扩展名为.ks 脚本内的文字除  注释,  命令 ,  段落标 ...