Skip to content
Snippets Groups Projects
Commit bf2cc48a authored by Besson Lucas's avatar Besson Lucas
Browse files

Add a menu and metrics

parent b29df385
No related branches found
No related tags found
No related merge requests found
import FranceMap from './components/FranceMap'; import FranceMap from './components/FranceMap';
import MetricsComponent from "./components/MetricsComponent";
// Composant des metrics à droite import TitleWithSearchComponent from "./components/UpBar";
const MetricsComponent = () => {
return (
<div style={{ backgroundColor: 'lightblue', padding: '20px', height: '100%' }}>
<h2 style={{ textAlign: "center" }}>Graphiques du département</h2>
</div>
);
};
// Composant principal // Composant principal
const App = () => { const App = () => {
return ( return (
<div style={{ display: 'flex', flexDirection: 'row', height: '100vh', margin: 0, boxSizing: 'border-box' }}> <div>
<TitleWithSearchComponent />
<div style={{ display: 'flex', flexDirection: 'row', height: '100vh', margin: 0, boxSizing: 'border-box', maxHeight: '85.3vh' }}>
{/* Partie gauche - Carte */} {/* Partie gauche - Carte */}
<div style={{ flex: 2, minWidth: '320px', height: '100%' }}> <div style={{ flex: 2, minWidth: '320px', height: '100%' }}>
<FranceMap /> <FranceMap />
...@@ -23,7 +18,7 @@ const App = () => { ...@@ -23,7 +18,7 @@ const App = () => {
<MetricsComponent /> <MetricsComponent />
</div> </div>
</div> </div>
</div>
); );
}; }
export default App; export default App;
import PropTypes from "prop-types";
import MetricsGraph from "./MetricsGraph";
// Composant représentant un bloc de métrique
const MetricBlock = ({ title, children }) => {
return (
<div style={{
backgroundColor: "white",
padding: "20px",
margin: "10px",
borderRadius: "8px",
boxShadow: "0 2px 5px rgba(0,0,0,0.1)"
}}>
<h3 style={{ marginBottom: "10px", textAlign: "center" }}>{title}</h3>
{children}
</div>
);
};
// Composant contenant plusieurs métriques
const MetricsComponent = () => {
return (
<div style={{
backgroundColor: "lightblue",
padding: "20px",
height: "100%",
maxHeight: "100vh",
overflowY: "auto",
display: "flex",
flexDirection: "column"
}}>
<MetricBlock title="Métrique 1">
<p>Valeur: 42</p>
</MetricBlock>
<MetricBlock title="Métrique 2">
<p>Valeur: 87</p>
</MetricBlock>
<MetricBlock title="Métrique 3">
<MetricsGraph />
</MetricBlock>
</div>
);
};
MetricBlock.propTypes = {
title: PropTypes.string.isRequired,
children: PropTypes.node
};
export default MetricsComponent;
import { useEffect, useRef } from "react";
import * as d3 from "d3";
const MetricsGraph = () => {
const svgRef = useRef();
useEffect(() => {
const svg = d3.select(svgRef.current);
const width = svg.node().parentNode.clientWidth;
const height = svg.node().parentNode.clientHeight || 300;
const margin = { top: 20, right: 30, bottom: 40, left: 50 };
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
svg.attr("viewBox", `0 0 ${width} ${height}`)
.attr("preserveAspectRatio", "xMidYMid meet");
// Données simulées
const data = [10, 25, 40, 60, 80, 100];
// Scales
const xScale = d3.scaleLinear().domain([0, data.length - 1]).range([0, innerWidth]);
const yScale = d3.scaleLinear().domain([0, 100]).range([innerHeight, 0]);
// Nettoyer avant de redessiner
svg.selectAll("*").remove();
// Groupe principal pour padding
const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
// Axe X
g.append("g")
.attr("transform", `translate(0,${innerHeight})`)
.call(d3.axisBottom(xScale).ticks(data.length).tickFormat(d => d + 1))
.selectAll("text")
.style("font-size", "12px");
// Axe Y
g.append("g")
.call(d3.axisLeft(yScale))
.selectAll("text")
.style("font-size", "12px");
// Ligne reliant les points
const line = d3.line()
.x((_, i) => xScale(i))
.y(d => yScale(d))
.curve(d3.curveMonotoneX);
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#007bff")
.attr("stroke-width", 2)
.attr("d", line);
// Points
g.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", (_, i) => xScale(i))
.attr("cy", d => yScale(d))
.attr("r", 6)
.attr("fill", "#007bff")
.attr("stroke", "white")
.attr("stroke-width", 2);
}, []);
return <svg ref={svgRef} style={{ width: "100%", height: "100%" }}></svg>;
};
export default MetricsGraph;
const TitleWithSearchComponent = () => {
return (
<div style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
padding: '10px 20px',
backgroundColor: '#1c49ba',
color: 'white',
fontFamily: 'Arial, sans-serif',
borderBottom: '3px solid #ddd',
}}>
{/* Titre */}
<h1 style={{
margin: 0,
fontSize: '1.8rem',
fontWeight: 'bold',
}}>Dashboard France</h1>
{/* Barre de recherche */}
<div style={{
display: 'flex',
alignItems: 'center',
backgroundColor: 'white',
borderRadius: '25px',
padding: '5px 15px',
width: '350px',
boxShadow: '0 2px 5px rgba(0, 0, 0, 0.1)'
}}>
<input
type="text"
placeholder="Rechercher..."
style={{
border: 'none',
outline: 'none',
flex: 1,
padding: '8px',
fontSize: '1rem',
borderRadius: '25px',
marginRight: '10px'
}}
/>
<button style={{
backgroundColor: '#1c49ba',
border: 'none',
color: 'white',
padding: '8px 15px',
fontSize: '1rem',
borderRadius: '25px',
cursor: 'pointer'
}}>
Rechercher
</button>
</div>
</div>
);
};
export default TitleWithSearchComponent;
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment