-
-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathsnowflakes.js
127 lines (104 loc) · 2.92 KB
/
snowflakes.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Shim for requestAnimationFrame with setTimeout fallback
const requestAnimFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback) {
return window.setTimeout(callback, 1000 / 60)
}
// Snowflake class
class Snowflake {
constructor(width, height) {
this.width = width
this.height = height
this.reset()
}
// Reset snowflake to a new random position and velocity
reset() {
this.x = Math.random() * this.width
this.y = Math.random() * -this.height
this.vy = 1 + (Math.random() * 3)
this.vx = 0.5 - Math.random()
this.r = 1 + (Math.random() * 2)
this.o = 0.5 + (Math.random() * 0.5)
}
// Move the snowflake
updatePosition() {
this.y += this.vy
this.x += this.vx
}
// Check if the snowflake has moved beyond the bottom
isOutOfView() {
return this.y > this.height
}
}
// Main function to create snowfall
const snowflakes = (target, count = 200) => {
// Determine if the target is a selector string or a DOM element
const container = typeof target === 'string' ? document.querySelector(target) : target
if (!container) {
return
}
// Create and configure canvas
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
let width = container.clientWidth
let height = container.clientHeight
let active = false
// Initialize canvas styles
canvas.style.position = 'absolute'
canvas.style.left = '0'
canvas.style.top = '0'
canvas.style.pointerEvents = 'none' // Allows clicks to pass through
// Snowflake instances
const flakes = []
// Create snowflakes
for (let i = 0; i < count; i++) {
flakes.push(new Snowflake(width, height))
}
// Handle canvas resizing
const onResize = () => {
width = container.clientWidth
height = container.clientHeight
canvas.width = width
canvas.height = height
ctx.fillStyle = '#fff'
// Reactivate animation only if width > 600
const wasActive = active
active = width > 600
// If animation was inactive but is now active, request next frame
if (!wasActive && active) {
requestAnimFrame(update)
}
}
// Animation loop
const update = () => {
// Clear the canvas
ctx.clearRect(0, 0, width, height)
// Stop updating if not active
if (!active) {
return
}
// Update and draw each snowflake
flakes.forEach(flake => {
flake.updatePosition()
ctx.globalAlpha = flake.o
ctx.beginPath()
ctx.arc(flake.x, flake.y, flake.r, 0, Math.PI * 2)
ctx.closePath()
ctx.fill()
// If out of view, reset the flake
if (flake.isOutOfView()) {
flake.reset()
}
})
requestAnimFrame(update)
}
// Initial setup
onResize()
window.addEventListener('resize', onResize, false)
container.append(canvas)
}
if (document.querySelector('.snowfall')) {
snowflakes('.snowfall', 100)
}