利用Canvas画出曲线运动的气泡

1,042 阅读2分钟

前言

最近在写一个HTML项目,里面需要实现一个效果:当鼠标移动到人物上时,冒出一些做曲线运动的气泡(静态效果见下,完整项目请浏览zdjzpg.github.io/html5/)),一开始确实没什么思路,在网上搜集了下资料,能差不多的写出来了,所以写个博客记录下,也希望能够帮助到其他人。

先把canvas准备好

  1. html上添加canvas标签

<canvas id="test" width="200" height="400"></canvas>

  1. 给页面添加点样式,让canvas居中显示
body{
    background-color: pink;
}
#test{
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    margin: auto;
    border: 1px solid;
}
canvas{
    background-color: white;
}
  1. js初步获取canvas
var canvas=document.getElementById('test')
if(canvas.getContext){
    var ctx=canvas.getContext('2d')//获取'画笔'
}

接下来就需要考虑怎么做呢?做曲线运动的气泡顾名思义其实不就是两件事,1.生成随机的气泡.2.让每个气泡做曲线运动

怎么随机的产生气泡呢

气泡其实就是一个个圆,canvas画圆的api是什么呢?正是 ctx.arc(x,y,r,startDeg,endDeg) ,x,y表示圆心位置,r表示半径,startDeg,endDeg表示初始角度和结束角度,因为画的形状是固定的,所以startDeg,endDeg也是固定的。所以我们只要随机生成x,y,r,再不断的把他画到画布上,不就实现了产生随机的气泡,但是x和y的范围是什么呢?我们可以观察到,气泡一开始是出现在最底部,所以x的范围不就是0-canvas的宽吗,y的位置需要根据半径r的大小不断调整让他处于canvas底部。说了这么多,让我们开始动手吧.

var r=Math.random()*10+3
var x=Math.random()*canvas.clientWidth
var y=canvas.clientHeight-r

这个只生成了一个气泡,很多的气泡要怎么办呢?我们可以设置定时器,定时产生一个气泡,并把他存到数组里,然后通过另一个定时器不断的取出数组里的数据作为画圆的参数画出来,如下:

var arr=[]
setInterval(function(){
    for(var i=0;i<arr.length;i++){
        ctx.save()
        ctx.arc(arr[i].x,arr[i].y,arr[i].r,0,2*Math.PI)//取出参数作为圆的参数
        ctx.fill()
        ctx.beginPath()
        ctx.restore()
    }
},1000/60)
setInterval(function(){
    var r=Math.random()*10+3
    var x=Math.random()*canvas.clientWidth
    var y=canvas.clientHeight-r
    arr.push({
        r,x,y//将参数推入数组
    })
},5000/60)

此时可以观察到圆的初始位置已经满足了,如下:

