Fixed typo. Thanks Steffi.
[fp-lecture.git] / js / confetti.js
1 var confetti = {
2 maxCount: 150, //set max confetti count
3 speed: 2, //set the particle animation speed
4 frameInterval: 15, //the confetti animation frame interval in milliseconds
5 alpha: 1.0, //the alpha opacity of the confetti (between 0 and 1, where 1 is opaque and 0 is invisible)
6 gradient: false, //whether to use gradients for the confetti particles
7 start: null, //call to start confetti animation (with optional timeout in milliseconds, and optional min and max random confetti count)
8 stop: null, //call to stop adding confetti
9 toggle: null, //call to start or stop the confetti animation depending on whether it's already running
10 pause: null, //call to freeze confetti animation
11 resume: null, //call to unfreeze confetti animation
12 togglePause: null, //call to toggle whether the confetti animation is paused
13 remove: null, //call to stop the confetti animation and remove all confetti immediately
14 isPaused: null, //call and returns true or false depending on whether the confetti animation is paused
15 isRunning: null //call and returns true or false depending on whether the animation is running
16 };
17
18 (function() {
19 confetti.start = startConfetti;
20 confetti.stop = stopConfetti;
21 confetti.toggle = toggleConfetti;
22 confetti.pause = pauseConfetti;
23 confetti.resume = resumeConfetti;
24 confetti.togglePause = toggleConfettiPause;
25 confetti.isPaused = isConfettiPaused;
26 confetti.remove = removeConfetti;
27 confetti.isRunning = isConfettiRunning;
28 var supportsAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame;
29 var colors = ["rgba(30,144,255,", "rgba(107,142,35,", "rgba(255,215,0,", "rgba(255,192,203,", "rgba(106,90,205,", "rgba(173,216,230,", "rgba(238,130,238,", "rgba(152,251,152,", "rgba(70,130,180,", "rgba(244,164,96,", "rgba(210,105,30,", "rgba(220,20,60,"];
30 var streamingConfetti = false;
31 var animationTimer = null;
32 var pause = false;
33 var lastFrameTime = Date.now();
34 var particles = [];
35 var waveAngle = 0;
36 var context = null;
37
38 function resetParticle(particle, width, height) {
39 particle.color = colors[(Math.random() * colors.length) | 0] + (confetti.alpha + ")");
40 particle.color2 = colors[(Math.random() * colors.length) | 0] + (confetti.alpha + ")");
41 particle.x = Math.random() * width;
42 particle.y = Math.random() * height - height;
43 particle.diameter = Math.random() * 10 + 5;
44 particle.tilt = Math.random() * 10 - 10;
45 particle.tiltAngleIncrement = Math.random() * 0.07 + 0.05;
46 particle.tiltAngle = Math.random() * Math.PI;
47 return particle;
48 }
49
50 function toggleConfettiPause() {
51 if (pause)
52 resumeConfetti();
53 else
54 pauseConfetti();
55 }
56
57 function isConfettiPaused() {
58 return pause;
59 }
60
61 function pauseConfetti() {
62 pause = true;
63 }
64
65 function resumeConfetti() {
66 pause = false;
67 runAnimation();
68 }
69
70 function runAnimation() {
71 if (pause)
72 return;
73 else if (particles.length === 0) {
74 context.clearRect(0, 0, window.innerWidth, window.innerHeight);
75 animationTimer = null;
76 } else {
77 var now = Date.now();
78 var delta = now - lastFrameTime;
79 if (!supportsAnimationFrame || delta > confetti.frameInterval) {
80 context.clearRect(0, 0, window.innerWidth, window.innerHeight);
81 updateParticles();
82 drawParticles(context);
83 lastFrameTime = now - (delta % confetti.frameInterval);
84 }
85 animationTimer = requestAnimationFrame(runAnimation);
86 }
87 }
88
89 function startConfetti(timeout, min, max) {
90 var width = window.innerWidth;
91 var height = window.innerHeight;
92 window.requestAnimationFrame = (function() {
93 return window.requestAnimationFrame ||
94 window.webkitRequestAnimationFrame ||
95 window.mozRequestAnimationFrame ||
96 window.oRequestAnimationFrame ||
97 window.msRequestAnimationFrame ||
98 function (callback) {
99 return window.setTimeout(callback, confetti.frameInterval);
100 };
101 })();
102 var canvas = document.getElementById("confetti-canvas");
103 if (canvas === null) {
104 canvas = document.createElement("canvas");
105 canvas.setAttribute("id", "confetti-canvas");
106 canvas.setAttribute("style", "display:block;z-index:999999;pointer-events:none;position:fixed;top:0");
107 document.body.prepend(canvas);
108 canvas.width = width;
109 canvas.height = height;
110 window.addEventListener("resize", function() {
111 canvas.width = window.innerWidth;
112 canvas.height = window.innerHeight;
113 }, true);
114 context = canvas.getContext("2d");
115 } else if (context === null)
116 context = canvas.getContext("2d");
117 var count = confetti.maxCount;
118 if (min) {
119 if (max) {
120 if (min == max)
121 count = particles.length + max;
122 else {
123 if (min > max) {
124 var temp = min;
125 min = max;
126 max = temp;
127 }
128 count = particles.length + ((Math.random() * (max - min) + min) | 0);
129 }
130 } else
131 count = particles.length + min;
132 } else if (max)
133 count = particles.length + max;
134 while (particles.length < count)
135 particles.push(resetParticle({}, width, height));
136 streamingConfetti = true;
137 pause = false;
138 runAnimation();
139 if (timeout) {
140 window.setTimeout(stopConfetti, timeout);
141 }
142 }
143
144 function stopConfetti() {
145 streamingConfetti = false;
146 }
147
148 function removeConfetti() {
149 stop();
150 pause = false;
151 particles = [];
152 }
153
154 function toggleConfetti() {
155 if (streamingConfetti)
156 stopConfetti();
157 else
158 startConfetti();
159 }
160
161 function isConfettiRunning() {
162 return streamingConfetti;
163 }
164
165 function drawParticles(context) {
166 var particle;
167 var x, y, x2, y2;
168 for (var i = 0; i < particles.length; i++) {
169 particle = particles[i];
170 context.beginPath();
171 context.lineWidth = particle.diameter;
172 x2 = particle.x + particle.tilt;
173 x = x2 + particle.diameter / 2;
174 y2 = particle.y + particle.tilt + particle.diameter / 2;
175 if (confetti.gradient) {
176 var gradient = context.createLinearGradient(x, particle.y, x2, y2);
177 gradient.addColorStop("0", particle.color);
178 gradient.addColorStop("1.0", particle.color2);
179 context.strokeStyle = gradient;
180 } else
181 context.strokeStyle = particle.color;
182 context.moveTo(x, particle.y);
183 context.lineTo(x2, y2);
184 context.stroke();
185 }
186 }
187
188 function updateParticles() {
189 var width = window.innerWidth;
190 var height = window.innerHeight;
191 var particle;
192 waveAngle += 0.01;
193 for (var i = 0; i < particles.length; i++) {
194 particle = particles[i];
195 if (!streamingConfetti && particle.y < -15)
196 particle.y = height + 100;
197 else {
198 particle.tiltAngle += particle.tiltAngleIncrement;
199 particle.x += Math.sin(waveAngle) - 0.5;
200 particle.y += (Math.cos(waveAngle) + particle.diameter + confetti.speed) * 0.5;
201 particle.tilt = Math.sin(particle.tiltAngle) * 15;
202 }
203 if (particle.x > width + 20 || particle.x < -20 || particle.y > height) {
204 if (streamingConfetti && particles.length <= confetti.maxCount)
205 resetParticle(particle, width, height);
206 else {
207 particles.splice(i, 1);
208 i--;
209 }
210 }
211 }
212 }
213 })();