再探canvas(小球实例)
之前学习过canvas的一些使用,也用过canvas绘制过时钟, 但是很久不用,有些遗忘了,这里做一个简单的回顾。
在web页面创建一个canvas画布非常简单,如下即可:
<canvas id = "parabolic" width="" height=""></canvas>
注意:canvas元素是一个内联元素。
当然我们也可以修改它的style,如下所示:
#parabolic {
display: block;
background: #ccc;
margin: 200px auto;
}
这样,我们就可以在页面上得到一个灰色的300px的画布了。
由于我们必须在确保使用<canvas>时所有的页面已经完全加载,所以在js中需要添加:
window.addEventListener("load", function() {
// Your code ...
},false);
接下来我们就可以获得这个canvas元素了:
var myCanvas = document.getElementById("parabolic");
然后,为了可以在canvas上画图,我们就得先获取到2d环境:
var parabolic = myCanvas.getContext("2d");
ok! 大功告成,一旦获得了2d环境,我们就可以利用canvas的API进行画图了。
比如最简单的 fillStyle用于设置绘制的颜色, fillRect可以绘制矩形。
parabolic.fillStyle = "#0000ff";
parabolic.fillRect(, , , );
这就会绘制一个颜色是蓝色的在画布中的位置为(20,40)的宽为50,高为100的矩形。如下:

而如果使用strokeStyle和strokeRect就会画出一个同样大小的矩形,只是外层是边框,没有完全填充:

在Canvas的API中还有一个rect方法,这个和strokeRect有什么区别呢? 其实并没有区别,知识,我们得用两步来完成,如下:
parabolic.beginPath();
parabolic.strokeStyle = "blue";
parabolic.rect(, , , );
parabolic.stroke();
效果如下所示:

于是可以总结区别:
- fillStyle是填充的样式,stroke是绘制的样式
- fillRect是填充矩形,必须喝fillStyle配合使用; strokeRect是绘制矩形,必须和strokeStyle配合使用。
到这里,其实我们就已经可以总结出规律了,基本上就是下面两种方式:
方式一:
- 先确定样式 (fillStyle)
- 再填充路径 (fillReact)
方式二:
- 先确定样式 (fillStyle)
- 在确定路径(react)
- 最后进行填充 (fill)
而 clearRect()的作用是清除选择矩形中的像素
parabolic.fillStyle = "#0000ff";
parabolic.fillRect(, , , );
parabolic.clearRect(,,,);
最终的效果如下所示:
即我们清除了上面一半的矩形,只剩下下面的矩形了。
如果我们想要绘制一条线,使用lineTo就可以了,如下所示:
parabolic.beginPath();
parabolic.lineWidth = "";
parabolic.strokeStyle = "red";
parabolic.moveTo(, );
parabolic.lineTo(, );
parabolic.stroke();
首先,要确定line的宽度,否则最后就什么都看不到了,我们这里是在绘制路径,所以要用stroke, 因为无法填充,所以如果使用fill是得不到结果的。
moveTo是指将起点移动到的位置,而lineTo是你画的这条线要截至的位置, 之前一直在描述这个路径是怎么样的,最后必须要使用stroke()才能将之绘制出并展示出来。 注意:在每次绘制路径前,我们最好使用 beginPath(), 这是一个好的习惯。

根据上图,可判断canvas的原点是在左上方的,向右为x轴正方向,向下为y轴正方向。
如果我们希望制作一个封闭的路径,那么使用closePath往往可以达到我们想要的效果:
parabolic.beginPath();
parabolic.lineWidth = "";
parabolic.strokeStyle = "red";
parabolic.moveTo(, );
parabolic.lineTo(, );
parabolic.lineTo(, );
parabolic.closePath();
parabolic.stroke();
即我们先从(50, 50)绘制到 (70, 100),然后接着到(90, 50),这时如果stroke我们可以得到一个v形,但是如果我们使用了closePath()方法,这个路径就可以自动闭合了,如下:

