|
36 | 36 | const root = document.querySelector(selectors.root); |
37 | 37 | if (!root) return; |
38 | 38 |
|
| 39 | + showLoading(root); |
| 40 | + |
| 41 | + const rankingRoot = document.querySelector("#fair-ranking-viz"); |
| 42 | + if (rankingRoot) showLoading(rankingRoot); |
| 43 | + |
39 | 44 | try { |
40 | 45 | const rows = await d3.csv(DATA_PATH, d3.autoType); |
41 | 46 |
|
|
44 | 49 |
|
45 | 50 | ensureRequiredColumns(); |
46 | 51 | injectStyles(); |
| 52 | + removeLoading(root); |
47 | 53 | buildScaffold(); |
48 | 54 | initializeState(); |
49 | 55 | populateControls(); |
|
931 | 937 | return d3.format(",.0f")(value); |
932 | 938 | } |
933 | 939 |
|
| 940 | + function showLoading(root) { |
| 941 | + root.classList.add("is-loading"); |
| 942 | + const slide = root.closest(".slide"); |
| 943 | + if (slide) slide.classList.add("is-loading"); |
| 944 | + const div = document.createElement("div"); |
| 945 | + div.className = "fair-loading"; |
| 946 | + div.textContent = "Loading data, please wait…"; |
| 947 | + root.appendChild(div); |
| 948 | + } |
| 949 | + |
| 950 | + function removeLoading(root) { |
| 951 | + root.classList.remove("is-loading"); |
| 952 | + const slide = root.closest(".slide"); |
| 953 | + if (slide) slide.classList.remove("is-loading"); |
| 954 | + root.querySelectorAll(".fair-loading").forEach(el => el.remove()); |
| 955 | + } |
| 956 | + |
934 | 957 | function showError(message) { |
935 | 958 | const root = document.querySelector(selectors.root); |
936 | 959 | if (!root) return; |
|
941 | 964 | function renderRankingTable() { |
942 | 965 | const root = d3.select("#fair-ranking-viz"); |
943 | 966 | if (root.empty()) return; |
| 967 | + root.classed("is-loading", false); |
| 968 | + const slide = root.node().closest(".slide"); |
| 969 | + if (slide) slide.classList.remove("is-loading"); |
944 | 970 |
|
945 | 971 | if (!state.rankingYear) { |
946 | 972 | state.rankingSeason = state.season; |
|
0 commit comments