【下篇】 -- 建议学习时间4小时  课程共(上中下)三篇

此笔记是我初次接触canvas的时候的学习笔记,这次特意整理为博客供大家入门学习,几乎涵盖了canvas所有的基础知识,并且有众多练习案例,建议大家学习10~15个小时,里面的案例请挨个敲一遍,这样才能转化为自己的知识。

技术要求:有html/css/js基础。

保存状态


save()restore()
save 和 restore 方法是用来保存和恢复 canvas 状态的,都没有参数。Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。

简单示例:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //线条链接处样式
ctx.fillStyle = "darkblue";
ctx.lineWidth = 1; ctx.fillRect(0,0,150,150);
ctx.save(); //第一次保存 保存了 fillStyle "darkblue" ctx.fillStyle = "#09f";
ctx.fillRect(15,15,120,120); ctx.save(); //第二次保存 保存了 fillStyle "#09f"
ctx.fillStyle = "#fff";
ctx.fillRect(30,30,90,90); ctx.restore(); //恢复到第二次保存的状态
ctx.fillRect(45,45,60,60); ctx.restore(); //恢复到第一次保存的状态
ctx.fillRect(60,60,30,30);

结果如下图:后两次 restore之后依次恢复到前面 save的颜色状态

画布变形


偏移

ctx.translate(disX,disY)  ,将绘图上下文向x和y方向移动一个距离,然后再作画 (真实的画布并没有移动)

示例:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); /* 移动位置 */
ctx.fillRect(0,0,50,50); ctx.translate(100,100); //将画布x,y方向分别移动 100px ctx.fillStyle = "#09f";
ctx.fillRect(0,0,50,50);

这里我们可以看到,虽然绘制都是使用 fillRect(0,0,5.,50),但第二次绘制的时候上下文已经偏移了 100像素,所以落到画布上的时候就偏移了100像素

旋转 

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

示例:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); ctx.translate(100,100); for(var i=1; i<6; i++){
ctx.save();
ctx.fillStyle = 'rgba('+ 51*i +','+ (255-51*i) +',255,1)';
for(var j=0; j<i*6; j++){
ctx.rotate(Math.PI*2/(i*6));
ctx.beginPath();
ctx.arc(0,i*12.5,5,0,Math.PI*2,true);
ctx.fill();
}
ctx.restore()
}

缩放

scale(x, y)
scale 方法接受两个参数。x,y 分别是横轴和纵轴的缩放因子,它们都必须是正值。值比 1.0 小表示缩小,比 1.0 大则表示放大,值为 1.0 时什么效果都没有。

示例:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); ctx.translate(100,100); ctx.save();
ctx.translate(200,80);
drawSpirograph(ctx,22,30,30);
ctx.restore();
ctx.scale(0.75,1);
drawSpirograph(ctx,22,6,5); function drawSpirograph(ctx,R,r,O){
var x1 = R-O;
var y1 = 0;
var i = 1;
ctx.beginPath();
ctx.moveTo(x1,y1);
do {
if (i>20000) break;
var x2 = (R+r)*Math.cos(i*Math.PI/72) - (r+O)*Math.cos(((R+r)/r)*(i*Math.PI/72))
var y2 = (R+r)*Math.sin(i*Math.PI/72) - (r+O)*Math.sin(((R+r)/r)*(i*Math.PI/72))
ctx.lineTo(x2,y2);
x1 = x2;
y1 = y2;
i++;
} while (x2 != R-O && y2 != 0 );
ctx.stroke();
}

 矩阵变换

transform(m11, m12, m21, m22, dx, dy)
这个方法是将当前的变形矩阵乘上一个基于自身参数的矩阵,在这里我们用下面的矩阵:
m11  m21  dx
m12  m22  dy
0       0       1

这个函数的参数各自代表如下:
m11:水平方向的缩放
m12:水平方向的偏移
m21:竖直方向的偏移
m22:竖直方向的缩放
dx:水平方向的移动
dy:竖直方向的移动

