一、变形

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. 20155308 2016-2017-2 《Java程序设计》第10周学习总结

    20155308 2016-2017-2 <Java程序设计>第10周学习总结 教材学习内容总结 网络概述 计算机网络:通过一定的物理设备将处于不同位置的计算机连接起来组成的网络,这个网络 ...

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

    20155322 2016-2017-2 <Java程序设计>第10周学习总结 教材学习内容总结 第10周学习的主要内容Java和Android开发学习指南(第二版)(EPUBIT,Jav ...

  3. 《Java程序设计》课堂实践内容总结

    <Java程序设计>课堂实践内容总结 实践一 要求 修改教材P98 Score2.java, 让执行结果数组填充是自己的学号: 提交在IDEA或命令行中运行结查截图,加上学号水印,没学号的 ...

  4. 【LG5019】[NOIP2018]道路铺设

    [LG5019][NOIP2018]道路铺设 题面 洛谷 题解 \(NOIP\) 抄 \(NOIP\)差评 设当前做到了位置\(i\) 且\(h_i\) \(-\) \(h_i\)\(_+\)\(_1 ...

  5. 欢迎使用 Flask¶

    欢迎使用 Flask¶ 欢迎阅读 Flask 文档. 本文档分为几个部分.我推荐您先从 安装 开始,之后再浏览 快速入门 章节. 教程 比快速入门更详细地介绍了如何用 Flask 创建一个完整的 应用 ...

  6. javaweb(十四)——JSP原理

    一.什么是JSP? JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术. JSP这门技术的最大的特点在于,写jsp就像在写h ...

  7. 一起来做chrome扩展《页面右键菜单》

    本文主要内容 contextMenus的设置 打开权限 创建菜单 点击菜单 background script向content script发送消息 1. contextMenus的设置 1.1 打开 ...

  8. katalon系列十:Katalon Studio自定义关键字之拖拽

    Katalon Studio自带关键字“Drag And Drop To Object”,可以在这个网站实践:http://jqueryui.com/droppable/#default 不过“Dra ...

  9. C语言—单链表

    单链表操作:读取,插入和删除 #include "stdafx.h" #include <string.h> #include <stdio.h> #inc ...

  10. 创建image

    摘要: 本节演示如何通过 Web GUI 和 CLI 两种方法创建 Image. 本节演示如何通过 Web GUI 和 CLI 两种方法创建 Image. OpenStack 为终端用户提供了 Web ...