再探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条件的内容内后 ...
随机推荐
- 请教一个Jquery ligerui 框架的小问题
关闭子窗体时,要刷新父窗体,百度了很多像使用“window.opener.location.reload();”都不行,和easyui框架是有区别的 在子窗体里写Response.Write(&quo ...
- (11)Web程序保存状态的几种方式,Application,Session,Cookie,ViewState
WEb程序保存状态的方式有这样几种: 1.Application:保存在Application中的数据是全局有效的:Application里面存放的应该是访问多修 改较少并且是全局至少大部分 ...
- CSS3中的新特性
一.CSS3新属性 CSS3还不属于W3C标准,所以不同浏览器的支持程度也不相同,对于不同浏览器,写法也不同,不同内核的浏览器要加不同的前缀,如下: transform:rotate(9deg); - ...
- angular 父组件调用子组件
import { Component, OnInit, ViewChild } from '@angular/core'; @Component({ selector: 'app-child', te ...
- MVC 异常过滤
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- 《spring 攻略》笔记1
chapter1 spring简介 两种spring ioc容器实现类型: BeanFactory ApplicationContext 应用程序上下文 DI技巧: @Autowired(requir ...
- MySQL 学习笔记(三):完整性和触发器设计
(一)完整性设计 方法一.在设计表时定义约束 删除数据库school,建立新数据库school1 drop database school; create database school; use s ...
- 【BZOJ3622】已经没什么好害怕的了 容斥原理+dp
Description Input Output Sample Input 4 2 5 35 15 45 40 20 10 30 Sample Output 4 HINT 输入的2*n个数字保证全不相 ...
- 6A - Daydreamin
#include <iostream> #include <cstdio> using namespace std; typedef long long ll; ll dp[] ...
- mysql 彻底解决:Incorrect string value: '\xF0\x9F\x98\xAD",...' for column 'commentContent' at row 1
彻底解决:Incorrect string value: '\xF0\x9F\x98\xAD",...' for column 'commentContent' at row 1 今天在爬取 ...