我们正在开发一个项目来创建交易平台,我需要复制我们在 Flutter 上做出反应时使用的图表。 我们已经使用了syncfusion并探索了suncfusion图表,但我们还没有办法精确复制图表
墨马线
我们尝试了 flutter 同步融合和 flutter 图表,但无法在 flutter 上复制图表的精确设计
您可以通过使用Area Series、Line Series和Spline Series的组合来实现上述要求,以按预期渲染系列。此外,您可以使用 primaryXAxis 的 plotBands 属性在背景中渲染列类型框并渲染绿线。要根据 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;
}
问候,
哈里·哈拉·苏丹。 K.