mardi, janvier 13

6 000 décès de plus que de naissances en 2025 en France. Le solde naturel devient négatif pour la première fois depuis la seconde guerre mondiale et, surtout, pour la première fois dans un contexte de paix depuis le début du XXe siècle. C’est le constat du dernier bilan démographique français pour l’année 2025 publié, mardi 13 janvier, par l’Institut national de la statistique et des études économiques.

S’il a fallu attendre 2025 pour franchir ce point de bascule symbolique au niveau national, il l’avait déjà été il y a plusieurs années dans de nombreuses parties de la France. Qu’en est-il dans votre commune ou votre département ?

`

}

fillHtml();

const deptDict = {
« 01 »: { « nom_d »: « Ain », « code_r »: « 084 », « nom_r »: « Auvergne-Rhône-Alpes » },
« 02 »: { « nom_d »: « Aisne », « code_r »: « 032 », « nom_r »: « Hauts-de-France » },
« 03 »: { « nom_d »: « Allier », « code_r »: « 084 », « nom_r »: « Auvergne-Rhône-Alpes » },
« 04 »: { « nom_d »: « Alpes-de-Haute-Provence », « code_r »: « 093 », « nom_r »: « Provence-Alpes-Côte d’Azur » },
« 05 »: { « nom_d »: « Hautes-Alpes », « code_r »: « 093 », « nom_r »: « Provence-Alpes-Côte d’Azur » },
« 06 »: { « nom_d »: « Alpes-Maritimes », « code_r »: « 093 », « nom_r »: « Provence-Alpes-Côte d’Azur » },
« 07 »: { « nom_d »: « Ardèche », « code_r »: « 084 », « nom_r »: « Auvergne-Rhône-Alpes » },
« 08 »: { « nom_d »: « Ardennes », « code_r »: « 044 », « nom_r »: « Grand-Est » },
« 09 »: { « nom_d »: « Ariège », « code_r »: « 076 », « nom_r »: « Occitanie » },
« 10 »: { « nom_d »: « Aube », « code_r »: « 044 », « nom_r »: « Grand-Est » },
« 11 »: { « nom_d »: « Aude », « code_r »: « 076 », « nom_r »: « Occitanie » },
« 12 »: { « nom_d »: « Aveyron », « code_r »: « 076 », « nom_r »: « Occitanie » },
« 13 »: { « nom_d »: « Bouches-du-Rhône », « code_r »: « 093 », « nom_r »: « Provence-Alpes-Côte d’Azur » },
« 14 »: { « nom_d »: « Calvados », « code_r »: « 028 », « nom_r »: « Normandie » },
« 15 »: { « nom_d »: « Cantal », « code_r »: « 084 », « nom_r »: « Auvergne-Rhône-Alpes » },
« 16 »: { « nom_d »: « Charente », « code_r »: « 075 », « nom_r »: « Nouvelle-Aquitaine » },
« 17 »: { « nom_d »: « Charente-Maritime », « code_r »: « 075 », « nom_r »: « Nouvelle-Aquitaine » },
« 18 »: { « nom_d »: « Cher », « code_r »: « 024 », « nom_r »: « Centre-Val de Loire » },
« 19 »: { « nom_d »: « Corrèze », « code_r »: « 075 », « nom_r »: « Nouvelle-Aquitaine » },
« 21 »: { « nom_d »: « Côte-d’Or », « code_r »: « 027 », « nom_r »: « Bourgogne-Franche-Comté » },
« 22 »: { « nom_d »: « Côtes-d’Armor », « code_r »: « 053 », « nom_r »: « Bretagne » },
« 23 »: { « nom_d »: « Creuse », « code_r »: « 075 », « nom_r »: « Nouvelle-Aquitaine » },
« 24 »: { « nom_d »: « Dordogne », « code_r »: « 075 », « nom_r »: « Nouvelle-Aquitaine » },
« 25 »: { « nom_d »: « Doubs », « code_r »: « 027 », « nom_r »: « Bourgogne-Franche-Comté » },
« 26 »: { « nom_d »: « Drôme », « code_r »: « 084 », « nom_r »: « Auvergne-Rhône-Alpes » },
« 27 »: { « nom_d »: « Eure », « code_r »: « 028 », « nom_r »: « Normandie » },
« 28 »: { « nom_d »: « Eure-et-Loir », « code_r »: « 024 », « nom_r »: « Centre-Val de Loire » },
« 29 »: { « nom_d »: « Finistère », « code_r »: « 053 », « nom_r »: « Bretagne » },
« 30 »: { « nom_d »: « Gard », « code_r »: « 076 », « nom_r »: « Occitanie » },
« 31 »: { « nom_d »: « Haute-Garonne », « code_r »: « 076 », « nom_r »: « Occitanie » },
« 32 »: { « nom_d »: « Gers », « code_r »: « 076 », « nom_r »: « Occitanie » },
« 33 »: { « nom_d »: « Gironde », « code_r »: « 075 », « nom_r »: « Nouvelle-Aquitaine » },
« 34 »: { « nom_d »: « Hérault », « code_r »: « 076 », « nom_r »: « Occitanie » },
« 35 »: { « nom_d »: « Ile-et-Vilaine », « code_r »: « 053 », « nom_r »: « Bretagne » },
« 36 »: { « nom_d »: « Indre », « code_r »: « 024 », « nom_r »: « Centre-Val de Loire » },
« 37 »: { « nom_d »: « Indre-et-Loire », « code_r »: « 024 », « nom_r »: « Centre-Val de Loire » },
« 38 »: { « nom_d »: « Isère », « code_r »: « 084 », « nom_r »: « Auvergne-Rhône-Alpes » },
« 39 »: { « nom_d »: « Jura », « code_r »: « 027 », « nom_r »: « Bourgogne-Franche-Comté » },
« 40 »: { « nom_d »: « Landes », « code_r »: « 075 », « nom_r »: « Nouvelle-Aquitaine » },
« 41 »: { « nom_d »: « Loir-et-Cher », « code_r »: « 024 », « nom_r »: « Centre-Val de Loire » },
« 42 »: { « nom_d »: « Loire », « code_r »: « 084 », « nom_r »: « Auvergne-Rhône-Alpes » },
« 43 »: { « nom_d »: « Haute-Loire », « code_r »: « 084 », « nom_r »: « Auvergne-Rhône-Alpes » },
« 44 »: { « nom_d »: « Loire-Atlantique », « code_r »: « 052 », « nom_r »: « Pays-de-la-Loire » },
« 45 »: { « nom_d »: « Loiret », « code_r »: « 024 », « nom_r »: « Centre-Val de Loire » },
« 46 »: { « nom_d »: « Lot », « code_r »: « 076 », « nom_r »: « Occitanie » },
« 47 »: { « nom_d »: « Lot-et-Garonne », « code_r »: « 075 », « nom_r »: « Nouvelle-Aquitaine » },
« 48 »: { « nom_d »: « Lozère », « code_r »: « 076 », « nom_r »: « Occitanie » },
« 49 »: { « nom_d »: « Maine-et-Loire », « code_r »: « 052 », « nom_r »: « Pays-de-la-Loire » },
« 50 »: { « nom_d »: « Manche », « code_r »: « 028 », « nom_r »: « Normandie » },
« 51 »: { « nom_d »: « Marne », « code_r »: « 044 », « nom_r »: « Grand-Est » },
« 52 »: { « nom_d »: « Haute-Marne », « code_r »: « 044 », « nom_r »: « Grand-Est » },
« 53 »: { « nom_d »: « Mayenne », « code_r »: « 052 », « nom_r »: « Pays-de-la-Loire » },
« 54 »: { « nom_d »: « Meurthe-et-Moselle », « code_r »: « 044 », « nom_r »: « Grand-Est » },
« 55 »: { « nom_d »: « Meuse », « code_r »: « 044 », « nom_r »: « Grand-Est » },
« 56 »: { « nom_d »: « Morbihan », « code_r »: « 053 », « nom_r »: « Bretagne » },
« 57 »: { « nom_d »: « Moselle », « code_r »: « 044 », « nom_r »: « Grand-Est » },
« 58 »: { « nom_d »: « Nièvre », « code_r »: « 027 », « nom_r »: « Bourgogne-Franche-Comté » },
« 59 »: { « nom_d »: « Nord », « code_r »: « 032 », « nom_r »: « Hauts-de-France » },
« 60 »: { « nom_d »: « Oise », « code_r »: « 032 », « nom_r »: « Hauts-de-France » },
« 61 »: { « nom_d »: « Orne », « code_r »: « 028 », « nom_r »: « Normandie » },
« 62 »: { « nom_d »: « Pas-de-Calais », « code_r »: « 032 », « nom_r »: « Hauts-de-France » },
« 63 »: { « nom_d »: « Puy-de-Dôme », « code_r »: « 084 », « nom_r »: « Auvergne-Rhône-Alpes » },
« 64 »: { « nom_d »: « Pyrénées-Atlantiques », « code_r »: « 075 », « nom_r »: « Nouvelle-Aquitaine » },
« 65 »: { « nom_d »: « Hautes-Pyrénées », « code_r »: « 076 », « nom_r »: « Occitanie » },
« 66 »: { « nom_d »: « Pyrénées-Orientales », « code_r »: « 076 », « nom_r »: « Occitanie » },
« 67 »: { « nom_d »: « Bas-Rhin », « code_r »: « 044 », « nom_r »: « Grand-Est » },
« 68 »: { « nom_d »: « Haut-Rhin », « code_r »: « 044 », « nom_r »: « Grand-Est » },
« 69 »: { « nom_d »: « Rhône », « code_r »: « 084 », « nom_r »: « Auvergne-Rhône-Alpes » },
« 70 »: { « nom_d »: « Haute-Saône », « code_r »: « 027 », « nom_r »: « Bourgogne-Franche-Comté » },
« 71 »: { « nom_d »: « Saône-et-Loire », « code_r »: « 027 », « nom_r »: « Bourgogne-Franche-Comté » },
« 72 »: { « nom_d »: « Sarthe », « code_r »: « 052 », « nom_r »: « Pays-de-la-Loire » },
« 73 »: { « nom_d »: « Savoie », « code_r »: « 084 », « nom_r »: « Auvergne-Rhône-Alpes » },
« 74 »: { « nom_d »: « Haute-Savoie », « code_r »: « 084 », « nom_r »: « Auvergne-Rhône-Alpes » },
« 75 »: { « nom_d »: « Paris », « code_r »: « 011 », « nom_r »: « Ile-de-France » },
« 76 »: { « nom_d »: « Seine-Maritime », « code_r »: « 028 », « nom_r »: « Normandie » },
« 77 »: { « nom_d »: « Seine-et-Marne », « code_r »: « 011 », « nom_r »: « Ile-de-France » },
« 78 »: { « nom_d »: « Yvelines », « code_r »: « 011 », « nom_r »: « Ile-de-France » },
« 79 »: { « nom_d »: « Deux-Sèvres », « code_r »: « 075 », « nom_r »: « Nouvelle-Aquitaine » },
« 80 »: { « nom_d »: « Somme », « code_r »: « 032 », « nom_r »: « Hauts-de-France » },
« 81 »: { « nom_d »: « Tarn », « code_r »: « 076 », « nom_r »: « Occitanie » },
« 82 »: { « nom_d »: « Tarn-et-Garonne », « code_r »: « 076 », « nom_r »: « Occitanie » },
« 83 »: { « nom_d »: « Var », « code_r »: « 093 », « nom_r »: « Provence-Alpes-Côte d’Azur » },
« 84 »: { « nom_d »: « Vaucluse », « code_r »: « 093 », « nom_r »: « Provence-Alpes-Côte d’Azur » },
« 85 »: { « nom_d »: « Vendée », « code_r »: « 052 », « nom_r »: « Pays-de-la-Loire » },
« 86 »: { « nom_d »: « Vienne », « code_r »: « 075 », « nom_r »: « Nouvelle-Aquitaine » },
« 87 »: { « nom_d »: « Haute-Vienne », « code_r »: « 075 », « nom_r »: « Nouvelle-Aquitaine » },
« 88 »: { « nom_d »: « Vosges », « code_r »: « 044 », « nom_r »: « Grand-Est » },
« 89 »: { « nom_d »: « Yonne », « code_r »: « 027 », « nom_r »: « Bourgogne-Franche-Comté » },
« 90 »: { « nom_d »: « Territoire de Belfort », « code_r »: « 027 », « nom_r »: « Bourgogne-Franche-Comté » },
« 91 »: { « nom_d »: « Essonne », « code_r »: « 011 », « nom_r »: « Ile-de-France » },
« 92 »: { « nom_d »: « Hauts-de-Seine », « code_r »: « 011 », « nom_r »: « Ile-de-France » },
« 93 »: { « nom_d »: « Seine-Saint-Denis », « code_r »: « 011 », « nom_r »: « Ile-de-France » },
« 94 »: { « nom_d »: « Val-de-Marne », « code_r »: « 011 », « nom_r »: « Ile-de-France » },
« 95 »: { « nom_d »: « Val-d’Oise », « code_r »: « 011 », « nom_r »: « Ile-de-France » },
« 2A »: { « nom_d »: « Corse-du-Sud », « code_r »: « 094 », « nom_r »: « Corse » },
« 2B »: { « nom_d »: « Haute-Corse », « code_r »: « 094 », « nom_r »: « Corse » },
« 971 »: { « nom_d »: « Guadeloupe », « code_r »: «  », « nom_r »: «  » },
« 972 »: { « nom_d »: « Martinique », « code_r »: «  », « nom_r »: «  » },
« 973 »: { « nom_d »: « Guyane », « code_r »: «  », « nom_r »: «  » },
« 974 »: { « nom_d »: « La Réunion », « code_r »: «  », « nom_r »: «  » },
« 975 »: { « nom_d »: « Saint-Pierre-et-Miquelon », « code_r »: «  », « nom_r »: «  » },
« 976 »: { « nom_d »: « Mayotte », « code_r »: «  », « nom_r »: «  » },
« 977 »: { « nom_d »: « Saint-Martin/Saint-Barthélemy », « code_r »: «  », « nom_r »: «  » },
« 978 »: { « nom_d »: « Saint-Martin/Saint-Barthélemy », « code_r »: «  », « nom_r »: «  » },
« 986 »: { « nom_d »: « Wallis et Futuna », « code_r »: «  », « nom_r »: «  » },
« 987 »: { « nom_d »: « Polynésie française », « code_r »: «  », « nom_r »: «  » },
« 988 »: { « nom_d »: « Nouvelle-Calédonie », « code_r »: «  », « nom_r »: «  » },
« 99 »: { « nom_d »: « Français de l’étranger », « code_r »: «  », « nom_r »: «  » }
};

const days = [‘dimanche’, ‘lundi’, ‘mardi’, ‘mercredi’, ‘jeudi’, ‘vendredi’, ‘samedi’];
const months = [‘janvier’, ‘février’, ‘mars’, ‘avril’, ‘mai’, ‘juin’, ‘juillet’, ‘août’, ‘septembre’, ‘octobre’, ‘novembre’, ‘décembre’];

const formatNb = (x) => {
let loc = lang == ‘fr’ ? ‘fr-FR’ : ‘en-GB’;
return x.toLocaleString(loc);
}

// Everything we need for canvas tooltip

let booleanPointInPolygon = turf.booleanPointInPolygon.default;

const delaunayNextring = (delaunay, currentZone, kernel) => {
if (!kernel) kernel = [];
let nextring = currentZone.flatMap((d, i, self) => […delaunay.neighbors(d)].filter(e => !self.includes(e) && !kernel.includes(e)));
return […new Set(nextring)];
};

// Define app and device situation

let inApp = window.location.href.match(/apps.([a-z]+-)?lemonde.fr/);

let isMobile = window.innerWidth <= 820 ? true : false;

if (!isMobile && window.innerHeight < 600) {
document.querySelector(« .eu_map_restrainer »).style.width= »78% »;
}

//d3.json(« https://assets-decodeurs.lemonde.fr/decodeurs/assets/20240325_europeennes/communes_2024.json »).then((comTopo) => {
d3.json(« https://assets-decodeurs.lemonde.fr/decodeurs/assets/Demographie2025/communes_2024_FR.json »).then((comTopo)=>{

// 0. Stop spinner

document.querySelector(« .eu_map_loader »).style.display = « none »;
document.querySelector(« .eu_map_restrainer »).style.display = « block »;
document.querySelector(« .eu_map_instrtxt »).innerHTML = isMobile ? `${text.zoom_m}` : `${text.zoom}`;

// 1. Prepare geo data

const communes = topojson.feature(comTopo, comTopo.objects.a_com);
const dept = topojson.feature(comTopo, comTopo.objects.a_dept);
const features = new Map(communes.features.map(d => [d.properties.c, d]));
const bordersFrance = topojson.merge(comTopo, comTopo.objects.a_dept.geometries);
const bordersDept = topojson.mesh(comTopo, comTopo.objects.a_dept, (a, b) => a !== b);
const separators = topojson.feature(comTopo, comTopo.objects.l_separateur);

// 2. Define dimensions

let dimensions = {
width: document.querySelector(« .eu_map »).offsetWidth,
margin: {
top: 0,
right: 0,
bottom: 0,
left: 0,
},
};

dimensions.height = dimensions.width * 1.1;

// 3. Define projection

let projDef = (w, h, layer) => {
return d3.geoIdentity().reflectY(true).fitExtent([[dimensions.margin.left, dimensions.margin.top], [w – dimensions.margin.right, h – dimensions.margin.bottom]], layer);
};
let proj = projDef(dimensions.width, dimensions.height, bordersFrance);
const pathGenerator = d3.geoPath(proj);

// 4. Format data

let tooltip = d3.select(« .eu_map_tooltip »);
let centroids = communes.features.map(f => d3.geoPath(proj).centroid(f));
let delaunay = d3.Delaunay.from(centroids);
let comData;
let currentDept;
let zoomedIn = false;

// les données par commune
const resMap = new Map(Object.entries( dataDemoOk).map(d => [d[0], d]));

// Par ici on définit les couleurs

let categ = ‘solde2024’;

extent = [-2800, 550]
const colorScaleSoldeNew = d3.scaleDivergingSymlog(t => d3.interpolateRdBu(1-t)).domain([extent[0], 0, extent[1]])

let dataC = communes.features.map(d => {

// dataDemoOk structure :
// com: commune INSEE number
//POPTOT_2022 : population totale
//NAI_2024 : nombre de naissances
//RIP_2024 : nombre de décès

let com = d.properties.c == ‘fe’ ? ’99’ : d.properties.c;
let a;
let ft = d;
let res;

let scsolde2024;
let solde2024 = « #f6f6f6 »;

//let s;

try {
res = resMap.get(com);
}
catch (error) {
console.log(« e »);
}

if (com == ’99’) console.log(res)

// Handle communes mortes de la Meuse
if (typeof (res) == ‘undefined’) {
//console.log(« undef », com)

if (com === ‘55039’ || com === ‘55239’ || com === ‘55189’ || com === ‘55307’ || com === ‘55139’ || com === ‘55050’)
n = 104;
else {
//console.log(« undefined! », com, res)
n = 103;
}
w = null;
}
else if (res[1] === null) {
console.log(« null », res[1])
n = 105;
w = null;
}
// TODO Other conditions
else {
naissances2024 = res[1][‘NAI_2024’];
deces2024 = res[1][‘RIP_2024’];
scsolde2024 = res[1][‘RIP_2024’] – res[1][‘NAI_2024’];
csolde2024 = scsolde2024 == ‘d’ || scsolde2024 == ‘u’ || scsolde2024 == ‘n’ ? ‘#BDC1C8’ : colorScaleSoldeNew(scsolde2024);
poptot2022 = res[1][‘POPTOT_2022’];
}

return {
com,
ft: ft,
naissances2024,
deces2024,
scsolde2024,
csolde2024,
poptot2022
}
}).sort((a, b) => a[‘sc’ + categ] < b[‘sc’ + categ] ? -1 : 1);

// Draw legend

Legend(« .eu_legend_wrapper », colorScaleSoldeNew, {
width: « 300 »,
tickValues: [0]
});

txtNeutre = d3.select(« div.eu_map_restrainer > div.eu_map_legend_nb > div > svg > g > g:nth-child(1) > text »).text(« Plus de naissances   <––   0   ––>       Plus de décès     « );

// 5. Init canvas

let comCanvas = document.querySelector(« canvas[data-layer= »com »] »);
let dpr = window.devicePixelRatio;

comCanvas.width = dimensions.width * dpr;
comCanvas.height = dimensions.height * dpr;

let comContext = comCanvas.getContext(‘2d’, { willReadFrequently: true });
comContext.scale(dpr, dpr);

// 6. Init svg (frame and borders)

const svg = d3.select(« .eu_map_wrapper »)
.append(« svg »)
.attr(« preserveAspectRatio », « xMinYMin meet »)
.attr(« viewBox », `0 0 ${dimensions.width} ${dimensions.height}`)
.attr(« class », « eu_map_svgcontent »)
.attr(« aria-label », « Carte communes européennes 2024 »);

const bg = svg.append(« g »)
.append(« rect »)
.attr(« width », dimensions.width)
.attr(« height », dimensions.height)
.attr(« class », « eu_map_svgbg »)
.attr(« fill », « transparent »)
.on(« click », resetMe);

const g = svg.append(« g »);

// 7. Draw zones

const borderColor = « var(–eu-dept-border-color) »;
const comStroke = dimensions.width * 0.0025;
const bdStroke = dimensions.width * 0.0012;
const bdStrokeZoomed = dimensions.width * 0.005;

const zones = g.append(« g »).selectAll(« .eu_map_zone »)
.data(dept.features)
.enter().append(« path »)
.attr(« class », « eu_map_zone »)
.attr(« name », d => d.properties.d)
.attr(« stroke-linejoin », « round »)
.attr(« d », pathGenerator)
.attr(« fill », « transparent »);

// 8. Draw borders

const intBorders = g.append(« path »)
.attr(« class », « eu_map_border »)
.datum(bordersDept)
.attr(« fill », « none »)
.attr(« stroke », borderColor)
.attr(« stroke-width », bdStroke)
.attr(« stroke-linejoin », « round »)
.attr(« d », pathGenerator)
.attr(« pointer-events », « none »);

const extBorders = g.append(« path »)
.attr(« class », « eu_map_border »)
.datum(bordersFrance)
.attr(« fill », « none »)
.attr(« stroke », borderColor)
.attr(« stroke-width », bdStroke)
.attr(« stroke-linejoin », « round »)
.attr(« d », pathGenerator)
.attr(« pointer-events », « none »);

let comBorders;

// Draw separators

const sepLines = g.append(« path »)
.datum(separators)
.attr(« class », « l_map_lines »)
.attr(« stroke-linejoin », « round »)
.attr(« d », pathGenerator)
.attr(« stroke-linejoin », « round »)
.attr(« stroke », « var(–eu-map-sep) »)
.attr(« stroke-width », 1);

// Add overseas legend

// const textOverseas = g.append(« text »)
// .attr(« y », isMobile ? dimensions.height * 0.9 : dimensions.height * 0.895)
// .attr(« x », dimensions.width * 0.15)
// .attr(« fill », « var(–eu-map-sep-text) »)
// .attr(« font-size », isMobile ? « 11px » : « 12px »)
// .attr(« pointer-events », « none »)
// .text(`${text.ov}`);

// 9. Draw communes

const drawMap = (x = 0, y = 0, k = 1) => {

comContext.clearRect(0, 0, comCanvas.width, comCanvas.height);

if (k > 1) {

comContext.save();
comContext.translate(x, y);
comContext.scale(k, k);
comContext.rect(0, 0, dimensions.width, dimensions.height);
comContext.clip();
}

let lastColor;
let geoPath = d3.geoPath(proj, comContext);
dataC.forEach(d => {
comContext.beginPath();

if (d[‘c’ + categ] != lastColor) {
comContext.fillStyle = d[‘c’ + categ];
}
geoPath(d.ft);
lastColor = d[‘c’ + categ];
comContext.fill();

});
if (k > 1) {
comContext.restore();
}

}

//let topPos = window.scrollY + document.querySelector(« .lmui-chart__title »).getBoundingClientRect().top – 300;
let bottomPos = window.scrollY + document.querySelector(« .eu_map_wrapper »).getBoundingClientRect().bottom + 200;

const handleMouseEvents = () => {
if (isMobile) {
d3.select(« .eu_map_tooltipcross »).on(« click », onMouseLeave);
svg.selectAll(« .eu_map_zone »)
.on(« mouseleave », onMouseLeave)
.on(« click touch », clicked);
d3.select(« .eu_map_wrapper »).on(« touchleave mouseleave », onMouseLeave);
d3.select(« .eu_peripheral_top »).on(« click », onMouseLeave);
d3.select(« .eu_map_accessibility »).on(« click », onMouseLeave);
/*if (!inApp) {
window.onscroll = () => {
let currentPos = window.pageYOffset;
if ((currentPos > bottomPos && currentPos > topPos) || (currentPos < topPos && currentPos < bottomPos)) {
tooltip.transition().duration(50)
.style(« transform », « translate(0, 150px) »)
.transition().delay(50)
.style(« display », « none »);
}
}
}*/
}
else {
d3.select(« .eu_map_wrapper »).on(« mousemove », moveDesktop).on(« mouseleave », onMouseLeave);
d3.selectAll(« .eu_map_zone »).on(« mouseleave », onMouseLeave).on(« click », clicked);
}
}

// Manage zoom on click

const zoom = d3.zoom().on(« zoom », zoomed);

async function clicked(event, d) {

document.querySelector(« .eu_map_instrtxt »).innerHTML = isMobile ? `${text.cta_com_m}` : `${text.cta_com}`;

if (isMobile) {
tooltip.transition().duration(200)
.style(« transform », « translate(0, 100px) »)
.transition().delay(200)
.style(« display », « none »);
}
else
tooltip.style(« display », « none »);

const [[x0, y0], [x1, y1]] = pathGenerator.bounds(d);

event.stopPropagation();

let dNb = d.properties.d == ‘978’ ? ‘977’ : d.properties.d;

if (dNb == ‘fe’) dNb = ’99’;
if (zoomedIn == true && currentDept == dNb && dNb != ‘977’) return;

document.querySelector(« .eu_map_deptname »).innerHTML = (lang == ‘en’ && dNb == ’99’) ? `${text.tt_fe}` : deptDict[dNb].nom_d;

d3.select(« .eu_map_reset »)
.transition().duration(50)
.style(« opacity », 1)
.transition().duration(100)
.style(« display », « block »);

if (comBorders) comBorders.transition().duration(50).attr(« stroke », null).remove();

// Adapt zoom max to device and dept shape
let zoomMax = 100;

if (dNb == 75 || dNb == 92 || dNb == 93 || dNb == 94 || dNb == 90)
zoomMax = 50;
else if (dNb == ’02’)
zoomMax = isMobile ? 9.5 : 100;
else if (dNb == 25)
zoomMax = isMobile ? 10 : 11;
else if (dNb == 31)
zoomMax = isMobile ? 8.5 : 11;
else if (dNb == 67)
zoomMax = 11;
else if (dNb == ‘2B’)
zoomMax = isMobile ? 8.5 : 100;

svg.transition().duration(750).call(
zoom.transform,
d3.zoomIdentity
.translate(dimensions.width / 2, dimensions.height / 2)
.scale(Math.min(zoomMax, 1 / Math.max((x1 – x0) / dimensions.width, (y1 – y0) / dimensions.height)))
.translate(-(x0 + x1) / 2, -(y0 + y1) / 2),
);

try {
comData = await d3.json(`https://assets-decodeurs.lemonde.fr/decodeurs/elections_snippets/europeennes/exports2024TEST/export_communes${dNb}.json`);
}
catch (error) {
comData = undefined;
}

