Showing
4 changed files
with
78 additions
and
40 deletions
@@ -11,6 +11,7 @@ | @@ -11,6 +11,7 @@ | ||
11 | - Remove deprecated methods | 11 | - Remove deprecated methods |
12 | - Document.save() now returns a Future | 12 | - Document.save() now returns a Future |
13 | - Add Widget.draw() to paint any widget on a canvas | 13 | - Add Widget.draw() to paint any widget on a canvas |
14 | +- Improve Chart labels | ||
14 | 15 | ||
15 | ## 1.13.0 | 16 | ## 1.13.0 |
16 | 17 |
@@ -92,6 +92,7 @@ class Chart extends Widget implements Inherited { | @@ -92,6 +92,7 @@ class Chart extends Widget implements Inherited { | ||
92 | if (left != null) left, | 92 | if (left != null) left, |
93 | Expanded( | 93 | Expanded( |
94 | child: Stack( | 94 | child: Stack( |
95 | + overflow: Overflow.visible, | ||
95 | children: <Widget>[ | 96 | children: <Widget>[ |
96 | grid, | 97 | grid, |
97 | if (overlay != null) overlay, | 98 | if (overlay != null) overlay, |
@@ -18,15 +18,17 @@ import 'dart:math' as math; | @@ -18,15 +18,17 @@ import 'dart:math' as math; | ||
18 | 18 | ||
19 | import 'package:pdf/pdf.dart'; | 19 | import 'package:pdf/pdf.dart'; |
20 | 20 | ||
21 | +import '../basic.dart'; | ||
21 | import '../flex.dart'; | 22 | import '../flex.dart'; |
22 | import '../geometry.dart'; | 23 | import '../geometry.dart'; |
24 | +import '../text.dart'; | ||
23 | import '../text_style.dart'; | 25 | import '../text_style.dart'; |
24 | -import '../theme.dart'; | ||
25 | import '../widget.dart'; | 26 | import '../widget.dart'; |
26 | import 'chart.dart'; | 27 | import 'chart.dart'; |
27 | import 'grid_cartesian.dart'; | 28 | import 'grid_cartesian.dart'; |
28 | 29 | ||
29 | typedef GridAxisFormat = String Function(num value); | 30 | typedef GridAxisFormat = String Function(num value); |
31 | +typedef GridAxisBuildLabel = Widget Function(num value); | ||
30 | 32 | ||
31 | abstract class GridAxis extends Widget { | 33 | abstract class GridAxis extends Widget { |
32 | GridAxis({ | 34 | GridAxis({ |
@@ -43,6 +45,8 @@ abstract class GridAxis extends Widget { | @@ -43,6 +45,8 @@ abstract class GridAxis extends Widget { | ||
43 | bool divisionsDashed, | 45 | bool divisionsDashed, |
44 | bool ticks, | 46 | bool ticks, |
45 | bool axisTick, | 47 | bool axisTick, |
48 | + this.angle = 0, | ||
49 | + this.buildLabel, | ||
46 | }) : format = format ?? _defaultFormat, | 50 | }) : format = format ?? _defaultFormat, |
47 | color = color ?? PdfColors.black, | 51 | color = color ?? PdfColors.black, |
48 | width = width ?? 1, | 52 | width = width ?? 1, |
@@ -59,6 +63,8 @@ abstract class GridAxis extends Widget { | @@ -59,6 +63,8 @@ abstract class GridAxis extends Widget { | ||
59 | 63 | ||
60 | final GridAxisFormat format; | 64 | final GridAxisFormat format; |
61 | 65 | ||
66 | + final GridAxisBuildLabel buildLabel; | ||
67 | + | ||
62 | final TextStyle textStyle; | 68 | final TextStyle textStyle; |
63 | 69 | ||
64 | final double margin; | 70 | final double margin; |
@@ -89,6 +95,8 @@ abstract class GridAxis extends Widget { | @@ -89,6 +95,8 @@ abstract class GridAxis extends Widget { | ||
89 | 95 | ||
90 | double axisPosition = 0; | 96 | double axisPosition = 0; |
91 | 97 | ||
98 | + final double angle; | ||
99 | + | ||
92 | static String _defaultFormat(num v) => v.toString(); | 100 | static String _defaultFormat(num v) => v.toString(); |
93 | 101 | ||
94 | double transfer(num input) { | 102 | double transfer(num input) { |
@@ -116,6 +124,8 @@ class FixedAxis<T extends num> extends GridAxis { | @@ -116,6 +124,8 @@ class FixedAxis<T extends num> extends GridAxis { | ||
116 | bool divisionsDashed, | 124 | bool divisionsDashed, |
117 | bool ticks, | 125 | bool ticks, |
118 | bool axisTick, | 126 | bool axisTick, |
127 | + double angle = 0, | ||
128 | + GridAxisBuildLabel buildLabel, | ||
119 | }) : assert(_isSortedAscending(values)), | 129 | }) : assert(_isSortedAscending(values)), |
120 | super( | 130 | super( |
121 | format: format, | 131 | format: format, |
@@ -131,6 +141,8 @@ class FixedAxis<T extends num> extends GridAxis { | @@ -131,6 +141,8 @@ class FixedAxis<T extends num> extends GridAxis { | ||
131 | divisionsDashed: divisionsDashed, | 141 | divisionsDashed: divisionsDashed, |
132 | ticks: ticks, | 142 | ticks: ticks, |
133 | axisTick: axisTick, | 143 | axisTick: axisTick, |
144 | + angle: angle, | ||
145 | + buildLabel: buildLabel, | ||
134 | ); | 146 | ); |
135 | 147 | ||
136 | static FixedAxis<int> fromStrings( | 148 | static FixedAxis<int> fromStrings( |
@@ -147,6 +159,8 @@ class FixedAxis<T extends num> extends GridAxis { | @@ -147,6 +159,8 @@ class FixedAxis<T extends num> extends GridAxis { | ||
147 | bool divisionsDashed, | 159 | bool divisionsDashed, |
148 | bool ticks, | 160 | bool ticks, |
149 | bool axisTick, | 161 | bool axisTick, |
162 | + double angle = 0, | ||
163 | + GridAxisBuildLabel buildLabel, | ||
150 | }) { | 164 | }) { |
151 | return FixedAxis<int>( | 165 | return FixedAxis<int>( |
152 | List<int>.generate(values.length, (int index) => index), | 166 | List<int>.generate(values.length, (int index) => index), |
@@ -163,6 +177,8 @@ class FixedAxis<T extends num> extends GridAxis { | @@ -163,6 +177,8 @@ class FixedAxis<T extends num> extends GridAxis { | ||
163 | divisionsDashed: divisionsDashed, | 177 | divisionsDashed: divisionsDashed, |
164 | ticks: ticks, | 178 | ticks: ticks, |
165 | axisTick: axisTick, | 179 | axisTick: axisTick, |
180 | + angle: angle, | ||
181 | + buildLabel: buildLabel, | ||
166 | ); | 182 | ); |
167 | } | 183 | } |
168 | 184 | ||
@@ -202,6 +218,30 @@ class FixedAxis<T extends num> extends GridAxis { | @@ -202,6 +218,30 @@ class FixedAxis<T extends num> extends GridAxis { | ||
202 | return null; | 218 | return null; |
203 | } | 219 | } |
204 | 220 | ||
221 | + Widget _text(num value) { | ||
222 | + final t = buildLabel == null | ||
223 | + ? Text(format(value), style: textStyle) | ||
224 | + : buildLabel(value); | ||
225 | + if (angle == 0.0) { | ||
226 | + return t; | ||
227 | + } | ||
228 | + | ||
229 | + return Transform.rotateBox( | ||
230 | + angle: angle, | ||
231 | + child: t, | ||
232 | + ); | ||
233 | + } | ||
234 | + | ||
235 | + int _angleDirection() { | ||
236 | + if (angle == 0.0) { | ||
237 | + return 0; | ||
238 | + } | ||
239 | + if (angle % math.pi > math.pi / 2) { | ||
240 | + return -1; | ||
241 | + } | ||
242 | + return 1; | ||
243 | + } | ||
244 | + | ||
205 | @override | 245 | @override |
206 | void layout(Context context, BoxConstraints constraints, | 246 | void layout(Context context, BoxConstraints constraints, |
207 | {bool parentUsesSize = false}) { | 247 | {bool parentUsesSize = false}) { |
@@ -209,26 +249,28 @@ class FixedAxis<T extends num> extends GridAxis { | @@ -209,26 +249,28 @@ class FixedAxis<T extends num> extends GridAxis { | ||
209 | '$runtimeType cannot be used without a Chart widget'); | 249 | '$runtimeType cannot be used without a Chart widget'); |
210 | 250 | ||
211 | final size = constraints.biggest; | 251 | final size = constraints.biggest; |
212 | - final style = Theme.of(context).defaultTextStyle.merge(textStyle); | ||
213 | - final font = style.font.getFont(context); | ||
214 | 252 | ||
215 | var maxWidth = 0.0; | 253 | var maxWidth = 0.0; |
216 | var maxHeight = 0.0; | 254 | var maxHeight = 0.0; |
217 | - PdfFontMetrics metricsFirst; | ||
218 | - PdfFontMetrics metrics; | 255 | + PdfPoint first; |
256 | + PdfPoint last; | ||
257 | + | ||
219 | for (final value in values) { | 258 | for (final value in values) { |
220 | - metrics = font.stringMetrics(format(value)) * style.fontSize; | ||
221 | - metricsFirst ??= metrics; | ||
222 | - maxWidth = math.max(maxWidth, metrics.maxWidth); | ||
223 | - maxHeight = math.max(maxHeight, metrics.maxHeight); | 259 | + last = Widget.measure(_text(value), context: context); |
260 | + maxWidth = math.max(maxWidth, last.x); | ||
261 | + maxHeight = math.max(maxHeight, last.y); | ||
262 | + first ??= last; | ||
224 | } | 263 | } |
225 | 264 | ||
265 | + final ad = _angleDirection(); | ||
266 | + | ||
226 | switch (direction) { | 267 | switch (direction) { |
227 | case Axis.horizontal: | 268 | case Axis.horizontal: |
228 | _textMargin = margin ?? 2; | 269 | _textMargin = margin ?? 2; |
229 | _axisTick ??= false; | 270 | _axisTick ??= false; |
230 | - final minStart = metricsFirst.maxWidth / 2; | ||
231 | - _marginEnd = math.max(_marginEnd, metrics.maxWidth / 2); | 271 | + final minStart = ad == 0 ? first.x / 2 : (ad > 0 ? first.x : 0.0); |
272 | + _marginEnd = math.max( | ||
273 | + _marginEnd, ad == 0 ? last.x / 2 : (ad > 0 ? 0.0 : last.x)); | ||
232 | crossAxisPosition = math.max(crossAxisPosition, minStart); | 274 | crossAxisPosition = math.max(crossAxisPosition, minStart); |
233 | axisPosition = math.max(axisPosition, maxHeight + _textMargin); | 275 | axisPosition = math.max(axisPosition, maxHeight + _textMargin); |
234 | box = PdfRect(0, 0, size.x, axisPosition); | 276 | box = PdfRect(0, 0, size.x, axisPosition); |
@@ -236,9 +278,9 @@ class FixedAxis<T extends num> extends GridAxis { | @@ -236,9 +278,9 @@ class FixedAxis<T extends num> extends GridAxis { | ||
236 | case Axis.vertical: | 278 | case Axis.vertical: |
237 | _textMargin = margin ?? 10; | 279 | _textMargin = margin ?? 10; |
238 | _axisTick ??= true; | 280 | _axisTick ??= true; |
239 | - _marginEnd = math.max(_marginEnd, metrics.maxHeight / 2); | ||
240 | - final minStart = metricsFirst.maxHeight / 2; | ||
241 | - _marginEnd = math.max(_marginEnd, metrics.maxWidth / 2); | 281 | + _marginEnd = math.max( |
282 | + _marginEnd, ad == 0 ? last.x / 2 : (ad < 0 ? last.x : 0.0)); | ||
283 | + final minStart = ad == 0 ? first.y / 2 : (ad > 0 ? first.x : 0.0); | ||
242 | crossAxisPosition = math.max(crossAxisPosition, minStart); | 284 | crossAxisPosition = math.max(crossAxisPosition, minStart); |
243 | axisPosition = math.max(axisPosition, maxWidth + _textMargin); | 285 | axisPosition = math.max(axisPosition, maxWidth + _textMargin); |
244 | box = PdfRect(0, 0, axisPosition, size.y); | 286 | box = PdfRect(0, 0, axisPosition, size.y); |
@@ -273,22 +315,19 @@ class FixedAxis<T extends num> extends GridAxis { | @@ -273,22 +315,19 @@ class FixedAxis<T extends num> extends GridAxis { | ||
273 | ..setLineJoin(PdfLineJoin.bevel) | 315 | ..setLineJoin(PdfLineJoin.bevel) |
274 | ..strokePath(); | 316 | ..strokePath(); |
275 | 317 | ||
318 | + final ad = _angleDirection(); | ||
319 | + | ||
276 | for (final y in values) { | 320 | for (final y in values) { |
277 | - final v = format(y); | ||
278 | - final style = Theme.of(context).defaultTextStyle.merge(textStyle); | ||
279 | - final font = style.font.getFont(context); | ||
280 | - final metrics = font.stringMetrics(v) * style.fontSize; | ||
281 | final p = toChart(y); | 321 | final p = toChart(y); |
282 | 322 | ||
283 | - context.canvas | ||
284 | - ..setColor(style.color) | ||
285 | - ..drawString( | ||
286 | - style.font.getFont(context), | ||
287 | - style.fontSize, | ||
288 | - v, | ||
289 | - axisPosition - _textMargin - metrics.maxWidth, | ||
290 | - p - (metrics.ascent + metrics.descent) / 2, | ||
291 | - ); | 323 | + Widget.draw( |
324 | + _text(y), | ||
325 | + offset: PdfPoint(axisPosition - _textMargin, p), | ||
326 | + context: context, | ||
327 | + alignment: ad == 0 | ||
328 | + ? Alignment.centerRight | ||
329 | + : (ad > 0 ? Alignment.topRight : Alignment.bottomRight), | ||
330 | + ); | ||
292 | } | 331 | } |
293 | } | 332 | } |
294 | 333 | ||
@@ -318,22 +357,19 @@ class FixedAxis<T extends num> extends GridAxis { | @@ -318,22 +357,19 @@ class FixedAxis<T extends num> extends GridAxis { | ||
318 | ..setLineJoin(PdfLineJoin.bevel) | 357 | ..setLineJoin(PdfLineJoin.bevel) |
319 | ..strokePath(); | 358 | ..strokePath(); |
320 | 359 | ||
360 | + final ad = _angleDirection(); | ||
361 | + | ||
321 | for (final num x in values) { | 362 | for (final num x in values) { |
322 | - final v = format(x); | ||
323 | - final style = Theme.of(context).defaultTextStyle.merge(textStyle); | ||
324 | - final font = style.font.getFont(context); | ||
325 | - final metrics = font.stringMetrics(v) * style.fontSize; | ||
326 | final p = toChart(x); | 363 | final p = toChart(x); |
327 | 364 | ||
328 | - context.canvas | ||
329 | - ..setColor(style.color) | ||
330 | - ..drawString( | ||
331 | - style.font.getFont(context), | ||
332 | - style.fontSize, | ||
333 | - v, | ||
334 | - p - metrics.maxWidth / 2, | ||
335 | - axisPosition - metrics.ascent - _textMargin, | ||
336 | - ); | 365 | + Widget.draw( |
366 | + _text(x), | ||
367 | + offset: PdfPoint(p, axisPosition - _textMargin), | ||
368 | + context: context, | ||
369 | + alignment: ad == 0 | ||
370 | + ? Alignment.topCenter | ||
371 | + : (ad > 0 ? Alignment.topRight : Alignment.topLeft), | ||
372 | + ); | ||
337 | } | 373 | } |
338 | } | 374 | } |
339 | 375 |
No preview for this file type
-
Please register or login to post a comment