|
<body onload=" |
|
// Get context and add it into scope chain |
|
with (a.getContext`2d`) |
|
// Main loop |
|
setInterval( |
|
// Array of particles is passed as 1st argument by reference |
|
// We can't use function-as-string here, or `with` won't work |
|
b => { |
|
// Black, slighly opaque color |
|
fillStyle='rgba(0,0,0,.1)'; |
|
// Fill the entire canvas. So old contents gets faded with each frame. |
|
// The context is never reset. |
|
fillRect(0, 0, 944, 524); |
|
// Render loop over all particles |
|
// We're going to mutate the array while traversing it, |
|
// so the forward direction is important. |
|
for(j=0; b[j]; j++) |
|
// Add the current particle to scope chain |
|
// The particle object: |
|
// { |
|
// a: boolean, // is a projectile (sparkle otherwise) |
|
// t: float, // time to live |
|
// s: string, // stroke color |
|
// x: number, y: number, // coordinates |
|
// X: number, Y: number, // velocity |
|
// } |
|
with (b[j]) |
|
// If TTL expired: |
|
if (t-- < 0){ |
|
// If it was a projectile: |
|
// Create a blast of 'sparkles' |
|
// If b[j] has own property 'a', then a is `b[j].a` |
|
// Otherwise a is `window.a`, that is a truthy canvas element |
|
if (a) |
|
for( |
|
// 1. Define the blast stroke color (r is Math.random) |
|
// 2. Set k = 99 for reverse loop traversal |
|
s = `hsl(${ r(k = 99) * 360 },99%,50%)` |
|
; |
|
k-- |
|
; |
|
// Add a new particle to the end of the array |
|
b.push({ |
|
a: 0, // Not a projectile |
|
t: r() * 50 + 200, // TTL |
|
s, // Same as 's: s', ES6 shorthand syntax FTW |
|
x, y, // Again, shorthands |
|
// X and Y velocity, using fancy trig. |
|
// This make the blast look more natural. |
|
// l is the angle 0 .. ~= 7.003 * 2 * PI |
|
// m is the amplitude (dfined later in code) |
|
X: Math.cos(l = r() * 44) * m, |
|
Y: Math.sin(l) * m |
|
}) |
|
) |
|
// Amplitude |
|
m = r() * 10 |
|
; |
|
// Remove array index, and rewind counter 1 step back |
|
b.splice(j--, 1) |
|
} else |
|
// Paint/physics |
|
// Particles are drawn as lines |
|
beginPath( |
|
// Set stroke color |
|
strokeStyle = s |
|
), |
|
// Line start |
|
moveTo(x, y), |
|
// If it's a sparkle, apply air resistance to its velocity |
|
a || (X *= .95, Y *= .95), |
|
// Line end |
|
lineTo( |
|
// Apply X velocity |
|
x += X, |
|
// Apply Y velocity and gravity |
|
y += Y +=.05 |
|
), |
|
stroke() |
|
; |
|
|
|
// Increment i at each frame and check |
|
// if i % 75 is not zero... |
|
i++ % 75 ? |
|
0 // Do nothing |
|
// else |
|
: |
|
// Create a new particle |
|
// j conveniently equals to b.length after the last loop end |
|
b[j] = { |
|
// a is unset, so `window.a` would be used in `with` |
|
t: 99, |
|
s: `#888`, |
|
x: 472, y: 524, |
|
X: (r=Math.random)() * 6 - 3, Y: r() - 7 |
|
} |
|
}, |
|
// timeout and a frame counter |
|
i = 16, |
|
// an array to become the b argument |
|
[] |
|
) |
|
// End of with |
|
"bgcolor=0><canvas id=a width=944 height=524> <!-- width is (bl.ocks.org frame width) - 2 * (default body margin) --> |