一、变形

1.1 translate

translate(x, y)

​ 用来移动 canvas 原点到指定的位置

​ translate方法接受两个参数。x 是左右偏移量,y 是上下偏移量,如右图所示。

在做变形之前先保存状态是一个良好的习惯。大多数情况下,调用 restore 方法比手动恢复原先的状态要简单得多。又如果你是在一个循环中做位移但没有保存和恢复canvas 的状态,很可能到最后会发现怎么有些东西不见了,那是因为它很可能已经超出 canvas 范围以外了。

​ 注意:translate移动的是canvas的坐标原点。(坐标变换)

 var ctx;
function draw(){
var canvas = document.getElementById('tutorial1');
if (!canvas.getContext) return;
var ctx = canvas.getContext("2d");
ctx.save(); //保存坐原点平移之前的状态
ctx.translate(100, 100);
ctx.strokeRect(0, 0, 100, 100)
ctx.restore(); //恢复到最初状态
ctx.translate(220, 220);
ctx.fillRect(0, 0, 100, 100)
}
draw();

1.2 rotate

rotate(angle)

​ 旋转坐标轴。

​ 这个方法只接受一个参数:旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。

​ 旋转的中心是坐标原点。

 var ctx;
function draw(){
var canvas = document.getElementById('tutorial1');
if (!canvas.getContext) return;
var ctx = canvas.getContext("2d"); ctx.fillStyle = "red";
ctx.save(); ctx.translate(100, 100);
ctx.rotate(Math.PI / 180 * 45);
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, 100, 100);
ctx.restore(); ctx.save();
ctx.translate(0, 0);
ctx.fillRect(0, 0, 50, 50)
ctx.restore();
}
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.

 var ctx;
function draw(){
var canvas = document.getElementById('tutorial1');
if (!canvas.getContext) return;
var ctx = canvas.getContext("2d");
ctx.transform(1, 1, 0, 1, 0, 0);
ctx.fillRect(0, 0, 100, 100);
}
draw();

  

二、合成

​ 在前面的所有例子中、,我们总是将一个图形画在另一个之上,对于其他更多的情况,仅仅这样是远远不够的。比如,对合成的图形来说,绘制顺序会有限制。不过,我们可以利用 globalCompositeOperation 属性来改变这种状况。

globalCompositeOperation = type

   var ctx;
function draw(){
var canvas = document.getElementById('tutorial1');
if (!canvas.getContext) return;
var ctx = canvas.getContext("2d"); ctx.fillStyle = "blue";
ctx.fillRect(0, 0, 200, 200); ctx.globalCompositeOperation = "source-over"; //全局合成操作
ctx.fillStyle = "red";
ctx.fillRect(100, 100, 200, 200);
}
draw(); </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()方法调用之前绘制的图像,则无法实现遮罩。

 var ctx;
function draw(){
var canvas = document.getElementById('tutorial1');
if (!canvas.getContext) return;
var ctx = canvas.getContext("2d"); ctx.beginPath();
ctx.arc(20,20, 100, 0, Math.PI * 2);
ctx.clip(); ctx.fillStyle = "pink";
ctx.fillRect(20, 20, 100,100);
}
draw();

四、动画

动画的基本步骤

  1. 清空canvas

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

  2. 保存canvas状态

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

  3. 绘制动画图形

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

  4. 恢复canvas状态

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

控制动画

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

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

一般用到下面三个方法:

  1. setInterval()
  2. setTimeout()
  3. requestAnimationFrame()

案例1:太阳系

 let sun;
let earth;
let moon;
let ctx;
function init(){
sun = new Image();
earth = new Image();
moon = new Image();
sun.src = "sun.png";
earth.src = "earth.png";
moon.src = "moon.png"; let canvas = document.querySelector("#solar");
ctx = canvas.getContext("2d"); sun.onload = function (){
draw()
} }
init();
function draw(){
ctx.clearRect(0, 0, 300, 300); //清空所有的内容
/*绘制 太阳*/
ctx.drawImage(sun, 0, 0, 300, 300); ctx.save();
ctx.translate(150, 150); //绘制earth轨道
ctx.beginPath();
ctx.strokeStyle = "rgba(255,255,0,0.5)";
ctx.arc(0, 0, 100, 0, 2 * Math.PI)
ctx.stroke() let time = new Date();
//绘制地球
ctx.rotate(2 * Math.PI / 60 * time.getSeconds() + 2 * Math.PI / 60000 * time.getMilliseconds())
ctx.translate(100, 0);
ctx.drawImage(earth, -12, -12) //绘制月球轨道
ctx.beginPath();
ctx.strokeStyle = "rgba(255,255,255,.3)";
ctx.arc(0, 0, 40, 0, 2 * Math.PI);
ctx.stroke(); //绘制月球
ctx.rotate(2 * Math.PI / 6 * time.getSeconds() + 2 * Math.PI / 6000 * time.getMilliseconds());
ctx.translate(40, 0);
ctx.drawImage(moon, -3.5, -3.5);
ctx.restore(); requestAnimationFrame(draw);
}