显然,这里的基本思路也是 样式 -> 路径 -> 填充 只是调用不同的api而已,其他并没有什么区别。
哈哈,在canvas中还有一个比较有意思的就是 arc()方法了, 它可以画弧线,接收六个参数,分别是圆心的x、y坐标,半径,起始和终止的弧度,还有一个可选的true/false即顺时针还是逆时针(true是逆时针),如下:
parabolic.beginPath();
parabolic.strokeStyle = "red";
parabolic.arc(, , , , Math.PI, true);
parabolic.stroke();
我们将绘制弧形的函数进行简单的封装,就可以做出下面的小丑的样式了,
window.addEventListener("load", function() {
var myCanvas = document.getElementById("parabolic");
var parabolic = myCanvas.getContext("2d");
// 将绘制圆形的函数进行封装,可以减少代码的重复使用
function paintArc(style, color, x, y, r, start, end, bool) {
parabolic.beginPath();
parabolic[style+"Style"] = color;
parabolic.arc(x, y, r, start, end, bool);
parabolic[style]();
}
paintArc("fill", "blue", , , , , Math.PI, false);
paintArc("fill", "blue", , , , , Math.PI, false);
paintArc("fill", "blue", , , , , Math.PI, true);
paintArc("fill", "blue", , , , , Math.PI, true);
paintArc("stroke", "red", , , , , Math.PI, true);
paintArc("stroke", "red", , , , , *Math.PI, true);
paintArc("fill", "green", , , , , *Math.PI, true);
paintArc("stroke", "red", , , , , *Math.PI, true);
paintArc("fill", "green", , , , , *Math.PI, true);
paintArc("fill", "yellow", , , , , *Math.PI, true);
paintArc("fill", "pink", , , , , Math.PI, false );
},false);
最终效果如下所示:

除此之外,我们还可以看到 quadraticCurveTo() 的二次贝塞尔曲线的API,使用起来也不难。
二次贝塞尔曲线需要两个点,一个是终点,另外一个是控制点,我们从官网上盗图得到:

这样,我们就可以得到了,如下所示:
parabolic.beginPath();
parabolic.moveTo(, );
parabolic.strokeStyle = "red";
parabolic.quadraticCurveTo(, , , );
parabolic.closePath();
parabolic.stroke();
效果如下:

这里封闭是因为我们使用了closePath方法。

三次贝塞尔曲线和二次贝塞尔曲线的区别并不大,只是多了一个控制点,如下所示:

下面我们使用贝塞尔曲线就可以绘制处nike的标志了,
window.addEventListener("load", function() {
var myCanvas = document.getElementById("parabolic");
var parabolic = myCanvas.getContext("2d");
parabolic.beginPath();
parabolic.moveTo(, );
parabolic.bezierCurveTo(, , , , , );
parabolic.bezierCurveTo( , , , , , );
parabolic.fill();
},false);
最终效果如下所示:

这个曲线是贝塞尔曲线的方程,博友写过一篇博客,就是讲解了关于二次贝塞尔曲线和三次贝塞尔曲线的。

在API中,我们还可以发现有一个rotate()方法,使用如下:
drawCurve();
function drawCurve() {
parabolic.beginPath();
parabolic.moveTo(, );
parabolic.rotate(*Math.PI/);
parabolic.bezierCurveTo(, , , , , );
parabolic.stroke();
}
注意:rotate一定要在 绘制之前, 否则是不起效果的, 可以看到我们一般使用 角度*Math.PI/180 的方式进行旋转

我们还可以使用 rotate的api,如下所示:
drawCurve();
function drawCurve() {
parabolic.beginPath();
parabolic.moveTo(, );
parabolic.scale(0.5, 0.5);
parabolic.bezierCurveTo(, , , , , );
parabolic.stroke();
}
最终效果如下:

不难看出,这时候两边是不一样高的,因为这里的缩放并没有对画布进行缩放, 而只是对最终我们要绘制的路径进行了缩放。即把我们输入的值进行了缩放, 而之前的moteTo里的值始终不改变。
当然,之前说过,原点默认是在左上方的,但是我们可以使用translate(x, y)方法,将目前处于(0,0)的原点移到(x,y),
我们还可以在canvas画布中添加字体:
parabolic.beginPath();
parabolic.font = "25px Arial";
parabolic.fillText("e瞳网", , );
其中,font可以设置字体的大小,样式,而fillText()方法可以填充字体, 我们还可以使用strokeText()方法来填充。
最后需要介绍的就是 save()方法和 restore()方法了
其中,前者可以保存当前环境的状态,而后者可以返回之前保存的状态。
最后,使用canvas练习了一个小的例子,但是对于计时器目前还没有完全的了解。
可以肯定的是,计时器被输出时是一个数字, 在相同的环境下, 被调用一次, 计时器的这个数字就会加1, 另外, 计时器setInterval(func, time)中的第二个参数一般情况下我们最好不要设置太高,控制台16ms以上是最好的,因为一般的浏览器刷新率为16ms一次,所以这个速度是比较合适的。
另外,在下面的这个例子中,我使用了这篇博文介绍的贝塞尔函数的计算用于控制小球的运动轨迹,效果如下:

