canvas繪制運動小球
知乎的網頁版登錄界面的背景有很多運動的小球,小球和小球運動的時候之間還有連線,給人一種三維立體變換的效果,看著十分的不錯,所以用canvas試著做了個和知乎登錄界面背景類似的效果,上面動圖就是做好效果的截圖。
實現思路
首先了解下canvas中的動畫原理?canvas中的動畫其實是通過不斷的重繪來實現動起來的效果的,打個比方一個小球初始的時候在畫布的X,Y坐標記作ball(x,y)
,然后每隔10毫秒更改小球的X,Y坐標為ball(x+5,y+5)
(在當前X,Y坐標加5個像素) 并且清除整個畫布,重新在畫布上繪制更改坐標后小球,由于10毫秒非常的短,所有在視覺上給我們的感覺就是小球在不斷運動著。canvas繪圖的原理基本就是這樣子。
- 定義小球對象
var ball = {
xPointer: 100, //小球初始x坐標
yPointer: 100, //小球初始y坐標
vx: 1, //x方向的速度
vy: 0.1, //y方向的速度
x: 1, //x軸運動方向(1表示正方向,-1表示反方向)
y: -1, //y軸運動方向
color: "blue", //小球顏色
radius: 10, //小球半徑
};
- 生成小球
demo中的小球有很多個,所以定義一個數組來裝這些小球,小球的起始坐標、顏色、運動方向都不同所以這些值需要隨機獲取。
var ballList = []; //小球數組
var canvas, ctx;
//生成多個小球
function initBall() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
//循環生成60個小球
for (var i = 0; i < 60; i++) {
// console.log(getIndex() + " " + getIndex())
var ball = {};
ball.xPointer = getRandom(20, 980); //隨機小球的X坐標
ball.yPointer = getRandom(20, 340); //隨機小球的y坐標
ball.x = getIndex(); //隨機小球x軸運動方向
ball.y = getIndex(); //隨機小球的y軸運動方向
ball.vx = Math.random(); //隨機小球x軸方向速度
ball.vy = Math.random(); //隨機小球y軸方向速度
ball.radius = 9; //小球半徑
ball.color = "#" + ("00000" + ((Math.random() * 16777215 + 0.5) >> 0).toString(16)).slice(-6); //隨機小球顏色
ballList.push(ball);
}
}
//隨機一個1或者-1的方法
function getIndex() {
var arr = [0, 1];
var index = Math.floor((Math.random() * arr.length));
if (index == 0) {
index = -1;
}
return index;
}
//獲取兩數之間的一個隨機數的方法
function getRandom(first, last) {
var choice = last - first + 1;
return Math.floor(Math.random() * choice + first);
}
- 通過canvas繪制小球
頁面canvas標簽
<canvas id="canvas" width="1000" height="360" style='background-color: #EEEEEE;'></canvas>
canvas繪制小球代碼
function draw(ctx) {
ctx.clearRect(0, 0, 1000, 360); //繪制前先清除畫布
for (var i = 0; i < ballList.length; i++) {
ctx.save();
ctx.beginPath();
ctx.fillStyle = ballList[i].color;
ctx.arc(ballList[i].xPointer, ballList[i].yPointer, ballList[i].radius, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
ctx.restore();
}
}
- 運動起來
小球運動的過程中使用了簡單的碰撞檢測,每次到達畫布的邊緣就改變小球的運動方向
//修改小球的狀態,使小球動起來的方法
function update(ballList, ctx) {
for (var i = 0; i < ballList.length; i++) {
ballList[i].xPointer += ballList[i].vx * ballList[i].x;
ballList[i].yPointer += ballList[i].vy * ballList[i].y;
//碰撞檢測 X軸方向
if (ballList[i].xPointer + ballList[i].radius >= canvas.width || ballList[i].xPointer - ballList[i].radius <= 0) {
ballList[i].x = ballList[i].x * -1;
}
//碰撞檢測 Y軸方向
if (ballList[i].yPointer + ballList[i].radius >= canvas.height || ballList[i].yPointer - ballList[i].radius <= 0) {
ballList[i].y = ballList[i].y * -1;
}
}
}
- 繪制小球和小球之間的連線
//小球之間連線
function drawLine(ballList, ctx) {
for (var i = 0; i < ballList.length; i++) {
for (var j = 0; j < ballList.length; j++) {
var xx = Math.pow((ballList[i].xPointer - ballList[j].xPointer), 2);
var yy = Math.pow((ballList[i].yPointer - ballList[j].yPointer), 2);
var zz = Math.sqrt(xx + yy);
//判斷兩個小球如果之間距離在20到100之間,就繪制一條直線
if (zz <= 100 && zz >= 20) {
console.log(zz)
ctx.save();
ctx.beginPath();
ctx.strokeStyle = "#999999";
ctx.lineWidth = 0.1;
// ctx.strokeStyle= "#" + ("00000" + ((Math.random() * 16777215 + 0.5) >> 0).toString(16)).slice(-6);
ctx.moveTo(ballList[i].xPointer, ballList[i].yPointer);
ctx.lineTo(ballList[j].xPointer, ballList[j].yPointer);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
}
}
}
- 運行
(function() {
initBall(); //生成小球
//計時器
setInterval(function() {
// console.log(selectfrom(0, 600) + " " + selectfrom(0, 600));
draw(ctx); //繪制
update(ballList, ctx); //修改小球狀態
drawLine(ballList, ctx); //畫線
}, 24)
})();
其它
由于代碼比較簡單,也就沒有做封裝處理
通過修改小球的半徑后得到了另一種不錯的顯示效果,如下圖
修改小球半徑后的小球運動效果
** 到此一個canvas小球運動效果的demo做完了,看著是不是有一種3d變換效果。**
文章如有誤,請不吝賜教~