-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Supprime l'ancien composant IndicateurCard
- Loading branch information
Showing
6 changed files
with
83 additions
and
244 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
200 changes: 75 additions & 125 deletions
200
...oiresentransitions.react/src/app/pages/collectivite/Indicateurs/chart/IndicateurChart.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,157 +1,107 @@ | ||
import { CustomLayerProps } from '@nivo/line'; | ||
import classNames from 'classnames'; | ||
|
||
import { SliceTooltip } from '@/app/app/pages/collectivite/Indicateurs/chart/SliceTooltip'; | ||
import Chart, { ChartInfosProps } from '@/app/ui/charts/Chart'; | ||
import { LineChartProps } from '@/app/ui/charts/Line/LineChart'; | ||
import PictoIndicateurVide from '@/app/ui/pictogrammes/PictoIndicateurVide'; | ||
import { | ||
LAYERS, | ||
ReactECharts, | ||
makeLineSeries, | ||
makeOption, | ||
} from '@/app/ui/charts/echarts'; | ||
import SpinnerLoader from '@/app/ui/shared/SpinnerLoader'; | ||
import { TIndicateurValeur } from '../useIndicateurValeurs'; | ||
import { getXTickValues, indicateurBaseData, prepareData } from './utils'; | ||
|
||
/** Data issues de l'api pour générer les données formatées pour Nivo */ | ||
/** Data issues de l'api pour générer les données formatées pour echarts */ | ||
/** TODO: le format devra être revu après la refonte indicateurs et la maj du fetch */ | ||
export type IndicateurChartData = { | ||
/** Unité affichée pour l'axe des abscisses et le tooltip */ | ||
unite?: string; | ||
/** Valeurs d'un indicateur issues de l'API */ | ||
valeurs: TIndicateurValeur[]; | ||
/** Valeurs de l'indicateur */ | ||
valeurs: { | ||
objectifs: TIndicateurValeur[]; | ||
resultats: TIndicateurValeur[]; | ||
}; | ||
}; | ||
|
||
/** Props du graphique générique Indicateur */ | ||
export type IndicateurChartProps = { | ||
/** Data issues de l'api pour générer les données formatées pour Nivo */ | ||
data: IndicateurChartData; | ||
/** Titre du graphe */ | ||
title?: string; | ||
/** Booléen de chargement des données et infos du graphique */ | ||
isLoading: boolean; | ||
/** Taille du graphe */ | ||
variant?: 'thumbnail' | 'modal' | 'detail'; | ||
/** ClassName du container */ | ||
className?: string; | ||
/** Configuration du graphique */ | ||
chartConfig?: Omit<LineChartProps, 'data'>; | ||
/** Information du graphique pour la modale de téléchargement */ | ||
chartInfos?: ChartInfosProps; | ||
}; | ||
|
||
/** Charge les données d'un indicateur et affiche le graphique */ | ||
const IndicateurChart = ({ | ||
data, | ||
title, | ||
isLoading, | ||
variant = 'detail', | ||
className, | ||
chartConfig, | ||
chartInfos, | ||
}: IndicateurChartProps) => { | ||
const noData = data.valeurs.length === 0; | ||
const { objectifs, resultats } = data.valeurs; | ||
|
||
const noData = objectifs.length === 0 && resultats.length === 0; | ||
|
||
if (noData) return null; | ||
|
||
const dataset = [ | ||
{ | ||
color: LAYERS.resultats.color, | ||
id: 'resultats', | ||
name: LAYERS.resultats.label, | ||
source: resultats.map((res) => ({ | ||
x: new Date(res.annee, 0, 1).toISOString(), | ||
y: res.valeur, | ||
})), | ||
}, | ||
{ | ||
color: LAYERS.objectifs.color, | ||
id: 'objectifs', | ||
name: LAYERS.objectifs.label, | ||
source: objectifs.map((obj) => ({ | ||
x: new Date(obj.annee, 0, 1).toISOString(), | ||
y: obj.valeur, | ||
})), | ||
}, | ||
]; | ||
|
||
/** | ||
* On déconstruit chartConfig afin de faire un traitement sur la valeur `gridXValues` | ||
* et quand même spread le reste des valeurs dans `axisBottom` | ||
*/ | ||
const { axisBottom, ...config } = chartConfig ?? {}; | ||
const style = { height: 450 }; | ||
if (variant === 'thumbnail') style.height = 320; | ||
if (variant === 'modal') style.height = 550; | ||
|
||
/** Permet de faire matcher le nombre de ligne de la grille avec le nombre de valeur affichées sur les ordonnées */ | ||
const axisBottomTickValues = config?.gridXValues | ||
? getXTickValues(data.valeurs, parseInt(config?.gridXValues as string)) | ||
: getXTickValues(data.valeurs); | ||
let grid = {}; | ||
if (variant === 'thumbnail') { | ||
grid = { top: '8%', bottom: '15%', right: '5%' }; | ||
} | ||
if (variant === 'detail') { | ||
grid = { left: 32, right: 32 }; | ||
} | ||
|
||
const option = makeOption({ | ||
option: { | ||
dataset, | ||
series: makeLineSeries(dataset), | ||
grid, | ||
title: variant === 'detail' ? { left: 28 } : {}, | ||
}, | ||
titre: title, | ||
unite: variant !== 'thumbnail' ? data.unite : undefined, | ||
disableToolbox: variant !== 'modal', | ||
}); | ||
|
||
return ( | ||
<div | ||
className={classNames('grow flex items-center justify-center', className)} | ||
> | ||
{ | ||
// Chargement | ||
isLoading ? ( | ||
<div | ||
className={classNames( | ||
'flex justify-center items-center', | ||
config.className | ||
)} | ||
> | ||
<SpinnerLoader className="w-8 h-8 fill-primary-5" /> | ||
</div> | ||
) : // Pas de données | ||
noData ? ( | ||
<PictoIndicateurVide className="grow" /> | ||
) : ( | ||
// Graphique | ||
<Chart | ||
line={{ | ||
chart: { | ||
data: prepareData(data.valeurs), | ||
theme: { | ||
axis: { | ||
ticks: { | ||
text: { | ||
fontSize: 14, | ||
}, | ||
}, | ||
}, | ||
}, | ||
colors: { datum: 'color' }, | ||
className, | ||
layers: [ | ||
'grid', | ||
'markers', | ||
'areas', | ||
generateStyledLines, | ||
'slices', | ||
'points', | ||
'axes', | ||
'legends', | ||
], | ||
xScale: { | ||
type: 'time', | ||
precision: 'year', | ||
format: '%Y', | ||
min: 'auto', | ||
max: 'auto', | ||
}, | ||
gridXValues: axisBottomTickValues, | ||
axisBottom: { | ||
format: '%Y', | ||
tickValues: axisBottomTickValues, | ||
...axisBottom, | ||
}, | ||
gridYValues: 5, | ||
axisLeft: { | ||
tickValues: config.gridYValues ?? 5, | ||
}, | ||
axisLeftLegend: data.unite, | ||
sliceTooltip: (props) => ( | ||
<SliceTooltip {...props} unite={data.unite ?? ''} /> | ||
), | ||
...config, | ||
}, | ||
}} | ||
infos={chartInfos} | ||
/> | ||
) | ||
} | ||
<div className={className} style={style}> | ||
{isLoading ? ( | ||
<div className="h-full w-full rounded-lg flex justify-center items-center bg-primary-0"> | ||
<SpinnerLoader className="w-8 h-8 fill-primary-5" /> | ||
</div> | ||
) : ( | ||
<ReactECharts option={option} style={style} /> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default IndicateurChart; | ||
|
||
/** Génère les lignes en appliquant le style correspondant à l'id de la série */ | ||
const generateStyledLines = ({ | ||
series, | ||
lineGenerator, | ||
xScale, | ||
yScale, | ||
}: CustomLayerProps) => { | ||
return series.map(({ id, data, color }) => ( | ||
<path | ||
key={id} | ||
d={ | ||
lineGenerator( | ||
data.map((d) => ({ | ||
x: (xScale as any)(d.data.x), | ||
y: (yScale as any)(d.data.y), | ||
})) | ||
) || undefined | ||
} | ||
fill="none" | ||
stroke={color} | ||
style={indicateurBaseData[id].style} | ||
/> | ||
)); | ||
}; |
107 changes: 0 additions & 107 deletions
107
...esentransitions.react/src/app/pages/collectivite/Indicateurs/chart/IndicateurChartNew.tsx
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.