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