目前正在带领app团队使用flutter重构公司的app,我负责其中一部分,其中有需要使用图表的组件,经过调研后决定使用fl_chart,功能强大且开发人员也比较活跃。但是发现折线图不能显示当前点的数据…没问题,clone下来自己修改下。
line_chart的示例
1 | LineChartBarData _createLineChatBarData(List<FlSpot> spots, List<int> xAxisIndex) { |
单折线使用showingTooltipIndicators和lineTouchData配合即可实现显示点的数值,效果大致如下:
但是如果为多折线,所有数据会显示在最上,效果如下:
显然和我们期待的不一致,所以需要另辟蹊径…
解决方法
查阅Fl_Chart的源码后发现,折线图文件分为“line_chart.dart”,”line_chart_data.dart”和“line_chart_painter.dart”三个文件,其中line_chart调用另两个文件,line_chart_data提供数据结构,也就是各种类文件,line_chart_painter负责具体绘制。
而我们需要做的就是在绘制图表上的点的同时,把当前点的y轴数值绘制上就可以了,经过一番查找,line_chart_data中 FlDotData负责定义点的数据,line_chart_painter中 _drawDots负责绘制,修改如下:
首先将fl_chart图表库放入plugins文件夹中,使用本地库引用。
在FlDotData的类中加入三个新属性:
1
2
3
4
5
bool showText, // 控制是否显示数值
GetTextStyleCallback getTextStyle, // 数值样式
Offset textOffset, // 数值偏移 (没用,还没实现)在line_chart_painter的_drawDots中的
1
for (int i = 0; i < barData.spots.length; i++) {}
循环最后加入绘制当前点的代码即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58// 修改:在每个点上面显示数值 = =
void _drawDots(Canvas canvas, Size viewSize, LineChartBarData barData) {
if (!barData.dotData.show || barData.spots == null || barData.spots.isEmpty) {
return;
}
viewSize = getChartUsableDrawSize(viewSize);
final barXDelta = _getBarLineXLength(barData, viewSize);
for (int i = 0; i < barData.spots.length; i++) {
final FlSpot spot = barData.spots[i];
if (barData.dotData.checkToShowDot(spot, barData)) {
final double x = getPixelX(spot.x, viewSize);
final double y = getPixelY(spot.y, viewSize);
final double xPercentInLine = ((x - getLeftOffsetDrawSize()) / barXDelta) * 100;
final dotColor = barData.dotData.getDotColor(spot, xPercentInLine, barData);
if (barData.dotData.getStrokeColor != null && barData.dotData.strokeWidth != null) {
canvas.drawCircle(
Offset(x, y),
barData.dotData.dotSize + (barData.dotData.strokeWidth / 2),
_dotPaint
..color = barData.dotData.getStrokeColor(spot, xPercentInLine, barData)
..strokeWidth = barData.dotData.strokeWidth
..style = PaintingStyle.stroke);
}
canvas.drawCircle(
Offset(x, y),
barData.dotData.dotSize,
_dotPaint
..color = dotColor
..style = PaintingStyle.fill);
// print("barData.dotData.show ${barData.dotData.show}");
// print("barData.dotData.dotSize ${barData.dotData.dotSize}");
// print("barData.dotData.showText ${barData.dotData.showText}");
if (barData.dotData.showText) {
TextStyle _defaultStyle = TextStyle(color: Colors.red, fontSize: 12, fontWeight: FontWeight.bold);
Offset _defaultOffset = Offset(x - 8, y - 20);
// 绘制spot点y轴数值
final TextSpan span = TextSpan(
style: barData.dotData.getTextStyle(spot),
text: "${spot.y.toInt()}",
);
final TextPainter tp = TextPainter(
text: span,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
textScaleFactor: textScale);
tp.layout();
final drawOffset = _defaultOffset;
tp.paint(canvas, drawOffset);
}
}
}
}
最后效果如图: