Spaces:
Running
Running
Download app.js from Qdonnars/COP_Comparator: direct link, hf CLI and curl.
- Browser
- Download file 7.66 kB
-
https://huggingface.co/spaces/Qdonnars/COP_Comparator/resolve/main/app.js
- Command line
-
hf download hf://spaces/Qdonnars/COP_Comparator/app.js
-
curl -L -o app.js https://huggingface.co/spaces/Qdonnars/COP_Comparator/resolve/main/app.js
7.66 kB
| /** | |
| * Application de comparaison des KPIs COP régionales | |
| */ | |
| // ============================================================ | |
| // Initialisation | |
| // ============================================================ | |
| document.addEventListener("DOMContentLoaded", () => { | |
| renderTiles(); | |
| renderTable(); | |
| }); | |
| // ============================================================ | |
| // Tuiles de synthèse | |
| // ============================================================ | |
| function renderTiles() { | |
| const container = document.getElementById("tiles-container"); | |
| container.innerHTML = ""; | |
| for (const [catName, catInfo] of Object.entries(CATEGORIES)) { | |
| const catKpis = KPI_DATA.filter(k => k.categorie === catName); | |
| const comparableCount = catKpis.filter(k => k.comparable).length; | |
| const total = catKpis.length; | |
| const pct = total > 0 ? Math.round((comparableCount / total) * 100) : 0; | |
| const col = document.createElement("div"); | |
| col.className = "fr-col-12 fr-col-sm-6 fr-col-md-4 fr-col-lg-3"; | |
| col.innerHTML = ` | |
| <div class="tile-category" onclick="filterByCategory('${catName}')" tabindex="0" | |
| role="button" aria-label="Filtrer par ${catName}"> | |
| <div class="tile-category__icon">${catInfo.icon}</div> | |
| <div class="tile-category__title">${catName}</div> | |
| <div class="tile-category__count"> | |
| ${total} KPI${total > 1 ? 's' : ''} — | |
| <strong>${comparableCount}</strong> comparable${comparableCount > 1 ? 's' : ''} | |
| </div> | |
| <div class="tile-category__bar"> | |
| <div class="tile-category__bar-fill bar-fill--green" style="width: ${pct}%"></div> | |
| </div> | |
| </div> | |
| `; | |
| container.appendChild(col); | |
| } | |
| } | |
| // ============================================================ | |
| // Tableau de comparaison | |
| // ============================================================ | |
| function renderTable(filteredData = null) { | |
| const tbody = document.getElementById("kpi-tbody"); | |
| tbody.innerHTML = ""; | |
| const data = filteredData || KPI_DATA; | |
| let currentCategory = ""; | |
| data.forEach(kpi => { | |
| // Ligne catégorie | |
| if (kpi.categorie !== currentCategory) { | |
| currentCategory = kpi.categorie; | |
| const catRow = document.createElement("tr"); | |
| catRow.className = "category-row"; | |
| catRow.dataset.category = currentCategory; | |
| const catInfo = CATEGORIES[currentCategory] || { icon: "📋" }; | |
| catRow.innerHTML = ` | |
| <td colspan="6" style="border-left: 4px solid ${catInfo.color || '#000091'}"> | |
| ${catInfo.icon} ${currentCategory} | |
| </td> | |
| `; | |
| tbody.appendChild(catRow); | |
| } | |
| // Ligne KPI | |
| const row = document.createElement("tr"); | |
| row.dataset.category = kpi.categorie; | |
| row.dataset.comparable = kpi.comparable ? "true" : "false"; | |
| const comparableTag = getComparableTag(kpi); | |
| row.innerHTML = ` | |
| <td class="col-indicateur"> | |
| <strong>${kpi.indicateur}</strong> | |
| <br><small style="color: #929292">${kpi.unite}</small> | |
| </td> | |
| <td class="col-region">${formatValueWithSource(kpi.grand_est, "grand_est", kpi.grand_est_page)}</td> | |
| <td class="col-region">${formatValueWithSource(kpi.occitanie, "occitanie", kpi.occitanie_page)}</td> | |
| <td class="col-region">${formatValueWithSource(kpi.aura, "aura", kpi.aura_page)}</td> | |
| <td class="col-region">${formatValueWithSource(kpi.normandie, "normandie", kpi.normandie_page)}</td> | |
| <td class="col-comparable">${comparableTag}</td> | |
| `; | |
| tbody.appendChild(row); | |
| }); | |
| // Compteur | |
| updateCounter(data); | |
| } | |
| function formatValueWithSource(val, regionKey, page) { | |
| if (!val || val === "Non chiffré" || val === "Non chiffré spécifiquement" || val === "Non traité" || val.startsWith("Non traité") || val.startsWith("Non chiffré") || val.startsWith("Non détaillé")) { | |
| const na = `<span class="value-na">${val || '—'}</span>`; | |
| return na; | |
| } | |
| // Mettre en avant les chiffres | |
| let formatted = val.replace(/(\d[\d\s,.×÷%]*(?:\s*(?:ktCO2eq|MtCO2eq|TWh|GWh|MW|MWc|km|ha|%|millions?|milliards?|M€|Mm3))?)/g, | |
| '<strong>$1</strong>'); | |
| // Ajouter le lien source avec page | |
| if (page && SOURCES[regionKey]) { | |
| const link = `${SOURCES[regionKey].url}#page=${page}`; | |
| formatted += ` <a href="${link}" target="_blank" rel="noopener" class="source-link" title="Voir page ${page} du PDF ${SOURCES[regionKey].name}">p.${page}</a>`; | |
| } | |
| return formatted; | |
| } | |
| function getComparableTag(kpi) { | |
| if (kpi.comparable) { | |
| return ` | |
| <span class="tag-comparable tag-comparable--yes" title="${kpi.comparableNote}"> | |
| ✓ Oui | |
| </span> | |
| `; | |
| } | |
| // Check if at least 2 regions have data | |
| const regions = [kpi.grand_est, kpi.occitanie, kpi.aura, kpi.normandie]; | |
| const withData = regions.filter(v => v && !v.startsWith("Non") && !v.includes("N/D")).length; | |
| if (withData >= 2) { | |
| return ` | |
| <span class="tag-comparable tag-comparable--partial" title="${kpi.comparableNote}"> | |
| ~ Partiel | |
| </span> | |
| `; | |
| } | |
| return ` | |
| <span class="tag-comparable tag-comparable--no" title="${kpi.comparableNote}"> | |
| — Non | |
| </span> | |
| `; | |
| } | |
| // ============================================================ | |
| // Filtrage | |
| // ============================================================ | |
| function filterTable() { | |
| const category = document.getElementById("filter-category").value; | |
| const search = document.getElementById("search-input").value.toLowerCase().trim(); | |
| const onlyComparable = document.getElementById("toggle-comparable").checked; | |
| let filtered = KPI_DATA; | |
| if (category !== "all") { | |
| filtered = filtered.filter(k => k.categorie === category); | |
| } | |
| if (search) { | |
| filtered = filtered.filter(k => | |
| k.indicateur.toLowerCase().includes(search) || | |
| k.categorie.toLowerCase().includes(search) || | |
| k.grand_est.toLowerCase().includes(search) || | |
| k.occitanie.toLowerCase().includes(search) || | |
| k.aura.toLowerCase().includes(search) || | |
| k.normandie.toLowerCase().includes(search) || | |
| k.unite.toLowerCase().includes(search) | |
| ); | |
| } | |
| if (onlyComparable) { | |
| filtered = filtered.filter(k => k.comparable); | |
| } | |
| renderTable(filtered); | |
| } | |
| function filterByCategory(catName) { | |
| const select = document.getElementById("filter-category"); | |
| if (select.value === catName) { | |
| select.value = "all"; | |
| } else { | |
| select.value = catName; | |
| } | |
| filterTable(); | |
| // Scroll to table | |
| document.getElementById("comparaison").scrollIntoView({ behavior: "smooth" }); | |
| } | |
| // ============================================================ | |
| // Compteur de résultats | |
| // ============================================================ | |
| function updateCounter(data) { | |
| const tableTitle = document.querySelector("#comparaison h2"); | |
| const total = data.length; | |
| const comparable = data.filter(k => k.comparable).length; | |
| tableTitle.innerHTML = `Comparaison détaillée des KPIs <span style="font-size: 0.875rem; font-weight: 400; color: #666">(${total} KPI${total > 1 ? 's' : ''}, dont ${comparable} comparable${comparable > 1 ? 's' : ''})</span>`; | |
| } | |