50D%HA`RYEJU[0_83]_7XZP.png

但是发现颜色是固定的,所以我们还需要给气泡随机颜色,代码如下:

var arr=[]
setInterval(function(){
    ctx.clearRect(0,0,canvas.clientWidth,canvas.clientHe
    for(var i=0;i<arr.length;i++){
        arr[i].deg+=5
        arr[i].x=arr[i].startX+Math.sin(arr[i].deg*Math.
        arr[i].y=arr[i].startY-(arr[i].deg*Math.PI/180)*
    }
    for(var i=0;i<arr.length;i++){
        ctx.save()
        ctx.fillStyle='rgba('+arr[i].red+","+arr[i].gree
        ctx.arc(arr[i].x,arr[i].y,arr[i].r,0,2*Math.PI)
        ctx.fill()
        ctx.beginPath()
        ctx.restore()
    }
},1000/60)
setInterval(function(){
    var red=Math.round(Math.random()*255) 
    var blue=Math.round(Math.random()*255) 
    var green=Math.round(Math.random()*255) 
    var alp=1
    var r=Math.random()*10+3
    var x=Math.random()*canvas.clientWidth
    var y=canvas.clientHeight-r
    var deg=0
    var step=Math.random()*20+10
    var startX=x
    var startY=y
    arr.push({
        red,blue,green,alp,r,x,y,step,startX,startY,deg
    })
},5000/60)

效果如下:

效果似乎已经达到要求了,但是结束了吗?当然没有,我们还没有考虑到这个功能实现里最重要的arr数组,他在干嘛呢?定时器不断地给他添加数据,他已经快爆了,我们有必要储存这么多数据吗?当然没必要,当气泡跳出canvas的范围,我们就不需要再去计算他,自然也不用保留他的各个信息,就可以把他从数组里删除,所以每次计算位置的时候给他加个判断,大功告成。当然还有没清除的定时器,这个需要根据你的需求,比如在我的项目中,移出人物所在位置,气泡消失,所以我可以在此时清除定时器。

if(arr[i].y<20){
    arr.splice(i,1)
}

这个时候我们才算正式把这个小Demo写完了。

总结

  • 创建canvas环境,获取画笔
  • 利用两个定时器生成随机气泡,初始位置需要设计,以及把气泡的所有信息全部储存在数组的每个对象里
  • 根据自己想实现的曲线,去设计弧度,再按需求放大缩小,以及每次画新的之前把前面的清除
  • 扫尾工作,从数组里把移动出固定范围的气泡的信息去掉,按需停止定时器等

大家都可以试着去写下,有不理解的可以评论我,我会尽量及时回复,有更好的办法也可以互相探讨(●'◡'●) 最后献上本文完整代码

 <!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            body{
                background-color: pink;
            }
            #test{
                position: absolute;
                top: 0;
                left: 0;
                bottom: 0;
                right: 0;
                margin: auto;
                border: 1px solid;
            }
            canvas{
                background-color: white;
            }
        </style>
    </head>
    <body>
        <canvas id="test" width="200" height="400"></canvas>
    </body>
    <script type="text/javascript">
        var canvas=document.getElementById('test')
        if(canvas.getContext){
            var ctx=canvas.getContext('2d')
            var arr=[]
            setInterval(function(){
                ctx.clearRect(0,0,canvas.clientWidth,canvas.clientHeight)
                for(var i=0;i<arr.length;i++){
                    arr[i].deg+=5
                    arr[i].x=arr[i].startX+Math.sin(arr[i].deg*Math.PI/180)*arr[i].step
                    arr[i].y=arr[i].startY-(arr[i].deg*Math.PI/180)*arr[i].step
                    if(arr[i].y<20){
                        arr.splice(i,1)
                    }
                }
                for(var i=0;i<arr.length;i++){
                    ctx.save()
                    ctx.fillStyle='rgba('+arr[i].red+","+arr[i].green+","+arr[i].blue+","+arr[i].alp+')'
                    ctx.arc(arr[i].x,arr[i].y,arr[i].r,0,2*Math.PI)
                    ctx.fill()
                    ctx.beginPath()
                    ctx.restore()
                }
            },1000/60)
            setInterval(function(){
                var red=Math.round(Math.random()*255) 
                var blue=Math.round(Math.random()*255) 
                var green=Math.round(Math.random()*255) 
                var alp=1
                var r=Math.random()*10+3
                var x=Math.random()*canvas.clientWidth
                var y=canvas.clientHeight-r
                var deg=0
                var step=Math.random()*20+10
                var startX=x
                var startY=y
                arr.push({
                    red,blue,green,alp,r,x,y,step,startX,startY,deg
                })
            },5000/60)
        }
        
    </script>
</html>
 <!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            body{
                background-color: pink;
            }
            #test{
                position: absolute;
                top: 0;
                left: 0;
                bottom: 0;
                right: 0;
                margin: auto;
                border: 1px solid;
            }
            canvas{
                background-color: white;
            }
        </style>
    </head>
    <body>
        <canvas id="test" width="200" height="400"></canvas>
    </body>
    <script type="text/javascript">
        var canvas=document.getElementById('test')
        if(canvas.getContext){
            var ctx=canvas.getContext('2d')
            var arr=[]
            setInterval(function(){
                ctx.clearRect(0,0,canvas.clientWidth,canvas.clientHeight)
                for(var i=0;i<arr.length;i++){
                    arr[i].deg+=5
                    arr[i].x=arr[i].startX+Math.sin(arr[i].deg*Math.PI/180)*arr[i].step
                    arr[i].y=arr[i].startY-(arr[i].deg*Math.PI/180)*arr[i].step
                    if(arr[i].y<20){
                        arr.splice(i,1)
                    }
                }
                for(var i=0;i<arr.length;i++){
                    ctx.save()
                    ctx.fillStyle='rgba('+arr[i].red+","+arr[i].green+","+arr[i].blue+","+arr[i].alp+')'
                    ctx.arc(arr[i].x,arr[i].y,arr[i].r,0,2*Math.PI)
                    ctx.fill()
                    ctx.beginPath()
                    ctx.restore()
                }
            },1000/60)
            setInterval(function(){
                var red=Math.round(Math.random()*255) 
                var blue=Math.round(Math.random()*255) 
                var green=Math.round(Math.random()*255) 
                var alp=1
                var r=Math.random()*10+3
                var x=Math.random()*canvas.clientWidth
                var y=canvas.clientHeight-r
                var deg=0
                var step=Math.random()*20+10
                var startX=x
                var startY=y
                arr.push({
                    red,blue,green,alp,r,x,y,step,startX,startY,deg
                })
            },5000/60)
        }
        
    </script>
</html>
 <!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            body{
                background-color: pink;
            }
            #test{
                position: absolute;
                top: 0;
                left: 0;
                bottom: 0;
                right: 0;
                margin: auto;
                border: 1px solid;
            }
            canvas{
                background-color: white;
            }
        </style>
    </head>
    <body>
        <canvas id="test" width="200" height="400"></canvas>
    </body>
    <script type="text/javascript">
        var canvas=document.getElementById('test')
        if(canvas.getContext){
            var ctx=canvas.getContext('2d')
            var arr=[]
            setInterval(function(){
                ctx.clearRect(0,0,canvas.clientWidth,canvas.clientHeight)
                for(var i=0;i<arr.length;i++){
                    arr[i].deg+=5
                    arr[i].x=arr[i].startX+Math.sin(arr[i].deg*Math.PI/180)*arr[i].step
                    arr[i].y=arr[i].startY-(arr[i].deg*Math.PI/180)*arr[i].step
                    if(arr[i].y<20){
                        arr.splice(i,1)
                    }
                }
                for(var i=0;i<arr.length;i++){
                    ctx.save()
                    ctx.fillStyle='rgba('+arr[i].red+","+arr[i].green+","+arr[i].blue+","+arr[i].alp+')'
                    ctx.arc(arr[i].x,arr[i].y,arr[i].r,0,2*Math.PI)
                    ctx.fill()
                    ctx.beginPath()
                    ctx.restore()
                }
            },1000/60)
            setInterval(function(){
                var red=Math.round(Math.random()*255) 
                var blue=Math.round(Math.random()*255) 
                var green=Math.round(Math.random()*255) 
                var alp=1
                var r=Math.random()*10+3
                var x=Math.random()*canvas.clientWidth
                var y=canvas.clientHeight-r
                var deg=0
                var step=Math.random()*20+10
                var startX=x
                var startY=y
                arr.push({
                    red,blue,green,alp,r,x,y,step,startX,startY,deg
                })
            },5000/60)
        }
        
    </script>
</html>

感谢阅读!!