Skip to content

Commit 92824db

Browse files
committed
trying to have a working non medaled page
1 parent 6b388d5 commit 92824db

4 files changed

Lines changed: 216 additions & 5 deletions

File tree

website/index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,12 @@ <h2>Where do the medal winners come from?</h2>
145145
<div class="slide" data-anchor="never-medaled">
146146
<h2>Who participates without reaching the podium?</h2>
147147
<div id="never-medaled-viz"></div>
148+
149+
<div class="medal-timeline never-timeline">
150+
<button id="never-play"></button>
151+
<input id="never-year" type="range">
152+
<span id="never-current-year"></span>
153+
</div>
148154
</div>
149155

150156
</div>

website/js/delegations.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,14 @@
491491

492492
d3.select(selectors.currentYear).text(state.currentYear);
493493

494+
window.dispatchEvent(new CustomEvent("olympic-year-change", {
495+
detail: {
496+
year: state.currentYear,
497+
season: state.currentSeason,
498+
source: "delegations"
499+
}
500+
}));
501+
494502
const sankeyData = buildSankeyData({
495503
year: state.currentYear,
496504
season: state.currentSeason,

website/js/never-medaled.js

Lines changed: 171 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,24 @@
1616
const WORLD_GEOJSON_PATH =
1717
"https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson";
1818

19+
const STOP_YEAR = 2016;
20+
1921
const selectors = {
20-
root: "#never-medaled-viz"
22+
root: "#never-medaled-viz",
23+
yearSlider: "#never-year",
24+
currentYear: "#never-current-year",
25+
play: "#never-play"
2126
};
2227

2328
const state = {
2429
rows: [],
2530
columns: {},
26-
worldGeo: null
31+
worldGeo: null,
32+
currentSeason: "Summer",
33+
currentYear: null,
34+
availableYears: [],
35+
playing: false,
36+
timer: null
2737
};
2838

2939
const continentOrder = [
@@ -264,7 +274,8 @@
264274
state.columns = detectColumns(rows);
265275

266276
injectStyles();
267-
render();
277+
setupControls();
278+
setSeason("Summer");
268279
} catch (error) {
269280
console.error(error);
270281
showError("Could not load never-medaled data.");
@@ -413,6 +424,149 @@
413424
document.head.appendChild(style);
414425
}
415426

427+
function setupControls() {
428+
d3.select(selectors.yearSlider).on("input", function () {
429+
stopPlaying();
430+
431+
const index = Number(this.value);
432+
const year = state.availableYears[index];
433+
434+
if (year !== undefined) {
435+
state.currentYear = year;
436+
update();
437+
broadcastYear(year);
438+
}
439+
});
440+
441+
d3.select(selectors.play).on("click", togglePlay);
442+
443+
window.addEventListener("olympic-year-change", event => {
444+
const year = Number(event.detail?.year);
445+
const season = event.detail?.season || state.currentSeason;
446+
447+
if (!Number.isFinite(year)) return;
448+
449+
state.currentSeason = season;
450+
state.availableYears = getAvailableYears(season);
451+
452+
if (state.availableYears.includes(year)) {
453+
state.currentYear = year;
454+
} else {
455+
state.currentYear = state.availableYears.reduce((closest, y) =>
456+
Math.abs(y - year) < Math.abs(closest - year) ? y : closest
457+
);
458+
}
459+
460+
updateSliderLimits();
461+
update();
462+
});
463+
}
464+
465+
function setSeason(season) {
466+
stopPlaying();
467+
468+
state.currentSeason = season;
469+
state.availableYears = getAvailableYears(season);
470+
471+
state.currentYear = state.availableYears[0];
472+
473+
updateSliderLimits();
474+
update();
475+
}
476+
477+
function getAvailableYears(season) {
478+
const { year: yearCol, season: seasonCol } = state.columns;
479+
480+
return Array.from(
481+
new Set(
482+
state.rows
483+
.filter(row => String(row[seasonCol] || "").trim() === season)
484+
.map(row => Number(row[yearCol]))
485+
.filter(year => Number.isFinite(year) && year <= STOP_YEAR)
486+
)
487+
).sort((a, b) => a - b);
488+
}
489+
490+
function updateSliderLimits() {
491+
d3.select(selectors.yearSlider)
492+
.attr("min", 0)
493+
.attr("max", Math.max(0, state.availableYears.length - 1))
494+
.attr("step", 1)
495+
.property("value", state.availableYears.indexOf(state.currentYear));
496+
497+
d3.select(selectors.currentYear).text(state.currentYear);
498+
}
499+
500+
function update() {
501+
if (!state.currentYear) return;
502+
503+
updateSliderLimits();
504+
render();
505+
}
506+
507+
function togglePlay() {
508+
if (state.playing) {
509+
stopPlaying();
510+
} else {
511+
startPlaying();
512+
}
513+
}
514+
515+
function startPlaying() {
516+
stopPlaying();
517+
518+
const currentIndex = state.availableYears.indexOf(state.currentYear);
519+
const lastIndex = state.availableYears.length - 1;
520+
521+
if (currentIndex >= lastIndex) return;
522+
523+
state.playing = true;
524+
d3.select(selectors.play).text("II");
525+
526+
playNextYear();
527+
}
528+
529+
function playNextYear() {
530+
if (!state.playing) return;
531+
532+
const currentIndex = state.availableYears.indexOf(state.currentYear);
533+
const lastIndex = state.availableYears.length - 1;
534+
535+
if (currentIndex >= lastIndex) {
536+
stopPlaying();
537+
return;
538+
}
539+
540+
const nextIndex = currentIndex + 1;
541+
state.currentYear = state.availableYears[nextIndex];
542+
543+
update();
544+
broadcastYear(state.currentYear);
545+
546+
state.timer = setTimeout(playNextYear, 1300);
547+
}
548+
549+
function stopPlaying() {
550+
state.playing = false;
551+
552+
if (state.timer !== null) {
553+
clearTimeout(state.timer);
554+
state.timer = null;
555+
}
556+
557+
d3.select(selectors.play).text("▶");
558+
}
559+
560+
function broadcastYear(year) {
561+
window.dispatchEvent(new CustomEvent("olympic-year-change", {
562+
detail: {
563+
year,
564+
season: state.currentSeason,
565+
source: "never-medaled"
566+
}
567+
}));
568+
}
569+
416570
function render() {
417571
const root = d3.select(selectors.root);
418572
root.selectAll("*").remove();
@@ -441,14 +595,26 @@
441595
function computeNeverMedaledCountries() {
442596
const c = state.columns;
443597

598+
const rowsForYear = state.rows.filter(row => {
599+
const rowYear = Number(row[c.year]);
600+
const rowSeason = String(row[c.season] || "").trim();
601+
602+
return (
603+
Number.isFinite(rowYear) &&
604+
rowYear <= state.currentYear &&
605+
rowYear <= STOP_YEAR &&
606+
rowSeason === state.currentSeason
607+
);
608+
});
609+
444610
if (!c.country || !c.medal || !c.sport) {
445611
throw new Error("Missing required columns: country, medal, or sport.");
446612
}
447613

448614
const allCountries = new Map();
449615
const medalCountries = new Set();
450616

451-
state.rows.forEach(row => {
617+
rowsForYear.forEach(row => {
452618
const country = normalizeCountryName(cleanCountry(row[c.country]));
453619
const medal = cleanLabel(row[c.medal]);
454620
const noc = c.noc ? cleanLabel(row[c.noc]) : "";
@@ -478,7 +644,7 @@
478644

479645
const neverSet = new Set(neverMedaledNames);
480646

481-
const rowsForNeverMedaled = state.rows.filter(row => {
647+
const rowsForNeverMedaled = rowsForYear.filter(row => {
482648
const country = normalizeCountryName(cleanCountry(row[c.country]));
483649
return neverSet.has(country);
484650
});

website/styles.css

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,37 @@ p {
362362
padding: 20px;
363363
}
364364

365+
/* =============================================
366+
Delegations section
367+
=========================================== */
368+
369+
.never-timeline {
370+
margin-top: 12px;
371+
}
372+
373+
#never-play {
374+
border: 2px solid #d9d9d9;
375+
border-radius: 8px;
376+
background: #111;
377+
color: white;
378+
width: 42px;
379+
height: 36px;
380+
cursor: pointer;
381+
font-size: 18px;
382+
}
383+
384+
#never-year {
385+
width: 340px;
386+
accent-color: #f0b000;
387+
}
388+
389+
#never-current-year {
390+
color: white;
391+
font-size: 24px;
392+
font-weight: 700;
393+
min-width: 64px;
394+
}
395+
365396
/* =============================================
366397
Responsive
367398
=========================================== */

0 commit comments

Comments
 (0)