currentDept = dNb;

const extract = {
type: « FeatureCollection »,
features: communes.features.filter(k => k.properties.d == d.properties.d)
};

comBorders = g.append(« g »).selectAll(« .eu_map_com »)
.data(extract.features)
.enter().append(« path »)
.attr(« class », « eu_map_com »)
.attr(« fill », « none »)
.attr(« name », d => d.properties.d)
.attr(« d », pathGenerator);

if (isMobile) {
comBorders.on(« click mouseover », mouseEnterCom).on(« mouseout », onMouseLeave);
}

else {
d3.select(« .eu_map_wrapper »).on(« touchmove mousemove », null);
comBorders.on(« mouseover », mouseEnterCom).on(« mouseout », onMouseLeave);
}

zones.attr(« fill », « var(–eu-map-overlay) »);

d3.select(this).attr(« fill », « none »);

zoomedIn = true;
}

// Zoom and redraw

let k = 1;
let x = 0;
let y = 0;

function zoomed(event) {
let { transform } = event;
g.attr(« transform », transform);

// Scale strokes
if (zoomedIn === true) {
intBorders.transition().duration(50).ease(d3.easeCubicInOut).attr(« stroke-width », bdStrokeZoomed / transform.k);
extBorders.attr(« stroke-width », bdStrokeZoomed / transform.k);
}
else {
intBorders.attr(« stroke-width », bdStroke / transform.k);
extBorders.attr(« stroke-width », bdStroke / transform.k);
}

if (comBorders)
comBorders.attr(« stroke-width », comStroke / transform.k).attr(« stroke », borderColor).attr(« stroke-opacity », 0.5).attr(« stroke-linejoin », « round »);

drawMap(transform.x, transform.y, transform.k);

x = transform.x;
y = transform.y;
k = transform.k;

}

