[Js进阶]Canvas实现雪花特效
index.html
<!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>
body {
background-color: black;
}
</style>
</head>
<body>
<script src="./js/snowflake2canvas.js"></script>
<script src="./js/clickEffect.js"></script>
</body>
</html>
clickEffect.js
;(function (global, factory) {
'use strict'
typeof exports === 'object' && typeof module !== 'undefined'
? (module.exports = factory())
: typeof define === 'function' && define.amd
? define(factory)
: ((global = global || self), (global.clickEffect = factory()))
})(typeof window !== 'undefined' ? window : this, function () {
function clickEffect() {
var balls = []
var longPressed = false
var longPress
var multiplier = 0
var width, height
var origin
var normal
var ctx
var colours = ['#F73859', '#14FFEC', '#00E0FF', '#FF99FE', '#FAF15D']
var canvas = document.createElement('canvas')
document.body.appendChild(canvas)
canvas.setAttribute(
'style',
'width: 100%; height: 100%; top: 0; left: 0; z-index: 99999; position: fixed; pointer-events: none;'
)
if (canvas.getContext && window.addEventListener) {
ctx = canvas.getContext('2d')
updateSize()
window.addEventListener('resize', updateSize, false)
loop()
window.addEventListener(
'mousedown',
function (e) {
pushBalls(randBetween(10, 20), e.clientX, e.clientY)
document.body.classList.add('is-pressed')
longPress = setTimeout(function () {
document.body.classList.add('is-longpress')
longPressed = true
}, 500)
},
false
)
window.addEventListener(
'mouseup',
function (e) {
clearTimeout(longPress)
if (longPressed == true) {
document.body.classList.remove('is-longpress')
pushBalls(randBetween(50 + Math.ceil(multiplier), 100 + Math.ceil(multiplier)), e.clientX, e.clientY)
longPressed = false
}
document.body.classList.remove('is-pressed')
},
false
)
} else {
console.log('canvas or addEventListener is unsupported!')
}
function updateSize() {
canvas.width = window.innerWidth * 2
canvas.height = window.innerHeight * 2
canvas.style.width = window.innerWidth + 'px'
canvas.style.height = window.innerHeight + 'px'
ctx.scale(2, 2)
width = canvas.width = window.innerWidth
height = canvas.height = window.innerHeight
origin = {
x: width / 2,
y: height / 2
}
normal = {
x: width / 2,
y: height / 2
}
}
class Ball {
constructor(x = origin.x, y = origin.y) {
this.x = x
this.y = y
this.angle = Math.PI * 2 * Math.random()
if (longPressed == true) {
this.multiplier = randBetween(14 + multiplier, 15 + multiplier)
} else {
this.multiplier = randBetween(6, 12)
}
this.vx = (this.multiplier + Math.random() * 0.5) * Math.cos(this.angle)
this.vy = (this.multiplier + Math.random() * 0.5) * Math.sin(this.angle)
this.r = randBetween(8, 12) + 3 * Math.random()
this.color = colours[Math.floor(Math.random() * colours.length)]
}
update() {
this.x += this.vx - normal.x
this.y += this.vy - normal.y
normal.x = (-2 / window.innerWidth) * Math.sin(this.angle)
normal.y = (-2 / window.innerHeight) * Math.cos(this.angle)
this.r -= 0.3
this.vx *= 0.9
this.vy *= 0.9
}
}
function pushBalls(count = 1, x = origin.x, y = origin.y) {
for (let i = 0; i < count; i++) {
balls.push(new Ball(x, y))
}
}
function pushMoveBalls(count = 1, x = origin.x, y = origin.y) {
for (let i = 0; i < count; i++) {
balls.push(new Ball(x, y))
}
}
function randBetween(min, max) {
return Math.floor(Math.random() * max) + min
}
function loop() {
ctx.fillStyle = 'rgba(255, 255, 255, 0)'
ctx.clearRect(0, 0, canvas.width, canvas.height)
for (let i = 0; i < balls.length; i++) {
let b = balls[i]
if (b.r < 0) continue
ctx.fillStyle = b.color
ctx.beginPath()
ctx.arc(b.x, b.y, b.r, 0, Math.PI * 2, false)
ctx.fill()
b.update()
}
if (longPressed == true) {
multiplier += 0.2
} else if (!longPressed && multiplier >= 0) {
multiplier -= 0.4
}
removeBall()
requestAnimationFrame(loop)
}
function removeBall() {
for (let i = 0; i < balls.length; i++) {
let b = balls[i]
if (b.x + b.r < 0 || b.x - b.r > width || b.y + b.r < 0 || b.y - b.r > height || b.r < 0) {
balls.splice(i, 1)
}
}
}
}
clickEffect()
return clickEffect
})
snowflake2canvas.js
;(function (global, factory) {
'use strict'
typeof exports === 'object' && typeof module !== 'undefined'
? (module.exports = factory())
: typeof define === 'function' && define.amd
? define(factory)
: ((global = global || self), (global.snowflake2canvas = factory()))
})(typeof window !== 'undefined' ? window : this, function () {
function snowflake2canvas() {
var canvasDom = document.getElementById('snowflakeCanvas')
if (!canvasDom) {
canvasDom = document.createElement('canvas')
document.body.appendChild(canvasDom)
}
var ctx = canvasDom.getContext('2d')
var fillStyleColor = '#fff'
var angle = 0
var W = window.innerWidth
var H = window.innerHeight
canvasDom.width = W
canvasDom.height = H
canvasDom.style.cssText += `
z-index: 99999;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
`
var flakesCount = 100
var flakes = []
for (var i = 0; i < flakesCount; i++) {
flakes.push({
x: Math.random() * W,
y: Math.random() * H,
r: Math.random() * 5 + 2,
d: Math.random() + 1,
})
}
requestAnimationFrame(drawFlakes)
function drawFlakes() {
ctx.clearRect(0, 0, W, H)
ctx.fillStyle = fillStyleColor
ctx.beginPath()
for (var i = 0; i < flakesCount; i++) {
var flake = flakes[i]
ctx.moveTo(flake.x, flake.y)
ctx.arc(flake.x, flake.y, flake.r, 0, Math.PI * 2, true)
}
ctx.fill()
moveFlakes()
requestAnimationFrame(drawFlakes)
}
function moveFlakes() {
angle += 0.01
for (var i = 0; i < flakesCount; i++) {
var flake = flakes[i]
flake.y += Math.pow(flake.d, 2) + 1
flake.x += Math.sin(angle) * 2
if (flake.y > H) {
flakes[i] = { x: Math.random() * W, y: 0, r: flake.r, d: flake.d }
}
}
}
}
snowflake2canvas()
return snowflake2canvas
})