canvas动画简单操作


canvas动画

小球滚动效果

关键api:
window.requestAnimationFrame(draw)
会递归调用draw函数,替代setInterval

var x = 20;
var speed = 4;
//电脑的帧率是1秒钟60Hz, 就相当于一秒钟可以播放60张图片,就相当于播放一张图片使用16.7ms

function draw () {
    //1. 先把画布清空
    context.clearRect(0, 0, canvas.width, canvas.height);
    //2. 画小球
    context.beginPath();
    var gradient = context.createRadialGradient(x-10,190,0,x,200,20);
    gradient.addColorStop(0,'#fff');
    gradient.addColorStop(1,'#333');
    context.fillStyle = gradient;
    context.arc(x, 200, 20, 0, 2*Math.PI);
    context.fill();
    //3. x要移动
    x += speed;
    if(x>canvas.width - 20||x<20){
        speed = -speed;
    }
    //被优化过的动画执行方向1.递归调用;2.可以自适应浏览器的刷新的帧率
    window.requestAnimationFrame(draw);
}
draw();

小球x,y轴回弹效果

关键点:
1.	跟上面例子差不多
2.	在y轴上加多一个speed即可

var xspeed = 2;
var yspeed = 2;
//小球的初始位置
var x = 20;
var y = 200;
function draw() {
    context.clearRect(0, 0, canvas.width, canvas.height);
    //创建一张新的玻璃纸
    context.beginPath();
    var gradient = context.createRadialGradient(x - 10, y-10, 0, x, y, 20);
    gradient.addColorStop(0, '#fff');
    gradient.addColorStop(1, '#333');
    context.fillStyle = gradient;
    context.arc(x, y, 20, 0, 2*Math.PI);
    context.fill();
    x += xspeed;
    y += yspeed;
    //水平方向到达了边界, 就调头, 速度往反方向
    if (x < 20 || x > canvas.width - 20) {
        xspeed = -xspeed;
    }
    if (y < 20 || y > canvas.height - 20) {
        yspeed = -yspeed;
    }
    window.requestAnimationFrame(draw);
}
draw();

小鸟挥动翅膀

var birdsImg = new Image();
birdsImg.src = "./img/birds.png";

//图片加载完成之后,才开始执行绘制操作
birdsImg.onload = function () {
    //翅膀扇了第几次
    var index = 0;
    //当前是第几张图片
    var xindex = 0;

    //每张小鸟图片的宽高
    var w = birdsImg.width / 3;
    var h = birdsImg.height;

    //小鸟的位置
    var x = 100;
    var y = 100;

    //小鸟往下掉的速度
    var yspeed = 5;

    function draw() {
        //使用第几张图片
        index += 1;
        xindex = index % 3;
        //清空画布
        context.clearRect(0, 0, canvas.width, canvas.height);
        //画每一张小鸟
        context.drawImage(birdsImg, xindex * w, 0, w, h, x, y, w, h);
        //小鸟往下掉
        y += yspeed;
        //递归调用draw方法,实现动画
        window.requestAnimationFrame(draw);
    }
    draw();
}

地球转动

判断两张图片都加载完成的方法

var sun = new Image();
var earth = new Image();
sun.src = "./img/Canvas_sun.png";
earth.src = "./img/Canvas_earth.png";

//计数器
var count = 0;
var images = [sun, earth];