案例2:模拟时钟

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body {
padding: 0;
margin: 0;
background-color: rgba(0, 0, 0, 0.1)
} canvas {
display: block;
margin: 200px auto;
}
</style>
</head>
<body>
<canvas id="solar" width="300" height="300"></canvas>
<script>
init(); function init(){
let canvas = document.querySelector("#solar");
let ctx = canvas.getContext("2d");
draw(ctx);
} function draw(ctx){
requestAnimationFrame(function step(){
drawDial(ctx); //绘制表盘
drawAllHands(ctx); //绘制时分秒针
requestAnimationFrame(step);
});
}
/*绘制时分秒针*/
function drawAllHands(ctx){
let time = new Date(); let s = time.getSeconds();
let m = time.getMinutes();
let h = time.getHours(); let pi = Math.PI;
let secondAngle = pi / 180 * 6 * s; //计算出来s针的弧度
let minuteAngle = pi / 180 * 6 * m + secondAngle / 60; //计算出来分针的弧度
let hourAngle = pi / 180 * 30 * h + minuteAngle / 12; //计算出来时针的弧度 drawHand(hourAngle, 60, 6, "red", ctx); //绘制时针
drawHand(minuteAngle, 106, 4, "green", ctx); //绘制分针
drawHand(secondAngle, 129, 2, "blue", ctx); //绘制秒针
}
/*绘制时针、或分针、或秒针
* 参数1:要绘制的针的角度
* 参数2:要绘制的针的长度
* 参数3:要绘制的针的宽度
* 参数4:要绘制的针的颜色
* 参数4:ctx
* */
function drawHand(angle, len, width, color, ctx){
ctx.save();
ctx.translate(150, 150); //把坐标轴的远点平移到原来的中心
ctx.rotate(-Math.PI / 2 + angle); //旋转坐标轴。 x轴就是针的角度
ctx.beginPath();
ctx.moveTo(-4, 0);
ctx.lineTo(len, 0); // 沿着x轴绘制针
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.lineCap = "round";
ctx.stroke();
ctx.closePath();
ctx.restore();
} /*绘制表盘*/
function drawDial(ctx){
let pi = Math.PI; ctx.clearRect(0, 0, 300, 300); //清除所有内容
ctx.save(); ctx.translate(150, 150); //一定坐标原点到原来的中心
ctx.beginPath();
ctx.arc(0, 0, 148, 0, 2 * pi); //绘制圆周
ctx.stroke();
ctx.closePath(); for (let i = 0; i < 60; i++){//绘制刻度。
ctx.save();
ctx.rotate(-pi / 2 + i * pi / 30); //旋转坐标轴。坐标轴x的正方形从 向上开始算起
ctx.beginPath();
ctx.moveTo(110, 0);
ctx.lineTo(140, 0);
ctx.lineWidth = i % 5 ? 2 : 4;
ctx.strokeStyle = i % 5 ? "blue" : "red";
ctx.stroke();
ctx.closePath();
ctx.restore();
}
ctx.restore();
}
</script>
</body>
</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. 20155302 2016-2017-2 《Java程序设计》第4周总结

    20155302 2016-2017-2 <Java程序设计>第4周学习总结 教材学习内容总结 有关类的继承的理解:类实现继承的格式:class 子类名 extends 父类名 类的继承有 ...

  2. 20155315实验四 Android程序设计

    实验内容 安装 Android Stuidio 学习Android Stuidio调试应用程序 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim ...

  3. day1 RHCE

    1.环境部署 classroom.example.com: 172.25.0.254 root Asimov server0.example.com: 172.25.0.11 root redhat ...

  4. DSP5509的USB协议开发

    1. 使用的板子 2. 原理图相关,这个1.5K的上拉电阻,全速和高速上拉在D+,低速上拉在D- 3. 中断处理函数没有搞明白是什么意思?这个工程我怎么基本看不懂? interrupt void US ...

  5. 在Centos7下安装与部署.net core

    在Centos7下安装与部署.net core 2018年02月28日 19:36:16 阅读数:388 个人安装流程,参照文档 https://www.cnblogs.com/Burt/p/6566 ...

  6. html面试题总结

    1.请描述一个网页从开始请求到最终显示的完整过程? 1).在浏览器中输入网址: 2).发送至DNS服务器并获得域名对应的WEB服务器的IP地址: 3).与WEB服务器简历TCP连接: 4).浏览器向W ...

  7. 为CentOS系统配置防火墙设置

    在各种操作系统中,为了保护系统在网络中是相对安全的,我们通常都会给操作系统配置防火墙,通过配置防火墙来限定哪些流量可以进来,哪些流量可以出去,通过这样的一种方式,可以有效的管理系统的流量,从一定程度上 ...

  8. python yagmail第三方库发送邮件--更简洁

    1.安装第三方库yagmail: pip install yagmail 2.上代码 import yagmail import os def send_email(): #链接邮箱服务器 serve ...

  9. 学习笔记之shell命令

    linux shell命令学习笔记:~这里只是对自己一些常用但是不熟悉的的命令进行记录 -------------------------------------------------------- ...

  10. Delphi 实现照片抽奖-原创

    有单位年会要用照片抽奖,上网搜了几个都不满意,且居然还要收费.自己写一个算了.只是有一点不爽,Delphi 7 在 Windows 7 64位下有问题,不能双击 dpr 文件直接打开项目! 关于性能: ...