参考链接
https://juejin.cn/post/6844903442188615687
效果展示
在线预览
参考代码
import Logo from '../img/firefox.png'
const mycan = document.getElementById('mycan')
const ctx = mycan.getContext('2d')
const IW = mycan.width = window.innerWidth
const IH = mycan.height = window.innerHeight
/**
*
* @param {图片地址} src
*/
function loadImg(src) {
return new Promise((resolve, reject) => {
let img = new Image()
img.onload = () => resolve(img)
img.onerror = reject
img.src = src
})
}
/**
*
* @param {参数执行当前帧所进行的时间} t
* @param {初始值} b
* @param {位移值} c
* @param {持续时间} d
*/
function easeInOutExpo(t, b, c, d) {
t /= d/2
if (t < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b
t--
return c/2 * (-Math.pow(2, -10 * t) + 2) + b
}
/**
*
* @param {Image对象} img
*/
function getParticles(img) {
const cols = 100
const rows = 100
let w = Math.min(500, IW - 20)
let h = ~~(w * (img.height / img.width))
let sx = (IW - w) / 2
let sy = (IH - h) / 2
let particles = []
let s_w = w / cols
let s_h = h / rows
ctx.drawImage(img, 0, 0, w, h)
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
let x = ~~(i * s_w)
let y = ~~(j * s_h)
const [r, g, b, a] = ctx.getImageData(x, y, 1, 1).data
if (a > 0) {
particles.push({
delay: Math.random() * 10000,
x: x + sx + (Math.random() - 0.5) * 10,
y: y + sy + (Math.random() - 0.5) * 10,
color: `rgba(${r}, ${g}, ${b}, ${a})`
})
}
}
}
return particles
}
/**
*
* @param {例子数组} particles
* @param {初始X坐标} sx
* @param {初始Y坐标} sy
* @param {持续时间} duration
*/
function play(particles, sx, sy, duration) {
let id = null
function draw(t) {
if (t > duration) {
cancelAnimationFrame(id)
return
}
ctx.clearRect(0, 0, IW, IH)
particles.forEach(({x, y, color, delay}) => {
let dx = easeInOutExpo(t, sx, x - sx, duration - delay)
let dy = easeInOutExpo(t, sy, y - sy, duration - delay)
ctx.fillStyle = color
ctx.fillRect(dx, dy, 1, 1)
})
id = requestAnimationFrame(draw)
}
id = requestAnimationFrame(draw)
}
async function init() {
let img = await loadImg(Logo)
let particles = getParticles(img)
play(particles, IW / 2, IH, 10000)
}
init()