JavaScript利用canvas繪制流星雨效果
前言
最近總是夢見一些小時候的故事,印象最深刻的就是夏天坐在屋頂上,看著滿天的繁星,一顆,兩顆,三顆...不由自主地開始了數(shù)星星的過程。不經(jīng)意間,一顆流星劃過夜間,雖然只是轉(zhuǎn)瞬即逝,但它似乎比夜空中的其它繁星更吸引著我。聽老人說,看見流星的時候許愿,愿望是可以實現(xiàn)的,此時早已把數(shù)星星拋之腦后,開始期待著下一顆流星的出現(xiàn)。但是那天晚上,流星再也沒有出現(xiàn),這也成了自己小時候的一個遺憾。
今天,我決定用canvas為大家?guī)硪粓隽餍怯暌曈X盛宴。

需求分析
首先我們需要的元素有:夜空、滿天繁星、流星雨。
滿天繁星: 這個其實就是畫上一個個點,然后不斷的通過顏色交替,營造出一種星星閃爍的意境。
流星雨: 流星處于他自己的運動軌跡之中,當(dāng)前的位置最亮,輪廓最清晰,而之前劃過的地方離當(dāng)前位置軌跡距離越遠(yuǎn)就越暗淡越模糊,其實它就是一個漸變的過程,恰巧canvas有方法可以創(chuàng)建一個沿參數(shù)坐標(biāo)指定的直線的漸變。然后讓它從右上向左下移動,這樣就能營造一種流星雨的效果,同時實現(xiàn)動畫的循環(huán)。
OK,需求分析結(jié)束,準(zhǔn)備動手開干~
實現(xiàn)過程
1.繪制滿天繁星
//創(chuàng)建一個星星對象
class Star {
constructor() {
this.x = windowWidth * Math.random(); //橫坐標(biāo)
this.y = 5000 * Math.random(); //縱坐標(biāo)
this.text = "."; //文本
this.color = "white"; //顏色
}
//初始化
init() {
this.getColor();
}
//繪制
draw() {
context.fillStyle = this.color;
context.fillText(this.text, this.x, this.y);
}
}
//畫星星
for (let i = 0; i < starCount; i++) {
let star = new Star();
star.init();
star.draw();
arr.push(star);
}
來看下此時的效果:

夜空中的滿天繁星現(xiàn)在是有了,但是缺乏一點意境,我們得想辦法讓這些繁星都閃爍起來。
2.滿天繁星閃起來
//創(chuàng)建一個星星對象
class Star {
constructor() {
this.x = windowWidth * Math.random(); //橫坐標(biāo)
this.y = 5000 * Math.random(); //縱坐標(biāo)
this.text = "."; //文本
this.color = "white"; //顏色
}
// 獲取隨機(jī)顏色
getColor() {
let _r = Math.random();
if (_r < 0.5) {
this.color = "#333";
} else {
this.color = "white";
}
}
//初始化
init() {
this.getColor();
}
//繪制
draw() {
context.fillStyle = this.color;
context.fillText(this.text, this.x, this.y);
}
}
//畫星星
for (let i = 0; i < starCount; i++) {
let star = new Star();
star.init();
star.draw();
arr.push(star);
}
//繁星閃起來
let t1
function playStars() {
for (let n = 0; n < starCount; n++) {
arr[n].getColor();
arr[n].draw();
}
t1 = requestAnimationFrame(playStars);
}
繁星閃爍的元素就在于這個getColor方法,通過不斷地切換星星的顏色,來達(dá)到星星閃爍的效果。
再來看看這時的效果:

此刻的自己就可以開始數(shù)星星了,一顆,兩顆,三顆...
3.繪制流星
簡單點理解,流星其實就是一條漸變的線段,當(dāng)前的位置最亮,輪廓最清晰,而之前劃過的地方離當(dāng)前位置軌跡距離越遠(yuǎn)就越暗淡越模糊。
這里的關(guān)鍵API是createLinearGradient,用于創(chuàng)建一個沿參數(shù)坐標(biāo)指定的直線的漸變。

