canvas動畫3:交互


canvas動畫3

時隔很久,本人終於又寫博客了(重度拖延症),把之前留下的canvas交互動畫講一講。

電腦上的交互,指的是鼠標和鍵盤,我們今天主要用的是鼠標。

既然是鼠標的話,就要獲取鼠標的各種事件,這次以mousemove做示例。

我們先定義一個鼠標對象,然后添加mousemove事件:

var mouse = {
    x: undefined,
    y: undefined
}
//這樣的話控制台就會跟隨我們的鼠標移動輸出相應的坐標
window.addEventListener("mousemove",function (event) {
    mouse.x = event.x;
    mouse.y = event.y;
    console.log(mouse);
});

我們聲明一個初始化函數init(),用於把制造圓的過程封裝:

function init() {
    circleArray = []
    for (var i = 0; i < 800; i++) {
        var x = Math.random()*window.innerWidth;
        var y = Math.random()*window.innerHeight;
        var dx = (Math.random()-0.5)*2;
        var dy = (Math.random()-0.5)*2;
        var radius = Math.random()*3 +1;
        circleArray.push(new Circle(x, y, dx, dy, radius));
    }
}
init();

這樣的話,按照上一篇文章的做法,我們的canvas會出現一些問題。所以,需要給Circle對象update()里的屬性都加上this

function Circle(x, y, dx, dy, radius) {
    this.x = x;
    this.y = y;
    this.dx = dx;
    this.dy = dy;
    this.radius = radius;

    this.draw = function() {
        ctx.beginPath();
        ctx.strokeStyle = "#000";
        ctx.arc(this.x,this.y,this.radius,Math.PI/180*0,Math.PI/180*360,false);
        ctx.stroke();
        ctx.fill();
    }
    this.update = function() {
        //圓觸碰邊界時反彈,偏移值為負
        if (this.x + this.radius > innerWidth || this.x - this.radius < 0 ) {
            this.dx = -this.dx;
        }
        if (this.y + this.radius > innerHeight || this.y - this.radius < 0 ) {
            this.dy = -this.dy;
        }
        //刷新繪制時圓的偏移運動
        this.x += this.dx;
        this.y += this.dy;
        //根據更新的值進行繪制
        this.draw();

    }
}

接下來我們就要用mousemove於動畫進行交互了,我們假定圓心在鼠標坐標周圍50px以內的時候圓會增大,這段代碼應該寫在update()里:

if (mouse.x - this.x < 50 && mouse.x - this.x >-50 && mouse.y - this.y < 50 && mouse.y - this.y >-50) {
    // if (this.radius < maxRadius) {
        this.radius += 1;
    // }
}
我們設置了10個圓,把鼠標移上去的時候會看到在控制范圍內的圓會不斷變大,不會停下來,所以我在前面就設置了一個圓半徑的最大值,以免它一直增大,然后把注釋的內容去掉,圓就不會無限增大了:

但是有一個問題,圓放大了以后不會縮小,那么我們就讓它在離開圓50px半徑范圍后縮小:

if (mouse.x - this.x < 50 && mouse.x - this.x >-50 && mouse.y - this.y < 50 && mouse.y - this.y >-50) {
    if (this.radius < maxRadius) {
        this.radius += 1;
    }
//其他的所有圓半徑不斷減小
}else{
    this.radius -= 1;
}

這時候又有新問題產生了,畫面一片空白,因為圓心不在鼠標固定范圍內的圓全都變小了,甚至半徑為負!顯然簡單的else是不成立的,還是得加個條件:

if (mouse.x - this.x < 50 && mouse.x - this.x >-50 && mouse.y - this.y < 50 && mouse.y - this.y >-50) {
    if (this.radius < maxRadius) {
        this.radius += 1;
    }
//其他的所有圓半徑減小到最小值
}else if (this.radius > this.minRadius) {
    this.radius -= 1;
}

這里出現了一個新值:minRadius,我加在了Circle對象里this.minRadius = radius;,以原本的初始值作為它的最小值。好了,現在基本效果已經成型了:

接下來就是顏色的問題了,只要懂得canvas的基本api,修改顏色完全就是小兒科。我們設置一個數組,用於存放顏色值。

var colorArray = [
    '#58D68D',
    '#E67F22',
    '#3598DB',
    '#E84C3D',
    '#9A59B5',
    '#27AE61',
    '#D25400',
    '#BEC3C7',
    '#297FB8'
]

然后在Circle對象里加上一個bg屬性:this.bg = colorArray[Math.floor(Math.random()*colorArray.length)];,再往Circle的繪制函數添上一句ctx.fillStyle = this.bg;,然后ctx.fill();,多彩運動的圓圈canvas就做完了。

