flutterflutter-charts

Customize the label in syncfusion_flutter_charts and adding extra padding


I am a new developer in flutter. I am developing a bar graph using syncfusion_flutter_charts in flutter. This is what I want to achieve in flutter. Expected Graph. And this is what I achieved after hours of struggle. Achieved Graph

You notice that in label the text is in superscripts format. I tried to achieve this but all effort in vain and moreover there is some padding before start of bar and y-labels are on the axis line. I did a lot research but I couldn't able to replicate these things. This is a university project and any help would be appreciated. This is my code.

  List<_ChartData> data= [];
int daysInMonth(DateTime date){
    var firstDayThisMonth = DateTime(date.year, date.month, date.day);
    var firstDayNextMonth = DateTime(firstDayThisMonth.year, firstDayThisMonth.month + 1, firstDayThisMonth.day);
    return firstDayNextMonth.difference(firstDayThisMonth).inDays;
  }
  List<String> months = <String>[ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  String ordinal(int number) {
    if(!(number >= 1 && number <= 100)) {
      throw Exception('Invalid number');
    }

    if(number >= 11 && number <= 13) {
      return 'th';
    }

    switch(number % 10) {
      case 1: return 'st';
      case 2: return 'nd';
      case 3: return 'rd';
      default: return 'th';
    }
  }
    for(int i=1;i<=daysInMonth(DateTime.now());i++){
      data.add(_ChartData('$i${ordinal(i)} ${months[DateTime.now().month-1]}', (Random().nextInt(11)+1).toDouble()));
    }

SizedBox(
  height: 25.h,
  child: SfCartesianChart(
      plotAreaBorderWidth: 0,

      primaryXAxis: CategoryAxis(
          isVisible: true,
          majorGridLines: const MajorGridLines(width: 0),
          interval: (daysInMonth(DateTime.now())+ ((daysInMonth(DateTime.now())-1) - 28))/2,
          labelAlignment: LabelAlignment.center,
        labelStyle: TextStyle(
            color: lightAxisGreyColor,
            fontSize: 10.sp,
        ),
          edgeLabelPlacement: EdgeLabelPlacement.shift,

          labelPlacement: LabelPlacement.onTicks,
        ),
      primaryYAxis: NumericAxis(
          minimum: 0, maximum: 12, interval: 12,
         labelPosition: ChartDataLabelPosition.outside,
          labelAlignment: LabelAlignment.end,
          rangePadding: ChartRangePadding.additional,
          labelStyle: TextStyle(
            color: blackBlueText,
            fontSize: 10.sp
          ),




          axisLine: const AxisLine(width: 0)),
      tooltipBehavior: TooltipBehavior(
        enable: true,
      ),
      series: <ChartSeries<_ChartData, String>>[
        ColumnSeries<_ChartData, String>(

            dataSource: data,
            xValueMapper: (_ChartData data, _) => data.x,
            yValueMapper: (_ChartData data, _) => data.y,
            name: 'Open Tasks',
            width: 1,
            spacing: 0.05,
            borderRadius: BorderRadius.only(topLeft: Radius.circular(0.25.w),topRight: Radius.circular(0.25.w)),
            color: colorPurple)
      ]),
)

Solution

  • I don't know if it's the way you want it, but at least I used Unicode.

    And I made it by referring to your code.

    this is result.

    result.

    I added the following part.

    var re = RegExp(r'(%u(?<hexData>[0-9A-Fa-f]{4}))|.');
    
    var th_sup = '%u1d57%u02b0';
    var st_sup = '%u02e2%u1d57';
    var nd_sup = '%u207f%u1d48';
    var rd_sup = '%u02b3%u1d48';
    
    convertedUnicodeStr(String sup) {
      var matches = re.allMatches(sup);
      var hexDatas = <int>[];
      for (var match in matches) {
        var hexData = match.namedGroup('hexData');
        if (hexData != null) {
        hexDatas.add(int.parse(hexData, radix: 16));
      } else {
        hexDatas += match.group(0)!.runes.toList();
      }
     }
     var decodedStr = String.fromCharCodes(hexDatas);
     return decodedStr;
    

    }

    and changed switch statement

    switch (number % 10) {
      case 1:
        return convertedUnicodeStr(st_sup); // previous one : return 'st';
      case 2:
        return convertedUnicodeStr(nd_sup); // previous one : return 'nd';
      case 3:
        return convertedUnicodeStr(rd_sup); // previous one : return 'rd';
      default:
        return convertedUnicodeStr(th_sup); // previous one : return 'th';
    }
    

    All Codes

    import 'dart:math';
    import 'package:flutter/material.dart';
    import 'package:syncfusion_flutter_charts/charts.dart';
    
    class _ChartData {
      final String x;
      final double y;
    
      _ChartData(this.x, this.y);
    }
    
    class ChartExample extends StatefulWidget {
      const ChartExample({Key? key}) : super(key: key);
    
      @override
      State<ChartExample> createState() => _ChartExampleState();
    }
    
    class _ChartExampleState extends State<ChartExample> {
      var re = RegExp(r'(%u(?<hexData>[0-9A-Fa-f]{4}))|.');
      var th_sup = '%u1d57%u02b0';
      var st_sup = '%u02e2%u1d57';
      var nd_sup = '%u207f%u1d48';
      var rd_sup = '%u02b3%u1d48';
    
      List<_ChartData> data = [];
    
      List<String> months = <String>[
        'Jan',
        'Feb',
        'Mar',
        'Apr',
        'May',
        'Jun',
        'Jul',
        'Aug',
        'Sep',
        'Oct',
        'Nov',
        'Dec'
      ];
    
      int daysInMonth(DateTime date) {
        var firstDayThisMonth = DateTime(date.year, date.month, date.day);
        var firstDayNextMonth = DateTime(firstDayThisMonth.year,
            firstDayThisMonth.month + 1, firstDayThisMonth.day);
        return firstDayNextMonth.difference(firstDayThisMonth).inDays;
      }
    
      String ordinal(int number) {
        if (!(number >= 1 && number <= 100)) {
          throw Exception('Invalid number');
        }
    
        if (number >= 11 && number <= 13) {
          return 'th';
        }
    
        switch (number % 10) {
          case 1:
            return convertedUnicodeStr(st_sup);
          case 2:
            return convertedUnicodeStr(nd_sup);
          case 3:
            return convertedUnicodeStr(rd_sup);
          default:
            // return 'th';
            return convertedUnicodeStr(th_sup);
        }
      }
    
      init() {
        for (int i = 1; i <= daysInMonth(DateTime.now()); i++) {
          data.add(_ChartData('$i${ordinal(i)} ${months[DateTime.now().month - 1]}',
              (Random().nextInt(11) + 1).toDouble()));
        }
      }
    
      convertedUnicodeStr(String sup) {
        var matches = re.allMatches(sup);
        var hexDatas = <int>[];
        for (var match in matches) {
          var hexData = match.namedGroup('hexData');
          if (hexData != null) {
            hexDatas.add(int.parse(hexData, radix: 16));
          } else {
            hexDatas += match.group(0)!.runes.toList();
          }
        }
        var decodedStr = String.fromCharCodes(hexDatas);
        return decodedStr;
      }
    
      @override
      void initState() {
        init();
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: SizedBox(
              height: 195,
              child: SfCartesianChart(
                  plotAreaBorderWidth: 0,
                  primaryXAxis: CategoryAxis(
                    isVisible: true,
                    majorGridLines: const MajorGridLines(width: 0),
                    interval: (daysInMonth(DateTime.now()) +
                            ((daysInMonth(DateTime.now()) - 1) - 28)) /
                        2,
                    labelAlignment: LabelAlignment.center,
                    labelStyle: TextStyle(
                      color: Colors.green,
                      fontSize: 10,
                    ),
                    edgeLabelPlacement: EdgeLabelPlacement.shift,
                    labelPlacement: LabelPlacement.onTicks,
                  ),
                  primaryYAxis: NumericAxis(
                      minimum: 0,
                      maximum: 12,
                      interval: 12,
                      labelPosition: ChartDataLabelPosition.outside,
                      labelAlignment: LabelAlignment.end,
                      rangePadding: ChartRangePadding.additional,
                      labelStyle: TextStyle(color: Colors.black, fontSize: 10),
                      axisLine: const AxisLine(width: 0)),
                  tooltipBehavior: TooltipBehavior(
                    enable: true,
                  ),
                  series: <ChartSeries<_ChartData, String>>[
                    ColumnSeries<_ChartData, String>(
                        dataSource: data,
                        xValueMapper: (_ChartData data, _) => data.x,
                        yValueMapper: (_ChartData data, _) => data.y,
                        name: 'Open Tasks',
                        width: 1,
                        spacing: 0.05,
                        borderRadius: BorderRadius.only(
                            topLeft: Radius.circular(0.25),
                            topRight: Radius.circular(0.25)),
                        color: Colors.purple)
                  ]),
            ),
          ),
        );
      }
    }
    

    Lastly, I think you'd better refer to this.

    I don't know if this is the answer you want. But I hope it helps.