Select Git revision
FranceMap.jsx
-
Besson Lucas authoredBesson Lucas authored
FranceMap.jsx 4.87 KiB
import { useEffect, useState, useRef } from "react";
import PropTypes from "prop-types";
import axios from "axios";
import * as d3 from "d3";
const FranceMap = ({ typeIndic = "indicateurs" }) => {
if (typeof typeIndic !== "string") {
console.error("typeIndic doit être une chaîne de caractères, reçu :", typeIndic);
typeIndic = "indicateurs"; // Valeur par défaut
}
console.log("typeIndic reçu :", typeIndic);
const [geoData, setGeoData] = useState(null);
const [deptColors, setDeptColors] = useState({});
const [deptAverages, setDeptAverages] = useState({});
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
const [selectedDept, setSelectedDept] = useState(null);
const svgRef = useRef();
const containerRef = useRef();
// Charger les données GeoJSON
useEffect(() => {
console.log("url : ", "http://localhost:5000/api/" + typeIndic);
axios
.get("/France_dep.geojson")
.then((res) => {
setGeoData(res.data.features);
})
.catch((err) => console.error("Erreur lors du chargement du GeoJSON :", err));
// Charger les couleurs depuis l'API backend
axios.get("http://localhost:5000/api/" + typeIndic)
.then((res) => {
console.log("Couleurs reçues du backend :", res.data.colors);
setDeptColors(res.data.colors);
console.log("Moyennes reçues du backend :", res.data.averages);
setDeptAverages(res.data.averages);
})
.catch((err) => console.error("Erreur lors du chargement des couleurs :", err));
}, [typeIndic]);
// Calculer la taille du conteneur parent et mettre à jour les dimensions
useEffect(() => {
const updateDimensions = () => {
const { clientWidth, clientHeight } = containerRef.current;
setDimensions({
width: clientWidth * 0.75,
height: clientHeight * 0.75,
});
};
updateDimensions();
window.addEventListener("resize", updateDimensions);
return () => window.removeEventListener("resize", updateDimensions);
}, []);
// Mettre à jour la carte avec les nouvelles dimensions et couleurs
useEffect(() => {
if (!geoData || dimensions.width === 0 || dimensions.height === 0) return;
const svg = d3.select(svgRef.current)
.attr("width", dimensions.width)
.attr("height", dimensions.height);
const projection = d3.geoMercator()
.fitSize([dimensions.width, dimensions.height], { type: "FeatureCollection", features: geoData });
const pathGenerator = d3.geoPath().projection(projection);
const tooltip = d3.select("#tooltip");
svg.selectAll("path")
.data(geoData)
.join("path")
.attr("d", pathGenerator)
.attr("stroke", "black")
.attr("fill", d => deptColors[d.properties.code] || "lightgray")
.attr("opacity", 0.8)
.on("click", function (event, d) {
if (d && d.properties) {
console.log(`Département sélectionné : ${d.properties.nom} (${d.properties.code})`);
setSelectedDept(d);
} else {
console.error("Données du département manquantes ou mal formatées", d);
}
})
.on("mouseover", function (event, d) {
// Diminuer l'opacité des autres départements (50%)
svg.selectAll("path")
.attr("opacity", (dept) => dept.properties.code === d.properties.code || dept === selectedDept ? 1 : 0.25);
tooltip.style("display", "block")
.html(`<strong>${d.properties.nom} (${d.properties.code})</strong><br>Score moyen : ${deptAverages[d.properties.code] || "N/A"}`)
.style("left", event.pageX + 3 + "px")
.style("top", event.pageY + 3 + "px");
})
.on("mousemove", function (event) {
tooltip.style("left", event.pageX -185 + "px")
.style("top", event.pageY -50 + "px");
})
.on("mouseout", function () {
// Rétablir l'opacité à 100% pour tous les départements
svg.selectAll("path")
.attr("opacity", 1);
tooltip.style("display", "none");
})
.attr("fill", (d) => {
if (selectedDept && selectedDept.properties.code === d.properties.code) {
return "red"; // Couleur pour le département sélectionné
}
return deptColors[d.properties.code] || "lightgray";
});
}, [geoData, deptColors, dimensions, selectedDept, deptAverages]);
return (
<div ref={containerRef} style={{ position: "relative", width: "100%", height: "100%", display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center" }}>
<h1 style={{ textAlign: "center", fontSize: "2em" }}>Carte de France</h1>
<svg ref={svgRef}></svg>
<div id="tooltip" style={{ position: "absolute", background: "white", padding: "5px", borderRadius: "5px", border: "1px solid black", display: "none" }}></div>
</div>
);
};
FranceMap.propTypes = {
typeIndic: PropTypes.string,
};
export default FranceMap;