這是一個運用mousemove事件做的canvas交互動畫,有興趣的可以嘗試其他事件(制作游戲用的鍵盤事件以及其他鼠標事件),或者思考如何給球加重力,如何檢測碰撞事件,canvas的世界並不只有這么一點,相關資料的話,給大家推薦本書《canvas開發詳解》。

本文的最終js代碼如下:

/**
 * 
 * @authors dkplus (dkplus@qq.com)
 * @date    2017-10-01 20:37:26
 * @version $1.0$
 */
/**
 * 獲取canvas對象,設置寬度高度自適應
 * @type {[type]}
 */
var canvas = document.querySelector("#canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

var ctx = canvas.getContext("2d");
/**
 * 屏幕鼠標坐標
 * @type {Object}
 */
var mouse = {
    x: undefined,
    y: undefined
}
/**
 * @param  {鼠標移動事件,回調函數,賦值給鼠標坐標}
 * @return {[type]}
 */
window.addEventListener("mousemove",function (event) {
    mouse.x = event.x;
    mouse.y = event.y;
    // console.log(mouse);
});
/**
 * @param  {重新設置窗口大小,使canvas寬高自適應屏幕}
 * @return {[type]}
 */
window.addEventListener("resize",function () {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    //初始化canvas
    init();
})
//繪制圓的最大半徑
var maxRadius = 40;
// var minRadius = 2;

//圓的顏色數組
var colorArray = [
    '#58D68D',
    '#E67F22',
    '#3598DB',
    '#E84C3D',
    '#9A59B5',
    '#27AE61',
    '#D25400',
    '#BEC3C7',
    '#297FB8'
]
/**
 * @param {x圓中心的x坐標}
 * @param {y圓中心的y坐標}
 * @param {dx圓運動的x偏移量}
 * @param {dy圓運動的y偏移量}
 * @param {radius圓的半徑}
 * minRadius圓的最小半徑
 * bg圓的背景顏色
 * draw繪制函數
 * update圓運動偏移
 */
function Circle(x, y, dx, dy, radius) {
    this.x = x;
    this.y = y;
    this.dx = dx;
    this.dy = dy;
    this.radius = radius;
    this.minRadius = radius;
    this.bg = colorArray[Math.floor(Math.random()*colorArray.length)];

    this.draw = function() {
        ctx.beginPath();
        ctx.strokeStyle = "#777";
        ctx.fillStyle = this.bg;
        ctx.arc(this.x,this.y,this.radius,Math.PI/180*0,Math.PI/180*360,false);
        // ctx.stroke();
        ctx.fill();
    }
    this.update = function() {
        //圓觸碰邊界時反彈,偏移值為負
        if (this.x + this.radius > innerWidth || this.x - this.radius < 0 ) {
            this.dx = -this.dx;
        }
        if (this.y + this.radius > innerHeight || this.y - this.radius < 0 ) {
            this.dy = -this.dy;
        }
        //刷新繪制時圓的偏移運動
        this.x += this.dx;
        this.y += this.dy;
        //鼠標半徑50像素范圍內的圓,它們的半徑逐步增加到最大值
        if (mouse.x - this.x < 50 && mouse.x - this.x >-50 && mouse.y - this.y < 50 && mouse.y - this.y >-50) {
            if (this.radius < maxRadius) {
                this.radius += 1;
            }
        //其他的所有圓半徑減小到最小值
        }else if (this.radius > this.minRadius) {
            this.radius -= 1;
        }
        //根據更新的值進行繪制
        this.draw();

    }
}
//圓的對象數組
var circleArray = [];
/**
 * 初始化函數,制造800個隨機坐標、偏移速度和半徑的圓,加入到對象數組
 * @return {[type]}
 */
function init() {
    circleArray = []
    for (var i = 0; i < 800; i++) {
        var x = Math.random()*window.innerWidth;
        var y = Math.random()*window.innerHeight;
        var dx = (Math.random()-0.5)*2;
        var dy = (Math.random()-0.5)*2;
        var radius = Math.random()*3 +1;
        circleArray.push(new Circle(x, y, dx, dy, radius));
    }
}
init();
/**
 * 動畫函數
 * @return {[type]}
 */
function animate() {
    //更新前清楚畫布
    ctx.clearRect(0,0,window.innerWidth,window.innerHeight);
    requestAnimationFrame(animate);
    //每個圓都調用update()方法
    for (var i = 0; i < circleArray.length; i++) {
        circleArray[i].update();
    }

}
animate();


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM