Is there any way in flutter i can build an chart like this

204 Views Asked by At

WE are working on an project to create trading platform i am in need to replicate this chart we used on react on flutter. Need to create chart like this on flutter we have used syncfusion and explored suncfusion charts and we are not yet got an way to exactly replicate the chart

SUMIMASEN

We tried flutter syncfusion and flutter charts but unable to replicate the exact design for the chart on flutter

1

There are 1 best solutions below

1
hariharasudhan kanagaraj On

You can achieve the mentioned requirements by using combinations of the Area Series, Line Series, and Spline Series to render the series as expected. Additionally, you can use the plotBands property of the primaryXAxis to render the column type box in the background and to render the green line. To render the Area Series and Line Series with two different colors based on the 0th value of the y axis, you can use the onCreateShader property to add a gradient according to your needs. It is important to note that there is no option to render the opposed x axis as mentioned in the provided snapshot, as the tick lines for the axis will be rendered from the start to the end of the axis and the position of the tick line cannot be changed.

However, we have used the CustomPaint widget to render the four tick lines and their text values along with the chart title at the specified location based on the width and height of the chart area. We have also used the title property of both the x and y axis to display the title of their respective axes.

import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'dart:ui' as ui;
 
void main() {
  runApp(const MainApp());
}
 
int index = 0;
 
class MainApp extends StatefulWidget {
  const MainApp({super.key});
 
  @override
  State<MainApp> createState() => _MainAppState();
}
 
class _MainAppState extends State<MainApp> {
  late List<ChartSampleData> _areaData;
  late List<ChartSampleData> _lineData;
  late List<ChartSampleData> _splineData;
  final GlobalKey<SfCartesianChartState> _cartesianGlobalKey = GlobalKey();
 
  @override
  void initState() {
    _areaData = <ChartSampleData>[
      ChartSampleData(18024, -68000),
      ChartSampleData(19539, 10000),
      ChartSampleData(21054, -68000),
    ];
    _lineData = <ChartSampleData>[
      ChartSampleData(18024, -68000),
      ChartSampleData(19350, 0),
      ChartSampleData(19539, 10000),
      ChartSampleData(19729, 0),
      ChartSampleData(21054, -68000),
    ];
    _splineData = <ChartSampleData>[
      ChartSampleData(19010, -18000),
      ChartSampleData(19539, 0),
      ChartSampleData(20070, -18000),
    ];
    super.initState();
  }
 
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Stack(
          children: [
            Center(
              child: SizedBox(
                height: 500,
                width: 1000,
                child: SfCartesianChart(
                  key: _cartesianGlobalKey,
                  primaryXAxis: NumericAxis(
                    interval: 505,
                    majorTickLines: const MajorTickLines(
                      color: Color(0xFF707070),
                    ),
                    majorGridLines: const MajorGridLines(
                      width: 1,
                      dashArray: [8, 8],
                    ),
                    plotBands: [
                      PlotBand(
                        start: 18950,
                        end: 19110,
                        color: Colors.grey.shade400,
                        opacity: 0.2,
                      ),
                      PlotBand(
                        start: 19110,
                        end: 19970,
                        color: const Color(0xFF466b52),
                        opacity: 0.2,
                      ),
                      PlotBand(
                        start: 19970,
                        end: 20140,
                        color: Colors.grey.shade400,
                        opacity: 0.2,
                      ),
                      PlotBand(
                        start: 19523,
                        end: 19523,
                        borderWidth: 2,
                        borderColor: Colors.green,
                        text: '19523',
                        horizontalTextAlignment: TextAnchor.end,
                        verticalTextAlignment: TextAnchor.start,
                        verticalTextPadding: '-30',
                        textStyle: const TextStyle(
                          fontSize: 16,
                          color: Color(0xFF01375A),
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ],
                    title: AxisTitle(
                      text: 'Underlying Price',
                      textStyle: const TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                        color: Colors.black,
                      ),
                    ),
                  ),
                  primaryYAxis: NumericAxis(
                    visibleMinimum: -70000,
                    visibleMaximum: 20000,
                    interval: 10000,
                    majorTickLines: const MajorTickLines(
                      color: Color(0xFF707070),
                    ),
                    title: AxisTitle(
                      text: 'Profit/Loss',
                      textStyle: const TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                        color: Colors.black,
                      ),
                    ),
                  ),
                  legend: const Legend(
                    isVisible: true,
                    position: LegendPosition.bottom,
                  ),
                  series: <CartesianSeries>[
                    AreaSeries<ChartSampleData, num>(
                      dataSource: _areaData,
                      isVisibleInLegend: false,
                      xValueMapper: (ChartSampleData sales, _) => sales.x,
                      yValueMapper: (ChartSampleData sales, _) => sales.y,
                      onCreateShader: (ShaderDetails shaderDetails) {
                        return ui.Gradient.linear(
                          shaderDetails.rect.topCenter,
                          shaderDetails.rect.bottomCenter,
                          [
                            Colors.green.withOpacity(0.5),
                            const Color(0xFFFCE1D3).withOpacity(0.5),
                          ],
                          [0.22, 0.225],
                        );
                      },
                    ),
                    SplineSeries<ChartSampleData, num>(
                      dataSource: _splineData,
                      xValueMapper: (ChartSampleData sales, _) => sales.x,
                      yValueMapper: (ChartSampleData sales, _) => sales.y,
                      splineType: SplineType.natural,
                      color: Colors.indigo,
                      legendItemText: 'on target date',
                      width: 2,
                      dashArray: const [5, 5],
                    ),
                    LineSeries<ChartSampleData, num>(
                      dataSource: _lineData,
                      xValueMapper: (ChartSampleData sales, _) => sales.x,
                      yValueMapper: (ChartSampleData sales, _) => sales.y,
                      legendItemText: 'on expiry date',
                      onCreateShader: (ShaderDetails shaderDetails) {
                        return ui.Gradient.linear(
                          shaderDetails.rect.topCenter,
                          shaderDetails.rect.bottomCenter,
                          [Colors.green, Colors.red],
                          [0.22, 0.225],
                        );
                      },
                      width: 5,
                    ),
                  ],
                ),
              ),
            ),
            // To render 1st tick line and alpha text values.
            CustomPaint(
              painter: CustomLineAndTextPainter(
                cartesianGlobalKey: _cartesianGlobalKey,
                text: '-2\u03C3',
                widthRatio: 2.75,
                textWidthRatio: 2.85,
              ),
            ),
            // To render 2nd tick line and alpha text values.
            CustomPaint(
              painter: CustomLineAndTextPainter(
                cartesianGlobalKey: _cartesianGlobalKey,
                text: '-1\u03C3',
                widthRatio: 2.43,
                textWidthRatio: 2.52,
              ),
            ),
            // To render 3rd tick line and alpha text values.
            CustomPaint(
              painter: CustomLineAndTextPainter(
                cartesianGlobalKey: _cartesianGlobalKey,
                text: '+1\u03C3',
                widthRatio: 1.5,
                textWidthRatio: 1.548,
              ),
            ),
            // To render 4th tick line and alpha text values along with the chart title.
            CustomPaint(
              painter: CustomLineAndTextPainter(
                cartesianGlobalKey: _cartesianGlobalKey,
                text: '+2\u03C3',
                widthRatio: 1.395,
                textWidthRatio: 1.43,
                titleText: 'Nifty',
              ),
            ),
          ],
        ),
      ),
    );
  }
}
 