語法:
CanvasGradient ctx.createLinearGradient(x0, y0, x1, y1);
- x0:起點的 x 軸坐標(biāo)。
- y0:起點的 y 軸坐標(biāo)。
- x1:終點的 x 軸坐標(biāo)。
- y1:終點的 y 軸坐標(biāo)。
使用createLinearGradient() 方法初始化一個線性漸變。在這個線性漸變中添加三種顏色,達(dá)到一種漸變的效果來模擬出流星劃過夜空的狀態(tài)。
/**繪制流星**/
draw() {
//繪制一個流星的函數(shù)
context.save();
context.beginPath();
context.lineWidth = 1; //寬度
context.globalAlpha = this.alpha; //設(shè)置透明度
//創(chuàng)建橫向漸變顏色,起點坐標(biāo)至終點坐標(biāo)
let line = context.createLinearGradient(
this.x,
this.y,
this.x + this.width,
this.y - this.height
);
//分段設(shè)置顏色
line.addColorStop(0, "white");
line.addColorStop(0.3, this.color1);
line.addColorStop(0.6, this.color2);
context.strokeStyle = line;
//起點
context.moveTo(this.x, this.y);
//終點
context.lineTo(this.x + this.width, this.y - this.height);
context.closePath();
context.stroke();
context.restore();
}
現(xiàn)在我們來看一看當(dāng)年的那個流星:

4.流星劃過夜空
流星有了,現(xiàn)在我們得想辦法讓它動起來。這里其實就是通過不斷地計算位置來達(dá)到流星動起來的效果。
move() {
//清空流星像素
let x = this.x + this.width - this.offset_x;
let y = this.y - this.height;
context.clearRect(x - 3, y - 3, this.offset_x + 5, this.offset_y + 5);
//重新計算位置,往左下移動
this.countPos();
//透明度增加
this.alpha -= 0.002;
//重繪
this.draw();
}

