Published
Edited
Oct 7, 2020
2 stars
Insert cell
md`# Ambient Background`
Insert cell
Insert cell
Insert cell
cancelAnimationFrame(window.myReq)
Insert cell
Insert cell
initParticles = function() {
let data = [];
let i;
for (i=0; i<vars.particleCount; i++) {
data[i] = initParticle(i)
}
return data;
}
Insert cell
initParticle = function(i){
const {baseTTL, rangeTTL, baseSpeed, rangeSpeed, baseSize, rangeSize, baseHue, rangeHue} = vars;

let x = Math.random() * canvas.a.width,
y = Math.random() * canvas.a.height,
theta = Math.atan2(window.center[1]-y, window.center[0]-x) //angle

return {
id: i,
x: x,
y: y,
vx: Math.cos(theta) * 6,
vy: Math.sin(theta) * 6,
life: 0,
ttl: baseTTL + (Math.random() * rangeTTL),
speed: baseSpeed + (Math.random() * rangeSpeed),
size: baseSize + (Math.random() * rangeSize),
hue: baseHue + (Math.random() * rangeHue),
}
}
Insert cell
function draw() {

const {backgroundColor} = vars;

ctx.a.clearRect(0, 0, canvas.a.width, canvas.a.height);
ctx.a.fillStyle = backgroundColor;
ctx.a.fillRect(0, 0, canvas.a.width, canvas.a.height)

updateParticle();

window.myReq = requestAnimationFrame(draw);

}

Insert cell
drawParticle = function() {
window.data.forEach(function(d) {
let xRel = d.x - (0.5 * d.size),
yRel = d.y - (0.5 * d.size);

ctx.a.save();
ctx.a.lineCap = 'round'
ctx.a.lineWidth = 1;
ctx.a.strokeStyle = `hsla(${d.hue},100%,60%,${fadeInOut(d.life, d.ttl)})`;
ctx.a.globalCompositeOperation = 'lighter';

ctx.a.beginPath();
ctx.a.translate(xRel, yRel);
ctx.a.rotate(d.theta);
ctx.a.strokeRect(0, 0, d.size, d.size);
ctx.a.closePath();
ctx.a.restore();
});
}
Insert cell
updateParticle = function() {
window.data.forEach(function(d,i){
const speed = 0.05
//Angle required to draw point back to origin
d.theta = Math.atan2(window.center[1]-d.y, window.center[0]-d.x) + thetaValue
//gradually dampen initiated straight-line vx....+ gradually introduce spiral vx
d.vx = (1-speed)*d.vx + speed*(2 * Math.cos(d.theta))
d.vy = (1-speed)*d.vy + speed*(2 * Math.sin(d.theta))
d.x = d.x + (d.vx * d.speed)
d.y = d.y + (d.vy * d.speed)
d.life ++;
d.life > d.ttl ? window.data[i] = initParticle() : null
})
drawParticle();

}
Insert cell
// parent_view = {
// const parent = DOM.element('div')
// d3.select(parent).attr("id","container")
// return parent;
// }
Insert cell
fadeInOut = function(t, m) {
let hm = 0.5 * m
return Math.abs((t + hm) % m - hm) / hm;
}
Insert cell
setup = {
resize();
window.data = initParticles();
draw();
}
Insert cell
canvas = {
let canvas = {
a: document.createElement('canvas'),
b: document.createElement('canvas')
};
return canvas
}
Insert cell
ctx = {
const ctx = {
a: canvas.a.getContext('2d'),
b: canvas.b.getContext('2d')
};
return ctx
}
Insert cell
resize = function() {
canvas.a.width = width;
canvas.a.height = height;
ctx.a.drawImage(canvas.b, 0, 0);
window.center = []
window.center[0] = 0.5 * canvas.a.width;
window.center[1] = 0.5 * canvas.a.height;
}
Insert cell
height = 600
Insert cell
d3 = require("d3@5")
Insert cell
import {slider} from "@jashkenas/inputs"
Insert cell
// const { PI, cos, sin, abs, sqrt, pow, round, random, atan2 } = Math;
// const HALF_PI = 0.5 * PI;
// const TAU = 2 * PI;
// const TO_RAD = PI / 180;
// const floor = n => n | 0;
// const rand = n => n * random();
// const randIn = (min, max) => rand(max - min) + min;
// const randRange = n => n - rand(2 * n);
// const fadeIn = (t, m) => t / m;
// const fadeOut = (t, m) => (m - t) / m;
// const fadeInOut = (t, m) => {
// let hm = 0.5 * m;
// return abs((t + hm) % m - hm) / (hm);
// };
// const dist = (x1, y1, x2, y2) => sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));
// const angle = (x1, y1, x2, y2) => atan2(y2 - y1, x2 - x1);
// const lerp = (n1, n2, speed) => (1 - speed) * n1 + speed * n2;
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more