Comment créer de superbes graphiques dans Flutter avec FL Chart

La collection et l’affichage des données via des graphiques sont de plus en plus utilisés. En effet, vous les trouverez principalement dans les applications d'investissement. Elles permettent d’afficher les prix des actions, la distribution des portefeuilles. Dans ce tutoriel nous allons vous montrer comment créer de superbes graphiques dans Flutter avec FL Chart.

Prérequis pour faire ce tutoriel

Pour faire ce tutoriel, nous allons utiliser :

  • Un éditeur de code : Visual studio ou Android studio
  • Le SDK Flutter        
  • NB : Des connaissances de bases en Flutter sont nécessaires. Si vous n'en avez pas, nous vous recommandons ce cours pratique :

Installation à faire

Avant de commencer la création des graphiques dans Flutter avec FL Chart, nous allons ajouter une dépendance à notre fichier : pubspec.yaml. Ça donnera ça :

dependencies:
fl_chart: ^0.45.0

Commençons par créer un graphique en courbe

Ce modèle va nous permettre de représenter nos données. Dans ce cas précis, nous allons créer un graphique pour les actions d’une entreprise. Pour ce faire, nous allons utiliser le Widget LineChart.

Ce dernier va prendre LineChartData comme paramètre clé avec swapAnimationDuration. En outre, nous allons affecter à ce dernier swapAnimationCurve comme paramètre optionnel pour contrôler l’animation pendant les changements d’état.

LineChart(
  LineChartData(
    // control how the chart looks like here
  ),
  swapAnimationDuration: Duration(milliseconds: 150), // Optional
  swapAnimationCurve: Curves.linear, // Optional
);

Simple, le rendu va ressembler à ça :

Revoyons notre code :

lass LineChartWidget extends StatelessWidget {
 final List<PricePoint> points;
 final bool isPositiveChange;

 const LineChartWidget(this.points, this.isPositiveChange, {Key? key})
     : super(key: key);

 @override
 Widget build(BuildContext context) {
   return AspectRatio(
     aspectRatio: 2,
     child: LineChart(
       LineChartData(
         lineBarsData: [
           LineChartBarData(
             spots: points.map((point) => FlSpot(point.x, point.y)).toList(),
             isCurved: false,
             colors: [
               isPositiveChange ? Colors.green : Colors.red,
             ],
             dotData: FlDotData(
               show: false,
             ),
           ),
         ],
       ),
     ),
   );
 }
}

LineChartData va contenir les informations de notre graphique. Nous avons utilisé la propriété lineBarsData qui prend une liste de LineChartBarData pour tracer les lignes sur le graphique. Nous avons aussi utilisé LineChartBarData pour définir à quoi vont ressembler les lignes individuelles.  Dans ce dernier, nous utilisons spots pour avoir des points similaires au point de tracer pour un graphique linéaire.

En général ces points sont marqués de figure circulaire, pour contrôler l’apparence, nous allons utiliser dotData. Nous pouvons aussi contrôler la forme courbée par le paramètre isCurved qui permet de faire des courbes.

Rendre propre le code

Rendons simple le code en éliminant les éléments inutiles. Cela va donner cet exemple.

Le code simplifié va ressembler à ça :

LineChartData(
…
….
 borderData: FlBorderData(
     border: const Border(bottom: BorderSide(), left: BorderSide())),
 gridData: FlGridData(show: false),
   titlesData: FlTitlesData(
     bottomTitles: _bottomTitles,
     leftTitles: SideTitles(showTitles: false),
     topTitles: SideTitles(showTitles: false),
     rightTitles: SideTitles(showTitles: false),
   )
),
…
…

​​SideTitles get _bottomTitles => SideTitles(
     showTitles: true,
     reservedSize: 22,
     margin: 10,
     interval: 1,
     getTextStyles: (context, value) => const TextStyle(
       color: Colors.blueGrey,
       fontWeight: FontWeight.bold,
       fontSize: 16,
     ),
     getTitles: (value) {
       switch (value.toInt()) {
         case 1:
           return 'Jan';
         case 3:
           return 'Mar';
         case 5:
           return 'May';
         case 7:
           return 'Jul';
         case 9:
           return 'Sep';
         case 11:
           return 'Nov';
       }
       return '';
     },
   );

