在flutter中有什么方法可以构建这样的图表

问题描述 投票:0回答:1

我们正在开发一个项目来创建交易平台,我需要复制我们在 Flutter 上做出反应时使用的图表。 Need to create chart like this on flutter 我们已经使用了syncfusion并探索了suncfusion图表,但我们还没有办法精确复制图表

墨马线

我们尝试了 flutter 同步融合和 flutter 图表,但无法在 flutter 上复制图表的精确设计

android flutter charts syncfusion flutter-charts
1个回答
0
投票

您可以通过使用Area SeriesLine SeriesSpline Series的组合来实现上述要求,以按预期渲染系列。此外,您可以使用 primaryXAxisplotBands 属性在背景中渲染列类型框并渲染绿线。要根据 y 轴的第 0 个值将 Area Series 和 Line Series 渲染为两种不同的颜色,可以使用 onCreateShader 属性根据需要添加渐变。需要注意的是,没有选项可以渲染所提供的快照中提到的相反的 x 轴,因为轴的刻度线将从轴的开始到结束进行渲染,并且刻度线的位置不能被改变。

但是,我们使用 CustomPaint 小部件根据图表区域的宽度和高度在指定位置渲染四个刻度线及其文本值以及图表标题。我们还使用了 x 轴和 y 轴的 title 属性来显示各自轴的标题。

请参考下面的代码片段:

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;
}

快照: replicated chart

问候,

哈里·哈拉·苏丹。 K.

© www.soinside.com 2019 - 2024. All rights reserved.