代码在我的github上。
再探canvas(小球实例)的更多相关文章
- 【再探backbone 02】集合-Collection
前言 昨天我们一起学习了backbone的model,我个人对backbone的熟悉程度提高了,但是也发现一个严重的问题!!! 我平时压根没有用到model这块的东西,事实上我只用到了view,所以昨 ...
- 再探jQuery
再探jQuery 前言:在使用jQuery的时候发现一些知识点记得并不牢固,因此希望通过总结知识点加深对jQuery的应用,也希望和各位博友共同分享. jQuery是一个JavaScript库,它极大 ...
- [老老实实学WCF] 第五篇 再探通信--ClientBase
老老实实学WCF 第五篇 再探通信--ClientBase 在上一篇中,我们抛开了服务引用和元数据交换,在客户端中手动添加了元数据代码,并利用通道工厂ChannelFactory<>类创 ...
- 再探ASP.NET 5(转载)
就在最近一段时间,微软又有大动作了,在IDE方面除了给我们发布了Viausl Studio 2013 社区版还发布了全新的Visual Studio 2015 Preview. Visual Stud ...
- c++再探string之eager-copy、COW和SSO方案
在牛客网上看到一题字符串拷贝相关的题目,深入挖掘了下才发现原来C++中string的实现还是有好几种优化方法的. 原始题目是这样的: 关于代码输出正确的结果是()(Linux g++ 环境下编译运行) ...
- ViewPager+Fragment再探:和TAB滑动条一起三者结合
Fragment前篇: <Android Fragment初探:静态Fragment组成Activity> ViewPager前篇: <Android ViewPager初探:让页面 ...
- h5 canvas 小球移动
h5 canvas 小球移动 <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...
- Spark Streaming揭秘 Day7 再探Job Scheduler
Spark Streaming揭秘 Day7 再探Job Scheduler 今天,我们对Job Scheduler再进一步深入一下,对一些更加细节的源码进行分析. Job Scheduler启动 在 ...
- 再探java基础——break和continue的用法
再探java基础——break和continue的用法 break break可用于循环和switch...case...语句中. 用于switch...case中: 执行完满足case条件的内容内后 ...
随机推荐
- wpf控件开发基础
wpf控件开发基础(3) -属性系统(2) http://www.cnblogs.com/Clingingboy/archive/2010/02/01/1661370.html 这个有必要看看 wpf ...
- 企业管理系统——第三周需求&原型改进_张正浩,黄锐斌
企业管理系统——需求&原型改进,架构设计,测试计划 组员:张正浩,黄锐斌 一.需求&原型改进 1.给目标用户展现原型,与目标用户进一步沟通理解需求 我们的目标用户是公司管理员 场景:随 ...
- Java集合类总结 (五)
集合框架 为了避免进行不必要的随机访问操作,Java引入了一种标签接口RandomAccess, 这个接口没有任何方法,只是一个标签,用来标记一个集合是否应该进行随机访问操作: if (c insta ...
- WinForm 中使用 Action 子线程对主线程 控制进行访问
/// <summary> /// 开启新线程执行 /// </summary> /// <param name="sender"></p ...
- Java Serializable(序列化)的理解和总结
1.序列化是干什么的? 简单说就是为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的对象状态再读出来.虽然你可以用你自己的各种各样的方法来保存object st ...
- 【[APIO/CTSC2007]动物园】状压DP
题目测评:https://www.luogu.org/problemnew/show/P3622 题目描述 新建的圆形动物园是亚太地区的骄傲.圆形动物园坐落于太平洋的一个小岛上,包含一大圈围栏,每个围 ...
- js实现深拷贝
type函数 首先我们要实现一个getType函数对元素进行类型判断,直接调用Object.prototype.toString 方法. function getType(obj){ //tostri ...
- linking against a dylib which is not safe for use in application extensions
完成到这里可能会出现警告 linking against a dylib which is not safe for use in application extensions 解决办法:
- Atcoder Grand Contest 031C(构造,思维,异或,DFS)
#include<bits/stdc++.h>using namespace std;int n,a,b,sum;void dfs(int x,int y,int ban){ if( ...
- java大数据批量处理实现方式
1. 各批量方式对比 Mybatis与JDBC批量插入MySQL数据库性能测试及解决方案 2. 原理解析 1)MySql PreparedStatement executeBatch过慢问题 3. 工 ...