第156天:canvas(三)
一、变形
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();
四、动画
动画的基本步骤
清空
canvas
再绘制每一帧动画之前,需要清空所有。清空所有最简单的做法就是
clearRect()
方法保存
canvas
状态如果在绘制的过程中会更改
canvas
的状态(颜色、移动了坐标原点等),又在绘制每一帧时都是原始状态的话,则最好保存下canvas
的状态绘制动画图形
这一步才是真正的绘制动画帧
恢复
canvas
状态如果你前面保存了
canvas
状态,则应该在绘制完成一帧之后恢复canvas
状态。
控制动画
我们可用通过canvas
的方法或者自定义的方法把图像会知道到canvas
上。正常情况,我们能看到绘制的结果是在脚本执行结束之后。例如,我们不可能在一个 for
循环内部完成动画。
也就是,为了执行动画,我们需要一些可以定时执行重绘的方法。
一般用到下面三个方法:
setInterval()
setTimeout()
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(三)的更多相关文章
- Flutter 36: 图解自定义 View 之 Canvas (三)
小菜继续学习 Canvas 的相关方法: drawVertices 绘制顶点 小菜上次没有整理 drawVertices 的绘制方法,这次补上:Vertice 即顶点,通过绘制多个顶点,在进行连线,多 ...
- [js高手之路] html5 canvas系列教程 - arcTo(弧度与二次,三次贝塞尔曲线以及在线工具)
之前,我写了一个arc函数的用法:[js高手之路] html5 canvas系列教程 - arc绘制曲线图形(曲线,弧线,圆形). arcTo: cxt.arcTo( cx, cy, x2, y2, ...
- canvas学习和面向对象(二)
Canvas 学习(二) 上一篇Canvas 学习(一)中我是用canvas绘制了一些基本和组合的图形. 现在开始绘制图片和动画帧,以及面向对象的升级版本. 还是一样,看代码,所有的代码都托管在git ...
- HTML5 Canvas 画布
一.Canvas是什么? canvas,是一个画布,canvas元素用于在网页上绘制图形. canvas 拥有多种绘制路径.矩形.圆形.字符以及添加图像的方法. 二.创建Canvas元素 加上基本的属 ...
- 中国地图 xaml Canvas
<Canvas x:Name="LayoutRoot" Height="560" Width="700" Background=&q ...
- 【javascript】谈谈HTML5: Web-Worker、canvas、indexedDB、拖拽事件
前言:作为一名Web开发者,可能你并没有对这个“H5”这个字眼投入太多的关注,但实际上它早已不知不觉进入到你的开发中,并且总有一天会让你不得不正视它,了解它并运用它 打个比方:<海贼王> ...
- HTML5的新标签之一的Canvas
一. <canvas>简介(了解) 1. 什么是canvas: 是HTML5提供的一种新标签 <canvas></canvas> 英 ['kænvəs] 美 [ ...
- html5 canvas高级贝塞尔曲线运动动画(好吧这一篇被批的体无完肤!都说看不懂了!没办法加注释了!当然数学不好的我也没办法了,当然这还涉及到一门叫做计算机图形学的学科)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- H5如何用Canvas画布生成并保存带图片文字的新年快乐的海报
摘要:初略算了算大概有20天没有写博客了,原本是打算1月1号元旦那天写一个年终总结的,博客园里大佬们都在总结过去,迎接将来,看得我热血沸腾,想想自己也工作快2年了,去年都没有去总结一下,今年势必要总结 ...
- 安卓自己定义View进阶-Canvas之绘制基本形状
Canvas之绘制基本形状 作者微博: @GcsSloop [本系列相关文章] 在上一篇自己定义View分类与流程中我们了解自己定义View相关的基本知识,只是,这些东西依然还是理论,并不能拿来(zh ...
随机推荐
- 20155305 2016-2017-2 《Java程序设计》实验二 Java面向对象程序设计
实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验步骤 单元测试 1. ...
- 20155315 2016-2017-2 《Java程序设计》第一周学习总结
教材学习内容总结 第一章中提到了Java的前世今生和三大平台,我了解到Java SE包括JVM,JRE,JDK和Java语言.java最基本的特性之一是"跨平台",这使得Java语 ...
- 20155327 嵌入式C语言课堂补交
嵌入式C语言 题目要求 在作业本上完成附图作业,要认真看题目要求. 提交作业截图 作弊本学期成绩清零(有雷同的,不管是给别人传答案,还是找别人要答案都清零) 题目分析 分析一:提取插入时间 根据老师上 ...
- week8课上实践
课上练习. 第一题: 参考 http://www.cnblogs.com/rocedu/p/6766748.html#SECCLA 在Linux下完成"求命令行传入整数参数的和" ...
- 【MongoDB】NoSQL Manager for MongoDB 教程(进阶篇)
项目做完,有点时间,接着写下第二篇吧.回顾戳这里 基础篇:安装.连接mongodb.使用shell.增删改查.表复制 本文属于进阶篇,为什么叫进阶篇,仅仅是因为这些功能属于DB范畴,一般使用的不多, ...
- equals和==方法比较(二)--Long中equals源码分析
接上篇,分析equals方法在Long包装类中的重写,其他类及我们自定义的类,同样可以根据需要重新equals方法. equals方法定义 equals方法是Object类中的方法,java中所有的对 ...
- 一个web应用的诞生(2)--使用模板
经过了第一章的内容,已经可以做出一些简单的页面,首先用这种方式做一个登录页面,首先要创建一个login的路由方法: @app.route("/login",methods=[&qu ...
- Linux环境配置备忘
1.Ubuntu服务器版本装scipy 预装版本可能fortran包版本过旧或者不全,安装scipy之前需要更新环境. sudo apt-get install gfortran libopenbla ...
- Django——多网页网站及网页互联
在helloapp文件夹下添加名为templates的文件夹(此文件夹名称是固定的),并在其下添加html文件,文件内容根据自己网页想呈现的内容而定 在views文件内添加新的函数 在urls文件内添 ...
- KRKR基础篇(二)
这里介绍一些krkr的语法规范,具体的命令含义及用法以后再叙述 一:kag语法及基本概念 KAG使用的剧本语言为KAG Script,文件扩展名为.ks 脚本内的文字除 注释, 命令 , 段落标 ...