//如果需要多个图片都加载完成之后,再操作, 应该怎么办:
images.forEach(function (img) {
    
    img.onload = function () {
        count += 1;
        if (count == images.length) {
			//。。。code
		}	

地球转动

var sun = new Image();
var earth = new Image();
sun.src = "./img/Canvas_sun.png";
earth.src = "./img/Canvas_earth.png";
//计数器
var count = 0;
var images = [sun, earth];
//如果需要多个图片都加载完成之后,再操作, 应该怎么办:
images.forEach(function (img) {
    img.onload = function () {
        count += 1;
        if (count == images.length) {
            console.log("所有的图片都加载完成了");
            function draw() {
                //0. 先把原始的坐标系的状态保存起来
                context.save();
                //1. 清空画布
                context.clearRect(0, 0, canvas.width, canvas.height);
                //2. 画太阳(五参模式, 原图显示)
                context.drawImage(sun, 0, 0, sun.width, sun.height);

                //3. 假设地球绕太阳一圈的时间是1分钟,只需要拿到当前的秒数,就可以用秒数/60*360计算出地球相于水平线的角度
                //拿到当前的秒数
                var now = new Date();

                //精确到毫秒,就能够形成一个连续的动画效果了
                var seconds = now.getSeconds();
                var millSeconds = now.getMilliseconds();
                seconds += millSeconds / 1000;

                //算出此时此刻的地球的角度(弧度)
                var radian = seconds / 60 * 2 * Math.PI;

                //4. 平移坐标系,将坐标的原点移到太阳的中心
                context.translate(sun.width/2, sun.height/2);

                //5. 旋转坐标系
                context.rotate(radian);

                //6. 画地球
                context.drawImage(earth, 120-earth.width/2, -earth.height/2, earth.width, earth.height);

                //7. 还原坐标系
                context.restore();

                window.requestAnimationFrame(draw);
            }

            draw();
        }
    }
})


关于save和restore

//save保存, restore恢复, 还原
//save的作用,是把context的当前的状态,保存起来;restore是把context最近一次保存的状态还原

context.fillStyle = "red";
context.strokeStyle = "blue";
context.shadowColor = "cyan";

//把当前的context整个保存一份
context.save(); //就会把当前的context整个保存一份

context.fillRect(100, 100, 100, 100);

context.fillStyle = "green";
context.fillRect(300, 200, 100, 100);

//把最近保存的那个context直接拿过来用
context.restore();

context.fillRect(500, 300, 100, 100);

钟表的实现

//画某一帧的方法
function draw() {
    //0. 把坐标系的原始状态保存
    context.save();

    //1. 清空画布
    context.clearRect(0, 0, canvas.width, canvas.height);

    //2. 先平移坐标系到中心点,再旋转坐标系到12点钟的方向
    context.translate(300, 200);
    //往反方向旋转90度
    context.rotate(-0.5*Math.PI);


    //3. 画表盘
    context.beginPath();
    context.arc(0, 0, 130, 0, 2*Math.PI);
    context.strokeStyle = "blue";
    context.lineWidth = 3;
    context.stroke();

    //4. 画时针的刻度
    context.beginPath();
    for (var i = 0; i<12; i++) {
        context.moveTo(115, 0);
        context.lineTo(126, 0);
        context.rotate(30/180*Math.PI);
    }

    context.strokeStyle = "#000";
    context.lineWidth = 6;
    context.stroke();

    //5. 画分针的刻度
    context.beginPath();
    for (var i = 0; i<60; i++) {
        if (i % 5 != 0) {
            context.moveTo(120, 0);
            context.lineTo(126, 0);
        }

        context.rotate(6/180*Math.PI);
    }

    context.lineWidth = 4;
    context.stroke();

    //6. 算出时针, 分针, 秒针的角度
    var now = new Date();
    var h = now.getHours();
    var m = now.getMinutes();
    var s = now.getSeconds();

    m = m + s/60; //精确到几点几分钟
    h = h + m/60; //精确到几点几小时

    var hradian = h / 12 * 2 * Math.PI;
    var mradian = m / 60 * 2 * Math.PI;
    var sradian = s / 60 * 2 * Math.PI;

    //7. 画时针
    context.save();
    context.beginPath();
    context.rotate(hradian);
    context.moveTo(-15, 0);
    context.lineTo(60, 0);
    context.strokeStyle = "blue";
    context.lineWidth = 6;
    context.lineCap = "round";
    context.stroke();
    context.restore();

    //8. 画分针
    context.save();
    context.beginPath();
    context.rotate(mradian);
    context.moveTo(-15, 0);
    context.lineTo(70, 0);
    context.strokeStyle = "blue";
    context.lineWidth = 5;
    context.lineCap = "round";
    context.stroke();
    context.restore();

    //9. 画秒针
    context.save();
    context.beginPath();
    context.rotate(sradian);
    context.moveTo(-15, 0);
    context.lineTo(85, 0);
    context.strokeStyle = "red";
    context.lineWidth = 3;
    context.lineCap = "round";
    context.stroke();
    context.restore();

    //10. 画表心
    context.beginPath();
    context.arc(0, 0, 5, 0, 2*Math.PI);
    context.fillStyle = "red";
    context.fill();

    //11. 还原坐标系
    context.restore();
}

//draw();

//没有必要使用requestAnimationFrame,因为这个钟表是一秒钟走一次
setInterval(draw, 1000);


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM