本文已參與好文召集令活動,點擊查看:後端、大前端雙賽道投稿,2萬元獎池等你挑戰!css
🎉我裁一段星河送給你,好叫你不遜色這漫天煙火html
漫天的煙火,在這璀璨的星空中閃耀,成就了這片星空的絢麗,更散發出了本身無限的光芒,今天就使用canvas來作一個煙花效果吧!✨前端
實現的效果仍是很不錯的,漫天的煙火肆意綻開html5
簡單的寫點基礎樣式,背景黑色,定義個canvas標籤web
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<style> * { margin: 0; padding: 0; } body { background-color: black; } canvas { position: absolute; z-index: 0; } </style>
</head>
<body>
<canvas>您的瀏覽器不支持</canvas>
<script src="index.js"></script>
</body>
</html>
複製代碼
在js中先獲取標籤,設置畫布大小,採用resize
監聽頁面的調整,及時的改變畫布的大小算法
// 元素獲取
const canvas = document.querySelector("canvas")
const ctx = canvas.getContext("2d");
// 設定畫布大小
function resizeCanvas() {
canvas.width = window.innerWidth
canvas.height = window.innerHeight
}
resizeCanvas();
// 頁面縮放改變畫布大小
window.addEventListener("resize", resizeCanvas)
複製代碼
經過e.clientX
和e.clientY
來獲取鼠標點擊的位置,用於在後面實如今鼠標點擊的位置,產生煙花canvas
function clickSite(e) {
// 獲取當前鼠標的座標
let x = e.clientX;
let y = e.clientY;
// 繪製
addFires(x, y);
}
document.addEventListener('click', clickSite);
複製代碼
咱們一步一步來實現,這是實現煙花效果的第一步,經過在點擊位置添加一個煙花雛形後端
,這是一個單純的靜態,在後面咱們慢慢的讓它動起來數組
function drawFires() {
// 初始半徑,以及粒子數量
let count = 10;
let radius = 10;
for (let i = 0; i < count; i++) {
// 渲染出當前數據
// 下面是點數學題
// moveX,moveY是粒子開始的座標,畫個三角形,角度半徑知道很容易就得出方程
let angle = 360 / count * i;
let radians = angle * Math.PI / 180;
let moveX = x + Math.cos(radians) * radius
let moveY = y + Math.sin(radians) * radius
// 開始路徑
ctx.beginPath();
ctx.arc(moveX, moveY, 2, Math.PI * 2, false);
// 結束
ctx.closePath();
ctx.fillStyle = '#ff0000'
ctx.fill();
}
}
複製代碼
當前效果瀏覽器
有了上面的鋪墊,每個小圓點都是即將要散開的煙花,那麼咱們只須要更新畫布讓它的半徑不斷的增大便可,實現散開的效果很簡單,那部分代碼就不貼了(節省篇幅),對於更新畫布,採用的一個html5中的新方法requestAnimationFrame
官方文檔
它相比於使用定時器實現動畫有什麼優勢呢?
requestAnimationFrame
將不會進行重繪或迴流,會減小對內存的使用requestAnimationFrame
會把每一幀中的全部DOM操做集中起來,在一次重繪或迴流中就完成動畫實現代碼
// 渲染,更新粒子的信息
function tick() {
// 更新畫布
drawFires();
requestAnimationFrame(tick);
}
tick()
複製代碼
當前實現效果
從上面的效果圖能夠看出,爆炸的效果咱們已經能基本實現了,可是煙花不是一個個的小球,咱們須要添加拖尾的效果,而且給每一個小球隨機顏色,這樣會更加的炫麗
拖尾效果代碼
在繪製完一幀後,繪製下一幀以前,添加一個半透明的蒙層就能實現一個拖尾的效果
function tick() {
// 設置拖影
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = 'rgba(0,0,0,' + 10 / 100 + ')';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'lighter';
// 更新畫布
drawFires();
requestAnimationFrame(tick);
}
複製代碼
隨機顏色代碼
採用的是hsla
函數來設定顏色,由於煙花的色彩都是接近的,因此咱們能夠經過調節色相值,來選擇煙花顏色。這裏採用的是固定飽和度爲100%,亮度顏色隨機在必定範圍內,使得顏色不會過於離譜
hsla() 函數使用色相、飽和度、亮度、透明度來定義顏色。
let hue = Math.random() * 360;
let hueVariance = 60;
function setColors(firework) {
firework.hue = Math.floor(Math.random() * ((hue + hueVariance) - (hue - hueVariance))) + (hue - hueVariance);
firework.brightness = Math.floor(Math.random() * 21) + 50;
firework.alpha = (Math.floor(Math.random() * 60) + 40) / 100;
}
複製代碼
當前效果
從上面的效果圖,咱們能夠認識到咱們還差兩部,煙花的下墜以及煙花的消失
咱們經過從新調整煙花路徑的算法,來實現煙花的下墜,在初始的代碼中對於煙花的爆炸路徑,採用的是普通的直線運動,咱們須要在這個基礎上讓它的y方向加大一點,這樣就會實現了一個拋物線的效果,同時,對於煙花的爆炸應當還要有個殆盡的效果,咱們經過改變透明度來實現,對於透明度小於0的咱們將它從數組中移除
let moveX = Math.cos(firework.radians) * firework.radius;
let moveY = Math.sin(firework.radians) * firework.radius + 1;
firework.x += moveX;
firework.y += moveY;
// 更新數據,讓圓擴散開來
firework.radius *= 1 - firework.speed / 120
firework.alpha -= 0.01;
// 若是透明度小於0就刪除這個粒子
if (firework.alpha <= 0) {
fireworks.splice(i, 1);
// 跳過此次循環,不進行繪製
continue;
}
複製代碼
改變了算法
每次畫布的更新都要讓透明度下降,同時每一個粒子的移動半徑不斷地減少,這樣會造成向中間合攏的趨勢,因爲每一個粒子都存放在數組當中,當粒子透明度小於0,從數組移除
只須要經過定時器,不斷的添加煙花便可
setInterval(() => {
// 能夠多調用幾回用來增長煙花的數量
addFires(Math.random() * canvas.width, Math.random() * canvas.height)
addFires(Math.random() * canvas.width, Math.random() * canvas.height)
}, 500)
複製代碼
能夠在頁面中加一些標籤,好比文字,實現的效果都是不錯的噢~ 本次的煙花效果就到這裏了,喜歡的話就本身嘗試的作一個吧~~