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();