Published
Edited
Jan 7, 2021
Insert cell
Insert cell
Insert cell
{
replay;
const div = html`<div style="height:${height}px;">`;
const canvas = div.appendChild(context.canvas);
context.canvas.style.maxWidth = "100%";
context.lineJoin = "round";
context.lineCap = "round";
let timer;
const duration = 10000;
const zoomDuration = 600;
const ease = d3.easeLinear;

function drawNation() {
// states
context.beginPath(); // starting path
context.lineWidth = 0.25; // set styles
context.strokeStyle = "#00000080"; // set styles
path(topojson.mesh(us, us.objects.states, (a, b) => a !== b)); // create path
context.stroke(); // apply stroke styles

// nation
context.beginPath();
context.lineWidth = 0.5;
context.strokeStyle = "#000";
path(topojson.feature(us, us.objects.nation));
context.stroke();
}

function pointStyles() {
context.fillStyle = "#94d2ff";
context.strokeStyle = "#EEE";
context.lineWidth = 0.5;
}

function drawPoints(data) {
for (var i = 0, n = data.length; i < n; ++i) {
const city = data[i];
if (city.current >= 0) {
context.beginPath();
context.arc(...city.coords, city.current, 0, city.current * Math.PI);
context.fill();
context.stroke();
}
}
}

function zoom(transform) {
context.save();
context.clearRect(0, 0, width, height);
context.translate(transform.x, transform.y);
context.scale(transform.k, transform.k);
drawNation();
pointStyles();
drawPoints(cities);
context.restore();
}

const interpolate = d3.interpolate(
{
k: 1,
x: 0,
y: 0
},
{
k: 4.09538760171377,
x: -2759.7118990427607,
y: -378.4222927920223
}
);

let start = null;
function step(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
var t = progress / zoomDuration;
var scale = interpolate(t);
zoom(scale);
if (progress < zoomDuration) {
window.requestAnimationFrame(step);
}
}

function animate() {
timer = d3.timer(elapsed => {
context.clearRect(0, 0, width, height);
pointStyles();

const time = Math.min(1, ease(elapsed / duration));
const filtered = cities.filter((c, i) => (1 - time) * cities.length < i);

filtered.forEach(city => {
city.current -= 0.05;
if (city.current < city.end) city.current = city.start;
});

drawPoints(filtered);
drawNation();

if (time === 1) {
timer.stop();
window.requestAnimationFrame(step);
}
});
}
Promises.delay(1000).then(() => {
animate();
});
yield visibility(div);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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