Search code examples
flutterbar-chartsyncfusion-chart

How to custom color Syncfusion BarChart column depending on value in Flutter?


Is there a way to change the color of the column depending on the value?

Highest/Lowest columns need to have different colors to separate them from the rest of the values.

  • I am using the BarSeries with the syncfusion-charts package to create my chart

  • My data is flexible changes depending on user can't hardcode column color


Solution

  • To customize the bar chart for each bar to have a different color there is the need to implement the BarSeries.onCreateRenderer. Take a look at the example below:

    Screenshot

    Here is a minimal-reproducible-example of this app:

    import 'package:flutter/material.dart';
    import 'package:syncfusion_flutter_charts/charts.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(),
          debugShowCheckedModeBanner: false,
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({Key? key}) : super(key: key);
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        return const Scaffold(
          body: BarHorizontal(),
        );
      }
    }
    
    /// Renders customized Column chart
    class BarHorizontal extends StatefulWidget {
      /// Creates customized Column chart
      const BarHorizontal({Key? key}) : super(key: key);
    
      @override
      State<BarHorizontal> createState() => _BarHorizontalState();
    }
    
    class _BarHorizontalState extends State<BarHorizontal> {
      _BarHorizontalState();
    
      @override
      Widget build(BuildContext context) {
        return SfCartesianChart(
          title: ChartTitle(text: 'PC vendor shipments - 2015 Q1'),
          primaryXAxis: CategoryAxis(
            majorGridLines: const MajorGridLines(width: 0),
          ),
          primaryYAxis: NumericAxis(
              labelFormat: '{value}M',
              title: AxisTitle(text: 'Shipments in million'),
              majorGridLines: const MajorGridLines(width: 0),
              majorTickLines: const MajorTickLines(size: 0)),
          series: <ChartSeries<ChartSampleData, String>>[
            BarSeries<ChartSampleData, String>(
              onCreateRenderer: (ChartSeries<ChartSampleData, String> series) =>
                  _CustomColumnSeriesRenderer(),
              dataLabelSettings: const DataLabelSettings(
                  isVisible: true, labelAlignment: ChartDataLabelAlignment.middle),
              dataSource: <ChartSampleData>[
                ChartSampleData(x: 'HP Inc', y: 12.54),
                ChartSampleData(x: 'Lenovo', y: 13.46),
                ChartSampleData(x: 'Dell', y: 9.18),
                ChartSampleData(x: 'Apple', y: 4.56),
                ChartSampleData(x: 'Asus', y: 5.29),
              ],
              width: 0.8,
              xValueMapper: (ChartSampleData sales, _) => sales.x as String,
              yValueMapper: (ChartSampleData sales, _) => sales.y,
            )
          ],
        );
      }
    }
    
    class _CustomColumnSeriesRenderer extends BarSeriesRenderer {
      _CustomColumnSeriesRenderer();
    
      @override
      BarSegment createSegment() {
        return _ColumnCustomPainter();
      }
    }
    
    class _ColumnCustomPainter extends BarSegment {
      final colorList = [
        const Color.fromRGBO(53, 92, 125, 1),
        const Color.fromRGBO(192, 108, 132, 1),
        const Color.fromRGBO(246, 114, 128, 1),
        const Color.fromRGBO(248, 177, 149, 1),
        const Color.fromRGBO(116, 180, 155, 1)
      ];
    
      @override
      Paint getFillPaint() {
        final Paint customerFillPaint = Paint();
        customerFillPaint.isAntiAlias = false;
        customerFillPaint.color = colorList[currentSegmentIndex!];
        customerFillPaint.style = PaintingStyle.fill;
        return customerFillPaint;
      }
    }
    
    class ChartSampleData {
      ChartSampleData({this.x, this.y});
    
      final dynamic x;
      final num? y;
    }