import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter_habit/common/I18N.dart';
import 'package:flutter_habit/common/provider/ThemeProvider.dart';
import 'package:flutter_habit/common/utils/ConvertUtils.dart';
import 'package:provider/provider.dart';
class DateValueMultiLineChart extends StatelessWidget {
final Map<String, List<FlSpot>> lineNameSportsMap;
final int size;
DateValueMultiLineChart({
@required this.lineNameSportsMap,
this.size,
});
List<LineChartBarData> getLineChartBarData(BuildContext context) {
int i = 0;
List<LineChartBarData> out = lineNameSportsMap.values.map((sports) {
LineChartBarData lineChartBarData = LineChartBarData(
spots: sports,
// 圆滑
isCurved: size > 7,
// 线条颜色
colors: [
Provider.of<ThemeProvider>(context, listen: false).otherColors[i]
],
// 线条宽度
barWidth: 3,
// 起点和终点是否圆滑
isStrokeCapRound: true,
// 点配置
dotData: FlDotData(
show: size < 30,
getDotColor: (spot, percent, barData) =>
Provider.of<ThemeProvider>(context, listen: false).otherColors[i],
dotSize: 3,
),
belowBarData: BarAreaData(
show: false,
colors: [
Theme.of(context).colorScheme.secondary.withOpacity(0.1 / (i + 1))
],
),
);
i = (i + 1) % (themeColors.length - 1);
return lineChartBarData;
}).toList();
return out;
}
@override
Widget build(BuildContext context) {
double maxY, minY, maxX, minX, xInterval, yInterval;
if (lineNameSportsMap.values.first.isNotEmpty) {
double now =
ConvertUtils.localDaysSinceEpoch(DateTime.now()).floorToDouble();
maxX = now;
minX = now - size;
maxY = lineNameSportsMap.values.first.first.y;
minY = lineNameSportsMap.values.first.first.y;
lineNameSportsMap.values.forEach((sports) {
sports.forEach((i) {
if (i.y < minY) {
minY = i.y;
}
if (i.y > maxY) {
maxY = i.y;
}
});
});
if (maxY == maxY) {
maxY = maxY + 10;
minY = minY - 10;
} else {
double height = maxY - minY;
maxY = maxY + height;
minY = minY - height;
}
switch (size) {
case 7:
xInterval = 1;
break;
case 30:
xInterval = 5;
break;
case 90:
xInterval = 18;
break;
default:
xInterval = 1;
break;
}
yInterval = ((maxY - minY) / 6);
}
int i = 0;
return lineNameSportsMap.values.first.isEmpty
? Container(
child: Column(
children: <Widget>[
Text(
I18N.of("无数据"),
style: Theme.of(context)
.textTheme
.displaySmall
.copyWith(color: Theme.of(context).colorScheme.secondary),
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
I18N.of("添加数据后会展示对应图表"),
style: Theme.of(context).textTheme.bodySmall,
),
],
),
],
))
: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: lineNameSportsMap.keys.map((s) {
// 右显数据
Widget w = Text(
"$s — ",
style: TextStyle(
color:
Provider.of<ThemeProvider>(context, listen: false)
.otherColors[i]),
);
i = (i + 1) % (themeColors.length - 1);
return w;
}).toList(),
),
Container(
height: 250,
padding: EdgeInsets.only(top: 20, left: 10, right: 20),
child: LineChart(
LineChartData(
clipToBorder: true,
// 边框信息
borderData: FlBorderData(
show: true,
border: Border.all(
color: Theme.of(context).colorScheme.secondary,
width: 1,
),
),
backgroundColor:
Theme.of(context)
.colorScheme
.secondary
.withOpacity(0.03),
gridData: FlGridData(
show: true,
drawVerticalLine: true,
drawHorizontalLine: false,
// 从左到右每隔几个整数数据画条竖线
verticalInterval: xInterval,
// 横向网格线
getDrawingHorizontalLine: (value) {
return FlLine(
color: Theme.of(context).colorScheme.secondary,
strokeWidth: 0.5,
);
},
horizontalInterval: yInterval,
// 纵向网格线
getDrawingVerticalLine: (value) {
return FlLine(
color: Theme.of(context).colorScheme.secondary,
strokeWidth: 1,
);
},
),
// 点击响应信息
lineTouchData: LineTouchData(
touchTooltipData: LineTouchTooltipData(
tooltipBgColor: Theme.of(context)
.colorScheme
.secondary
.withOpacity(0.2)
.withAlpha(100),
fitInsideHorizontally: true,
),
),
titlesData: FlTitlesData(
show: true,
// 下方文字
bottomTitles: SideTitles(
// 每隔几个显示一个底部标签
interval: xInterval,
showTitles: true,
// 文字与图表上边界距离
// margin: 8,
// 文字预留空间
// reservedSize: 22,
textStyle: Theme.of(context).textTheme.bodyMedium,
getTitles: (value) {
DateTime dateTime =
ConvertUtils.dateTimeOfLocalDaysSinceEpoch(value);
return "${dateTime.month}-${dateTime.day}";
},
),
leftTitles: SideTitles(
// 每隔几个显示一个左侧标签
interval: yInterval,
showTitles: true,
// 文字与图表左边界距离
// margin: 8,
// 文字预留空间
reservedSize: ConvertUtils.fixedDouble(maxY, 1).toString().length * 6.5,
textStyle: Theme.of(context).textTheme.bodyMedium,
getTitles: (value) {
return ConvertUtils.fixedDouble(value, 1).toString();
},
),
),
// 各轴显示的最值 (不设置则缩放)
minX: minX,
maxX: maxX,
maxY: maxY,
minY: minY,
// 数据
lineBarsData: getLineChartBarData(context),
),
),
)
],
);
}
}