// Reset map on click

function resetMe() {

if (zoomedIn == false) return;
document.querySelector(« .eu_map_instrtxt »).innerHTML = isMobile ? `${text.zoom_m}` : `${text.zoom}`;

// Reset svg additions
if (comBorders) comBorders.transition().duration(50).attr(« stroke », null).remove();
zones.attr(« fill », « transparent »);

// Hide arrow
d3.selectAll(« .eu_map_reset »).transition().duration(100).style(« opacity », 0);

// Dezoom
svg.transition().duration(750).call(
zoom.transform,
d3.zoomIdentity,
d3.zoomTransform(svg.node()).invert([dimensions.width / 2, dimensions.height / 2])
);

// Reset mouse events
handleMouseEvents();

// Hide tooltip
if (isMobile) {
tooltip.transition().duration(200).style(« transform », « translate(0, 100px) »).transition().duration(200).style(« display », « none »);
}
else {
tooltip.style(« display », « none »);
}

zoomedIn = false;
}

// Manage tooltips

function onMouseLeave(event, d) {
if (isMobile) {
tooltip.transition().duration(200)
.style(« transform », « translate(0, 100px) »)
.transition().delay(200)
.style(« display », « none »);
}
else {
tooltip.style(« display », « none »);
}
d3.select(this).attr(« stroke-width », comStroke / k);
}

