Initial commit: spec + squelette site + données causes/facteurs
Site perso comparant causes de décès réelles (CépiDc/CIM-10) et positions des partis sur leurs facteurs de risque, en vue des présidentielles 2027. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BfMPw3qHuYEtf1msg2DhfE
This commit is contained in:
commit
e19e3aeb96
10 changed files with 638 additions and 0 deletions
116
app.js
Normal file
116
app.js
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
async function loadJSON(name) {
|
||||
const res = await fetch(`data/${name}`);
|
||||
return res.json();
|
||||
}
|
||||
|
||||
const STANCE_LABEL = { pour: 'Pour', contre: 'Contre', divise: 'Divisé' };
|
||||
|
||||
function buildCauseNode(cause, causes, partis, facteurById, causeFacteurs, positions) {
|
||||
const children = causes.filter(c => c.parent_id === cause.id);
|
||||
const details = document.createElement('details');
|
||||
const summary = document.createElement('summary');
|
||||
summary.textContent = `${cause.nom} (${cause.code_cim10})`;
|
||||
details.appendChild(summary);
|
||||
|
||||
if (children.length) {
|
||||
for (const child of children) {
|
||||
details.appendChild(buildCauseNode(child, causes, partis, facteurById, causeFacteurs, positions));
|
||||
}
|
||||
} else {
|
||||
details.appendChild(buildFacteurTable(cause.id, partis, facteurById, causeFacteurs, positions));
|
||||
}
|
||||
return details;
|
||||
}
|
||||
|
||||
function buildFacteurTable(causeId, partis, facteurById, causeFacteurs, positions) {
|
||||
const table = document.createElement('table');
|
||||
const facteurIds = causeFacteurs[causeId] || [];
|
||||
|
||||
const thead = document.createElement('tr');
|
||||
thead.innerHTML = '<th>Facteur de risque</th>' +
|
||||
partis.map(p => `<th style="background:${p.couleur}44">${p.nom}</th>`).join('');
|
||||
table.appendChild(thead);
|
||||
|
||||
for (const facteurId of facteurIds) {
|
||||
const tr = document.createElement('tr');
|
||||
const facteurCell = document.createElement('td');
|
||||
facteurCell.textContent = facteurById[facteurId].nom;
|
||||
tr.appendChild(facteurCell);
|
||||
|
||||
for (const parti of partis) {
|
||||
const td = document.createElement('td');
|
||||
td.style.background = `${parti.couleur}22`;
|
||||
const pos = positions.find(p => p.cause_id === causeId && p.facteur_id === facteurId && p.parti_id === parti.id);
|
||||
if (pos) {
|
||||
td.classList.add('pos-cell');
|
||||
td.innerHTML = `<span class="pill pill-${pos.stance}">${STANCE_LABEL[pos.stance]}</span>`;
|
||||
td.addEventListener('click', () => showDetail(parti.nom, pos));
|
||||
} else {
|
||||
td.textContent = '—';
|
||||
}
|
||||
tr.appendChild(td);
|
||||
}
|
||||
table.appendChild(tr);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
function buildFacteursTable(facteurs, causeFacteurs, causes) {
|
||||
const byId = Object.fromEntries(causes.map(c => [c.id, c]));
|
||||
const causesByFacteur = {};
|
||||
for (const [causeId, facteurIds] of Object.entries(causeFacteurs)) {
|
||||
for (const facteurId of facteurIds) {
|
||||
(causesByFacteur[facteurId] ??= []).push(causeId);
|
||||
}
|
||||
}
|
||||
|
||||
const rows = facteurs
|
||||
.map(f => ({ facteur: f, causeIds: causesByFacteur[f.id] || [] }))
|
||||
.filter(r => r.causeIds.length > 1)
|
||||
.sort((a, b) => b.causeIds.length - a.causeIds.length);
|
||||
|
||||
const table = document.getElementById('facteurs-table');
|
||||
const thead = document.createElement('tr');
|
||||
thead.innerHTML = '<th>Facteur de risque</th><th>Nb causes touchées</th><th>Causes concernées</th>';
|
||||
table.appendChild(thead);
|
||||
|
||||
for (const row of rows) {
|
||||
const tr = document.createElement('tr');
|
||||
const names = row.causeIds.map(id => byId[id].nom).join(', ');
|
||||
tr.innerHTML = `<td>${row.facteur.nom}</td><td>${row.causeIds.length}</td><td>${names}</td>`;
|
||||
table.appendChild(tr);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const [causes, partis, facteurs, causeFacteurs, positions] = await Promise.all([
|
||||
loadJSON('causes.json'),
|
||||
loadJSON('partis.json'),
|
||||
loadJSON('facteurs.json'),
|
||||
loadJSON('cause_facteurs.json'),
|
||||
loadJSON('positions.json'),
|
||||
]);
|
||||
|
||||
const facteurById = Object.fromEntries(facteurs.map(f => [f.id, f]));
|
||||
const chapitres = causes
|
||||
.filter(c => c.parent_id === null)
|
||||
.sort((a, b) => (a.rang ?? 999) - (b.rang ?? 999));
|
||||
|
||||
const tree = document.getElementById('causes-tree');
|
||||
for (const chapitre of chapitres) {
|
||||
tree.appendChild(buildCauseNode(chapitre, causes, partis, facteurById, causeFacteurs, positions));
|
||||
}
|
||||
|
||||
buildFacteursTable(facteurs, causeFacteurs, causes);
|
||||
}
|
||||
|
||||
function showDetail(partiNom, pos) {
|
||||
document.getElementById('detail-title').textContent = partiNom;
|
||||
document.getElementById('detail-text').textContent = pos.position;
|
||||
const source = document.getElementById('detail-source');
|
||||
source.href = pos.source_url;
|
||||
source.textContent = pos.source_url;
|
||||
document.getElementById('detail').showModal();
|
||||
}
|
||||
|
||||
main();
|
||||
Loading…
Add table
Add a link
Reference in a new issue