canvas多个元素的动画

2018-01-17  本文已影响0人  英俊又可爱XD

多个图片元素的动画绘制

步骤:
  1. 每一帧动画的元素都重新绘制在画板中;
  2. 将元素创建的对象放入数组中,遍历元素,图片加载onload后绘制;
var imgArr=[obj1, obj2 …];     //对象数组
var count = 0;      //遍历对象的计数器
imgArr.forEach( function(img){
count++;    //计数器计数
if (count == imgArr.length) {  //imgArr中所有元素加载完毕
function draw( ){
 绘制每一帧的动作;    //tips: 重置画布画纸、画各个元素、递归
window.requestAnimationFrame(draw);  //递归:自适应帧率
}
draw();    //第一次调用:推一下,跑起来~
}
})
  1. 将每个元素的绘制都封装在函数draw中,在draw中写递归(draw外手动调用);
  2. draw函数开始需要进行重置:清空画布、换纸
  3. 每个图片、文字或图形的绘制参数可以进行封装;
  4. 画布进行位移/旋转前进行context的读档和存档,换纸。

案例:地球围绕太阳转

实现效果:


地球绕着太阳转.gif
步骤:
  1. 创建图片对象并添加到数组,forEach遍历数组,加载图片
  2. 图片加载后执行函数draw,每次执行draw都会把太阳图片和地球图片重新drawImage一次
太阳与地球分析.jpg

代码如下:

<body><canvas height="400" width="600" id="canvas"></canvas></body>
<script>
    var canvas = document.getElementById("canvas");
    var context = canvas.getContext("2d");
    var earth = new Image();     //创建元素的对象和数组
    var sun = new Image();
    sun.src = "./img/Canvas_sun.png";
    earth.src = "./img/Canvas_earth.png";
    var imgArr = [sun, earth]; 
    var count = 0;
    imgArr.forEach(function (img) {     //forEach遍历
        img.onload = function () {
            count++;
            if (count == imgArr.length) {
                function draw(){     //函数draw
                context.save();     //清画板,存档画笔状态
                // context.beginPath();
                context.drawImage(sun, 0, 0);     //画太阳
                var now = new Date();     //算草稿纸角度:秒和千秒
                var seconds = now.getSeconds() + now.getMilliseconds()/1000 ;
                var earthR = seconds/30*Math.PI;
                var earthX = sun.width/2 - earth.width;     //算地球xy
                var earthY = -earth.height/2;
                context.translate(sun.width/2, sun.height/2);     //挪纸,转角度
                context.rotate(earthR);
                context.drawImage(earth, earthX, earthY);     //画地球
                context.restore();     //读档画笔状态(重置状态)
                window.requestAnimationFrame(draw);     //自适应帧率动画,回调draw
                }
                draw();     //第一次调用
            }
        }
    })
</script>

案例:机械时钟的绘制

呈现效果:


机械钟.gif
思路:

1.每一帧都重新绘制所有元素,包括表盘和指针。
2.时刻线、指针均用草稿纸旋转完成,每一根指针的绘制都需要重新读档存档。
3.每一帧开始前都需要保证画板的坐标处于原始状态。


时钟在画布上的角度分析.png

代码实现:

<body>
<canvas width="600" height="400" id="canvas" style = "border:1px solid #555"></canvas></body>
</html>
<script>
    var canvas= document.getElementById("canvas");
    var context = canvas.getContext("2d");
    function draw(){     //draw函数
        context.clearRect(0,0,600,400);     //初始化
        context.beginPath();
    //画表盘
        context.strokeStyle="seagreen";
        context.lineWidth = 4;
        context.arc(300,200,140,0,2*Math.PI);     //画圆
        context.stroke();
        context.beginPath();    //新纸
        //存档ct
        context.save();   //存档1:坐标系0, 笔粗4
        //循环:转稿纸画线
            context.translate(300,200); //坐标系300-200, 笔粗4
        for(var i =0; i<12; i++){
            context.rotate(Math.PI/6);
            context.moveTo(125,0);
            context.lineTo(135,0);
        }
        context.stroke();
        context.beginPath();  //新纸
            context.lineWidth = 2;   //坐标系300-200 笔粗2
        for(var i =0; i<60; i++){
            context.rotate(Math.PI/30);
            context.moveTo(130,0); 
            context.lineTo(135,0);
        }
        context.stroke();     //印制,新纸
        context.beginPath();
    //画时针
        var now = new Date();     //获取时间,算角度
        var hourR =now.getHours()>12?(now.getHours()-12)*Math.PI/6 : (now.getHours())*Math.PI/6;
        //读档,位移,旋转,印制,新纸
        context.restore();  //读存档1:坐标系0, 笔粗4
        context.save();      //存档1:坐标系0, 笔粗4
        context.translate(300,200);    //坐标系300-200, 笔粗4
        context.rotate(-Math.PI/2);    //坐标系300-200,-90° 笔粗4
        context.lineWidth=8;     //坐标系300-200,-90° 笔粗8
        context.lineCap="round";
        context.save();   //存档2:坐标系300-200,-90° 笔粗8
        context.rotate(hourR); 
        context.moveTo(-10,0);
        context.lineTo(50,0);
        context.stroke();
        context.beginPath();  //新纸
    //画分针
        var minuteR = now.getMinutes()/30*Math.PI; //算角度
        // console.log(minuteR);
        //读档,位移,旋转,印制,新纸
        context.restore();   //读存档2:坐标系300-200,-90°
        context.save();  //存档2
        context.rotate(minuteR);
        context.moveTo(-15,0);
        context.lineTo(95,0);
        context.lineWidth = 6;
        context.stroke();
        context.beginPath();
    //画秒针
        var secondR = now.getSeconds()/30*Math.PI;   //算角度
        //读档,位移,旋转,印制
        context.restore();    //读存档2:坐标系300-200,-90°
        context.rotate(secondR);
        context.moveTo(-25,0);
        context.lineTo(115,0);
        context.lineWidth = 2;
        context.strokeStyle="#53C686";
        context.stroke();
    //画表芯:新纸,读档,印圆
        context.restore();    //读存档1:坐标系0, 笔粗4
        context.beginPath();
        context.fillStyle = "#53C686";
        context.arc(300,200,8,0,2*Math.PI);
        context.fill();
        window.requestAnimationFrame(draw); //自适应帧率,递归调用
    }
    draw();     //第一次draw
</script>

2018.1.17

上一篇下一篇

猜你喜欢

热点阅读