canvas(五角星碰撞)
马上9月份要找工作了,琢磨着要做个作品作为面试时的加分项。
本来打算仿一个淘宝网,但写完淘宝首页竟花了我一个星期!!!光html、css就有4000多行,看着首页都能想象出来后台数据的庞大,估计半年都写不完这个作业了,想罢果断放弃掉做淘宝的任务。
最终决定做一个尽量炫一点的个人网站。
在参考了liuyubobobo老师关于canvas的课程(这位老师的canvas课程真的炒鸡好~!!)后,我在这个个人网站的顶部横幅中添加了一个这样的效果,如下图
在canvas画布我添加了30个大小随机、运动方向随机、运动速度随机、碰到画布边缘会反弹回来的五角星。
作为一个从来没用过canvas画图的新手,在这个过程中也踩了不少坑。
实现:
html代码如下:
- <div class="carouselBox">
- <canvas id="stars">请升级到最新的浏览器以观看最佳效果</canvas>
- <h1>兴趣使然的小站</h1>
- </div>
css代码如下,这里我是用less表示的(不懂这种表示法的同学稍微百度一下,so easy):
- .carouselBox{
- width: 100%;
- height: 300px;
- background-color: rgba(200, 200, 255, 0.3);
- position: relative;
- text-align: center;
- #stars{
- position: absolute;
- left: 0;
- top: 0;
- z-index: 5;
- }
- h1{
- position: relative;
- z-index: 10;
- font-size: 50px;
- line-height: 300px;
- color: rgba(0, 0, 0, 0.7)
- }
- }
canvas画布的长度和宽度我放在了js文件中实现。
重点在JS代码上:
我这里在获取元素用到了jquery,你不用jqueyr来获取,改用document.getElementById之类的原生javascript方法当然也没有问题。
首先获取canvas对象和canvas上下文,并设置canvas画布的高宽。
- //五角星画布
- var carouselBox = $('.carouselBox')
- var carouselHeight = carouselBox.height()//获取canvas外层的盒子高度
- var carouselWidth = carouselBox.width()//获取canvas外层的盒子高度
- var drawing2 = $('#stars').get(0)//通过jquery获得一个用jquery包装的canvas对象,由get(0)方法获取原生canvas对象
- //一定不能用jquery来设置高度与宽度,否则会出现莫名其妙的错误
- drawing2.height = carouselHeight//将canvas画布填满到外层盒子
- drawing2.width = carouselWidth
- var context2 = drawing2.getContext('2d')//获取canvas的上下文
这其中要注意的是,canvas画布设置宽高一定要通过 canvas.height和canvas.width的方式来设置。
一定不能由canvas.style.height,canvas.style.width或者jquery方式$canvas.css({....})来设置宽高!!!否则会让画布里的坐标单位出现问题,导致你画的图像完全不在你预期的位置上。
接下来,先设置一个for循环来随机生成30个五角星的属性,每一组属性生成一个对象,并将生成的30个对象依次推入一个数组中。
- var stars = []//用来装五角星的数组
- for (var i = 0; i < 30; i++) {
- var R = Math.floor(Math.random()*100+155)
- var G = Math.floor(Math.random()*100+155)
- var B = Math.floor(Math.random()*100+155)
- var r = Math.random()*30 + 20
- var rot = Math.random()*360
- aStar = {
- color:'rgb('+R+','+G+','+B+')',
- r:r,
- x:Math.random()*(drawing2.width - 2*r) + r,
- y:Math.random()*(drawing2.height - 2*r) + r,
- rot:rot,
- vx:(Math.random()*2+2)*Math.pow(-1,Math.floor(Math.random()*100)),
- vy:(Math.random()*2+2)*Math.pow(-1,Math.floor(Math.random()*100)),
- wv:(Math.random()*2+2)*Math.pow(-1,Math.floor(Math.random()*100))
- }
- stars[i] = aStar
- }
- setInterval(function(){
- draw(context2)//绘制函数
- update(drawing2.width,drawing2.height)//更新每个五角星的状态
- },30)
绘制函数如下:
将每个五角星的属性传入到drawStar()方法,从而创建大小、运动方向不同的五角星
- function draw(context){
- var canvas = context.canvas
- context.clearRect(0,0,canvas.width,canvas.height)//设置一个矩形区域,将该矩形区域中的所有内容清除,会将背景一起清除掉
- context.globalCompositeOperation = 'xor'//全局设定,两图案相交处取空
- for (var i = 0; i < stars.length; i++) {
- context.fillStyle = stars[i].color//设置五角星填充颜色
- drawStar(context2,stars[i].r,stars[i].x,stars[i].y,stars[i].rot)
- context.fill()
- }
- }
drawStar方法如下
这里用图形变换的方法来绘制每个五角星,由于图形变换都是基于上次变换结果进行绘制的,因此需要设置“存储点”,在绘制完一个五角星之后回到“存储点”。
- function drawStar(context,R,x,y,rot){
- context.save()//设置存储点
- context.translate(x,y)//平移变换
- context.rotate(rot/180*Math.PI)//旋转变换
- context.scale(R,R)//缩放变换
- starPath(context)//绘制五角星的边
- context.restore()//回到存储点
- }
由于context.scale()不仅会缩放图形大小,也会缩放图形的位置点和边框,因此在五角星边的绘制中,我们没有设置边的宽度和五角星的偏移。
在下列代码中,即XcanterP和YcenterP都没有设置。
- function starPath(context){
- context.beginPath()
- for (var i = 0; i < 5; i++) {
- //x = Rcosθ + XcenterP
- //θ = α/180*π 其中α为度数表示的角度,θ为以π为单位表示的角度
- //y = -Rsinθ + YcenterP
- context.lineTo(Math.cos((18+i*72)/180*Math.PI),-Math.sin((18+i*72)/180*Math.PI))
- context.lineTo(Math.cos((54+i*72)/180*Math.PI)/1.8,-Math.sin((54+i*72)/180*Math.PI)/1.8)
- }
- context.closePath()
- }
最后,更新五角星状态的代码如下
这里更新了五角星的位移、角度,也检测了画布边缘碰撞,当碰触到边缘时,五角星的速度取反。
PS这里:五角星的X和Y坐标位于五角星的中心。
- //更新小球的状态(属性)
- function update(canvasWidth,canvasHeight){
- for (var i = 0; i < stars.length; i++) {
- stars[i].x += stars[i].vx
- stars[i].y += stars[i].vy
- stars[i].rot += stars[i].wv
- if (stars[i].x - stars[i].r <= 0) {
- stars[i].vx = -stars[i].vx
- stars[i].x = stars[i].r
- }
- if (stars[i].x + stars[i].r >= canvasWidth) {
- stars[i].vx = -stars[i].vx
- stars[i].x = canvasWidth - stars[i].r
- }
- if (stars[i].y - stars[i].r <= 0) {
- stars[i].vy = -stars[i].vy
- stars[i].y = stars[i].r
- }
- if (stars[i].y + stars[i].r >= canvasHeight) {
- stars[i].vy = -stars[i].vy
- stars[i].y = canvasHeight - stars[i].r
- }
- }
- }
最后,等我网站写完了,我会附上链接让大家看看效果哦~!