Ajoutons des éléments tactiles

Nous allons y ajouter des éléments tactiles pour rendre notre graphique interactif. Par défaut, le LineCharData affiche des informations sous forme de bulle avec y comme valeur. Nous pouvons le personnaliser pour afficher des textes avec un style différent. N’est-ce pas génial !

L’intégration de LineTouchData nous permet d’utiliser un tas de propriété comme touchCallback, TouchTooltipData.

Vous aurez ça comme résultat :

Le code complet de notre application va ressembler à ça :

import 'dart:math';

import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';

import 'data/price_point.dart';

const _dashArray = [4, 2];

class LineChartWidget extends StatelessWidget {
 final List<PricePoint> points;
 final bool isPositiveChange;

 const LineChartWidget(this.points, this.isPositiveChange, {Key? key})
     : super(key: key);

 @override
 Widget build(BuildContext context) {
   final minY = points.map((point) => point.y).reduce(min);
   final maxY = points.map((point) => point.y).reduce(max);

   return AspectRatio(
     aspectRatio: 2,
     child: LineChart(
       LineChartData(
           lineTouchData: LineTouchData(
               enabled: true,
               touchCallback:
                   (FlTouchEvent event, LineTouchResponse? touchResponse) {
                 // TODO : Utilize touch event here to perform any operation
               },
               touchTooltipData: LineTouchTooltipData(
                 tooltipBgColor: Colors.blue,
                 tooltipRoundedRadius: 20.0,
                 showOnTopOfTheChartBoxArea: true,
                 fitInsideHorizontally: true,
                 tooltipMargin: 0,
                 getTooltipItems: (touchedSpots) {
                   return touchedSpots.map(
                     (LineBarSpot touchedSpot) {
                       const textStyle = TextStyle(
                         fontSize: 10,
                         fontWeight: FontWeight.w700,
                         color: Colors.white,
                       );
                       return LineTooltipItem(
                         points[touchedSpot.spotIndex].y.toInt().toString(),
                         textStyle,
                       );
                     },
                   ).toList();
                 },
               ),
               getTouchedSpotIndicator:
                   (LineChartBarData barData, List<int> indicators) {
                 return indicators.map(
                   (int index) {
                     final line = FlLine(
                         color: Colors.grey,
                         strokeWidth: 1,
                         dashArray: _dashArray);
                     return TouchedSpotIndicatorData(
                       line,
                       FlDotData(show: false),
                     );
                   },
                 ).toList();
               },
               getTouchLineEnd: (_, __) => double.infinity),
           lineBarsData: [
             LineChartBarData(
               spots: points.map((point) => FlSpot(point.x, point.y)).toList(),
               isCurved: false,
               colors: [
                 isPositiveChange ? Colors.green : Colors.red,
               ],
               dotData: FlDotData(
                 show: false,
               ),
             ),
           ],
           minY: minY,
           minX: 0,
           maxY: maxY,
           borderData: FlBorderData(
               border: const Border(bottom: BorderSide(), left: BorderSide())),
           gridData: FlGridData(show: false),
           titlesData: FlTitlesData(
             bottomTitles: _bottomTitles,
             leftTitles: SideTitles(showTitles: false),
             topTitles: SideTitles(showTitles: false),
             rightTitles: SideTitles(showTitles: false),
           )),
     ),
   );
 }
}

SideTitles get _bottomTitles => SideTitles(
     showTitles: true,
     reservedSize: 22,
     margin: 10,
     interval: 1,
     getTextStyles: (context, value) => const TextStyle(
       color: Colors.blueGrey,
       fontWeight: FontWeight.bold,
       fontSize: 16,
     ),
     getTitles: (value) {
       switch (value.toInt()) {
         case 1:
           return 'Jan';
         case 3:
           return 'Mar';
         case 5:
           return 'May';
         case 7:
           return 'Jul';
         case 9:
           return 'Sep';
         case 11:
           return 'Nov';
       }
       return '';
     },
   );
Vous venez de coder votre premier graphique en Flutter. Envie d’en savoir plus, télécharger notre programme de formation accélérée en Flutter.