class CustomLineAndTextPainter extends CustomPainter {
  CustomLineAndTextPainter({
    this.titleText,
    required this.text,
    required this.widthRatio,
    required this.textWidthRatio,
    required this.cartesianGlobalKey,
  });
 
  final String text;
  final String? titleText;
  final double widthRatio;
  final double textWidthRatio;
  final GlobalKey<SfCartesianChartState> cartesianGlobalKey;
 
  @override
  void paint(Canvas canvas, Size size) {
    final RenderBox renderBox =
        cartesianGlobalKey.currentContext!.findRenderObject() as RenderBox;
    final Offset chartOriginOffset = (renderBox).localToGlobal(Offset.zero);
    final Rect chartBounds = renderBox.paintBounds;
 
    // To draw the tick lines at the opposed x axis.
    canvas.drawLine(
      chartOriginOffset.translate(
        chartBounds.width / widthRatio,
        (chartBounds.top + 05),
      ),
      chartOriginOffset.translate(
        chartBounds.width / widthRatio,
        (chartBounds.top + 10),
      ),
      Paint()
        ..color = const Color(0xFF707070)
        ..strokeWidth = 1,
    );
 
    // To render the text with sigma symbol at the opposed x axis.
    final TextSpan textSpan = TextSpan(
      text: text,
      style: const TextStyle(
        fontSize: 18,
        color: Color(0xFF01375A),
        fontWeight: FontWeight.bold,
      ),
    );
 
    final TextPainter textPainter = TextPainter(
      text: textSpan,
      textDirection: TextDirection.ltr,
      textAlign: TextAlign.center,
    );
 
    textPainter.layout();
 
    textPainter.paint(
      canvas,
      chartOriginOffset.translate(
        chartBounds.width / textWidthRatio,
        (chartBounds.top - 30),
      ),
    );
 
    // To render the title of the chart at the specified position.
    if (titleText != null) {
      final TextSpan titleTextSpan = TextSpan(
        text: titleText,
        style: const TextStyle(
          fontSize: 22,
          letterSpacing: 1,
          color: Color(0xFF01375A),
          fontWeight: FontWeight.bold,
        ),
      );
 
      final TextPainter titleTextPainter = TextPainter(
        text: titleTextSpan,
        textDirection: TextDirection.ltr,
        textAlign: TextAlign.center,
        maxLines: 1,
      );
 
      titleTextPainter.layout();
 
      titleTextPainter.paint(
        canvas,
        chartOriginOffset.translate(
          chartBounds.width / 2,
          (chartBounds.top - 60),
        ),
      );
    }
  }
 
  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}
 
class ChartSampleData {
  ChartSampleData(this.x, this.y);
 
  final num x;
  final num y;
}

Snapshot: replicated chart