Skip to content
Snippets Groups Projects
Commit 45320303 authored by Aymeric Chaumont's avatar Aymeric Chaumont
Browse files

improve graph display & add avg graph

parent 1e77bfaf
No related branches found
No related tags found
1 merge request!38graph rework
...@@ -105,11 +105,11 @@ def get_avg_graph(place: str, db: Session): ...@@ -105,11 +105,11 @@ def get_avg_graph(place: str, db: Session):
weekday, current_time = current_date.weekday(), current_date.time() weekday, current_time = current_date.weekday(), current_date.time()
first_timeslot = get_timeslot(place, weekday, True, db) first_timeslot = get_timeslot(place, weekday, True, db)
if first_timeslot and current_time <= first_timeslot[1]: if first_timeslot and current_time <= first_timeslot[1]:
return get_avg_graph_points(place, weekday, first_timeslot[0], first_timeslot[1], timedelta(minutes=5), db), first_timeslot[0], first_timeslot[1] return get_avg_graph_points(place, weekday, first_timeslot[0], first_timeslot[1], timedelta(minutes=5), db)
second_timeslot = get_timeslot(place, weekday, False, db) second_timeslot = get_timeslot(place, weekday, False, db)
if second_timeslot and current_time <= second_timeslot[1]: if second_timeslot and current_time <= second_timeslot[1]:
return get_avg_graph_points(place, weekday, second_timeslot[0], second_timeslot[1], timedelta(minutes=5), db), second_timeslot[0], second_timeslot[1] return get_avg_graph_points(place, weekday, second_timeslot[0], second_timeslot[1], timedelta(minutes=5), db)
return [], None, None return []
def get_current_graph_points(place: str, current_date: date, min_time: time, max_time: time, interval: timedelta, db: Session): def get_current_graph_points(place: str, current_date: date, min_time: time, max_time: time, interval: timedelta, db: Session):
...@@ -173,7 +173,7 @@ def get_current_graph(place: str, db: Session): ...@@ -173,7 +173,7 @@ def get_current_graph(place: str, db: Session):
if second_timeslot and current_time <= second_timeslot[0]: if second_timeslot and current_time <= second_timeslot[0]:
return [], None, None return [], None, None
elif second_timeslot and current_time <= second_timeslot[1]: elif second_timeslot and current_time <= second_timeslot[1]:
points = get_current_graph_points(place, day, second_timeslot[0], current_time, timedelta(minutes=5), db), second_timeslot[0], second_timeslot[1] points = get_current_graph_points(place, day, second_timeslot[0], current_time, timedelta(minutes=5), db)
start_time = 60 * second_timeslot[0].hour + second_timeslot[0].minute start_time = 60 * second_timeslot[0].hour + second_timeslot[0].minute
end_time = 60 * second_timeslot[1].hour + second_timeslot[1].minute end_time = 60 * second_timeslot[1].hour + second_timeslot[1].minute
return points, start_time, end_time return points, start_time, end_time
......
...@@ -14,7 +14,7 @@ async def waiting_time(place: str, db: Session = Depends(get_db)): ...@@ -14,7 +14,7 @@ async def waiting_time(place: str, db: Session = Depends(get_db)):
return crud.get_waiting_time(place, db) return crud.get_waiting_time(place, db)
@router.get('/{place}/stats/avg_graph', response_model=Tuple[list, int, int]) @router.get('/{place}/stats/avg_graph', response_model=list)
async def stats(place: str, db: Session = Depends(get_db)): async def stats(place: str, db: Session = Depends(get_db)):
return crud.get_avg_graph(place, db) return crud.get_avg_graph(place, db)
......
import React from "react"; import React from "react";
import axios from "axios"; import axios from "axios";
import { import {
AreaChart, Line,
Area, Area,
XAxis, XAxis,
YAxis, YAxis,
CartesianGrid, CartesianGrid,
Tooltip, Tooltip,
ResponsiveContainer, ResponsiveContainer,
ComposedChart,
} from "recharts"; } from "recharts";
import ToggleButton from "react-bootstrap/ToggleButton";
import "../styles/Graph.css"; import "../styles/Graph.css";
const CustomTooltip = ({ active, payload }) => { const CustomTooltip = ({ active, payload, label }) => {
return ( return (
<> <>
{active && payload && payload.length && ( {active && payload && payload.length && (
<div className="custom-tooltip"> <div className="custom-tooltip">
<p className="label">{`${formatXAxis(label)}`}</p>
<p className="label">{`Temps d'attente : ${payload[0].value} minutes`}</p> <p className="label">{`Temps d'attente : ${payload[0].value} minutes`}</p>
</div> </div>
)} )}
...@@ -24,40 +27,60 @@ const CustomTooltip = ({ active, payload }) => { ...@@ -24,40 +27,60 @@ const CustomTooltip = ({ active, payload }) => {
}; };
function formatXAxis(value) { function formatXAxis(value) {
if (value == 0) return "";
return Math.floor(value / 60).toString() + "h" + (value % 60).toString().padStart(2, "0"); return Math.floor(value / 60).toString() + "h" + (value % 60).toString().padStart(2, "0");
} }
export default function Graph({ place, type }) { export default function Graph({ place }) {
const [data, setData] = React.useState([]); const [checked, setChecked] = React.useState(false);
const [currentData, setCurrentData] = React.useState([[], 0, 0]);
React.useEffect(() => { React.useEffect(() => {
axios axios
.get( .get(
`${process.env.REACT_APP_BASE_URL_BACK}/${encodeURIComponent( `${process.env.REACT_APP_BASE_URL_BACK}/${encodeURIComponent(place)}/stats/current_graph`,
place,
)}/stats/${encodeURIComponent(type)}_graph`,
) )
.then((response) => { .then((response) => {
setData(response.data[0]); setCurrentData(response.data);
});
}, []);
const [avgData, setAvgData] = React.useState([[], 0, 0]);
React.useEffect(() => {
axios
.get(`${process.env.REACT_APP_BASE_URL_BACK}/${encodeURIComponent(place)}/stats/avg_graph`)
.then((response) => {
setAvgData(response.data);
}); });
}, []); }, []);
console.log(data[0]);
return ( return (
<> <>
{!!data.length && ( {!!currentData[0].length && (
<div style={{ height: "60%", padding: "3rem" }}> <div style={{ height: "60%", padding: "3rem" }}>
<div className="graph"> <div className="graph">
<ResponsiveContainer width="100%" height="100%"> <ResponsiveContainer width="100%" height="100%">
<AreaChart <ComposedChart
data={data}
margin={{ margin={{
top: 5, top: 5,
right: 30, right: 30,
left: 20, left: -10,
bottom: 5, bottom: 5,
}} }}
> >
{checked ? (
<Line
data={avgData}
type="monotone"
dataKey="time"
stroke="#FF0000"
strokeWidth={2}
dot={{ stroke: "#FF0000", strokeWidth: 2, fill: "#fff" }}
/>
) : (
<div />
)}
<defs> <defs>
<linearGradient id="colorGradient" x1="0" y1="0" x2="0" y2="1"> <linearGradient id="colorGradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="10%" stopColor="#ff0000" stopOpacity={0.55} /> <stop offset="10%" stopColor="#ff0000" stopOpacity={0.55} />
...@@ -72,36 +95,53 @@ export default function Graph({ place, type }) { ...@@ -72,36 +95,53 @@ export default function Graph({ place, type }) {
tick={{ fill: "#FFFFFF", fontSize: "18" }} tick={{ fill: "#FFFFFF", fontSize: "18" }}
dataKey="name" dataKey="name"
type="number" type="number"
domain={[840, 1020]} interval="preserveStartEnd"
domain={[currentData[1], currentData[2]]}
tickFormatter={formatXAxis} tickFormatter={formatXAxis}
/> />
<YAxis <YAxis
axisLine={false} axisLine={false}
tickLine={false} tickLine={false}
tick={{ fill: "#FFFFFF", fontSize: "18" }} tick={{ fill: "#FFFFFF", fontSize: "18" }}
/*tickInt*/ tickInt
tickCount={10} tickCount={10}
dataKey="time" dataKey="time"
type="number" type="number"
domain={[0, 50]} domain={[0, (dataMax) => 10 * Math.floor((dataMax + 10) / 10)]}
/*domain={[0, (dataMax) => 10 * Math.floor((dataMax + 10) / 10)]}*/
allowDecimals={false} allowDecimals={false}
name="Temps d'attente" name="Temps d'attente"
/> />
<Tooltip content={<CustomTooltip />} /> <Tooltip content={<CustomTooltip />} />
<Area <Area
data={currentData[0]}
type="monotone" type="monotone"
dataKey="time" dataKey="time"
stroke="#FFFFFF" stroke="#FFFFFF"
strokeWidth={1} strokeWidth={2}
fillOpacity={1} fillOpacity={1}
fill="url(#colorGradient)" fill="url(#colorGradient)"
dot={{ stroke: "#0967D2", strokeWidth: 2, fill: "#fff" }} dot={{ stroke: "#0967D2", strokeWidth: 2, fill: "#fff" }}
/> />
</AreaChart> </ComposedChart>
</ResponsiveContainer> </ResponsiveContainer>
</div> </div>
<div className="graph-title">Temps d&apos;attente estimé depuis l&apos;ouverture</div> <div className="graph-title">
Temps d&apos;attente estimé depuis l&apos;ouverture (en minutes)
</div>
<div className="graph-button">
<ToggleButton
id="toggle-check"
type="checkbox"
variant="primary"
checked={checked}
value="0"
onChange={() => setChecked(!checked)}
>
{checked
? "Retirer le temps d'attente moyen pour ce créneau"
: "Afficher le temps d'attente moyen pour ce créneau"}
</ToggleButton>
</div>
</div> </div>
)} )}
</> </>
......
...@@ -8,3 +8,7 @@ ...@@ -8,3 +8,7 @@
width: 100%; width: 100%;
display: inline-block; display: inline-block;
} }
.graph-button{
margin-top: 10px;
}
\ 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