Restructuration
This commit is contained in:
		@@ -1,572 +1,80 @@
 | 
				
			|||||||
import {useParams} from "react-router-dom"
 | 
					import {useParams} from "react-router-dom"
 | 
				
			||||||
import {MenuItem, Select} from "@mui/material"
 | 
					import {AppBar, Container, Toolbar} from "@mui/material"
 | 
				
			||||||
import FormGroup from '@mui/material/FormGroup'
 | 
					 | 
				
			||||||
import FormControlLabel from '@mui/material/FormControlLabel'
 | 
					 | 
				
			||||||
import Table from '@mui/material/Table'
 | 
					 | 
				
			||||||
import TableBody from '@mui/material/TableBody'
 | 
					 | 
				
			||||||
import TableCell from '@mui/material/TableCell'
 | 
					 | 
				
			||||||
import TableContainer from '@mui/material/TableContainer'
 | 
					 | 
				
			||||||
import TableHead from '@mui/material/TableHead'
 | 
					 | 
				
			||||||
import TableRow from '@mui/material/TableRow'
 | 
					 | 
				
			||||||
import Paper from '@mui/material/Paper'
 | 
					 | 
				
			||||||
import Switch from '@mui/material/Switch'
 | 
					 | 
				
			||||||
import * as Highcharts from 'highcharts'
 | 
					import * as Highcharts from 'highcharts'
 | 
				
			||||||
import highchartsItem from 'highcharts/modules/item-series'
 | 
					import highchartsItem from 'highcharts/modules/item-series'
 | 
				
			||||||
import HighchartsReact from 'highcharts-react-official'
 | 
					 | 
				
			||||||
import {useEffect, useMemo, useState} from "react"
 | 
					import {useEffect, useMemo, useState} from "react"
 | 
				
			||||||
import {GeoJSON, MapContainer, Popup, TileLayer, useMap} from "react-leaflet"
 | 
					import {
 | 
				
			||||||
 | 
					  SelectionAffichage,
 | 
				
			||||||
import bbox from 'geojson-bbox'
 | 
					  TableauParticipation,
 | 
				
			||||||
 | 
					  CarteResultats,
 | 
				
			||||||
 | 
					  HistogrammeVoix, CompositionHemicycle, GroupementParBloc, RetirerSeuil
 | 
				
			||||||
 | 
					} from "./includes/composants_elections"
 | 
				
			||||||
 | 
					import {TableauResultatsEuropeennes} from "./includes/composants_elections_europeennes"
 | 
				
			||||||
 | 
					import {calculerSieges, getNomZone, regrouperVoix} from "./utils"
 | 
				
			||||||
import 'leaflet/dist/leaflet.css'
 | 
					import 'leaflet/dist/leaflet.css'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
highchartsItem(Highcharts)
 | 
					highchartsItem(Highcharts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function ResultatsTable({blocs, nuances, listes, resultats, siegesParListe}) {
 | 
					 | 
				
			||||||
  const voix_listes = resultats?.voix_listes ?? {}
 | 
					 | 
				
			||||||
  const listes_triees = listes.toSorted((l1, l2) => {
 | 
					 | 
				
			||||||
    return (voix_listes[l2.numero] || 0) - (voix_listes[l1.numero] || 0)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <>
 | 
					 | 
				
			||||||
    <TableContainer component={Paper}>
 | 
					 | 
				
			||||||
      <Table sx={{ minWidth: 650 }} aria-label="simple table">
 | 
					 | 
				
			||||||
        <TableHead>
 | 
					 | 
				
			||||||
          <TableRow>
 | 
					 | 
				
			||||||
            <TableCell>Numéro</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>Liste</TableCell>
 | 
					 | 
				
			||||||
            <TableCell colSpan={2}>Nuance</TableCell>
 | 
					 | 
				
			||||||
            <TableCell colSpan={2}>Bloc</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>Voix</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>% Inscrit⋅es</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>% Exprimé⋅es</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>Sièges</TableCell>
 | 
					 | 
				
			||||||
          </TableRow>
 | 
					 | 
				
			||||||
        </TableHead>
 | 
					 | 
				
			||||||
        <TableBody>
 | 
					 | 
				
			||||||
          {listes_triees.map((liste) => (
 | 
					 | 
				
			||||||
            <ListeRow key={liste.numero} liste={liste} voix={voix_listes[liste.numero] || 0} resultats={resultats} siegesParListe={siegesParListe} blocs={blocs} nuances={nuances} />
 | 
					 | 
				
			||||||
          ))}
 | 
					 | 
				
			||||||
        </TableBody>
 | 
					 | 
				
			||||||
      </Table>
 | 
					 | 
				
			||||||
    </TableContainer>
 | 
					 | 
				
			||||||
  </>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function ListeRow({liste, voix, resultats, siegesParListe, blocs, nuances}) {
 | 
					 | 
				
			||||||
  const bloc = blocs.filter(bloc => bloc.nom === liste.bloc)[0]
 | 
					 | 
				
			||||||
  const nuance = nuances.filter(nuance => nuance.code === liste.nuance)[0]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <TableRow key={liste.numero}>
 | 
					 | 
				
			||||||
    <TableCell>{liste.numero}</TableCell>
 | 
					 | 
				
			||||||
    <TableCell>{liste.nom}</TableCell>
 | 
					 | 
				
			||||||
    <TableCell sx={{backgroundColor: nuance.couleur, padding: "0.2em"}}></TableCell>
 | 
					 | 
				
			||||||
    <TableCell>{liste.nuance}</TableCell>
 | 
					 | 
				
			||||||
    <TableCell sx={{backgroundColor: bloc.couleur, padding: "0.2em"}}></TableCell>
 | 
					 | 
				
			||||||
    <TableCell>{liste.bloc}</TableCell>
 | 
					 | 
				
			||||||
    <TableCell>{voix}</TableCell>
 | 
					 | 
				
			||||||
    <TableCell>{(100 * voix / resultats.inscrits).toFixed(2)} %</TableCell>
 | 
					 | 
				
			||||||
    <TableCell>{(100 * voix / resultats.exprimes).toFixed(2)} %</TableCell>
 | 
					 | 
				
			||||||
    <TableCell>{siegesParListe[liste.numero]}</TableCell>
 | 
					 | 
				
			||||||
  </TableRow>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function ParticipationTable({resultats}) {
 | 
					 | 
				
			||||||
  return <>
 | 
					 | 
				
			||||||
    <TableContainer component={Paper}>
 | 
					 | 
				
			||||||
      <Table sx={{ minWidth: 650 }} aria-label="simple table">
 | 
					 | 
				
			||||||
        <TableHead>
 | 
					 | 
				
			||||||
          <TableRow>
 | 
					 | 
				
			||||||
            <TableCell></TableCell>
 | 
					 | 
				
			||||||
            <TableCell>Nombre</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>% Inscrit⋅es</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>% Votant⋅es</TableCell>
 | 
					 | 
				
			||||||
          </TableRow>
 | 
					 | 
				
			||||||
        </TableHead>
 | 
					 | 
				
			||||||
        <TableBody>
 | 
					 | 
				
			||||||
          <TableRow key={"Inscrit⋅es"}>
 | 
					 | 
				
			||||||
            <TableCell>Inscrit⋅es</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>{resultats.inscrits}</TableCell>
 | 
					 | 
				
			||||||
            <TableCell></TableCell>
 | 
					 | 
				
			||||||
            <TableCell></TableCell>
 | 
					 | 
				
			||||||
          </TableRow>
 | 
					 | 
				
			||||||
          <TableRow key={"Abstentions"}>
 | 
					 | 
				
			||||||
            <TableCell>Abstention</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>{resultats.abstentions}</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>{(100 * resultats.abstentions / resultats.inscrits).toFixed(2)} %</TableCell>
 | 
					 | 
				
			||||||
            <TableCell></TableCell>
 | 
					 | 
				
			||||||
          </TableRow>
 | 
					 | 
				
			||||||
          <TableRow key={"Votant⋅es"}>
 | 
					 | 
				
			||||||
            <TableCell>Votant⋅es</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>{resultats.votants}</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>{(100 * resultats.votants / resultats.inscrits).toFixed(2)} %</TableCell>
 | 
					 | 
				
			||||||
            <TableCell></TableCell>
 | 
					 | 
				
			||||||
          </TableRow>
 | 
					 | 
				
			||||||
          <TableRow key={"Blancs"}>
 | 
					 | 
				
			||||||
            <TableCell>Blancs</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>{resultats.blancs}</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>{(100 * resultats.blancs / resultats.inscrits).toFixed(2)} %</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>{(100 * resultats.blancs / resultats.votants).toFixed(2)} %</TableCell>
 | 
					 | 
				
			||||||
          </TableRow>
 | 
					 | 
				
			||||||
          <TableRow key={"Nuls"}>
 | 
					 | 
				
			||||||
            <TableCell>Nuls</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>{resultats.nuls}</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>{(100 * resultats.nuls / resultats.inscrits).toFixed(2)} %</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>{(100 * resultats.nuls / resultats.votants).toFixed(2)} %</TableCell>
 | 
					 | 
				
			||||||
          </TableRow>
 | 
					 | 
				
			||||||
          <TableRow key={"Exprimés"}>
 | 
					 | 
				
			||||||
            <TableCell>Exprimés</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>{resultats.exprimes}</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>{(100 * resultats.exprimes / resultats.inscrits).toFixed(2)} %</TableCell>
 | 
					 | 
				
			||||||
            <TableCell>{(100 * resultats.exprimes / resultats.votants).toFixed(2)} %</TableCell>
 | 
					 | 
				
			||||||
          </TableRow>
 | 
					 | 
				
			||||||
        </TableBody>
 | 
					 | 
				
			||||||
      </Table>
 | 
					 | 
				
			||||||
    </TableContainer>
 | 
					 | 
				
			||||||
  </>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function ZoneGeoJSON({typeResultats, resultatsZone, typeZone, listes, blocs, nuances, grouperParBloc = false}) {
 | 
					 | 
				
			||||||
  const [idZone, nomZone] = useMemo(() => {
 | 
					 | 
				
			||||||
    if (!resultatsZone[typeZone])
 | 
					 | 
				
			||||||
      return ["", ""]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (typeZone === "region" || typeZone === "departement" || typeZone === "commune")
 | 
					 | 
				
			||||||
      return [resultatsZone[typeZone].code_insee, resultatsZone[typeZone].nom]
 | 
					 | 
				
			||||||
    else if (typeZone === "circonscription")
 | 
					 | 
				
			||||||
      return [resultatsZone.circonscription.id, `Circonscription ${resultatsZone.circonscription.id}`]
 | 
					 | 
				
			||||||
    else if (typeZone === "bureau_vote")
 | 
					 | 
				
			||||||
      return [resultatsZone.bureau_vote.id, resultatsZone.bureau_vote.libelle]
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      return ["", ""]
 | 
					 | 
				
			||||||
  }, [typeZone, resultatsZone])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const voix_listes = resultatsZone?.voix_listes ?? {}
 | 
					 | 
				
			||||||
  const listes_triees = listes.toSorted((l1, l2) => {
 | 
					 | 
				
			||||||
    return (voix_listes[l2.numero] || 0) - (voix_listes[l1.numero] || 0)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const voixParBloc = {}
 | 
					 | 
				
			||||||
  const voixParNuance = {}
 | 
					 | 
				
			||||||
  for (let bloc of blocs) {
 | 
					 | 
				
			||||||
    voixParBloc[bloc.nom] = 0
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  for (let nuance of nuances) {
 | 
					 | 
				
			||||||
    voixParNuance[nuance.code] = 0
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (let liste of listes) {
 | 
					 | 
				
			||||||
    voixParBloc[liste.bloc] += resultatsZone.voix_listes[liste.numero] || 0
 | 
					 | 
				
			||||||
    voixParNuance[liste.nuance] += resultatsZone.voix_listes[liste.numero] || 0
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  let couleur = 'grey'
 | 
					 | 
				
			||||||
  if (grouperParBloc) {
 | 
					 | 
				
			||||||
    let maxVoix = 0
 | 
					 | 
				
			||||||
    for (let bloc of blocs) {
 | 
					 | 
				
			||||||
      if (voixParBloc[bloc.nom] > maxVoix) {
 | 
					 | 
				
			||||||
        maxVoix = voixParBloc[bloc.nom]
 | 
					 | 
				
			||||||
        couleur = bloc.couleur
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  else {
 | 
					 | 
				
			||||||
    let maxVoix = 0
 | 
					 | 
				
			||||||
    for (let nuance of nuances) {
 | 
					 | 
				
			||||||
      if (voixParNuance[nuance.code] > maxVoix) {
 | 
					 | 
				
			||||||
        maxVoix = voixParNuance[nuance.code]
 | 
					 | 
				
			||||||
        couleur = nuance.couleur
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <GeoJSON
 | 
					 | 
				
			||||||
    data={{'type': "Feature", 'geometry': resultatsZone.geometry}}
 | 
					 | 
				
			||||||
    style={{fillColor: couleur, fillOpacity: 0.5, color: 'white', weight: 1}}>
 | 
					 | 
				
			||||||
    <Popup>
 | 
					 | 
				
			||||||
      <strong><a href={`/elections/europeennes/2024/${typeZone}/${idZone}/`}>{nomZone}</a></strong>
 | 
					 | 
				
			||||||
      <ul>
 | 
					 | 
				
			||||||
        {listes_triees.slice(0, 5).map(liste =>
 | 
					 | 
				
			||||||
          <li key={liste.numero}>{liste.nom} : {voix_listes[liste.numero]} ({(100 * voix_listes[liste.numero] / resultatsZone.exprimes).toFixed(2)} %)</li>)}
 | 
					 | 
				
			||||||
      </ul>
 | 
					 | 
				
			||||||
    </Popup>
 | 
					 | 
				
			||||||
  </GeoJSON>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function ContenuCarte({typeResultats, resultats, typeZone, listes, blocs, nuances, grouperParBloc = false}) {
 | 
					 | 
				
			||||||
  const map = useMap()
 | 
					 | 
				
			||||||
  const [resultatsZones, setResultatsZones] = useState([])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const zones = useMemo(() => {
 | 
					 | 
				
			||||||
    const data = resultats[typeResultats]
 | 
					 | 
				
			||||||
    if (!data)
 | 
					 | 
				
			||||||
      return []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (typeZone === "region")
 | 
					 | 
				
			||||||
      return data?.regions ?? []
 | 
					 | 
				
			||||||
    else if (typeZone === "departement")
 | 
					 | 
				
			||||||
      return data?.departements ?? []
 | 
					 | 
				
			||||||
    else if (typeZone === "circonscription")
 | 
					 | 
				
			||||||
      return data?.circonscriptions ?? []
 | 
					 | 
				
			||||||
    else if (typeZone === "commune")
 | 
					 | 
				
			||||||
      return data?.communes ?? []
 | 
					 | 
				
			||||||
    else if (typeZone === "bureau_vote") {
 | 
					 | 
				
			||||||
      if (typeResultats === "bureau_vote")
 | 
					 | 
				
			||||||
        return data ? [data.id] : []
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        return data?.bureaux_vote ?? []
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      return []
 | 
					 | 
				
			||||||
  }, [typeResultats, resultats, typeZone])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    if (typeResultats === "france")
 | 
					 | 
				
			||||||
      return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const geometry = resultats.geometry
 | 
					 | 
				
			||||||
    if (geometry) {
 | 
					 | 
				
			||||||
      // On centre la carte sur la zone
 | 
					 | 
				
			||||||
      const geometry_bbox = bbox(geometry)
 | 
					 | 
				
			||||||
      map.fitBounds([[geometry_bbox[1], geometry_bbox[0]], [geometry_bbox[3], geometry_bbox[2]]])
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }, [typeResultats, resultats, map])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    if (!zones)
 | 
					 | 
				
			||||||
      return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setResultatsZones(resultatsZones => [])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    zones.forEach(zone_id => {
 | 
					 | 
				
			||||||
      fetch(`/data/resultats/europeennes2024/${typeZone}/${zone_id}.json`).then(response => response.json())
 | 
					 | 
				
			||||||
        .then(resultatsZone => setResultatsZones(resultatsZones => [...resultatsZones, resultatsZone]))
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
  }, [typeZone, zones, resultats])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  function getZoneIdentifier(typeZone, zone) {
 | 
					 | 
				
			||||||
    if (typeZone === "region" || typeZone === "departement" || typeZone === "commune")
 | 
					 | 
				
			||||||
      return zone.code_insee
 | 
					 | 
				
			||||||
    else if (typeZone === "circonscription" || typeZone === "bureau_vote")
 | 
					 | 
				
			||||||
      return zone.id
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      return ""
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <>
 | 
					 | 
				
			||||||
    {resultatsZones.filter(resultatsZone => resultatsZone.geometry['type']).map(resultatsZone =>
 | 
					 | 
				
			||||||
      <ZoneGeoJSON key={getZoneIdentifier(resultatsZone[typeZone])}
 | 
					 | 
				
			||||||
                   typeResultats={typeResultats} resultatsZone={resultatsZone} typeZone={typeZone} listes={listes}
 | 
					 | 
				
			||||||
                   blocs={blocs} nuances={nuances} grouperParBloc={grouperParBloc}/>)}
 | 
					 | 
				
			||||||
  </>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function Carte({typeResultats, resultats, typeZone, listes, blocs, nuances, grouperParBloc = false}) {
 | 
					 | 
				
			||||||
  const center = typeResultats === "france" ? [46.603354, 1.888334] : [0, 0]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <>
 | 
					 | 
				
			||||||
    <MapContainer center={center} zoom={6} style={{height: "90vh"}}>
 | 
					 | 
				
			||||||
      <TileLayer
 | 
					 | 
				
			||||||
        attribution='© Les contributeur⋅rices <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
 | 
					 | 
				
			||||||
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <ContenuCarte typeResultats={typeResultats} resultats={resultats} typeZone={typeZone} listes={listes} blocs={blocs} nuances={nuances} grouperParBloc={grouperParBloc} />
 | 
					 | 
				
			||||||
  </MapContainer>
 | 
					 | 
				
			||||||
  </>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function SelectionAffichage({typeResultats, typeZone, setTypeZone}) {
 | 
					 | 
				
			||||||
  const items = useMemo(() => {
 | 
					 | 
				
			||||||
    const items = []
 | 
					 | 
				
			||||||
    if (typeResultats === "france") {
 | 
					 | 
				
			||||||
      setTypeZone("region")
 | 
					 | 
				
			||||||
      items.push(<MenuItem value="region">Région</MenuItem>)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (typeResultats === "france" || typeResultats === "region") {
 | 
					 | 
				
			||||||
      if (typeResultats !== "france")
 | 
					 | 
				
			||||||
        setTypeZone("departement")
 | 
					 | 
				
			||||||
      items.push(<MenuItem value="departement">Département</MenuItem>)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (typeResultats === "france" || typeResultats === "region" || typeResultats === "departement") {
 | 
					 | 
				
			||||||
      if (typeResultats !== "france" && typeResultats !== "region")
 | 
					 | 
				
			||||||
        setTypeZone("circonscription")
 | 
					 | 
				
			||||||
      items.push(<MenuItem value="circonscription">Circonscription</MenuItem>)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (typeResultats === "departement") {
 | 
					 | 
				
			||||||
      items.push(<MenuItem value="commune">Communes</MenuItem>)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (typeResultats === "circonscription" || typeResultats === "commune" || typeResultats === "bureau_vote") {
 | 
					 | 
				
			||||||
      setTypeZone("bureau_vote")
 | 
					 | 
				
			||||||
      items.push(<MenuItem value="bureau_vote">Bureau de vote</MenuItem>)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return items
 | 
					 | 
				
			||||||
  }, [typeResultats, setTypeZone])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <Select value={typeZone} onChange={event => setTypeZone(event.target.value)}>
 | 
					 | 
				
			||||||
    {items}
 | 
					 | 
				
			||||||
  </Select>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default function Election2024() {
 | 
					export default function Election2024() {
 | 
				
			||||||
  const {typeResultats, zoneId} = useParams()
 | 
					  const {typeResultats, zoneId} = useParams()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [zoneName, setZoneName] = useState("France")
 | 
					 | 
				
			||||||
  const [grouperParBloc, setGrouperParBloc] = useState(false)
 | 
					  const [grouperParBloc, setGrouperParBloc] = useState(false)
 | 
				
			||||||
  const [retirerSeuil, setRetirerSeuil] = useState(false)
 | 
					  const [retirerSeuil, setRetirerSeuil] = useState(false)
 | 
				
			||||||
  const [blocs, setBlocs] = useState([])
 | 
					  const [blocs, setBlocs] = useState([])
 | 
				
			||||||
  const [nuances, setNuances] = useState([])
 | 
					  const [nuances, setNuances] = useState([])
 | 
				
			||||||
  const [listes, setListes] = useState([])
 | 
					  const [listes, setListes] = useState([])
 | 
				
			||||||
  const [resultats, setResultats] = useState([])
 | 
					  const [resultats, setResultats] = useState([])
 | 
				
			||||||
  const [siegesParListe, setSiegesParListe] = useState({})
 | 
					 | 
				
			||||||
  const [voixParBloc, setVoixParBloc] = useState([])
 | 
					 | 
				
			||||||
  const [voixParNuance, setVoixParNuance] = useState([])
 | 
					 | 
				
			||||||
  const [siegesParBloc, setSiegesParBloc] = useState([])
 | 
					 | 
				
			||||||
  const [siegesParNuance, setSiegesParNuance] = useState([])
 | 
					 | 
				
			||||||
  const [categoriesVoix, setCategoriesVoix] = useState([])
 | 
					 | 
				
			||||||
  const [dataVoix, setDataVoix] = useState([])
 | 
					 | 
				
			||||||
  const [dataSieges, setDataSieges] = useState([])
 | 
					 | 
				
			||||||
  const [typeZone, setTypeZone] = useState("region")
 | 
					  const [typeZone, setTypeZone] = useState("region")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    fetch("/data/resultats/europeennes2024/blocs.json").then(response => response.json())
 | 
					    fetch("/data/resultats/europeennes/2024/blocs.json").then(response => response.json())
 | 
				
			||||||
      .then(data => setBlocs(data))
 | 
					      .then(data => setBlocs(data))
 | 
				
			||||||
    fetch("/data/resultats/europeennes2024/nuances.json").then(response => response.json())
 | 
					    fetch("/data/resultats/europeennes/2024/nuances.json").then(response => response.json())
 | 
				
			||||||
      .then(data => setNuances(data))
 | 
					      .then(data => setNuances(data))
 | 
				
			||||||
    fetch("/data/resultats/europeennes2024/listes.json").then(response => response.json())
 | 
					    fetch("/data/resultats/europeennes/2024/listes.json").then(response => response.json())
 | 
				
			||||||
      .then(data => setListes(data))
 | 
					      .then(data => setListes(data))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (typeResultats === "france") {
 | 
					    if (typeResultats === "france") {
 | 
				
			||||||
      fetch("/data/resultats/europeennes2024/france.json").then(response => response.json())
 | 
					      fetch("/data/resultats/europeennes/2024/france.json").then(response => response.json())
 | 
				
			||||||
        .then(data => setResultats(data))
 | 
					        .then(data => setResultats(data))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
      fetch(`/data/resultats/europeennes2024/${typeResultats}/${zoneId}.json`).then(response => response.json())
 | 
					      fetch(`/data/resultats/europeennes/2024/${typeResultats}/${zoneId}.json`)
 | 
				
			||||||
 | 
					        .then(response => response.json())
 | 
				
			||||||
        .then(data => setResultats(data))
 | 
					        .then(data => setResultats(data))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }, [typeResultats, zoneId])
 | 
					  }, [typeResultats, zoneId])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  const nomZone = useMemo(() => getNomZone(typeResultats, resultats),
 | 
				
			||||||
    if (!resultats || resultats.length === 0)
 | 
					    [typeResultats, resultats])
 | 
				
			||||||
      setZoneName("")
 | 
					 | 
				
			||||||
    else if (typeResultats === "france")
 | 
					 | 
				
			||||||
      setZoneName("France")
 | 
					 | 
				
			||||||
    else if (typeResultats === "region")
 | 
					 | 
				
			||||||
      setZoneName(`Région ${resultats.region.nom}`)
 | 
					 | 
				
			||||||
    else if (typeResultats === "departement")
 | 
					 | 
				
			||||||
      setZoneName(`Département ${resultats.departement.nom}`)
 | 
					 | 
				
			||||||
    else if (typeResultats === "circonscription")
 | 
					 | 
				
			||||||
      setZoneName(`Circonscription ${resultats.circonscription.id}`)
 | 
					 | 
				
			||||||
    else if (typeResultats === "commune")
 | 
					 | 
				
			||||||
      setZoneName(`Commune ${resultats.commune.nom}`)
 | 
					 | 
				
			||||||
    else if (typeResultats === "bureau_vote")
 | 
					 | 
				
			||||||
      setZoneName(resultats.bureau_vote.libelle)
 | 
					 | 
				
			||||||
  }, [typeResultats, resultats])
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  const [voixParBloc, voixParNuance] = regrouperVoix(resultats.voix, listes, blocs, nuances)
 | 
				
			||||||
    if (!resultats['voix_listes'])
 | 
					 | 
				
			||||||
      return
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const parBloc = {}
 | 
					  const siegesParListe = calculerSieges(listes, resultats, retirerSeuil ? 0 : 0.05)
 | 
				
			||||||
    const parNuance = {}
 | 
					  const [siegesParBloc, siegesParNuance] = regrouperVoix(siegesParListe, listes, blocs, nuances)
 | 
				
			||||||
    for (let bloc of blocs) {
 | 
					 | 
				
			||||||
      parBloc[bloc.nom] = 0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for (let nuance of nuances) {
 | 
					 | 
				
			||||||
      parNuance[nuance.code] = 0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (let liste of listes) {
 | 
					 | 
				
			||||||
      parBloc[liste.bloc] += resultats?.voix_listes[liste.numero] ?? 0
 | 
					 | 
				
			||||||
      parNuance[liste.nuance] += resultats?.voix_listes[liste.numero] ?? 0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setVoixParBloc(parBloc)
 | 
					 | 
				
			||||||
    setVoixParNuance(parNuance)
 | 
					 | 
				
			||||||
  }, [blocs, nuances, listes, resultats])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    const categories = []
 | 
					 | 
				
			||||||
    const data = []
 | 
					 | 
				
			||||||
    if (grouperParBloc) {
 | 
					 | 
				
			||||||
      for (let bloc of blocs) {
 | 
					 | 
				
			||||||
        categories.push(bloc.nom)
 | 
					 | 
				
			||||||
        data.push([bloc.nom, voixParBloc[bloc.nom], bloc.couleur, bloc.nom])
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
      for (let nuance of nuances) {
 | 
					 | 
				
			||||||
        categories.push(nuance.nom)
 | 
					 | 
				
			||||||
        data.push([nuance.nom, voixParNuance[nuance.code], nuance.couleur, nuance.nom])
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    setCategoriesVoix(categories)
 | 
					 | 
				
			||||||
    setDataVoix(data)
 | 
					 | 
				
			||||||
  }, [voixParBloc, voixParNuance, blocs, nuances, grouperParBloc])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    if (!resultats['voix_listes'])
 | 
					 | 
				
			||||||
      return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const MAX_SIEGES = 81
 | 
					 | 
				
			||||||
    const sieges = {}
 | 
					 | 
				
			||||||
    const listesElues = []
 | 
					 | 
				
			||||||
    let siegesAffectes = 0
 | 
					 | 
				
			||||||
    let totalVoix = resultats.exprimes
 | 
					 | 
				
			||||||
    for (let liste of listes) {
 | 
					 | 
				
			||||||
      const voix = resultats?.voix_listes[liste.numero] ?? 0
 | 
					 | 
				
			||||||
      if (voix / resultats.exprimes < 0.05 && !retirerSeuil) {
 | 
					 | 
				
			||||||
        // Barre des 5 % non franchie
 | 
					 | 
				
			||||||
        totalVoix -= voix
 | 
					 | 
				
			||||||
        sieges[liste.numero] = 0
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      else {
 | 
					 | 
				
			||||||
        listesElues.push(liste)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (listesElues.length === 0)
 | 
					 | 
				
			||||||
      return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (let liste of listesElues) {
 | 
					 | 
				
			||||||
      const voix = resultats?.voix_listes[liste.numero] ?? 0
 | 
					 | 
				
			||||||
      sieges[liste.numero] = Math.floor(MAX_SIEGES * voix / totalVoix)
 | 
					 | 
				
			||||||
      siegesAffectes += sieges[liste.numero]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while (siegesAffectes < MAX_SIEGES) {
 | 
					 | 
				
			||||||
      // Méthode de la plus forte moyenne pour affecter les sièges restants
 | 
					 | 
				
			||||||
      let maxMoyenne = 0
 | 
					 | 
				
			||||||
      let listeElue = null
 | 
					 | 
				
			||||||
      for (let liste of listesElues) {
 | 
					 | 
				
			||||||
        if (sieges[liste.numero] < MAX_SIEGES) {
 | 
					 | 
				
			||||||
          const voix = resultats?.voix_listes[liste.numero] ?? 0
 | 
					 | 
				
			||||||
          const moyenne = voix / (sieges[liste.numero] + 1)
 | 
					 | 
				
			||||||
          if (moyenne > maxMoyenne) {
 | 
					 | 
				
			||||||
            maxMoyenne = moyenne
 | 
					 | 
				
			||||||
            listeElue = liste
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      sieges[listeElue.numero]++
 | 
					 | 
				
			||||||
      siegesAffectes++
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setSiegesParListe(sieges)
 | 
					 | 
				
			||||||
  }, [listes, resultats, retirerSeuil])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    const parBloc = {}
 | 
					 | 
				
			||||||
    const parNuance = {}
 | 
					 | 
				
			||||||
    for (let bloc of blocs) {
 | 
					 | 
				
			||||||
      parBloc[bloc.nom] = 0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for (let nuance of nuances) {
 | 
					 | 
				
			||||||
      parNuance[nuance.code] = 0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (let liste of listes) {
 | 
					 | 
				
			||||||
      parBloc[liste.bloc] += siegesParListe[liste.numero] || 0
 | 
					 | 
				
			||||||
      parNuance[liste.nuance] += siegesParListe[liste.numero] || 0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setSiegesParBloc(parBloc)
 | 
					 | 
				
			||||||
    setSiegesParNuance(parNuance)
 | 
					 | 
				
			||||||
  }, [blocs, nuances, listes, siegesParListe])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    const data = []
 | 
					 | 
				
			||||||
    if (grouperParBloc) {
 | 
					 | 
				
			||||||
      for (let bloc of blocs) {
 | 
					 | 
				
			||||||
        data.push([bloc.nom, siegesParBloc[bloc.nom], bloc.couleur, bloc.nom])
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
      for (let nuance of nuances) {
 | 
					 | 
				
			||||||
        data.push([nuance.nom, siegesParNuance[nuance.code], nuance.couleur, nuance.nom])
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    setDataSieges(data)
 | 
					 | 
				
			||||||
  }, [blocs, nuances, siegesParBloc, siegesParNuance, grouperParBloc])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const compositonOptions = {
 | 
					 | 
				
			||||||
    chart: {
 | 
					 | 
				
			||||||
      type: 'item'
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    title: {
 | 
					 | 
				
			||||||
      text: 'Projection eurodéputé⋅es français⋅es 2024'
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    legend: {
 | 
					 | 
				
			||||||
      labelFormat: '{name} <span style="opacity: 0.4">{y}</span>'
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    series: [{
 | 
					 | 
				
			||||||
      name: 'Nombre de sièges',
 | 
					 | 
				
			||||||
      keys: ['name', 'y', 'color', 'label'],
 | 
					 | 
				
			||||||
      data: dataSieges,
 | 
					 | 
				
			||||||
      dataLabels: {
 | 
					 | 
				
			||||||
        enabled: false,
 | 
					 | 
				
			||||||
        format: '{point.label}'
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      // Circular options
 | 
					 | 
				
			||||||
      center: ['50%', '88%'],
 | 
					 | 
				
			||||||
      size: '170%',
 | 
					 | 
				
			||||||
      startAngle: -100,
 | 
					 | 
				
			||||||
      endAngle: 100
 | 
					 | 
				
			||||||
    }]
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const scoreOptions = {
 | 
					 | 
				
			||||||
    chart: {
 | 
					 | 
				
			||||||
      type: 'column'
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    title: {
 | 
					 | 
				
			||||||
      text: `Résultats des élections européennes 2024 : ${zoneName}`,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    tooltip: {
 | 
					 | 
				
			||||||
      formatter: function () {
 | 
					 | 
				
			||||||
        return `<span>${this.x}</span> : <strong>${this.y}</strong> voix (${(100 * this.y / resultats.exprimes).toFixed(2)} %)<br>`
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    xAxis: {
 | 
					 | 
				
			||||||
      categories: categoriesVoix,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    series: [{
 | 
					 | 
				
			||||||
      name: "Nombre de voix",
 | 
					 | 
				
			||||||
      keys: ['name', 'y', 'color', 'label'],
 | 
					 | 
				
			||||||
      data: dataVoix,
 | 
					 | 
				
			||||||
    }]
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return <>
 | 
					  return <>
 | 
				
			||||||
    <FormGroup>
 | 
					    <AppBar position="sticky">
 | 
				
			||||||
      <FormControlLabel control={<Switch checked={grouperParBloc} onChange={event => setGrouperParBloc(event.target.checked)} inputProps={{ 'aria-label': 'controlled' }} />}
 | 
					      <Toolbar>
 | 
				
			||||||
                        label="Grouper par bloc plutôt que nuance politique" />
 | 
					        <GroupementParBloc grouperParBloc={grouperParBloc} setGrouperParBloc={setGrouperParBloc} />
 | 
				
			||||||
    </FormGroup>
 | 
					        <RetirerSeuil retirerSeuil={retirerSeuil} setRetirerSeuil={setRetirerSeuil} />
 | 
				
			||||||
    <FormGroup>
 | 
					        <SelectionAffichage typeResultats={typeResultats} typeZone={typeZone} setTypeZone={setTypeZone} />
 | 
				
			||||||
      <FormControlLabel control={<Switch checked={retirerSeuil} onChange={event => setRetirerSeuil(event.target.checked)} inputProps={{ 'aria-label': 'controlled' }} />}
 | 
					      </Toolbar>
 | 
				
			||||||
                        label="Retirer le seuil des 5 %" />
 | 
					    </AppBar>
 | 
				
			||||||
    </FormGroup>
 | 
					    <Container>
 | 
				
			||||||
    <HighchartsReact
 | 
					      <HistogrammeVoix titre={`Résultats des élections européennes 2024 : ${nomZone}`}
 | 
				
			||||||
      id="composition-eurodeputees"
 | 
					                       resultats={resultats} voixParNuance={voixParNuance} voixParBloc={voixParBloc}
 | 
				
			||||||
      highcharts={Highcharts}
 | 
					                       blocs={blocs} nuances={nuances} grouperParBloc={grouperParBloc} />
 | 
				
			||||||
      options={scoreOptions}
 | 
					      <CompositionHemicycle titre={`Eurodéputé⋅es français⋅es dans l'hémicycle européen 2024 : ${nomZone}`}
 | 
				
			||||||
    />
 | 
					                            blocs={blocs} nuances={nuances} siegesParBloc={siegesParBloc} siegesParNuance={siegesParNuance}
 | 
				
			||||||
    <HighchartsReact
 | 
					                            grouperParBloc={grouperParBloc} />
 | 
				
			||||||
      id="composition-eurodeputees"
 | 
					      <TableauResultatsEuropeennes blocs={blocs} nuances={nuances} listes={listes} resultats={resultats} siegesParListe={siegesParListe} />
 | 
				
			||||||
      highcharts={Highcharts}
 | 
					      <TableauParticipation resultats={resultats} />
 | 
				
			||||||
      options={compositonOptions}
 | 
					      <CarteResultats typeElection={"europeennes"} anneeElection={"2024"}
 | 
				
			||||||
    />
 | 
					                      typeResultats={typeResultats} resultats={resultats} typeZone={typeZone}
 | 
				
			||||||
    <ResultatsTable blocs={blocs} nuances={nuances} listes={listes} resultats={resultats} siegesParListe={siegesParListe} />
 | 
					                      candidats={listes} blocs={blocs} nuances={nuances}
 | 
				
			||||||
    <ParticipationTable resultats={resultats} />
 | 
					                      voixParBloc={voixParBloc} voixParNuance={voixParNuance} grouperParBloc={grouperParBloc} />
 | 
				
			||||||
    <FormGroup>
 | 
					    </Container>
 | 
				
			||||||
      <FormControlLabel control={<SelectionAffichage typeResultats={typeResultats} typeZone={typeZone} setTypeZone={setTypeZone} />}
 | 
					 | 
				
			||||||
                        label="Type d'affichage pour la carte" />
 | 
					 | 
				
			||||||
    </FormGroup>
 | 
					 | 
				
			||||||
    <Carte typeResultats={typeResultats} resultats={resultats} typeZone={typeZone} listes={listes} blocs={blocs} nuances={nuances} voixParBloc={voixParBloc} voixParNuance={voixParNuance} grouperParBloc={grouperParBloc} />
 | 
					 | 
				
			||||||
  </>
 | 
					  </>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										374
									
								
								nupes-elections-front/src/includes/composants_elections.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										374
									
								
								nupes-elections-front/src/includes/composants_elections.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,374 @@
 | 
				
			|||||||
 | 
					import {trierCandidats, regrouperVoix} from "../utils"
 | 
				
			||||||
 | 
					import TableContainer from "@mui/material/TableContainer"
 | 
				
			||||||
 | 
					import Paper from "@mui/material/Paper"
 | 
				
			||||||
 | 
					import Table from "@mui/material/Table"
 | 
				
			||||||
 | 
					import TableHead from "@mui/material/TableHead"
 | 
				
			||||||
 | 
					import TableRow from "@mui/material/TableRow"
 | 
				
			||||||
 | 
					import TableCell from "@mui/material/TableCell"
 | 
				
			||||||
 | 
					import TableBody from "@mui/material/TableBody"
 | 
				
			||||||
 | 
					import {useEffect, useMemo, useState} from "react"
 | 
				
			||||||
 | 
					import {GeoJSON, MapContainer, Popup, TileLayer, useMap} from "react-leaflet"
 | 
				
			||||||
 | 
					import bbox from "geojson-bbox"
 | 
				
			||||||
 | 
					import {FormControl, InputLabel, MenuItem, Select} from "@mui/material"
 | 
				
			||||||
 | 
					import * as Highcharts from "highcharts";
 | 
				
			||||||
 | 
					import HighchartsReact from "highcharts-react-official";
 | 
				
			||||||
 | 
					import Switch from "@mui/material/Switch";
 | 
				
			||||||
 | 
					import FormControlLabel from "@mui/material/FormControlLabel";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function HistogrammeVoix({titre, resultats, voixParNuance, voixParBloc, blocs, nuances, grouperParBloc}) {
 | 
				
			||||||
 | 
					  const [categoriesVoix, dataVoix] = useMemo(() => {
 | 
				
			||||||
 | 
					    const categories = []
 | 
				
			||||||
 | 
					    const data = []
 | 
				
			||||||
 | 
					    if (grouperParBloc) {
 | 
				
			||||||
 | 
					      for (let bloc of blocs) {
 | 
				
			||||||
 | 
					        categories.push(bloc.nom)
 | 
				
			||||||
 | 
					        data.push([bloc.nom, voixParBloc[bloc.nom], bloc.couleur, bloc.nom])
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      for (let nuance of nuances) {
 | 
				
			||||||
 | 
					        categories.push(nuance.nom)
 | 
				
			||||||
 | 
					        data.push([nuance.nom, voixParNuance[nuance.code], nuance.couleur, nuance.nom])
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return [categories, data]
 | 
				
			||||||
 | 
					  }, [voixParBloc, voixParNuance, blocs, nuances, grouperParBloc])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const scoreOptions = {
 | 
				
			||||||
 | 
					    chart: {
 | 
				
			||||||
 | 
					      type: 'column'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    title: {
 | 
				
			||||||
 | 
					      text: titre,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    tooltip: {
 | 
				
			||||||
 | 
					      formatter: function () {
 | 
				
			||||||
 | 
					        return `<span>${this.x}</span> : <strong>${this.y}</strong> voix (${(100 * this.y / resultats.exprimes).toFixed(2)} %)<br>`
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    xAxis: {
 | 
				
			||||||
 | 
					      categories: categoriesVoix,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    series: [{
 | 
				
			||||||
 | 
					      name: "Nombre de voix",
 | 
				
			||||||
 | 
					      keys: ['name', 'y', 'color', 'label'],
 | 
				
			||||||
 | 
					      data: dataVoix,
 | 
				
			||||||
 | 
					    }]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <HighchartsReact
 | 
				
			||||||
 | 
					    highcharts={Highcharts}
 | 
				
			||||||
 | 
					    options={scoreOptions}
 | 
				
			||||||
 | 
					  />
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function CompositionHemicycle({titre, blocs, nuances, siegesParBloc, siegesParNuance, grouperParBloc}) {
 | 
				
			||||||
 | 
					  const dataSieges = useMemo(() => {
 | 
				
			||||||
 | 
					    const data = []
 | 
				
			||||||
 | 
					    if (grouperParBloc) {
 | 
				
			||||||
 | 
					      for (let bloc of blocs) {
 | 
				
			||||||
 | 
					        data.push([bloc.nom, siegesParBloc[bloc.nom], bloc.couleur, bloc.nom])
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      for (let nuance of nuances) {
 | 
				
			||||||
 | 
					        data.push([nuance.nom, siegesParNuance[nuance.code], nuance.couleur, nuance.nom])
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return data
 | 
				
			||||||
 | 
					  }, [blocs, nuances, siegesParBloc, siegesParNuance, grouperParBloc])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const compositonOptions = {
 | 
				
			||||||
 | 
					    chart: {
 | 
				
			||||||
 | 
					      type: 'item'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    title: {
 | 
				
			||||||
 | 
					      text: titre,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    legend: {
 | 
				
			||||||
 | 
					      labelFormat: '{name} <span style="opacity: 0.4">{y}</span>'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    series: [{
 | 
				
			||||||
 | 
					      name: 'Nombre de sièges',
 | 
				
			||||||
 | 
					      keys: ['name', 'y', 'color', 'label'],
 | 
				
			||||||
 | 
					      data: dataSieges,
 | 
				
			||||||
 | 
					      dataLabels: {
 | 
				
			||||||
 | 
					        enabled: false,
 | 
				
			||||||
 | 
					        format: '{point.label}'
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      // Circular options
 | 
				
			||||||
 | 
					      center: ['50%', '88%'],
 | 
				
			||||||
 | 
					      size: '170%',
 | 
				
			||||||
 | 
					      startAngle: -100,
 | 
				
			||||||
 | 
					      endAngle: 100
 | 
				
			||||||
 | 
					    }]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <HighchartsReact
 | 
				
			||||||
 | 
					    highcharts={Highcharts}
 | 
				
			||||||
 | 
					    options={compositonOptions}
 | 
				
			||||||
 | 
					  />
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Tableau de participation de l'élection dans la zone concernée
 | 
				
			||||||
 | 
					 * @param resultats
 | 
				
			||||||
 | 
					 * @return {JSX.Element}
 | 
				
			||||||
 | 
					 * @constructor
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function TableauParticipation({resultats}) {
 | 
				
			||||||
 | 
					  return <>
 | 
				
			||||||
 | 
					    <TableContainer component={Paper}>
 | 
				
			||||||
 | 
					      <Table sx={{ minWidth: 650 }} aria-label="simple table">
 | 
				
			||||||
 | 
					        <TableHead>
 | 
				
			||||||
 | 
					          <TableRow>
 | 
				
			||||||
 | 
					            <TableCell></TableCell>
 | 
				
			||||||
 | 
					            <TableCell>Nombre</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>% Inscrit⋅es</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>% Votant⋅es</TableCell>
 | 
				
			||||||
 | 
					          </TableRow>
 | 
				
			||||||
 | 
					        </TableHead>
 | 
				
			||||||
 | 
					        <TableBody>
 | 
				
			||||||
 | 
					          <TableRow key={"Inscrit⋅es"}>
 | 
				
			||||||
 | 
					            <TableCell>Inscrit⋅es</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>{resultats.inscrits}</TableCell>
 | 
				
			||||||
 | 
					            <TableCell></TableCell>
 | 
				
			||||||
 | 
					            <TableCell></TableCell>
 | 
				
			||||||
 | 
					          </TableRow>
 | 
				
			||||||
 | 
					          <TableRow key={"Abstentions"}>
 | 
				
			||||||
 | 
					            <TableCell>Abstention</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>{resultats.abstentions}</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>{(100 * resultats.abstentions / resultats.inscrits).toFixed(2)} %</TableCell>
 | 
				
			||||||
 | 
					            <TableCell></TableCell>
 | 
				
			||||||
 | 
					          </TableRow>
 | 
				
			||||||
 | 
					          <TableRow key={"Votant⋅es"}>
 | 
				
			||||||
 | 
					            <TableCell>Votant⋅es</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>{resultats.votants}</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>{(100 * resultats.votants / resultats.inscrits).toFixed(2)} %</TableCell>
 | 
				
			||||||
 | 
					            <TableCell></TableCell>
 | 
				
			||||||
 | 
					          </TableRow>
 | 
				
			||||||
 | 
					          <TableRow key={"Blancs"}>
 | 
				
			||||||
 | 
					            <TableCell>Blancs</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>{resultats.blancs}</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>{(100 * resultats.blancs / resultats.inscrits).toFixed(2)} %</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>{(100 * resultats.blancs / resultats.votants).toFixed(2)} %</TableCell>
 | 
				
			||||||
 | 
					          </TableRow>
 | 
				
			||||||
 | 
					          <TableRow key={"Nuls"}>
 | 
				
			||||||
 | 
					            <TableCell>Nuls</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>{resultats.nuls}</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>{(100 * resultats.nuls / resultats.inscrits).toFixed(2)} %</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>{(100 * resultats.nuls / resultats.votants).toFixed(2)} %</TableCell>
 | 
				
			||||||
 | 
					          </TableRow>
 | 
				
			||||||
 | 
					          <TableRow key={"Exprimés"}>
 | 
				
			||||||
 | 
					            <TableCell>Exprimés</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>{resultats.exprimes}</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>{(100 * resultats.exprimes / resultats.inscrits).toFixed(2)} %</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>{(100 * resultats.exprimes / resultats.votants).toFixed(2)} %</TableCell>
 | 
				
			||||||
 | 
					          </TableRow>
 | 
				
			||||||
 | 
					        </TableBody>
 | 
				
			||||||
 | 
					      </Table>
 | 
				
			||||||
 | 
					    </TableContainer>
 | 
				
			||||||
 | 
					  </>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function GroupementParBloc({grouperParBloc, setGrouperParBloc}) {
 | 
				
			||||||
 | 
					  return <FormControlLabel control={<Switch checked={grouperParBloc} onChange={event => setGrouperParBloc(event.target.checked)} inputProps={{ 'aria-label': 'controlled' }} />}
 | 
				
			||||||
 | 
					                          label="Grouper par bloc plutôt que nuance politique" />
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function RetirerSeuil({retirerSeuil, setRetirerSeuil}) {
 | 
				
			||||||
 | 
					  return <FormControlLabel control={<Switch checked={retirerSeuil} onChange={event => setRetirerSeuil(event.target.checked)} inputProps={{ 'aria-label': 'controlled' }} />}
 | 
				
			||||||
 | 
					                           label="Retirer le seuil des 5 %" />
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function SelectionAffichage({typeResultats, typeZone, setTypeZone}) {
 | 
				
			||||||
 | 
					  const items = useMemo(() => {
 | 
				
			||||||
 | 
					    const items = []
 | 
				
			||||||
 | 
					    if (typeResultats === "france") {
 | 
				
			||||||
 | 
					      setTypeZone("region")
 | 
				
			||||||
 | 
					      items.push(<MenuItem value="region">Région</MenuItem>)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (typeResultats === "france" || typeResultats === "region") {
 | 
				
			||||||
 | 
					      if (typeResultats !== "france")
 | 
				
			||||||
 | 
					        setTypeZone("departement")
 | 
				
			||||||
 | 
					      items.push(<MenuItem value="departement">Département</MenuItem>)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (typeResultats === "france" || typeResultats === "region" || typeResultats === "departement") {
 | 
				
			||||||
 | 
					      if (typeResultats !== "france" && typeResultats !== "region")
 | 
				
			||||||
 | 
					        setTypeZone("circonscription")
 | 
				
			||||||
 | 
					      items.push(<MenuItem value="circonscription">Circonscription</MenuItem>)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (typeResultats === "departement") {
 | 
				
			||||||
 | 
					      items.push(<MenuItem value="commune">Communes</MenuItem>)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (typeResultats === "circonscription" || typeResultats === "commune" || typeResultats === "bureau_vote") {
 | 
				
			||||||
 | 
					      setTypeZone("bureau_vote")
 | 
				
			||||||
 | 
					      items.push(<MenuItem value="bureau_vote">Bureau de vote</MenuItem>)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return items
 | 
				
			||||||
 | 
					  }, [typeResultats, setTypeZone])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <FormControl>
 | 
				
			||||||
 | 
					    <InputLabel>
 | 
				
			||||||
 | 
					      Zone à afficher
 | 
				
			||||||
 | 
					  </InputLabel>
 | 
				
			||||||
 | 
					    <Select value={typeZone}
 | 
				
			||||||
 | 
					            onChange={event => setTypeZone(event.target.value)}
 | 
				
			||||||
 | 
					            label="Zone à afficher">
 | 
				
			||||||
 | 
					      {items}
 | 
				
			||||||
 | 
					    </Select>
 | 
				
			||||||
 | 
					  </FormControl>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function ZoneGeoJSON({typeElection, anneeElection, resultatsZone, typeZone,
 | 
				
			||||||
 | 
					                       candidats, blocs, nuances, grouperParBloc = false}) {
 | 
				
			||||||
 | 
					  const [idZone, nomZone] = useMemo(() => {
 | 
				
			||||||
 | 
					    if (!resultatsZone[typeZone])
 | 
				
			||||||
 | 
					      return ["", ""]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (typeZone === "region" || typeZone === "departement" || typeZone === "commune")
 | 
				
			||||||
 | 
					      return [resultatsZone[typeZone].code_insee, resultatsZone[typeZone].nom]
 | 
				
			||||||
 | 
					    else if (typeZone === "circonscription")
 | 
				
			||||||
 | 
					      return [resultatsZone.circonscription.id, `Circonscription ${resultatsZone.circonscription.id}`]
 | 
				
			||||||
 | 
					    else if (typeZone === "bureau_vote")
 | 
				
			||||||
 | 
					      return [resultatsZone.bureau_vote.id, resultatsZone.bureau_vote.libelle]
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      return ["", ""]
 | 
				
			||||||
 | 
					  }, [typeZone, resultatsZone])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const voixCandidats = useMemo(() => resultatsZone?.voix ?? {}, [resultatsZone])
 | 
				
			||||||
 | 
					  const candidatsTries = trierCandidats(candidats, voixCandidats)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [voixParBloc, voixParNuance] = regrouperVoix(voixCandidats, candidats, blocs, nuances)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let couleur = 'grey'
 | 
				
			||||||
 | 
					  if (grouperParBloc) {
 | 
				
			||||||
 | 
					    let maxVoix = 0
 | 
				
			||||||
 | 
					    for (let bloc of blocs) {
 | 
				
			||||||
 | 
					      if (voixParBloc[bloc.nom] > maxVoix) {
 | 
				
			||||||
 | 
					        maxVoix = voixParBloc[bloc.nom]
 | 
				
			||||||
 | 
					        couleur = bloc.couleur
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else {
 | 
				
			||||||
 | 
					    let maxVoix = 0
 | 
				
			||||||
 | 
					    for (let nuance of nuances) {
 | 
				
			||||||
 | 
					      if (voixParNuance[nuance.code] > maxVoix) {
 | 
				
			||||||
 | 
					        maxVoix = voixParNuance[nuance.code]
 | 
				
			||||||
 | 
					        couleur = nuance.couleur
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <GeoJSON
 | 
				
			||||||
 | 
					    data={{'type': "Feature", 'geometry': resultatsZone.geometry}}
 | 
				
			||||||
 | 
					    style={{fillColor: couleur, fillOpacity: 0.5, color: 'white', weight: 1}}>
 | 
				
			||||||
 | 
					    <Popup>
 | 
				
			||||||
 | 
					      <strong><a href={`/elections/${typeElection}/${anneeElection}/${typeZone}/${idZone}/`}>{nomZone}</a></strong>
 | 
				
			||||||
 | 
					      <ul>
 | 
				
			||||||
 | 
					        {candidatsTries.slice(0, 5).map(candidat =>
 | 
				
			||||||
 | 
					          <li key={candidat.numero}>
 | 
				
			||||||
 | 
					            {candidat.nom} : {voixCandidats[candidat.numero]} ({(100 * voixCandidats[candidat.numero] / resultatsZone.exprimes).toFixed(2)} %)
 | 
				
			||||||
 | 
					          </li>)}
 | 
				
			||||||
 | 
					      </ul>
 | 
				
			||||||
 | 
					    </Popup>
 | 
				
			||||||
 | 
					  </GeoJSON>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function ContenuCarte({typeElection, anneeElection, typeResultats, resultats,
 | 
				
			||||||
 | 
					                        typeZone, candidats, blocs, nuances, grouperParBloc = false}) {
 | 
				
			||||||
 | 
					  const map = useMap()
 | 
				
			||||||
 | 
					  const [resultatsZones, setResultatsZones] = useState([])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const zones = useMemo(() => {
 | 
				
			||||||
 | 
					    const data = resultats[typeResultats]
 | 
				
			||||||
 | 
					    if (!data)
 | 
				
			||||||
 | 
					      return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (typeZone === "region")
 | 
				
			||||||
 | 
					      return data?.regions ?? []
 | 
				
			||||||
 | 
					    else if (typeZone === "departement")
 | 
				
			||||||
 | 
					      return data?.departements ?? []
 | 
				
			||||||
 | 
					    else if (typeZone === "circonscription")
 | 
				
			||||||
 | 
					      return data?.circonscriptions ?? []
 | 
				
			||||||
 | 
					    else if (typeZone === "commune")
 | 
				
			||||||
 | 
					      return data?.communes ?? []
 | 
				
			||||||
 | 
					    else if (typeZone === "bureau_vote") {
 | 
				
			||||||
 | 
					      if (typeResultats === "bureau_vote")
 | 
				
			||||||
 | 
					        return data ? [data.id] : []
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        return data?.bureaux_vote ?? []
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      return []
 | 
				
			||||||
 | 
					  }, [typeResultats, resultats, typeZone])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (typeResultats === "france")
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const geometry = resultats.geometry
 | 
				
			||||||
 | 
					    if (geometry) {
 | 
				
			||||||
 | 
					      // On centre la carte sur la zone
 | 
				
			||||||
 | 
					      const geometry_bbox = bbox(geometry)
 | 
				
			||||||
 | 
					      map.fitBounds([[geometry_bbox[1], geometry_bbox[0]], [geometry_bbox[3], geometry_bbox[2]]])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [typeResultats, resultats, map])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (!zones)
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setResultatsZones(resultatsZones => [])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    zones.forEach(zoneId => {
 | 
				
			||||||
 | 
					      fetch(`/data/resultats/${typeElection}/${anneeElection}/${typeZone}/${zoneId}.json`)
 | 
				
			||||||
 | 
					        .then(response => response.json())
 | 
				
			||||||
 | 
					        .then(resultatsZone => setResultatsZones(resultatsZones => [...resultatsZones, resultatsZone]))
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }, [typeElection, anneeElection, typeZone, zones, resultats])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function getZoneIdentifier(typeZone, zone) {
 | 
				
			||||||
 | 
					    if (typeZone === "region" || typeZone === "departement" || typeZone === "commune")
 | 
				
			||||||
 | 
					      return zone.code_insee
 | 
				
			||||||
 | 
					    else if (typeZone === "circonscription" || typeZone === "bureau_vote")
 | 
				
			||||||
 | 
					      return zone.id
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      return ""
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <>
 | 
				
			||||||
 | 
					    {resultatsZones.filter(resultatsZone => resultatsZone.geometry['type']).map(resultatsZone =>
 | 
				
			||||||
 | 
					      <ZoneGeoJSON key={getZoneIdentifier(resultatsZone[typeZone])}
 | 
				
			||||||
 | 
					                   typeElection={typeElection} anneeElection={anneeElection}
 | 
				
			||||||
 | 
					                   resultatsZone={resultatsZone} typeZone={typeZone} candidats={candidats}
 | 
				
			||||||
 | 
					                   blocs={blocs} nuances={nuances} grouperParBloc={grouperParBloc}/>)}
 | 
				
			||||||
 | 
					  </>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function CarteResultats({typeElection, anneeElection, typeResultats, resultats,
 | 
				
			||||||
 | 
					                                 typeZone, candidats, blocs, nuances, grouperParBloc = false}) {
 | 
				
			||||||
 | 
					  const center = typeResultats === "france" ? [46.603354, 1.888334] : [0, 0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <>
 | 
				
			||||||
 | 
					    <MapContainer center={center} zoom={6} style={{height: "90vh"}}>
 | 
				
			||||||
 | 
					      <TileLayer
 | 
				
			||||||
 | 
					        attribution='© Les contributeur⋅rices <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
 | 
				
			||||||
 | 
					        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <ContenuCarte typeElection={typeElection} anneeElection={anneeElection} typeResultats={typeResultats}
 | 
				
			||||||
 | 
					                    resultats={resultats} typeZone={typeZone} candidats={candidats}
 | 
				
			||||||
 | 
					                    blocs={blocs} nuances={nuances} grouperParBloc={grouperParBloc} />
 | 
				
			||||||
 | 
					  </MapContainer>
 | 
				
			||||||
 | 
					  </>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,66 @@
 | 
				
			|||||||
 | 
					import {trierCandidats} from "../utils"
 | 
				
			||||||
 | 
					import TableContainer from "@mui/material/TableContainer"
 | 
				
			||||||
 | 
					import Paper from "@mui/material/Paper"
 | 
				
			||||||
 | 
					import Table from "@mui/material/Table"
 | 
				
			||||||
 | 
					import TableHead from "@mui/material/TableHead"
 | 
				
			||||||
 | 
					import TableRow from "@mui/material/TableRow"
 | 
				
			||||||
 | 
					import TableCell from "@mui/material/TableCell"
 | 
				
			||||||
 | 
					import TableBody from "@mui/material/TableBody"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Composant pour le tableau des résultats des élections européennes par liste
 | 
				
			||||||
 | 
					 * @param blocs
 | 
				
			||||||
 | 
					 * @param nuances
 | 
				
			||||||
 | 
					 * @param listes
 | 
				
			||||||
 | 
					 * @param resultats
 | 
				
			||||||
 | 
					 * @param siegesParListe
 | 
				
			||||||
 | 
					 * @return {JSX.Element}
 | 
				
			||||||
 | 
					 * @constructor
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function TableauResultatsEuropeennes({blocs, nuances, listes, resultats, siegesParListe}) {
 | 
				
			||||||
 | 
					  const voix_listes = resultats?.voix_listes ?? {}
 | 
				
			||||||
 | 
					  const listes_triees = trierCandidats(listes, voix_listes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <>
 | 
				
			||||||
 | 
					    <TableContainer component={Paper}>
 | 
				
			||||||
 | 
					      <Table sx={{ minWidth: 650 }} aria-label="simple table">
 | 
				
			||||||
 | 
					        <TableHead>
 | 
				
			||||||
 | 
					          <TableRow>
 | 
				
			||||||
 | 
					            <TableCell>Numéro</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>Liste</TableCell>
 | 
				
			||||||
 | 
					            <TableCell colSpan={2}>Nuance</TableCell>
 | 
				
			||||||
 | 
					            <TableCell colSpan={2}>Bloc</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>Voix</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>% Inscrit⋅es</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>% Exprimé⋅es</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>Sièges</TableCell>
 | 
				
			||||||
 | 
					          </TableRow>
 | 
				
			||||||
 | 
					        </TableHead>
 | 
				
			||||||
 | 
					        <TableBody>
 | 
				
			||||||
 | 
					          {listes_triees.map((liste) => (
 | 
				
			||||||
 | 
					            <LigneListe key={liste.numero} liste={liste} voix={voix_listes[liste.numero] || 0}
 | 
				
			||||||
 | 
					                        resultats={resultats} siegesParListe={siegesParListe} blocs={blocs} nuances={nuances} />
 | 
				
			||||||
 | 
					          ))}
 | 
				
			||||||
 | 
					        </TableBody>
 | 
				
			||||||
 | 
					      </Table>
 | 
				
			||||||
 | 
					    </TableContainer>
 | 
				
			||||||
 | 
					  </>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function LigneListe({liste, voix, resultats, siegesParListe, blocs, nuances}) {
 | 
				
			||||||
 | 
					  const bloc = blocs.filter(bloc => bloc.nom === liste.bloc)[0]
 | 
				
			||||||
 | 
					  const nuance = nuances.filter(nuance => nuance.code === liste.nuance)[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <TableRow key={liste.numero}>
 | 
				
			||||||
 | 
					    <TableCell>{liste.numero}</TableCell>
 | 
				
			||||||
 | 
					    <TableCell>{liste.nom}</TableCell>
 | 
				
			||||||
 | 
					    <TableCell sx={{backgroundColor: nuance.couleur, padding: "0.2em"}}></TableCell>
 | 
				
			||||||
 | 
					    <TableCell>{liste.nuance}</TableCell>
 | 
				
			||||||
 | 
					    <TableCell sx={{backgroundColor: bloc.couleur, padding: "0.2em"}}></TableCell>
 | 
				
			||||||
 | 
					    <TableCell>{liste.bloc}</TableCell>
 | 
				
			||||||
 | 
					    <TableCell>{voix}</TableCell>
 | 
				
			||||||
 | 
					    <TableCell>{(100 * voix / resultats.inscrits).toFixed(2)} %</TableCell>
 | 
				
			||||||
 | 
					    <TableCell>{(100 * voix / resultats.exprimes).toFixed(2)} %</TableCell>
 | 
				
			||||||
 | 
					    <TableCell>{siegesParListe[liste.numero]}</TableCell>
 | 
				
			||||||
 | 
					  </TableRow>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										96
									
								
								nupes-elections-front/src/utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								nupes-elections-front/src/utils.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					export function getNomZone(typeResultats, resultats) {
 | 
				
			||||||
 | 
					  if (!resultats || resultats.length === 0)
 | 
				
			||||||
 | 
					    return ""
 | 
				
			||||||
 | 
					  else if (typeResultats === "france")
 | 
				
			||||||
 | 
					    return "France"
 | 
				
			||||||
 | 
					  else if (typeResultats === "region")
 | 
				
			||||||
 | 
					    return `Région ${resultats.region.nom}`
 | 
				
			||||||
 | 
					  else if (typeResultats === "departement")
 | 
				
			||||||
 | 
					    return `Département ${resultats.departement.nom}`
 | 
				
			||||||
 | 
					  else if (typeResultats === "circonscription")
 | 
				
			||||||
 | 
					    return `Circonscription ${resultats.circonscription.id}`
 | 
				
			||||||
 | 
					  else if (typeResultats === "commune")
 | 
				
			||||||
 | 
					    return `Commune ${resultats.commune.nom}`
 | 
				
			||||||
 | 
					  else if (typeResultats === "bureau_vote")
 | 
				
			||||||
 | 
					    return resultats.bureau_vote.libelle
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function trierCandidats(candidats, voix_par_candidat) {
 | 
				
			||||||
 | 
					  return candidats.toSorted((l1, l2) => {
 | 
				
			||||||
 | 
					    return (voix_par_candidat[l2.numero] || 0) - (voix_par_candidat[l1.numero] || 0)
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function regrouperVoix(voixCandidats, candidats, blocs, nuances) {
 | 
				
			||||||
 | 
					  if (!candidats || !voixCandidats || !blocs || !nuances
 | 
				
			||||||
 | 
					      || candidats.length === 0 || blocs.length === 0 || nuances.length === 0)
 | 
				
			||||||
 | 
					    return [{}, {}]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const parBloc = {}
 | 
				
			||||||
 | 
					  const parNuance = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (let bloc of blocs) {
 | 
				
			||||||
 | 
					    parBloc[bloc.nom] = 0
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  for (let nuance of nuances) {
 | 
				
			||||||
 | 
					    parNuance[nuance.code] = 0
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (let candidat of candidats) {
 | 
				
			||||||
 | 
					    parBloc[candidat.bloc] += voixCandidats[candidat.numero] || 0
 | 
				
			||||||
 | 
					    parNuance[candidat.nuance] += voixCandidats[candidat.numero] || 0
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return [parBloc, parNuance]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function calculerSieges(listes, resultats, seuil = 0.05) {
 | 
				
			||||||
 | 
					  if (!resultats['voix'])
 | 
				
			||||||
 | 
					    return {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const MAX_SIEGES = 81
 | 
				
			||||||
 | 
					  const sieges = {}
 | 
				
			||||||
 | 
					  const listesElues = []
 | 
				
			||||||
 | 
					  let siegesAffectes = 0
 | 
				
			||||||
 | 
					  let totalVoix = resultats.exprimes
 | 
				
			||||||
 | 
					  for (let liste of listes) {
 | 
				
			||||||
 | 
					    const voix = resultats?.voix[liste.numero] ?? 0
 | 
				
			||||||
 | 
					    if (voix / resultats.exprimes < seuil) {
 | 
				
			||||||
 | 
					      // Barre des 5 % non franchie
 | 
				
			||||||
 | 
					      totalVoix -= voix
 | 
				
			||||||
 | 
					      sieges[liste.numero] = 0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      listesElues.push(liste)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (listesElues.length === 0)
 | 
				
			||||||
 | 
					    return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (let liste of listesElues) {
 | 
				
			||||||
 | 
					    const voix = resultats?.voix[liste.numero] ?? 0
 | 
				
			||||||
 | 
					    sieges[liste.numero] = Math.floor(MAX_SIEGES * voix / totalVoix)
 | 
				
			||||||
 | 
					    siegesAffectes += sieges[liste.numero]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (siegesAffectes < MAX_SIEGES) {
 | 
				
			||||||
 | 
					    // Méthode de la plus forte moyenne pour affecter les sièges restants
 | 
				
			||||||
 | 
					    let maxMoyenne = 0
 | 
				
			||||||
 | 
					    let listeElue = null
 | 
				
			||||||
 | 
					    for (let liste of listesElues) {
 | 
				
			||||||
 | 
					      if (sieges[liste.numero] < MAX_SIEGES) {
 | 
				
			||||||
 | 
					        const voix = resultats?.voix[liste.numero] ?? 0
 | 
				
			||||||
 | 
					        const moyenne = voix / (sieges[liste.numero] + 1)
 | 
				
			||||||
 | 
					        if (moyenne > maxMoyenne) {
 | 
				
			||||||
 | 
					          maxMoyenne = moyenne
 | 
				
			||||||
 | 
					          listeElue = liste
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    sieges[listeElue.numero]++
 | 
				
			||||||
 | 
					    siegesAffectes++
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return sieges
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
@@ -22,7 +22,7 @@ def exporter_listes(engine: Engine, verbose: bool = False) -> None:
 | 
				
			|||||||
            bloc_json = {'id': bloc.id, 'nom': bloc.nom, 'couleur': bloc.couleur}
 | 
					            bloc_json = {'id': bloc.id, 'nom': bloc.nom, 'couleur': bloc.couleur}
 | 
				
			||||||
            blocs_json.append(bloc_json)
 | 
					            blocs_json.append(bloc_json)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        file = DATA_DIR / "resultats" / "europeennes2024" / "blocs.json"
 | 
					        file = DATA_DIR / "resultats" / "europeennes" / "2024" / "blocs.json"
 | 
				
			||||||
        if not file.parent.is_dir():
 | 
					        if not file.parent.is_dir():
 | 
				
			||||||
            file.parent.mkdir(parents=True)
 | 
					            file.parent.mkdir(parents=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -36,7 +36,7 @@ def exporter_listes(engine: Engine, verbose: bool = False) -> None:
 | 
				
			|||||||
            nuance_json = {'code': nuance.code, 'nom': nuance.nom, 'couleur': nuance.couleur}
 | 
					            nuance_json = {'code': nuance.code, 'nom': nuance.nom, 'couleur': nuance.couleur}
 | 
				
			||||||
            nuances_json.append(nuance_json)
 | 
					            nuances_json.append(nuance_json)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        file = DATA_DIR / "resultats" / "europeennes2024" / "nuances.json"
 | 
					        file = DATA_DIR / "resultats" / "europeennes" / "2024" / "nuances.json"
 | 
				
			||||||
        if not file.parent.is_dir():
 | 
					        if not file.parent.is_dir():
 | 
				
			||||||
            file.parent.mkdir(parents=True)
 | 
					            file.parent.mkdir(parents=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -57,7 +57,7 @@ def exporter_listes(engine: Engine, verbose: bool = False) -> None:
 | 
				
			|||||||
                          'bloc': liste.bloc.nom, 'candidats': candidats}
 | 
					                          'bloc': liste.bloc.nom, 'candidats': candidats}
 | 
				
			||||||
            listes_json.append(liste_json)
 | 
					            listes_json.append(liste_json)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        file = DATA_DIR / "resultats" / "europeennes2024" / "listes.json"
 | 
					        file = DATA_DIR / "resultats" / "europeennes" / "2024" / "listes.json"
 | 
				
			||||||
        if not file.parent.is_dir():
 | 
					        if not file.parent.is_dir():
 | 
				
			||||||
            file.parent.mkdir(parents=True)
 | 
					            file.parent.mkdir(parents=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -88,11 +88,11 @@ def exporter_resultats_france(engine: Engine, verbose: bool = False) -> None:
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        resultats_listes = {}
 | 
					        resultats_listes = {}
 | 
				
			||||||
        resultats_dict['voix_listes'] = resultats_listes
 | 
					        resultats_dict['voix'] = resultats_listes
 | 
				
			||||||
        for voix_liste in resultats_france.voix_listes:
 | 
					        for voix_liste in resultats_france.voix_listes:
 | 
				
			||||||
            resultats_listes[voix_liste.liste.numero] = voix_liste.voix
 | 
					            resultats_listes[voix_liste.liste.numero] = voix_liste.voix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        file = DATA_DIR / "resultats" / "europeennes2024" / "france.json"
 | 
					        file = DATA_DIR / "resultats" / "europeennes" / "2024" / "france.json"
 | 
				
			||||||
        if not file.parent.is_dir():
 | 
					        if not file.parent.is_dir():
 | 
				
			||||||
            file.parent.mkdir(parents=True)
 | 
					            file.parent.mkdir(parents=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -136,11 +136,11 @@ def exporter_resultats_regions(engine: Engine, verbose: bool = False) -> None:
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            resultats_listes = {}
 | 
					            resultats_listes = {}
 | 
				
			||||||
            resultats_dict['voix_listes'] = resultats_listes
 | 
					            resultats_dict['voix'] = resultats_listes
 | 
				
			||||||
            for voix_liste in resultats_region.voix_listes:
 | 
					            for voix_liste in resultats_region.voix_listes:
 | 
				
			||||||
                resultats_listes[voix_liste.liste.numero] = voix_liste.voix
 | 
					                resultats_listes[voix_liste.liste.numero] = voix_liste.voix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            file = DATA_DIR / "resultats" / "europeennes2024" / "region" / f"{region.code_insee}.json"
 | 
					            file = DATA_DIR / "resultats" / "europeennes" / "2024" / "region" / f"{region.code_insee}.json"
 | 
				
			||||||
            if not file.parent.is_dir():
 | 
					            if not file.parent.is_dir():
 | 
				
			||||||
                file.parent.mkdir(parents=True)
 | 
					                file.parent.mkdir(parents=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -149,7 +149,7 @@ def exporter_resultats_regions(engine: Engine, verbose: bool = False) -> None:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        session.commit()
 | 
					        session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    regions_file = DATA_DIR / "resultats" / "europeennes2024" / "region" / "regions.json"
 | 
					    regions_file = DATA_DIR / "resultats" / "europeennes" / "2024" / "region" / "regions.json"
 | 
				
			||||||
    if not regions_file.parent.is_dir():
 | 
					    if not regions_file.parent.is_dir():
 | 
				
			||||||
        regions_file.parent.mkdir(parents=True)
 | 
					        regions_file.parent.mkdir(parents=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -191,11 +191,11 @@ def exporter_resultats_departements(engine: Engine, verbose: bool = False) -> No
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            resultats_listes = {}
 | 
					            resultats_listes = {}
 | 
				
			||||||
            resultats_dict['voix_listes'] = resultats_listes
 | 
					            resultats_dict['voix'] = resultats_listes
 | 
				
			||||||
            for voix_liste in resultats_departement.voix_listes:
 | 
					            for voix_liste in resultats_departement.voix_listes:
 | 
				
			||||||
                resultats_listes[voix_liste.liste.numero] = voix_liste.voix
 | 
					                resultats_listes[voix_liste.liste.numero] = voix_liste.voix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            file = DATA_DIR / "resultats" / "europeennes2024" / "departement" / f"{departement.code_insee}.json"
 | 
					            file = DATA_DIR / "resultats" / "europeennes" / "2024" / "departement" / f"{departement.code_insee}.json"
 | 
				
			||||||
            if not file.parent.is_dir():
 | 
					            if not file.parent.is_dir():
 | 
				
			||||||
                file.parent.mkdir(parents=True)
 | 
					                file.parent.mkdir(parents=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -204,7 +204,7 @@ def exporter_resultats_departements(engine: Engine, verbose: bool = False) -> No
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        session.commit()
 | 
					        session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    departements_file = DATA_DIR / "resultats" / "europeennes2024" / "departement" / "departements.json"
 | 
					    departements_file = DATA_DIR / "resultats" / "europeennes" / "2024" / "departement" / "departements.json"
 | 
				
			||||||
    if not departements_file.parent.is_dir():
 | 
					    if not departements_file.parent.is_dir():
 | 
				
			||||||
        departements_file.parent.mkdir(parents=True)
 | 
					        departements_file.parent.mkdir(parents=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -245,11 +245,11 @@ def exporter_resultats_circonscriptions(engine: Engine, verbose: bool = False) -
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            resultats_listes = {}
 | 
					            resultats_listes = {}
 | 
				
			||||||
            resultats_dict['voix_listes'] = resultats_listes
 | 
					            resultats_dict['voix'] = resultats_listes
 | 
				
			||||||
            for voix_liste in resultats_circonscription.voix_listes:
 | 
					            for voix_liste in resultats_circonscription.voix_listes:
 | 
				
			||||||
                resultats_listes[voix_liste.liste.numero] = voix_liste.voix
 | 
					                resultats_listes[voix_liste.liste.numero] = voix_liste.voix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            file = DATA_DIR / "resultats" / "europeennes2024" / "circonscription" / f"{circonscription.id}.json"
 | 
					            file = DATA_DIR / "resultats" / "europeennes" / "2024" / "circonscription" / f"{circonscription.id}.json"
 | 
				
			||||||
            if not file.parent.is_dir():
 | 
					            if not file.parent.is_dir():
 | 
				
			||||||
                file.parent.mkdir(parents=True)
 | 
					                file.parent.mkdir(parents=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -258,7 +258,8 @@ def exporter_resultats_circonscriptions(engine: Engine, verbose: bool = False) -
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        session.commit()
 | 
					        session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    circonscriptions_file = DATA_DIR / "resultats" / "europeennes2024" / "circonscription" / "circonscriptions.json"
 | 
					    circonscriptions_file = (DATA_DIR / "resultats" / "europeennes" / "2024"
 | 
				
			||||||
 | 
					                             / "circonscription" / "circonscriptions.json")
 | 
				
			||||||
    if not circonscriptions_file.parent.is_dir():
 | 
					    if not circonscriptions_file.parent.is_dir():
 | 
				
			||||||
        circonscriptions_file.parent.mkdir(parents=True)
 | 
					        circonscriptions_file.parent.mkdir(parents=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -299,11 +300,11 @@ def exporter_resultats_communes(engine: Engine, verbose: bool = False) -> None:
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            resultats_listes = {}
 | 
					            resultats_listes = {}
 | 
				
			||||||
            resultats_dict['voix_listes'] = resultats_listes
 | 
					            resultats_dict['voix'] = resultats_listes
 | 
				
			||||||
            for voix_liste in resultats_commune.voix_listes:
 | 
					            for voix_liste in resultats_commune.voix_listes:
 | 
				
			||||||
                resultats_listes[voix_liste.liste.numero] = voix_liste.voix
 | 
					                resultats_listes[voix_liste.liste.numero] = voix_liste.voix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            file = DATA_DIR / "resultats" / "europeennes2024" / "commune" / f"{commune.code_insee}.json"
 | 
					            file = DATA_DIR / "resultats" / "europeennes" / "2024" / "commune" / f"{commune.code_insee}.json"
 | 
				
			||||||
            if not file.parent.is_dir():
 | 
					            if not file.parent.is_dir():
 | 
				
			||||||
                file.parent.mkdir(parents=True)
 | 
					                file.parent.mkdir(parents=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -312,7 +313,7 @@ def exporter_resultats_communes(engine: Engine, verbose: bool = False) -> None:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        session.commit()
 | 
					        session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    communes_file = DATA_DIR / "resultats" / "europeennes2024" / "commune" / "communes.json"
 | 
					    communes_file = DATA_DIR / "resultats" / "europeennes" / "2024" / "commune" / "communes.json"
 | 
				
			||||||
    if not communes_file.parent.is_dir():
 | 
					    if not communes_file.parent.is_dir():
 | 
				
			||||||
        communes_file.parent.mkdir(parents=True)
 | 
					        communes_file.parent.mkdir(parents=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -354,11 +355,11 @@ def exporter_resultats_bureaux_vote(engine: Engine, verbose: bool = False) -> No
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            resultats_listes = {}
 | 
					            resultats_listes = {}
 | 
				
			||||||
            resultats_dict['voix_listes'] = resultats_listes
 | 
					            resultats_dict['voix'] = resultats_listes
 | 
				
			||||||
            for voix_liste in resultats_bureau_vote.voix_listes:
 | 
					            for voix_liste in resultats_bureau_vote.voix_listes:
 | 
				
			||||||
                resultats_listes[voix_liste.liste.numero] = voix_liste.voix
 | 
					                resultats_listes[voix_liste.liste.numero] = voix_liste.voix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            file = DATA_DIR / "resultats" / "europeennes2024" / "bureau_vote" / f"{bureau_vote.id}.json"
 | 
					            file = DATA_DIR / "resultats" / "europeennes" / "2024" / "bureau_vote" / f"{bureau_vote.id}.json"
 | 
				
			||||||
            if not file.parent.is_dir():
 | 
					            if not file.parent.is_dir():
 | 
				
			||||||
                file.parent.mkdir(parents=True)
 | 
					                file.parent.mkdir(parents=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -367,7 +368,7 @@ def exporter_resultats_bureaux_vote(engine: Engine, verbose: bool = False) -> No
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        session.commit()
 | 
					        session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bureaux_vote_file = DATA_DIR / "resultats" / "europeennes2024" / "bureau_vote" / "bureaux_vote.json"
 | 
					    bureaux_vote_file = DATA_DIR / "resultats" / "europeennes" / "2024" / "bureau_vote" / "bureaux_vote.json"
 | 
				
			||||||
    if not bureaux_vote_file.parent.is_dir():
 | 
					    if not bureaux_vote_file.parent.is_dir():
 | 
				
			||||||
        bureaux_vote_file.parent.mkdir(parents=True)
 | 
					        bureaux_vote_file.parent.mkdir(parents=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user