LineChart extra lines label bugs
- Dominant language
- Dart
- Stars
- 7.6k
- Forks
- 2k
- Avg merge
- 9d 1h
- Merged PRs (30d)
- 2
Description
**Describe the bug**
- Extra lines labels will be cut off, if any border is set to be clipped
- The padding on extra-line labels does not work correctly. On VerticalExtraLines I expect top padding to move the label down, which does not happen. Horizontal lines should be moved up by adding bottom padding, which also does not happen.
**To Reproduce**
The following code can be run in the example app provided with the repository.
Code to reproduce issue
Complete code for line_chart_sample1.dart with ExtraLinesData
``` dart
import 'package:fl_chart_app/presentation/resources/app_resources.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
class _LineChart extends StatelessWidget {
const _LineChart({required this.isShowingMainData});
final bool isShowingMainData;
@override
Widget build(BuildContext context) {
return LineChart(
isShowingMainData ? sampleData1 : sampleData2,
duration: const Duration(milliseconds: 250),
);
}
LineChartData get sampleData1 => LineChartData(
lineTouchData: lineTouchData1,
gridData: gridData,
titlesData: titlesData1,
borderData: borderData,
lineBarsData: lineBarsData1,
minX: 0,
maxX: 14,
maxY: 4,
minY: 0,
extraLinesData: ExtraLinesData(extraLinesOnTop: true, verticalLines: [
VerticalLine(
x: 1,
color: AppColors.mainTextColor2,
strokeWidth: 1,
label: VerticalLineLabel(
labelResolver: (p0) => "Line 2",
show: true,
style: const TextStyle(color: Colors.white),
padding: const EdgeInsets.only(top: 10),
alignment: Alignment.bottomCenter,
)),
], horizontalLines: [
HorizontalLine(
y: 4,
color: AppColors.mainTextColor2,
strokeWidth: 1,
label: HorizontalLineLabel(
labelResolver: (p0) => "Line 1",
show: true,
style: const TextStyle(color: Colors.white),
alignment: Alignment.bottomCenter,
padding: const EdgeInsets.only(top: 20),
))
]),
clipData: const FlClipData.all(),
);
LineChartData get sampleData2 => LineChartData(
lineTouchData: lineTouchData2,
gridData: gridData,
titlesData: titlesData2,
borderData: borderData,
lineBarsData: lineBarsData2,
minX: 0,
maxX: 14,
maxY: 6,
minY: 0,
);
LineTouchData get lineTouchData1 => LineTouchData(
handleBuiltInTouches: true,
touchTooltipData: LineTouchTooltipData(
tooltipBgColor: Colors.blueGrey.withOpacity(0.8),
),
);
FlTitlesData get titlesData1 => FlTitlesData(
bottomTitles: AxisTitles(
sideTitles: bottomTitles,
),
rightTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
leftTitles: AxisTitles(
sideTitles: leftTitles(),
),
);
List get lineBarsData1 => [
lineChartBarData1_1,
lineChartBarData1_2,
lineChartBarData1_3,
];
LineTouchData get lineTouchData2 => const LineTouchData(
enabled: false,
);
FlTitlesData get titlesData2 => FlTitlesData(
bottomTitles: AxisTitles(
sideTitles: bottomTitles,
),
rightTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
leftTitles: AxisTitles(
sideTitles: leftTitles(),
),
);
List get lineBarsData2 => [
lineChartBarData2_1,
lineChartBarData2_2,
lineChartBarData2_3,
];
Widget leftTitleWidgets(double value, TitleMeta meta) {
const style = TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
);
String text;
switch (value.toInt()) {
case 1:
text = '1m';
break;
case 2:
text = '2m';
break;
case 3:
text = '3m';
break;
case 4:
text = '5m';
break;
case 5:
text = '6m';
break;
default:
return Container();
}
return Text(text, style: style, textAlign: TextAlign.center);
}
SideTitles leftTitles() => SideTitles(
getTitlesWidget: leftTitleWidgets,
showTitles: true,
interval: 1,
reservedSize: 40,
);
Widget bottomTitleWidgets(double value, TitleMeta meta) {
const style = TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
);
Widget text;
switch (value.toInt()) {
case 2:
text = const Text('SEPT', style: style);
break;
case 7:
text = const Text('OCT', style: style);
break;
case 12:
text = const Text('DEC', style: style);
break;
default:
text = const Text('');
break;
}
return SideTitleWidget(
axisSide: meta.axisSide,
space: 10,
child: text,
);
}
SideTitles get bottomTitles => SideTitles(
showTitles: true,
reservedSize: 32,
interval: 1,
getTitlesWidget: bottomTitleWidgets,
);
FlGridData get gridData => const FlGridData(show: false);
FlBorderData get borderData => FlBorderData(
show: true,
border: Border(
bottom:
BorderSide(color: AppColors.primary.withOpacity(0.2), width: 4),
left: const BorderSide(color: Colors.transparent),
right: const BorderSide(color: Colors.transparent),
top: const BorderSide(color: Colors.transparent),
),
);
LineChartBarData get lineChartBarData1_1 => LineChartBarData(
isCurved: true,
color: AppColors.contentColorGreen,
barWidth: 8,
isStrokeCapRound: true,
dotData: const FlDotData(show: false),
belowBarData: BarAreaData(show: false),
spots: const [
FlSpot(1, 1),
FlSpot(3, 1.5),
FlSpot(5, 1.4),
FlSpot(7, 3.4),
FlSpot(10, 2),
FlSpot(12, 2.2),
FlSpot(13, 1.8),
FlSpot(18, 1.8),
],
);
LineChartBarData get lineChartBarData1_2 => LineChartBarData(
isCurved: true,
color: AppColors.contentColorPink,
barWidth: 8,
isStrokeCapRound: true,
dotData: const FlDotData(show: false),
belowBarData: BarAreaData(
show: false,
color: AppColors.contentColorPink.withOpacity(0),
),
spots: const [
FlSpot(1, 1),
FlSpot(3, 2.8),
FlSpot(7, 1.2),
FlSpot(10, 2.8),
FlSpot(12, 2.6),
FlSpot(13, 3.9),
],
);
LineChartBarData get lineChartBarData1_3 => LineChartBarData(
isCurved: true,
color: AppColors.contentColorCyan,
barWidth: 8,
isStrokeCapRound: true,
dotData: const FlDotData(show: false),
belowBarData: BarAreaData(show: false),
spots: const [
FlSpot(1, 2.8),
FlSpot(3, 1.9),
FlSpot(6, 3),
FlSpot(10, 1.3),
FlSpot(13, 2.5),
],
);
LineChartBarData get lineChartBarData2_1 => LineChartBarData(
isCurved: true,
curveSmoothness: 0,
color: AppColors.contentColorGreen.withOpacity(0.5),
barWidth: 4,
isStrokeCapRound: true,
dotData: const FlDotData(show: false),
belowBarData: BarAreaData(show: false),
spots: const [
FlSpot(1, 1),
FlSpot(3, 4),
FlSpot(5, 1.8),
FlSpot(7, 5),
FlSpot(10, 2),
FlSpot(12, 2.2),
FlSpot(13, 1.8),
],
);
LineChartBarData get lineChartBarData2_2 => LineChartBarData(
isCurved: true,
color: AppColors.contentColorPink.withOpacity(0.5),
barWidth: 4,
isStrokeCapRound: true,
dotData: const FlDotData(show: false),
belowBarData: BarAreaData(
show: true,
color: AppColors.contentColorPink.withOpacity(0.2),
),
spots: const [
FlSpot(1, 1),
FlSpot(3, 2.8),
FlSpot(7, 1.2),
FlSpot(10, 2.8),
FlSpot(12, 2.6),
FlSpot(13, 3.9),
],
);
LineChartBarData get lineChartBarData2_3 => LineChartBarData(
isCurved: true,
curveSmoothness: 0,
color: AppColors.contentColorCyan.withOpacity(0.5),
barWidth: 2,
isStrokeCapRound: true,
dotData: const FlDotData(show: true),
belowBarData: BarAreaData(show: false),
spots: const [
FlSpot(1, 3.8),
FlSpot(3, 1.9),
FlSpot(6, 5),
FlSpot(10, 3.3),
FlSpot(13, 4.5),
],
);
}
class LineChartSample1 extends StatefulWidget {
const LineChartSample1({super.key});
@override
State createState() => LineChartSample1State();
}
class LineChartSample1State extends State {
late bool isShowingMainData;
@override
void initState() {
super.initState();
isShowingMainData = true;
}
@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1.23,
child: Stack(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(
height: 37,
),
const Text(
'Monthly Sales',
style: TextStyle(
color: AppColors.primary,
fontSize: 32,
fontWeight: FontWeight.bold,
letterSpacing: 2,
),
textAlign: TextAlign.center,
),
const SizedBox(
height: 37,
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 16, left: 6),
child: _LineChart(isShowingMainData: isShowingMainData),
),
),
const SizedBox(
height: 10,
),
],
),
IconButton(
icon: Icon(
Icons.refresh,
color: Colors.white.withOpacity(isShowingMainData ? 1.0 : 0.5),
),
onPressed: () {
setState(() {
isShowingMainData = !isShowingMainData;
});
},
)
],
),
);
}
}
```
**Screenshots**
Current | Expected
--- | ---
 | 
**Versions**
- Flutter: 3.13.0
- FlChart: 0.63.0
Contributor guide
Research direction
Start by running the example app with the reproduced line_chart_sample1.dart configuration, including FlClipData.all(), ExtraLinesData, VerticalLineLabel, and HorizontalLineLabel. Trace the extra-line label rendering from those options and verify the labels are not clipped and that top or bottom padding moves them in the expected direction.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart, flutter
- Domain
- data-visualization, frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100