const percentage = (value, total) => {
return (Math.round(((value / total) * 100) * 10) / 10).toString().replace(‘.’, ‘,’);
};

// Zoomed in tooltip
function mouseEnterCom(event, datum) {

d3.select(this).attr(« stroke-width », comStroke * 2 / k);

const toFind = datum.properties.c == ‘fe’ ? ’99’ : datum.properties.c;
const link = toFind === ‘fe’ ? « https://www.lemonde.fr/resultats-europeennes-2024/outre-mer/francais-de-l-etranger/ » : `https://www.lemonde.fr/resultats-europeennes-2024/commune-${toFind}/`;

/*let locData;

locData = comData === undefined ? undefined : comData[toFind];*/

let locData = dataC.find(d => d.com == toFind);
let score = locData[‘sc’ + categ];
console.log(locData, score);
let title = `

${currentDept == ’99’ ? `${text.tt_fe}` : `${datum.properties.l}`}

`;

let content= » »;
if (toFind === ‘55039’ || toFind === ‘55239’ || toFind === ‘55189’ || toFind === ‘55307’ || toFind === ‘55139’ || toFind === ‘55050’) {
content = `${text.tt_meuse}`;
}
else if (locData == undefined || score == undefined) {
content = `${text.tt_nores}`;
if (!isMobile) {
content += `

${text.tt_nores}

`
}
}
else if (score == ‘n’) {
content = `

`;
}

else {
if (categ == ‘solde2024’) {
console.log(locData);
let plural = Math.abs(score > 1)|| Math.abs(score < -1) ? ‘s’ :  »;

let rise = score >= 0
? score == 0
? ` Autant de naissances que de décès`
: `${new String(score).replace(‘.’, ‘,’)} décès de plus que de naissances`
: `${new String(score).replace(‘-‘,  »).replace(‘.’, ‘,’)} naissance${plural} de plus que de décès`;
content = `

${rise}.
${locData[‘naissances2024’]} naissances et ${locData[‘deces2024’]} décès en 2024, pour ${locData[‘poptot2022’]} habitants (2022)

`;
}
}

// Fill and show

tooltip.select(‘.eu_map_tooltiptitle’)
.attr(‘aria-label’, `Titre infobulle`)
.html(title);

tooltip.select(‘.eu_map_tooltipvalue’)
.attr(‘aria-label’, ‘Contenu infobulle’)
.html(content);

if (!isMobile) {
const [x, y] = d3.pointer(event, svg.node());
tooltip.style(« transform », `translate(`
+ `calc(-50% + ${x >= Math.round(dimensions.width * 0.5) ? x – 70 : x + 70}px),`
+ `calc(-110% + ${y}px))`);
}
if (isMobile) {
tooltip.style(« display », « block »).transition().duration(200).style(« transform », « translate(0, -100px) »);
}
else {
tooltip.style(« display », « block »);
}
}

