Skip to content

Commit e58b6b1

Browse files
authored
feat: allow titles to overlay on chart area (#1959)
* test: add overlayOnChart test * feat: allow titles to overlay on chart area A simple change to allow the user to set the axis titles to overlay on top of the chart area instead of being pushed off to their appropriate side. Resolves #1946 * feat: add enum for side titles alignment * test: remove use of LineChartLeaf * fix: add sideTitleAlignment to lerp and copyWith * test: add sideTitleAlignment.border test * doc: add sideTitleAlignment to base_chart.md
1 parent 4b981f4 commit e58b6b1

File tree

4 files changed

+141
-5
lines changed

4 files changed

+141
-5
lines changed

lib/src/chart/base/axis_chart/axis_chart_data.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ enum AxisSide {
112112
}
113113
}
114114

115+
/// Represents where the [SideTitles] are drawn in relation to the chart.
116+
enum SideTitleAlignment { outside, border, inside }
117+
115118
/// Contains meta information about the drawing title.
116119
class TitleMeta {
117120
TitleMeta({
@@ -355,6 +358,7 @@ class AxisTitles with EquatableMixin {
355358
this.axisNameSize = 16,
356359
this.sideTitles = const SideTitles(),
357360
this.drawBelowEverything = true,
361+
this.sideTitleAlignment = SideTitleAlignment.outside,
358362
});
359363

360364
/// Determines the size of [axisName]
@@ -372,6 +376,9 @@ class AxisTitles with EquatableMixin {
372376
/// In the future, we will convert tooltips to a widget, that would solve this problem.
373377
final bool drawBelowEverything;
374378

379+
/// Where the [SideTitles] are drawn in relation to the chart.
380+
final SideTitleAlignment sideTitleAlignment;
381+
375382
/// If there is something to show as axisTitles, it returns true
376383
bool get showAxisTitles => axisNameWidget != null && axisNameSize != 0;
377384

@@ -385,6 +392,7 @@ class AxisTitles with EquatableMixin {
385392
axisNameSize: lerpDouble(a.axisNameSize, b.axisNameSize, t)!,
386393
sideTitles: SideTitles.lerp(a.sideTitles, b.sideTitles, t),
387394
drawBelowEverything: b.drawBelowEverything,
395+
sideTitleAlignment: b.sideTitleAlignment,
388396
);
389397

390398
/// Copies current [SideTitles] to a new [SideTitles],
@@ -394,12 +402,14 @@ class AxisTitles with EquatableMixin {
394402
double? axisNameSize,
395403
SideTitles? sideTitles,
396404
bool? drawBelowEverything,
405+
SideTitleAlignment? sideTitleAlignment,
397406
}) =>
398407
AxisTitles(
399408
axisNameWidget: axisNameWidget ?? this.axisNameWidget,
400409
axisNameSize: axisNameSize ?? this.axisNameSize,
401410
sideTitles: sideTitles ?? this.sideTitles,
402411
drawBelowEverything: drawBelowEverything ?? this.drawBelowEverything,
412+
sideTitleAlignment: sideTitleAlignment ?? this.sideTitleAlignment,
403413
);
404414

405415
/// Used for equality check, see [EquatableMixin].
@@ -409,6 +419,7 @@ class AxisTitles with EquatableMixin {
409419
axisNameSize,
410420
sideTitles,
411421
drawBelowEverything,
422+
sideTitleAlignment,
412423
];
413424
}
414425

lib/src/extensions/fl_titles_data_extension.dart

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,31 @@ import 'package:flutter/widgets.dart';
44

55
extension FlTitlesDataExtension on FlTitlesData {
66
EdgeInsets get allSidesPadding => EdgeInsets.only(
7-
left: show ? leftTitles.totalReservedSize : 0.0,
8-
top: show ? topTitles.totalReservedSize : 0.0,
9-
right: show ? rightTitles.totalReservedSize : 0.0,
10-
bottom: show ? bottomTitles.totalReservedSize : 0.0,
7+
left: _getPadding(
8+
leftTitles.sideTitleAlignment,
9+
leftTitles.totalReservedSize,
10+
),
11+
top: _getPadding(
12+
topTitles.sideTitleAlignment,
13+
topTitles.totalReservedSize,
14+
),
15+
right: _getPadding(
16+
rightTitles.sideTitleAlignment,
17+
rightTitles.totalReservedSize,
18+
),
19+
bottom: _getPadding(
20+
bottomTitles.sideTitleAlignment,
21+
bottomTitles.totalReservedSize,
22+
),
1123
);
24+
25+
double _getPadding(SideTitleAlignment alignment, double reservedSize) {
26+
if (!show || alignment == SideTitleAlignment.inside) {
27+
return 0;
28+
} else if (alignment == SideTitleAlignment.border) {
29+
return reservedSize / 2;
30+
} else {
31+
return reservedSize;
32+
}
33+
}
1234
}

repo_files/documentations/base_chart.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
|axisNameWidget| It shows the name of axis (you can pass a Widget)| `null`|
2424
|sideTitles| It accepts a [SideTitles](#SideTitles) which is responsible to show your axis side titles| `SideTitles()`|
2525
|drawBehindEverything| If titles are showing on top of your tooltip, you can draw them behind everything.| `true`|
26+
|sideTitleAlignment| It accepts a [SideTitleAlignment](#SideTitleAlignment) which is responsible for positioning the axis labels inside, outside, or on the border of the chart| `SideTitleAlignment.outside`
2627

2728
### SideTitles
2829
|PropName |Description |default value|
@@ -34,7 +35,6 @@
3435
|minIncluded| Determines whether to include title for minimum data value | true |
3536
|maxIncluded| Determines whether to include title for maximum data value | true |
3637

37-
3838
### SideTitleFitInsideData
3939
|PropName |Description |default value|
4040
|:---------------|:---------------|:-------|
@@ -207,3 +207,10 @@ enum values {`center`, `left`, `right`}
207207
|x|x value of the touched spot|required|
208208
|y|y value of the touched spot|required|
209209
|AxisSpotIndicatorPainter|a painter that is used to draw the touched spot indicator. You can use this to customize the appearance of the touched spot indicator (Or you can implement your own painter).|AxisLinesIndicatorPainter()|
210+
211+
### SideTitleAlignment
212+
|Option |Description | Is Default
213+
|:---------------|:---------------|:-------|
214+
|`SideTitleAlignment.outside`| Places the axis labels outside the chart area| Yes|
215+
|`SideTitleAlignment.border`| Places the axis labels along the border of the chart area| No|
216+
|`SideTitleAlignment.inside`| Places the axis labels inside the border of the chart area| No|

test/chart/base/axis_chart/side_titles/side_titles_test.dart

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,100 @@ void main() {
7878
}
7979
},
8080
);
81+
82+
testWidgets('LineChart with only left titles overlayed on chart area',
83+
(WidgetTester tester) async {
84+
await tester.pumpWidget(
85+
MaterialApp(
86+
home: Scaffold(
87+
body: Center(
88+
child: SizedBox(
89+
width: viewSize.width,
90+
height: viewSize.height,
91+
child: LineChart(
92+
LineChartData(
93+
titlesData: FlTitlesData(
94+
leftTitles: AxisTitles(
95+
sideTitleAlignment: SideTitleAlignment.inside,
96+
axisNameWidget: const Text('Left Titles'),
97+
sideTitles: SideTitles(
98+
showTitles: true,
99+
getTitlesWidget: (double value, TitleMeta meta) {
100+
return Text('L-${value.toInt()}');
101+
},
102+
interval: 1,
103+
),
104+
),
105+
),
106+
lineBarsData: [
107+
LineChartBarData(
108+
spots: data,
109+
),
110+
],
111+
),
112+
),
113+
),
114+
),
115+
),
116+
),
117+
);
118+
119+
final leftTitleFinder = find.text('L-0');
120+
expect(leftTitleFinder, findsOneWidget);
121+
122+
final leftTitleRect = tester.getRect(leftTitleFinder);
123+
124+
final chartFinder = find.byType(LineChart);
125+
final chartRect = tester.getRect(chartFinder);
126+
127+
expect(leftTitleRect.left >= chartRect.left, true);
128+
});
129+
130+
testWidgets('LineChart with only left titles overlayed on chart border',
131+
(WidgetTester tester) async {
132+
await tester.pumpWidget(
133+
MaterialApp(
134+
home: Scaffold(
135+
body: Center(
136+
child: SizedBox(
137+
width: viewSize.width,
138+
height: viewSize.height,
139+
child: LineChart(
140+
LineChartData(
141+
titlesData: FlTitlesData(
142+
leftTitles: AxisTitles(
143+
sideTitleAlignment: SideTitleAlignment.border,
144+
axisNameWidget: const Text('Left Titles'),
145+
sideTitles: SideTitles(
146+
showTitles: true,
147+
getTitlesWidget: (double value, TitleMeta meta) {
148+
return Text('L-${value.toInt()}');
149+
},
150+
interval: 1,
151+
),
152+
),
153+
),
154+
lineBarsData: [
155+
LineChartBarData(
156+
spots: data,
157+
),
158+
],
159+
),
160+
),
161+
),
162+
),
163+
),
164+
),
165+
);
166+
167+
final leftTitleFinder = find.text('L-0');
168+
expect(leftTitleFinder, findsOneWidget);
169+
170+
final leftTitleRect = tester.getRect(leftTitleFinder);
171+
172+
final chartFinder = find.byType(LineChart);
173+
final chartRect = tester.getRect(chartFinder);
174+
175+
expect(leftTitleRect.left >= chartRect.left, true);
176+
});
81177
}

0 commit comments

Comments
 (0)