1. 程式人生 > >【被玩壞的博客園】之canvas裝飾博客園側邊欄

【被玩壞的博客園】之canvas裝飾博客園側邊欄

ctx tail lang num radi sid 應用 ack 火狐

最近抽空學了學canvas,然後用canvas做了個小球運動的demo,大致的效果如下:

技術分享圖片

雖然網上已經有很多這樣的demo,但是還是想根據自己的思路來寫一個,下面先跟大家講解一下源代碼,先看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(講解都寫在註釋裏了,寫的比較基礎,方便沒多少基礎的人看):

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()+‘)‘;
    };
  };
  

寫完之後,還是想把他應用起來的,所以我就想用來他裝飾博客園的側邊欄,所以進到:

技術分享圖片

把上面的js改了改,插入到博客園頁面:

技術分享圖片

完整代碼如下:

<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.getElementById(‘home‘);
    var header = document.getElementById(‘header‘);
    canvas.width = header.clientWidth;
    // canvas.height = body.clientHeight;
    canvas.height = body.clientHeight;
    var bound = canvas.getBoundingClientRect();
    var ctx = canvas.getContext(‘2d‘);
    var width = bound.width, height = bound.height;
    var submit = document.getElementById(‘btn_comment_submit‘);
    submit.addEventListener(‘click‘, function() {
setTimeout(function() {
body = document.getElementById(‘home‘);
canvas.height = body.clientHeight;
var circle = new Circle({
        ballNums: 200,
        fillColor: ‘rgba(255, 255, 255, .5)‘
    });
    circle.init();
},1000);
});
    var circle = new Circle({
        ballNums: 200,
        fillColor: ‘rgba(255, 255, 255, .5)‘
    });
    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

寫在這裏只是希望更多的人一起來學習,一起享受代碼的作用,項目代碼中還有很多優化的地方,歡迎大牛拍磚,也希望剛入門的人你呢個看懂,不懂可以留言問我。

PS: 抽空我會優化剛進頁面左邊白屏的問題

【被玩壞的博客園】之canvas裝飾博客園側邊欄