// Desktop non-zoomed tooltip
function moveDesktop(e,) {
let geoPath = d3.geoPath(proj, comContext);

let ptMouse, l, j, iter = 0;
const [x, y] = this ? d3.pointer(e) : [200, 200];
j = delaunay.find(x, y, j);
//let isHovering = comCanvas.getContext(‘2d’).getImageData(x, y, 1, 1).data[3] > 60;
let isHovering = true;

if (isHovering) {
ptMouse = proj.invert([x, y]);
let inPolygon = booleanPointInPolygon(ptMouse, communes.features[j]);
if (!inPolygon && j != 1) {
let currentZone = [j], kernel = [], nextZone;

while (l === undefined && iter++ < 4) {
nextZone = delaunayNextring(delaunay, currentZone, kernel);
l = nextZone.find(k => booleanPointInPolygon(ptMouse, communes.features[k]));
kernel = kernel.concat(currentZone);
currentZone = nextZone;
}
if (l !== undefined) j = l;
else j = undefined;
}
if (j === undefined) {
tooltip.style(« display », « none »);
return;
}
if (j == 1) j = 99;

if (j !== undefined) {
let com;
let deptNb;
let comName;
let data;
if (j == 99) {
com = communes.features.find(d => d.properties.c == ‘fe’);
deptNb = j;
comName = com.properties.l;
data = dataC.find(d => d.com == ’99’);
}
else {
com = communes.features[j].properties;
deptNb = com.c.slice(0, -3);
if (deptNb !== ‘2A’ && deptNb !== ‘2B’ && parseInt(deptNb) >= 96) deptNb = com.c.slice(0, -2);
comName = com.l;
data = dataC.find(d => d.com == com.c);
}
let score = data[‘sc’ + categ];

let deptName = deptDict[deptNb].nom_d;
let title = deptNb == 99 ? `${text.tt_fe}` : `${comName} (${deptName})`;
let content;

if (data.n == 103)
content = `${text.tt_nores}`;
else if (data.n == 104)
content = `${text.tt_meuse}`;
else if (data.n == 105)
content = `${text.tt_cc}`;
else {
if (score == ‘u’ || score == ‘undefined’)
content = « Solde naturel non disponible. »;
else if (categ == ‘solde2024’) {
let plural = Math.abs(score > 1) ||Math.abs(score < -1) ? ‘s’ :  »;
let rise = score >= 0
? score == 0
? ` Autant de naissances que de décès`
: `${new String(score).replace(‘.’, ‘,’)} décès de plus que de naissances`
: `${new String(score).replace(‘-‘,  »).replace(‘.’, ‘,’)} naissance${plural} de plus que de décès`;
content = `

${rise} en 2024

${text.tt_cta_dz}

`;
}
}

tooltip.select(‘.eu_map_tooltiptitle’)
.attr(‘aria-label’, ‘Infobulle’)
.html(`${title}`);

tooltip.select(‘.eu_map_tooltipvalue’)
.html(`

${content}

`);

tooltip.style(« transform », `translate(`
+ `calc(-50% + ${x >= Math.round(dimensions.width * 0.3) ? (x >= Math.round(dimensions.width * 0.6)) ? x – 70 : x : x + 70}px),`
+ `calc(-110% + ${y}px)`
+ `)`).style(« display », « block »);
}
else {
tooltip.style(« display », « none »);
}
}
else {
tooltip.style(« display », « none »);
}
}

// Watch categ buttons
document.querySelectorAll(« .eu_map_select »).forEach(button => {
button.onclick = (e) => {
let newCateg = button.getAttribute(« name »);
if (newCateg != categ) {
categ = newCateg;
dataC.sort((a, b) => a[‘c’ + categ] < b[‘c’ + categ] ? -1 : 1);
document.querySelectorAll(« .eu_map_select »).forEach(b => {
b.classList.remove(« eu_map_selected »);
});
button.classList.add(« eu_map_selected »);
drawMap(x, y, k);
drawLegend({
color: categ == ‘solde2024’ ? colorScaleSolde : colorScaleRatio,
divWidth: dimensions.width,
});
}
}
});

// Watch reset button

document.querySelector(« .eu_map_reset »).onclick = (e) => {
resetMe();
}

// Watch visibility change

document.onvisibilitychange = async (evt) => {
if (document.visibilityState === « hidden ») {
console.log(« hidden »);
} else {
console.log(« visible »);
drawMap(x, y, k);
}
};

drawMap();
handleMouseEvents();

}).catch((error) => {
throw error;
});

}

initMap(« fr »);

Il vous reste 56.75% de cet article à lire. La suite est réservée aux abonnés.

Share.
Exit mobile version