示例:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); ctx.translate(100,100); var sin = Math.sin(Math.PI/6);
var cos = Math.cos(Math.PI/6);
var c = 0;
for(var i=0; i<=12; i++){
c = Math.floor(255/12*i);
ctx.fillStyle = "rgb("+c+","+c+","+c+")";
ctx.fillRect(0,0,100,10);
ctx.transform(cos,sin,-sin,cos,0,0);
}
ctx.setTransform(1,0,0,1,100,100);
ctx.fillStyle = "rgba(255,128,255,0.5)";
ctx.fillRect(0,0,100,50);

综合案例


案例1:星空

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
*{margin: 0;padding: 0}
canvas{border: 1px solid #a4e2f9;margin: 10px;}
</style>
</head>
<body>
<canvas height="300" width="600" id="myCanvas"></canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //线条链接处样式
ctx.strokeStyle = "#09f";
ctx.lineWidth = 1; ctx.fillRect(0,0,450,450);
ctx.translate(150,150); ctx.beginPath();
ctx.arc(0,0,140,0,Math.PI*2,true);
ctx.clip(); //这个表示裁剪,只有路径区域中的部分才可见。 var lingrad = ctx.createLinearGradient(0,-175,0,250);
lingrad.addColorStop(0,"#232256");
lingrad.addColorStop(1,"#143778"); //绘制渐变背景
ctx.fillStyle = lingrad;
ctx.fillRect(-175,-175,350,350); //绘制星星
for(var j=1; j<100; j++){
ctx.save();
ctx.fillStyle = "#fff";
ctx.translate(140-Math.floor(Math.random()*280),140-Math.floor(Math.random()*280));
drawStar(ctx, Math.floor(Math.random()*8)+2);
ctx.restore();
} //绘制星星的方法
function drawStar(ctx,r){
ctx.save();
ctx.beginPath();
ctx.moveTo(r,0);
for(var i=0; i<9; i++){
ctx.rotate(Math.PI/5);
if(i%2 == 0){
ctx.lineTo((r/0.525731)*0.200811,0);
}else{
ctx.lineTo(r,0);
}
}
ctx.closePath();
ctx.fill();
ctx.restore();
} </script>
</body>
</html>

案例2:时钟

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
*{margin: 0;padding: 0}
canvas{border: 1px solid #a4e2f9;margin: 30px auto;display: block} </style>
</head>
<body>
<canvas height="300" width="600" id="myCanvas"></canvas> <script> function clock(){
var now = new Date();
var ctx = document.getElementById('myCanvas').getContext('2d');
ctx.save();
ctx.clearRect(0,0,150,150);
ctx.translate(75,75);
ctx.scale(0.4,0.4);
ctx.rotate(-Math.PI/2);
ctx.strokeStyle = "black";
ctx.fillStyle = "white";
ctx. lineWidth = 8;
ctx.lineCap = "round"; //时
ctx.save();
for(var i=0; i<12; i++){
ctx.beginPath();
ctx.rotate(Math.PI/6);
ctx.moveTo(100,0);
ctx.lineTo(120,0);
ctx.stroke();
}
ctx.restore(); //分
ctx.save();
ctx.lineWidth = 5;
for(var i=0; i<60; i++){
if(i%5 != 0){
ctx.beginPath();
ctx.moveTo(117,0);
ctx.lineTo(120,0);
ctx.stroke();
} ctx.rotate(Math.PI/30); }
ctx.restore(); var sec = now.getSeconds();
var min = now.getMinutes();
var hr = now.getHours();
hr = hr >= 12 ? hr-12 : hr; ctx.fillStyle = "black"; //时针
ctx.save();
ctx.rotate( hr*(Math.PI/6)+(Math.PI/360)*min+(Math.PI/21600)*sec );
ctx.lineWidth = 14;
ctx.beginPath();
ctx.moveTo(-20,0);
ctx.lineTo(80,0);
ctx.stroke();
ctx.restore(); //分针
ctx.save();
ctx.rotate( (Math.PI/30)*min+(Math.PI/1800)*sec );
ctx.lineWidth = 10;
ctx.beginPath();
ctx.moveTo(-20,0);
ctx.lineTo(112,0);
ctx.stroke();
ctx.restore(); //秒针
ctx.save();
ctx.rotate( (Math.PI/30)*sec );
ctx.strokeStyle = "#D40000";
ctx.fillStyle = "#D40000";
ctx.lineWidth = 6;
ctx.beginPath();
ctx.moveTo(-30,0);
ctx.lineTo(83,0);
ctx.stroke(); ctx.beginPath();
ctx.arc(0,0,10,0,Math.PI*2,true);
ctx.fill(); ctx.beginPath();
ctx.arc(95,0,10,0,Math.PI*2,true);
ctx.stroke(); ctx.restore(); //外圈
ctx.beginPath();
ctx.lineWidth = 14;
ctx.strokeStyle = '#325FA2';
ctx.arc(0,0,142,0,Math.PI*2,true);
ctx.stroke(); ctx. restore(); window.requestAnimationFrame(clock);
} window.requestAnimationFrame(clock); </script>
</body>
</html>

 案例3:运动的小球

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
*{margin: 0;padding: 0}
canvas{border: 1px solid #a4e2f9;} </style>
</head>
<body>
<canvas height="300" width="600" id="myCanvas"></canvas> <script> var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var raf; //小球对象
var ball = {
x: 100,
y: 100,
vx: 5,
vy: 1,
radius: 25,
color: '#1895c3',
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
}; //清除画布
function clear() {
ctx.fillStyle = 'rgba(255,255,255,0.3)';
ctx.fillRect(0,0,canvas.width,canvas.height);
} //小球运动及绘制的方法
function draw() {
clear();
ball.x += ball.vx;
ball.y += ball.vy; if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
ball.vx = -ball.vx;
} ball.draw();
raf = window.requestAnimationFrame(draw);
} //鼠标移动的时候 让小球跟着鼠标走
canvas.addEventListener('mousemove', function(e){
clear();
ball.x = e.clientX;
ball.y = e.clientY;
ball.draw();
}); //鼠标移入停止动画
canvas.addEventListener("mouseenter",function(e){
window.cancelAnimationFrame(raf);
}); //鼠标移出继续动画
canvas.addEventListener("mouseout",function(e){
raf = window.requestAnimationFrame(draw);
}); //开始第一帧动画
draw(); </script>
</body>
</html>

今天就讲到这里,canvas基础部分就结束了,后续会找时间更新一些canvas比较炫酷的综合案例,请期待。

关注公众号,博客更新即可收到推送

canvas学习笔记(下篇) -- canvas入门教程--保存状态/变形/旋转/缩放/矩阵变换/综合案例(星空/时钟/小球)的更多相关文章

  1. canvas学习笔记:canvas对图片的像素级处理--ImageData的应用

    学习了canvas的基本绘图功能后,惊喜的发现canvas对图片数据也有相当强大的处理功能,能够从像素级别操作位图,当然[lte ie8]不支持. 主要的函数有三个: ctx.createImageD ...

  2. canvas学习笔记、小函数整理

    http://bbs.csdn.net/topics/391493648 canvas实例分享 2016-3-16 http://bbs.csdn.net/topics/390582151 html5 ...

  3. tensorflow学习笔记二:入门基础 好教程 可用

    http://www.cnblogs.com/denny402/p/5852083.html tensorflow学习笔记二:入门基础   TensorFlow用张量这种数据结构来表示所有的数据.用一 ...

  4. Canvas学习:封装Canvas绘制基本图形API

    Canvas学习:封装Canvas绘制基本图形API Canvas Canvas学习   从前面的文章中我们了解到,通过Canvas中的CanvasRenderingContext2D对象中的属性和方 ...

  5. 学习笔记《简明python教程》

    学习笔记<简明python教程> 体会:言简意赅,很适合新手入门 2018年3月14日21:45:59 1.global 语句 在不使用 global 语句的情况下,不可能为一个定义于函数 ...

  6. Hadoop学习笔记(1) ——菜鸟入门

    Hadoop学习笔记(1) ——菜鸟入门 Hadoop是什么?先问一下百度吧: [百度百科]一个分布式系统基础架构,由Apache基金会所开发.用户可以在不了解分布式底层细节的情况下,开发分布式程序. ...

  7. iOS学习笔记-地图MapKit入门

    代码地址如下:http://www.demodashi.com/demo/11682.html 这篇文章还是翻译自raywenderlich,用Objective-C改写了代码.没有逐字翻译,如有错漏 ...

  8. canvas学习笔记(中篇) -- canvas入门教程-- 颜色/透明度/渐变色/线宽/线条样式/虚线/文本/阴影/图片/像素处理

    [中篇] -- 建议学习时间4小时  课程共(上中下)三篇 此笔记是我初次接触canvas的时候的学习笔记,这次特意整理为博客供大家入门学习,几乎涵盖了canvas所有的基础知识,并且有众多练习案例, ...

  9. canvas学习笔记(上篇)-- canvas入门教程 -- canvas标签/方块/描边/路径/圆形/曲线

    [上篇] -- 建议学习时间4小时  课程共(上中下)三篇 此笔记是我初次接触canvas的时候的学习笔记,这次特意整理为博客供大家入门学习,几乎涵盖了canvas所有的基础知识,并且有众多练习案例, ...

随机推荐

  1. 实验四实验报告————Android基础开发

    实验四实验报告----Android基础开发 任务一 关于R类 关于apk文件 实验成果 任务二 活动声明周期 实验成果 任务三 关于PendingIntent类 实验成果 任务四 关于布局 实验成果 ...

  2. 二叉搜索树BStree

    二叉搜索树,实际上是有点类似于二分查找.实际上很简单,就是递归.直接上代码,有点要注意的就是删除的时候,如果是左子树和右子树都存在的话,要寻找继承者(successor). import java.u ...

  3. JS零基础一步一步做应用全记录

    1.起因 作为几个外卖重度依赖癌晚期患者,呆宿舍的时候几个人一起叫外卖已经是常事.偶然看到隔壁宿舍在饿了么订餐的时候,看到在饿了么的首页上有一个谁去拿外卖的一个小游戏/工具,感觉这个小细节,饿了么把握 ...

  4. fedora19/opensuse13.1 配置openvpn client

    Date: 20140207Auth: Jin 1.install # yum -y install openvpn #zypper install openvpn 2.copy user key # ...

  5. FIREDAC用于LINUX报头文件FireDAC.VCLUI.Wait找不到

    FIREDAC用于LINUX报头文件FireDAC.VCLUI.Wait找不到 FIREDAC LINUX下面,此控件 此属性 必须设为CONSOLE.  默认值只能用于WINDOWS操作系统.

  6. google的开源项目总结

    转自http://www.feng5166.com/blog/424.html google的开源项目值得我们一用的,这些项目很有意义,甚至可以直接用在我们自己的工作上!学习编程的的一个比较好的方式就 ...

  7. 【Linux C 多线程编程】互斥锁与条件变量

    一.互斥锁 互斥量从本质上说就是一把锁, 提供对共享资源的保护访问. 1) 初始化: 在Linux下, 线程的互斥量数据类型是pthread_mutex_t. 在使用前, 要对它进行初始化: 对于静态 ...

  8. 利用pycharm进行重构学习记录

    pycharm是非常强大的pythonIDE,集成了很多实用的功能,其中就包括重构Refactor 记录下使用pycharm的重构 pycharm的Refactor默认在主菜单上就有了 Refacto ...

  9. C++ 初始化列表(转载)

    何谓初始化列表 与其他函数不同,构造函数除了有名字,参数列表和函数体之外,还可以有初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段.在 C++中,struct和class的唯一区别是 ...

  10. Tomcat 访问 Manager App,Host Manager

     1.启动tomcat,在浏览器输入:http://localhost:8080/ 2.配置tomcat-users.xml 文件 在主目录的cong文件夹下找到tomcat-users.xml 文件 ...