canvas动画
小球滚动效果
关键api:
window.requestAnimationFrame(draw)
会递归调用draw函数,替代setIntervalvar x = 20;
var speed = 4;
//电脑的帧率是1秒钟60Hz, 就相当于一秒钟可以播放60张图片,就相当于播放一张图片使用16.7msfunction 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);
更多专业前端知识,请上 【猿2048】www.mk2048.com