All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m46s
169 lines
6.0 KiB
JavaScript
169 lines
6.0 KiB
JavaScript
import {Area, AreaChart, CartesianGrid, Cell, Pie, PieChart, ResponsiveContainer, Sector, Tooltip, XAxis, YAxis} from "recharts";
|
|
import {useEffect, useState} from "react";
|
|
import {getSaison} from "../../utils/Tools.js";
|
|
|
|
export default function StatsLazy({data}) {
|
|
return <div className="container">
|
|
<div className="row" style={{marginTop: "2em"}}>
|
|
<h3>Nombre de licences</h3>
|
|
<div className="col-lg-8" style={{margin: "auto"}}>
|
|
<div style={{width: '100%', aspectRatio: 1.5}}>
|
|
<NbGraph raw_data={data}/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="row" style={{marginTop: "3em"}}>
|
|
<h3>Nombre de licences par catégorie pour {getSaison()}</h3>
|
|
<div className="col-lg-8" style={{margin: "auto"}}>
|
|
<div style={{width: '100%', aspectRatio: 1.5}}>
|
|
<CatGraph raw_data={data}/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
function NbGraph({raw_data}) {
|
|
const [showData, setShowData] = useState([])
|
|
|
|
useEffect(() => {
|
|
const data = []
|
|
for (const k in raw_data.licences) {
|
|
data.push({
|
|
name: k + "-" + (parseInt(k) + 1),
|
|
h: raw_data.licences[k].h,
|
|
f: raw_data.licences[k].f,
|
|
na: raw_data.licences[k].na,
|
|
not_valid: raw_data.licences[k].not_valid,
|
|
})
|
|
}
|
|
setShowData(data)
|
|
}, [raw_data])
|
|
|
|
const colors = ['#6e6e6e', '#1a07f8', '#f659d5', '#f80000']
|
|
|
|
return <ResponsiveContainer>
|
|
<AreaChart
|
|
width={500}
|
|
height={400}
|
|
data={showData}
|
|
margin={{
|
|
top: 10,
|
|
right: 30,
|
|
left: 0,
|
|
bottom: 0,
|
|
}}>
|
|
<CartesianGrid strokeDasharray="3 3"/>
|
|
<XAxis dataKey="name"/>
|
|
<YAxis/>
|
|
<Tooltip/>
|
|
<Area type="monotone" dataKey="na" name="Non définie" stackId="1" stroke={colors[0]} fill={colors[0]}/>
|
|
<Area type="monotone" dataKey="h" name="Homme" stackId="1" stroke={colors[1]} fill={colors[1]}/>
|
|
<Area type="monotone" dataKey="f" name="Femme" stackId="1" stroke={colors[2]} fill={colors[2]}/>
|
|
<Area type="monotone" dataKey="not_valid" name="Non validée" stackId="2" stroke={colors[3]} fill={colors[3]} strokeDasharray="5 5"
|
|
fillOpacity="30%"/>
|
|
</AreaChart>
|
|
</ResponsiveContainer>
|
|
}
|
|
|
|
function CatGraph({raw_data}) {
|
|
const [showData, setShowData] = useState([])
|
|
const [activeIndex, setActiveIndex] = useState(0)
|
|
|
|
|
|
useEffect(() => {
|
|
const data = []
|
|
for (const k of raw_data.categories) {
|
|
data.push({
|
|
name: k.name,
|
|
value: k.count + 1,
|
|
})
|
|
}
|
|
setShowData(data)
|
|
}, [raw_data])
|
|
|
|
const COLORS = ['#ffff99', '#a6cee3', '#1f78b4', '#b2df8a'
|
|
, '#33a02c', '#fb9a99', '#e31a1c', '#fdbf6f'
|
|
, '#ff7f00', '#cab2d6', '#6a3d9a'];
|
|
|
|
const RADIAN = Math.PI / 180;
|
|
const renderCustomizedLabel = ({cx, cy, midAngle, innerRadius, outerRadius, index}) => {
|
|
const radius = innerRadius + (outerRadius - innerRadius) * 0.6;
|
|
const x = cx + radius * Math.cos(-midAngle * RADIAN);
|
|
const y = cy + radius * Math.sin(-midAngle * RADIAN);
|
|
|
|
return <> {
|
|
showData[index]['value'] > 0 &&
|
|
<text x={x} y={y} fill={(index === 2 || index === 6 || index === 10) ? "white" : "black"} textAnchor="middle" dominantBaseline="central">
|
|
{`${showData[index]['name']}`}
|
|
</text>
|
|
|
|
}</>;
|
|
};
|
|
|
|
const onPieEnter = (_, index) => {
|
|
setActiveIndex(index);
|
|
};
|
|
|
|
const renderActiveShape = (props) => {
|
|
const RADIAN = Math.PI / 180;
|
|
const {cx, cy, midAngle, innerRadius, outerRadius, startAngle, endAngle, fill, payload, percent, value} = props;
|
|
const sin = Math.sin(-RADIAN * midAngle);
|
|
const cos = Math.cos(-RADIAN * midAngle);
|
|
const sx = cx + (outerRadius + 10) * cos;
|
|
const sy = cy + (outerRadius + 10) * sin;
|
|
const mx = cx + (outerRadius + 30) * cos;
|
|
const my = cy + (outerRadius + 30) * sin;
|
|
const ex = mx + (cos >= 0 ? 1 : -1) * 22;
|
|
const ey = my;
|
|
const textAnchor = cos >= 0 ? 'start' : 'end';
|
|
|
|
return <g>
|
|
<Sector
|
|
cx={cx}
|
|
cy={cy}
|
|
innerRadius={innerRadius}
|
|
outerRadius={outerRadius}
|
|
startAngle={startAngle}
|
|
endAngle={endAngle}
|
|
fill={fill}
|
|
/>
|
|
<Sector
|
|
cx={cx}
|
|
cy={cy}
|
|
startAngle={startAngle}
|
|
endAngle={endAngle}
|
|
innerRadius={outerRadius + 6}
|
|
outerRadius={outerRadius + 10}
|
|
fill={fill}
|
|
/>
|
|
<path d={`M${sx},${sy}L${mx},${my}L${ex},${ey}`} stroke={fill} fill="none"/>
|
|
<circle cx={ex} cy={ey} r={2} fill={fill} stroke="none"/>
|
|
<text x={ex + (cos >= 0 ? 1 : -1) * 12} y={ey} textAnchor={textAnchor} fill="#333">{`${payload.name}`}</text>
|
|
<text x={ex + (cos >= 0 ? 1 : -1) * 12} y={ey} dy={18} textAnchor={textAnchor} fill="#999">
|
|
{`${value} (${(percent * 100).toFixed(0)}%)`}
|
|
</text>
|
|
</g>;
|
|
};
|
|
|
|
return <ResponsiveContainer>
|
|
<PieChart>
|
|
<Pie
|
|
activeIndex={activeIndex}
|
|
activeShape={renderActiveShape}
|
|
data={showData}
|
|
labelLine={false}
|
|
label={renderCustomizedLabel}
|
|
outerRadius="80%"
|
|
fill="#8884d8"
|
|
dataKey="value"
|
|
|
|
onMouseEnter={onPieEnter}>
|
|
{showData.map((entry, index) => (
|
|
<Cell key={`cell-${index}`} fill={COLORS[(index) % COLORS.length]}/>
|
|
))}
|
|
</Pie>
|
|
</PieChart>
|
|
</ResponsiveContainer>
|
|
}
|