現(xiàn)在,我們就可以看到當(dāng)年的那顆流星了,是不是很激動。稍安勿躁,為了彌補當(dāng)年的遺憾,這里決定來一場從未真實見過的流星雨。
5.流星雨
寫到這里,實現(xiàn)流星雨其實就很簡單了,我們只需要再多生成一些流星,為它們各自分配不同的坐標(biāo)即可。
let t2
// 創(chuàng)建流星雨對象
class MeteorRain {
constructor() {
this.x = -1;
this.y = -1;
this.length = -1; //長度
this.angle = 30; //傾斜角度
this.width = -1; //寬度
this.height = -1; //高度
this.speed = 1; //速度
this.offset_x = -1; //橫軸移動偏移量
this.offset_y = -1; //縱軸移動偏移量
this.alpha = 1; //透明度
this.color1 = ""; //流星的色彩
this.color2 = ""; //流星的色彩
}
init() {
//初始化
this.getPos();
this.alpha = 1; //透明度
this.getRandomColor();
//最小長度,最大長度
let x = Math.random() * 80 + 150;
this.length = Math.ceil(x);
x = Math.random() + 0.5;
this.speed = Math.ceil(x); //流星的速度
let cos = Math.cos((this.angle * 3.14) / 180);
let sin = Math.sin((this.angle * 3.14) / 180);
this.width = this.length * cos;
this.height = this.length * sin;
this.offset_x = this.speed * cos;
this.offset_y = this.speed * sin;
}
/**獲取隨機(jī)顏色函數(shù)**/
getRandomColor() {
let a = Math.ceil(255 - 240 * Math.random());
//中段顏色
this.color1 = "rgba(" + a + "," + a + "," + a + ",1)";
//結(jié)束顏色
this.color2 = "black";
}
/**重新計算流星坐標(biāo)的函數(shù)**/
countPos() {
//
//往左下移動,x減少,y增加
this.x = this.x - this.offset_x;
this.y = this.y + this.offset_y;
}
/**獲取隨機(jī)坐標(biāo)的函數(shù)**/
getPos() {
//
//橫坐標(biāo)
this.x = Math.random() * window.innerWidth; //窗口高度
//縱坐標(biāo)
this.y = Math.random() * window.innerHeight; //窗口寬度
}
/**繪制流星**/
draw() {
//繪制一個流星的函數(shù)
context.save();
context.beginPath();
context.lineWidth = 1; //寬度
context.globalAlpha = this.alpha; //設(shè)置透明度
//創(chuàng)建橫向漸變顏色,起點坐標(biāo)至終點坐標(biāo)
let line = context.createLinearGradient(
this.x,
this.y,
this.x + this.width,
this.y - this.height
);
//分段設(shè)置顏色
line.addColorStop(0, "white");
line.addColorStop(0.3, this.color1);
line.addColorStop(0.6, this.color2);
context.strokeStyle = line;
//起點
context.moveTo(this.x, this.y);
//終點
context.lineTo(this.x + this.width, this.y - this.height);
context.closePath();
context.stroke();
context.restore();
}
move() {
//清空流星像素
let x = this.x + this.width - this.offset_x;
let y = this.y - this.height;
context.clearRect(x - 3, y - 3, this.offset_x + 5, this.offset_y + 5);
//重新計算位置,往左下移動
this.countPos();
//透明度增加
this.alpha -= 0.002;
//重繪
this.draw();
}
}
//繪制流星
function playRains() {
for (let n = 0; n < rainCount; n++) {
// console.log(rains, "--");
let rain = rains[n];
rain.move(); //移動
if (rain.y > window.innerHeight) {
//超出界限后重來
context.clearRect(rain.x, rain.y - rain.height, rain.width, rain.height);
rains[n] = new MeteorRain();
rains[n].init();
}
}
t2 = requestAnimationFrame(playRains);
}

6.merge視覺盛宴
流星極短暫的星星是也,它不像恒星和行星那般耀眼,卻用短暫的生命,劃破夜空,用瞬間瀟灑的弧線留住美麗的光輝。曇花和流星瞬間之美令我無法忘懷,大自然神奇的造物者給了我們許多的美,不論瞬間的還是永恒的,我們都要用真心去欣賞去品味。
通過合并前面五個步驟,我們就能夠一睹這流星剎那間的交錯,而后瞬間就穿透為永恒,只是一刻用生命幻化的美。

以上就是JavaScript利用canvas繪制流星雨效果的詳細(xì)內(nèi)容,更多關(guān)于JavaScript canvas繪制流星雨的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript給事件委托批量添加事件監(jiān)聽詳細(xì)流程
事件委托,一般來講,會把一個或者一組元素的事件委托到它的父層或者更外層元素上,真正綁定事件的是外層元素,當(dāng)事件響應(yīng)到需要綁定的元素上時,會通過事件冒泡機(jī)制從而觸發(fā)它的外層元素的綁定事件上,然后在外層元素上去執(zhí)行函數(shù)2021-10-10
JavaScript+HTML5實現(xiàn)的日期比較功能示例
這篇文章主要介紹了JavaScript+HTML5實現(xiàn)的日期比較功能,涉及javascript結(jié)合HTML5針對日期的轉(zhuǎn)換與運算相關(guān)操作技巧,需要的朋友可以參考下2017-07-07
LayUI+Shiro實現(xiàn)動態(tài)菜單并記住菜單收展的示例
這篇文章主要介紹了LayUI+Shiro實現(xiàn)動態(tài)菜單并記住菜單收展的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
javascript學(xué)習(xí)總結(jié)之js使用技巧
本篇文章給大家分享javascript學(xué)習(xí)總結(jié)之js使用技巧,都是精華喔~小伙伴快來學(xué)習(xí)吧。2015-09-09

