experiments-d3/inequality/www/main.js
2024-12-16 23:22:42 -06:00

83 lines
2.7 KiB
JavaScript

// create empty chart SVGs - pyramid charts start with a centered group
const dollarsG = makeChart("#pyramidDollars", 200)
.append("g")
.attr("transform", `translate(${chartWidth / 2}, ${margin.top})`);
const percentG = makeChart("#pyramidPercent", 200)
.append("g")
.attr("transform", `translate(${chartWidth / 2}, ${margin.top})`);
const lineDollars = makeChart("#lineChartDollars", 400);
const linePercent = makeChart("#lineChartPercent", 400);
// global state
let levelsData = []; // placeholder of data to be loaded
let yearIndex = 0; // currently displayed year index
let timerFunc = null; // handle to timer function if animating
// called every frame of animation -- draw all charts
// actual functions to draw charts are in other JS files (pyramid/linechart.js)
function updateCharts() {
drawPyramid(dollarsG, yearIndex, "dollars");
drawPyramid(percentG, yearIndex, "percent");
drawLineChart(lineDollars, levelsData, "dollars");
drawLineChart(linePercent, levelsData, "percent");
}
// disable timer (see below setInterval code)
function stopTimer() {
clearInterval(timerFunc);
timerFunc = null;
d3.select("#playPause").text("Play");
}
// The below global code runs on page load to set up the application.
// color the text in the paragraph to act as a key
d3.selectAll(".pyramidLabel").style("color", (d, i) => d3.schemeOranges[5][i]);
// load CSV and parse data -- then draw charts for first time
d3.csv("levels.csv").then((data) => {
levelsData = data;
updateCharts();
});
// if they drag the slider, update charts
d3.select("#timeSlider").on("change", function (e) {
// update the index & redraw
yearIndex = e.target.value;
updateCharts();
});
// if play button is clicked toggle play state
d3.select("#playPause").on("click", function (e) {
// toggle the playing class -- used for display
// as well as knowing if the animation is active
e.target.classList.toggle("playing");
// if the state is now playing -- start a timer function
if (e.target.classList.contains("playing")) {
// toggle button to say 'Pause'
d3.select(e.target).text("Pause");
// reset timer if they've gone past the end
if (yearIndex >= levelsData.length) {
yearIndex = 0;
}
// setInterval will call this function every 100ms until cancelled
// the variable "timerFunc" stores a reference to the timer so we can
// pause/cancel it
timerFunc = setInterval(function () {
yearIndex += 1;
const timeSlider = d3.select("#timeSlider");
if (yearIndex >= levelsData.length && timerFunc) {
stopTimer();
yearIndex = levelsData.length - 1;
}
timeSlider.attr("value", yearIndex);
updateCharts();
}, 100);
} else if (timerFunc) {
stopTimer();
}
});