最近抽空學了學canvas,而後用canvas作了個小球運動的demo,大體的效果以下:css
雖然網上已經有不少這樣的demo,可是仍是想根據本身的思路來寫一個,下面先跟你們講解一下源代碼,先看html代碼:html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"/> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> html, body { padding: 0; margin: 0; width: 100%; height: 100%; } canvas { background-image: linear-gradient(-50deg,RGB(255, 106, 100),RGB(71, 0, 182));/*對canvas作背景顏色漸變處理,第一個參數是角度,後面2個是起始顏色,這個我就不細講了,查查就知道*/ } </style> </head> <body> <canvas id="canvas"> </canvas> <script src="./index.js"></script> </body> </html>
html很簡單,沒啥講的,就是css那塊兼容性大家注意下就好(我懶,沒寫兼容),再看看canvas的js處理代碼,就是上面引入的index.js(講解都寫在註釋裏了,寫的比較基礎,方便沒多少基礎的人看):git
window.onload = function(){// 頁面加載完了以後再處理 var canvas = document.getElementById('canvas'); var body = document.getElementsByTagName('body')[0];//getElementsByTagName是以標籤名獲取元素,返回是一個數組,因此用[0] canvas.width = body.clientWidth;// 獲取body的【客戶端寬度】,這個時候body已經加載完成了,頁面大小已經造成。 canvas.height = body.clientHeight; var bound = canvas.getBoundingClientRect();// 這個叫作獲取邊界客戶端矩形,能夠用來獲取canvas的長寬 var ctx = canvas.getContext('2d');// 獲取canvas的上下文環境(能夠理解爲買下一個畫筆) var width = bound.width, height = bound.height; var circleConfig = {// 配置信息 ballNums: 300,// 球的數量 fillColor: 'rgba(255, 255, 255, .5)',// 球的填充顏色 radius: 1// 球的半徑 }; var circle = new Circle(circleConfig);// 初始化球 circle.init();// 初始化 var zoom=function(e){ // 這個函數是用來縮放球的大小的,簡單作了個縮放改變球的效果,目前可能就在chrome下有用 var e = e || window.event; if (!e.deltaX) {// 縮放的時候這個值是爲0或-0的 if (e.deltaY < 0) {// 小於0好像是放大吧 if (circleConfig.radius) { circleConfig.radius = null; var circle = new Circle({ ballNums: 300, fillColor: 'rgba(255, 255, 255, .5)', // radius: 1 }); circle.init(); } } else { if (!circleConfig.radius) { circleConfig.radius = 1; var circle = new Circle({ ballNums: 300, fillColor: 'rgba(255, 255, 255, .5)', radius: 1 }); circle.init(); } } } if(e.wheelDelta && event.ctrlKey){// 禁止網頁縮放 event.returnValue = false }else if(e.detail){ event.returnValue = false; } } if(document.addEventListener){ document.addEventListener('DOMMouseScroll' , zoom , false); // 兼容火狐 } window.onmousewheel = document.onmousewheel = zoom;// 除火狐以外的瀏覽器 function Circle(o) {// 好了,這裏纔是故事真正開始的地方 o = o || {}; this.instance = [];// 能夠理解爲實例數組,用來存球的 this.maxLineLength = o.maxLineLength || 100;// 最大線長度,就是2個球在這個距離內會在之間畫根線 function Ball() { this.radius = o.radius || (o.MaxRadius || 20) * Math.random(); this.startDeg = 0;// 開始角度 this.endDeg = Math.PI * 2;// 終結角度 this.clockWay = false; // 順時針仍是逆時針 this.fillColor = o.fillColor || randomColor();// 填充顏色 this.borderColor = 'transparent';// 球的border設置爲透明的否則難看 this.dirX = 1;// 球的水平方向(控制正反) this.dirY = 1;// 如上 this.speed = o.speed || 1 * Math.random() - 0.3;// 球的移動速度 this.X = getRandom(width);// 這裏是初始化球的起始位置,值是0-width this.Y = getRandom(height); this.resetDir = function() {// 控制方向 // X的位置若是小於半徑或者大於canvas的寬度-半徑就改變方向,Y同理 if (this.X < this.radius || this.X > width - this.radius) { this.dirX = -this.dirX; } if (this.Y < this.radius || this.Y > height - this.radius) { this.dirY = -this.dirY; } }; this.init = function() {// 球的初始化 this.move(); }; this.move = function() {// 這個就是移動球,每執行一次就檢查方向和改變XY的帶系喔啊 this.resetDir(); this.X += this.dirX * this.speed;// 移動 this.Y += this.dirY * this.speed; }; } this.ball = { }; this.arc = function() {// 畫圓函數 // ctx.translate(this.X, this.Y); for (var i = 0; i < this.instance.length; i++) { var ball = this.instance[i];// 從實例數組中取出來 // ctx.save();// 保存狀態 ctx.fillStyle = ball.fillColor;// 球的填充顏色 (準備好填充顏料) ctx.strokeStyle = ball.borderColor;// 球的線就是border(理解爲準備好顏料) ctx.beginPath();// 開始路徑,能夠理解爲拿起畫筆 ctx.arc(ball.X, ball.Y, ball.radius, ball.startDeg, ball.endDeg, this.clockWay);// 畫圓 ctx.fill(); // 填充圓(就至關於給圓上色) ctx.closePath();// 放下筆 // ctx.restore(); for(var j = i + 1; j < this.instance.length; j++) { var s = Math.pow(ball.X - this.instance[j].X, 2) + Math.pow(ball.Y - this.instance[j].Y, 2); s = Math.sqrt(s);// 獲取圓與圓之間的距離,x的平方加y的平方而後開根號,初中數學知識 if (s < this.maxLineLength) {// 判斷何時能夠畫線 ctx.beginPath(); ctx.moveTo(ball.X, ball.Y);// 把筆移動到 ctx.lineTo(this.instance[j].X, this.instance[j].Y);// 畫線到這個位置 ctx.strokeStyle = 'rgba(255, 255, 255, ' + (this.maxLineLength - s) / (this.maxLineLength * 1.3)+')'; // 上面是調整線的顏色 ctx.strokeWidth = 1;// 線寬 ctx.stroke();// 畫 ctx.closePath(); } } } }; this.draw = function() { ctx.clearRect(0,0,width,height);// 你要是把這個給注了你會發現不同的世界 this.arc();// 執行畫圓函數 }; this.move = function() { for(var i = 0; i < this.instance.length; i++) { var ball = this.instance[i]; ball.init();// 球的初始化函數,其實跟ball.move()是同樣的,就是改變球的位置 } this.draw(); requestAnimationFrame(this.move.bind(this));// 這裏用bind是強行改變move函數的上下文環境,否則在requestAnimationFrame中的this會變得 // requestAnimationFrame 請求動畫幀,能夠理解爲控制函數執行的頻率(原本這裏能夠用遞歸執行,可是遞歸控制不了頻率,會卡死頁面的,setTimeout也能夠實現相似的效果) }; this.init = function() { for(var i = 0; i < o.ballNums; i++) { this.instance.push(new Ball()); // 初始化球 } this.move(); }; } function getRandom(s) { return Math.ceil(Math.random() * s);// 獲取0 -(s-1)之間的值 } function randomColor() { return 'rgba('+getRandom(255)+','+getRandom(255)+','+getRandom(255)+','+Math.random()+')'; }; };
寫完以後,仍是想把他應用起來的,因此我就想用來他裝飾博客園的側邊欄,因此進到:github
把上面的js改了改,插入到博客園頁面:chrome
完整代碼以下:canvas
<script> var sideBar = document.getElementById('home'); var canvas = document.createElement('canvas'); canvas.id = 'canvas'; sideBar.appendChild(canvas); window.onload = function(){ var canvas = document.getElementById('canvas'); // var body = document.getElementById('home'); var body = document.getElementsByTagName('html')[0]; var header = document.getElementById('header'); canvas.width = header.clientWidth; // canvas.height = body.clientHeight; canvas.height = window.screen.height; var bound = canvas.getBoundingClientRect(); var ctx = canvas.getContext('2d'); var width = bound.width, height = bound.height; var submit = document.getElementById('btn_comment_submit'); submit && submit.addEventListener('click', function() { setTimeout(function() { body = document.getElementsByTagName('html')[0]; canvas.height = window.screen.height; var circle = new Circle({ ballNums: 100, fillColor: 'rgba(255, 255, 255, .5)', radius:1 }); circle.init(); },1000); }); var circle = new Circle({ ballNums: 100, fillColor: 'rgba(255, 255, 255, .5)', radius: 1 }); circle.init(); function Circle(o) { o = o || {}; this.instance = []; this.maxLineLength = o.maxLineLength || 100; function Ball() { this.radius = o.radius || (o.MaxRadius || 20) * Math.random(); this.startDeg = 0; this.endDeg = Math.PI * 2; this.clockWay = false; this.fillColor = o.fillColor || randomColor(); this.borderColor = 'transparent'; this.dirX = 1; this.dirY = 1; this.speed = o.speed || 1 * Math.random() - 0.3; this.X = getRandom(width); this.Y = getRandom(height); this.resetDir = function() { if (this.X < this.radius || this.X > width - this.radius) { this.dirX = -this.dirX; } if (this.Y < this.radius || this.Y > height - this.radius) { this.dirY = -this.dirY; } }; this.init = function() { this.move(); }; this.move = function() { this.resetDir(); this.X += this.dirX * this.speed; this.Y += this.dirY * this.speed; }; } this.ball = { }; this.arc = function() { // ctx.translate(this.X, this.Y); for (var i = 0; i < this.instance.length; i++) { var ball = this.instance[i]; ctx.save(); ctx.fillStyle = ball.fillColor; ctx.strokeStyle = ball.borderColor; ctx.beginPath(); ctx.arc(ball.X, ball.Y, ball.radius, ball.startDeg, ball.endDeg, this.clockWay); ctx.fill(); ctx.closePath(); ctx.restore(); for(var j = i + 1; j < this.instance.length; j++) { var s = Math.pow(ball.X - this.instance[j].X, 2) + Math.pow(ball.Y - this.instance[j].Y, 2); s = Math.sqrt(s); if (s < this.maxLineLength) { ctx.beginPath(); ctx.moveTo(ball.X, ball.Y);// 把筆移動到 ctx.lineTo(this.instance[j].X, this.instance[j].Y);// 畫線到這個位置 ctx.strokeStyle = 'rgba(255, 255, 255, ' + (this.maxLineLength - s) / (this.maxLineLength * 1.3)+')'; // 上面是調整線的顏色 ctx.strokeWidth = 1;// 線寬 ctx.stroke();// 畫 ctx.closePath(); } } } }; this.draw = function() { ctx.clearRect(0,0,width,height); this.arc(); }; this.move = function() { for(var i = 0; i < this.instance.length; i++) { var ball = this.instance[i]; ball.init(); } this.draw(); requestAnimationFrame(this.move.bind(this)); }; this.init = function() { for(var i = 0; i < o.ballNums; i++) { this.instance.push(new Ball()); } this.move(); }; } function getRandom(s) { return Math.ceil(Math.random() * s); } function randomColor() { return 'rgba('+getRandom(255)+','+getRandom(255)+','+getRandom(255)+','+Math.random()+')'; }; }; </script>
而後再調整下CSS代碼,就能夠達到我博客的左邊側邊欄動畫效果,以下:數組
canvas的源代碼:https://github.com/lhlybly/canvas-circle,歡迎star瀏覽器
寫在這裏只是但願更多的人一塊兒來學習,一塊兒享受代碼的做用,項目代碼中還有不少優化的地方,歡迎大牛拍磚,也但願剛入門的人你呢個看懂,不懂能夠留言問我。app
PS: 抽空我會優化剛進頁面左邊白屏的問題 dom