Showing
5 changed files
with
319 additions
and
59 deletions
| @@ -33,6 +33,7 @@ part 'widgets/basic.dart'; | @@ -33,6 +33,7 @@ part 'widgets/basic.dart'; | ||
| 33 | part 'widgets/chart/chart.dart'; | 33 | part 'widgets/chart/chart.dart'; |
| 34 | part 'widgets/chart/linear_grid.dart'; | 34 | part 'widgets/chart/linear_grid.dart'; |
| 35 | part 'widgets/chart/line_chart.dart'; | 35 | part 'widgets/chart/line_chart.dart'; |
| 36 | +part 'widgets/chart/bar_chart.dart'; | ||
| 36 | part 'widgets/clip.dart'; | 37 | part 'widgets/clip.dart'; |
| 37 | part 'widgets/container.dart'; | 38 | part 'widgets/container.dart'; |
| 38 | part 'widgets/content.dart'; | 39 | part 'widgets/content.dart'; |
pdf/lib/widgets/chart/bar_chart.dart
0 → 100644
| 1 | +/* | ||
| 2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +// ignore_for_file: omit_local_variable_types | ||
| 18 | + | ||
| 19 | +part of widget; | ||
| 20 | + | ||
| 21 | +class BarDataSet extends DataSet { | ||
| 22 | + BarDataSet({ | ||
| 23 | + @required this.data, | ||
| 24 | + this.borderColor, | ||
| 25 | + this.borderWidth = 1.5, | ||
| 26 | + this.color = PdfColors.blue, | ||
| 27 | + this.drawBorder = true, | ||
| 28 | + this.drawSurface = true, | ||
| 29 | + this.surfaceOpacity = 1, | ||
| 30 | + this.width = 20, | ||
| 31 | + this.offset = 0, | ||
| 32 | + this.margin = 5, | ||
| 33 | + }) : assert(drawBorder || drawSurface); | ||
| 34 | + | ||
| 35 | + final List<LineChartValue> data; | ||
| 36 | + final double width; | ||
| 37 | + final double offset; | ||
| 38 | + final double margin; | ||
| 39 | + | ||
| 40 | + final bool drawBorder; | ||
| 41 | + final PdfColor borderColor; | ||
| 42 | + final double borderWidth; | ||
| 43 | + | ||
| 44 | + final bool drawSurface; | ||
| 45 | + final PdfColor color; | ||
| 46 | + final double surfaceOpacity; | ||
| 47 | + | ||
| 48 | + void _drawSurface(Context context, ChartGrid grid, LineChartValue value) { | ||
| 49 | + final double y = (grid is LinearGrid) ? grid.xAxisOffset : 0; | ||
| 50 | + final PdfPoint p = grid.tochart(value.point); | ||
| 51 | + | ||
| 52 | + context.canvas.drawRect(p.x + offset - width / 2, y, width, p.y); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + @override | ||
| 56 | + void paintBackground(Context context, ChartGrid grid) {} | ||
| 57 | + | ||
| 58 | + @override | ||
| 59 | + void paintForeground(Context context, ChartGrid grid) { | ||
| 60 | + if (data.isEmpty) { | ||
| 61 | + return; | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + if (data.isEmpty) { | ||
| 65 | + return; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + if (drawSurface) { | ||
| 69 | + for (final LineChartValue value in data) { | ||
| 70 | + _drawSurface(context, grid, value); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + if (surfaceOpacity != 1) { | ||
| 74 | + context.canvas | ||
| 75 | + ..saveContext() | ||
| 76 | + ..setGraphicState( | ||
| 77 | + PdfGraphicState(opacity: surfaceOpacity), | ||
| 78 | + ); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + context.canvas | ||
| 82 | + ..setFillColor(color) | ||
| 83 | + ..fillPath(); | ||
| 84 | + | ||
| 85 | + if (surfaceOpacity != 1) { | ||
| 86 | + context.canvas.restoreContext(); | ||
| 87 | + } | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + if (drawBorder) { | ||
| 91 | + for (final LineChartValue value in data) { | ||
| 92 | + _drawSurface(context, grid, value); | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + context.canvas | ||
| 96 | + ..setStrokeColor(borderColor ?? color) | ||
| 97 | + ..setLineWidth(borderWidth) | ||
| 98 | + ..strokePath(); | ||
| 99 | + } | ||
| 100 | + } | ||
| 101 | +} |
| @@ -18,6 +18,7 @@ | @@ -18,6 +18,7 @@ | ||
| 18 | 18 | ||
| 19 | part of widget; | 19 | part of widget; |
| 20 | 20 | ||
| 21 | +/// This widget is in preview and the API is subject to change | ||
| 21 | class Chart extends Widget { | 22 | class Chart extends Widget { |
| 22 | Chart({ | 23 | Chart({ |
| 23 | @required this.grid, | 24 | @required this.grid, |
| @@ -68,12 +69,17 @@ class Chart extends Widget { | @@ -68,12 +69,17 @@ class Chart extends Widget { | ||
| 68 | ..setTransform(mat); | 69 | ..setTransform(mat); |
| 69 | 70 | ||
| 70 | grid.paintBackground(context, box.size); | 71 | grid.paintBackground(context, box.size); |
| 72 | + grid.clip(context, box.size); | ||
| 71 | for (DataSet dataSet in data) { | 73 | for (DataSet dataSet in data) { |
| 72 | dataSet.paintBackground(context, grid); | 74 | dataSet.paintBackground(context, grid); |
| 73 | } | 75 | } |
| 76 | + grid.unClip(context, box.size); | ||
| 77 | + grid.paint(context, box.size); | ||
| 78 | + grid.clip(context, box.size); | ||
| 74 | for (DataSet dataSet in data) { | 79 | for (DataSet dataSet in data) { |
| 75 | dataSet.paintForeground(context, grid); | 80 | dataSet.paintForeground(context, grid); |
| 76 | } | 81 | } |
| 82 | + grid.unClip(context, box.size); | ||
| 77 | grid.paintForeground(context, box.size); | 83 | grid.paintForeground(context, box.size); |
| 78 | context.canvas.restoreContext(); | 84 | context.canvas.restoreContext(); |
| 79 | } | 85 | } |
| @@ -82,8 +88,12 @@ class Chart extends Widget { | @@ -82,8 +88,12 @@ class Chart extends Widget { | ||
| 82 | abstract class ChartGrid { | 88 | abstract class ChartGrid { |
| 83 | void layout(Context context, PdfPoint size); | 89 | void layout(Context context, PdfPoint size); |
| 84 | void paintBackground(Context context, PdfPoint size); | 90 | void paintBackground(Context context, PdfPoint size); |
| 91 | + void paint(Context context, PdfPoint size); | ||
| 85 | void paintForeground(Context context, PdfPoint size); | 92 | void paintForeground(Context context, PdfPoint size); |
| 86 | 93 | ||
| 94 | + void clip(Context context, PdfPoint size); | ||
| 95 | + void unClip(Context context, PdfPoint size); | ||
| 96 | + | ||
| 87 | PdfPoint tochart(PdfPoint p); | 97 | PdfPoint tochart(PdfPoint p); |
| 88 | } | 98 | } |
| 89 | 99 |
| @@ -35,21 +35,31 @@ class LineDataSet extends DataSet { | @@ -35,21 +35,31 @@ class LineDataSet extends DataSet { | ||
| 35 | this.lineWidth = 2, | 35 | this.lineWidth = 2, |
| 36 | this.drawLine = true, | 36 | this.drawLine = true, |
| 37 | this.drawPoints = true, | 37 | this.drawPoints = true, |
| 38 | + this.drawSurface = false, | ||
| 39 | + this.surfaceOpacity = .2, | ||
| 40 | + this.surfaceColor, | ||
| 38 | this.isCurved = false, | 41 | this.isCurved = false, |
| 39 | this.smoothness = 0.35, | 42 | this.smoothness = 0.35, |
| 40 | - }) : assert(drawLine || drawPoints); | 43 | + }) : assert(drawLine || drawPoints || drawSurface); |
| 41 | 44 | ||
| 42 | final List<LineChartValue> data; | 45 | final List<LineChartValue> data; |
| 43 | - final PdfColor pointColor; | ||
| 44 | - final double pointSize; | 46 | + |
| 47 | + final bool drawLine; | ||
| 45 | final PdfColor color; | 48 | final PdfColor color; |
| 46 | final double lineWidth; | 49 | final double lineWidth; |
| 47 | - final bool drawLine; | 50 | + |
| 48 | final bool drawPoints; | 51 | final bool drawPoints; |
| 52 | + final PdfColor pointColor; | ||
| 53 | + final double pointSize; | ||
| 54 | + | ||
| 55 | + final bool drawSurface; | ||
| 56 | + final PdfColor surfaceColor; | ||
| 57 | + final double surfaceOpacity; | ||
| 58 | + | ||
| 49 | final bool isCurved; | 59 | final bool isCurved; |
| 50 | final double smoothness; | 60 | final double smoothness; |
| 51 | 61 | ||
| 52 | - void _drawLine(Context context, ChartGrid grid) { | 62 | + void _drawLine(Context context, ChartGrid grid, bool moveTo) { |
| 53 | if (data.length < 2) { | 63 | if (data.length < 2) { |
| 54 | return; | 64 | return; |
| 55 | } | 65 | } |
| @@ -57,7 +67,11 @@ class LineDataSet extends DataSet { | @@ -57,7 +67,11 @@ class LineDataSet extends DataSet { | ||
| 57 | PdfPoint t = const PdfPoint(0, 0); | 67 | PdfPoint t = const PdfPoint(0, 0); |
| 58 | 68 | ||
| 59 | final PdfPoint p = grid.tochart(data.first.point); | 69 | final PdfPoint p = grid.tochart(data.first.point); |
| 60 | - context.canvas.moveTo(p.x, p.y); | 70 | + if (moveTo) { |
| 71 | + context.canvas.moveTo(p.x, p.y); | ||
| 72 | + } else { | ||
| 73 | + context.canvas.lineTo(p.x, p.y); | ||
| 74 | + } | ||
| 61 | 75 | ||
| 62 | for (int i = 1; i < data.length; i++) { | 76 | for (int i = 1; i < data.length; i++) { |
| 63 | final PdfPoint p = grid.tochart(data[i].point); | 77 | final PdfPoint p = grid.tochart(data[i].point); |
| @@ -82,6 +96,20 @@ class LineDataSet extends DataSet { | @@ -82,6 +96,20 @@ class LineDataSet extends DataSet { | ||
| 82 | } | 96 | } |
| 83 | } | 97 | } |
| 84 | 98 | ||
| 99 | + void _drawSurface(Context context, ChartGrid grid) { | ||
| 100 | + if (data.length < 2) { | ||
| 101 | + return; | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + final double y = (grid is LinearGrid) ? grid.xAxisOffset : 0; | ||
| 105 | + _drawLine(context, grid, true); | ||
| 106 | + | ||
| 107 | + final PdfPoint pe = grid.tochart(data.last.point); | ||
| 108 | + context.canvas.lineTo(pe.x, y); | ||
| 109 | + final PdfPoint pf = grid.tochart(data.first.point); | ||
| 110 | + context.canvas.lineTo(pf.x, y); | ||
| 111 | + } | ||
| 112 | + | ||
| 85 | void _drawPoints(Context context, ChartGrid grid) { | 113 | void _drawPoints(Context context, ChartGrid grid) { |
| 86 | for (final LineChartValue value in data) { | 114 | for (final LineChartValue value in data) { |
| 87 | final PdfPoint p = grid.tochart(value.point); | 115 | final PdfPoint p = grid.tochart(value.point); |
| @@ -90,7 +118,31 @@ class LineDataSet extends DataSet { | @@ -90,7 +118,31 @@ class LineDataSet extends DataSet { | ||
| 90 | } | 118 | } |
| 91 | 119 | ||
| 92 | @override | 120 | @override |
| 93 | - void paintBackground(Context context, ChartGrid grid) {} | 121 | + void paintBackground(Context context, ChartGrid grid) { |
| 122 | + if (data.isEmpty) { | ||
| 123 | + return; | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + if (drawSurface) { | ||
| 127 | + _drawSurface(context, grid); | ||
| 128 | + | ||
| 129 | + if (surfaceOpacity != 1) { | ||
| 130 | + context.canvas | ||
| 131 | + ..saveContext() | ||
| 132 | + ..setGraphicState( | ||
| 133 | + PdfGraphicState(opacity: surfaceOpacity), | ||
| 134 | + ); | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + context.canvas | ||
| 138 | + ..setFillColor(surfaceColor ?? color) | ||
| 139 | + ..fillPath(); | ||
| 140 | + | ||
| 141 | + if (surfaceOpacity != 1) { | ||
| 142 | + context.canvas.restoreContext(); | ||
| 143 | + } | ||
| 144 | + } | ||
| 145 | + } | ||
| 94 | 146 | ||
| 95 | @override | 147 | @override |
| 96 | void paintForeground(Context context, ChartGrid grid) { | 148 | void paintForeground(Context context, ChartGrid grid) { |
| @@ -99,7 +151,7 @@ class LineDataSet extends DataSet { | @@ -99,7 +151,7 @@ class LineDataSet extends DataSet { | ||
| 99 | } | 151 | } |
| 100 | 152 | ||
| 101 | if (drawLine) { | 153 | if (drawLine) { |
| 102 | - _drawLine(context, grid); | 154 | + _drawLine(context, grid, true); |
| 103 | 155 | ||
| 104 | context.canvas | 156 | context.canvas |
| 105 | ..setStrokeColor(color) | 157 | ..setStrokeColor(color) |
| @@ -18,6 +18,8 @@ | @@ -18,6 +18,8 @@ | ||
| 18 | 18 | ||
| 19 | part of widget; | 19 | part of widget; |
| 20 | 20 | ||
| 21 | +typedef GridAxisFormat = String Function(double value); | ||
| 22 | + | ||
| 21 | class LinearGrid extends ChartGrid { | 23 | class LinearGrid extends ChartGrid { |
| 22 | LinearGrid({ | 24 | LinearGrid({ |
| 23 | @required this.xAxis, | 25 | @required this.xAxis, |
| @@ -28,7 +30,11 @@ class LinearGrid extends ChartGrid { | @@ -28,7 +30,11 @@ class LinearGrid extends ChartGrid { | ||
| 28 | this.lineWidth = 1, | 30 | this.lineWidth = 1, |
| 29 | this.color = PdfColors.black, | 31 | this.color = PdfColors.black, |
| 30 | this.separatorLineWidth = .5, | 32 | this.separatorLineWidth = .5, |
| 33 | + this.drawXDivisions = false, | ||
| 34 | + this.drawYDivisions = true, | ||
| 31 | this.separatorColor = PdfColors.grey, | 35 | this.separatorColor = PdfColors.grey, |
| 36 | + this.xAxisFormat = _defaultFormat, | ||
| 37 | + this.yAxisFormat = _defaultFormat, | ||
| 32 | }) : assert(_isSortedAscending(xAxis)), | 38 | }) : assert(_isSortedAscending(xAxis)), |
| 33 | assert(_isSortedAscending(yAxis)); | 39 | assert(_isSortedAscending(yAxis)); |
| 34 | 40 | ||
| @@ -41,20 +47,24 @@ class LinearGrid extends ChartGrid { | @@ -41,20 +47,24 @@ class LinearGrid extends ChartGrid { | ||
| 41 | final PdfColor color; | 47 | final PdfColor color; |
| 42 | final double separatorLineWidth; | 48 | final double separatorLineWidth; |
| 43 | final PdfColor separatorColor; | 49 | final PdfColor separatorColor; |
| 50 | + final bool drawXDivisions; | ||
| 51 | + final bool drawYDivisions; | ||
| 52 | + final GridAxisFormat xAxisFormat; | ||
| 53 | + final GridAxisFormat yAxisFormat; | ||
| 44 | 54 | ||
| 45 | TextStyle style; | 55 | TextStyle style; |
| 46 | PdfFont font; | 56 | PdfFont font; |
| 47 | - PdfFontMetrics xAxisFontMetric; | ||
| 48 | - PdfFontMetrics yAxisFontMetric; | ||
| 49 | PdfRect gridBox; | 57 | PdfRect gridBox; |
| 50 | double xOffset; | 58 | double xOffset; |
| 51 | double xTotal; | 59 | double xTotal; |
| 52 | double yOffset; | 60 | double yOffset; |
| 53 | double yTotal; | 61 | double yTotal; |
| 54 | 62 | ||
| 63 | + static String _defaultFormat(double v) => v.toString(); | ||
| 64 | + | ||
| 55 | static bool _isSortedAscending(List<double> list) { | 65 | static bool _isSortedAscending(List<double> list) { |
| 56 | double prev = list.first; | 66 | double prev = list.first; |
| 57 | - for (double elem in list) { | 67 | + for (final double elem in list) { |
| 58 | if (prev > elem) { | 68 | if (prev > elem) { |
| 59 | return false; | 69 | return false; |
| 60 | } | 70 | } |
| @@ -64,30 +74,34 @@ class LinearGrid extends ChartGrid { | @@ -64,30 +74,34 @@ class LinearGrid extends ChartGrid { | ||
| 64 | } | 74 | } |
| 65 | 75 | ||
| 66 | @override | 76 | @override |
| 67 | - PdfPoint tochart(PdfPoint p) { | ||
| 68 | - return PdfPoint( | ||
| 69 | - gridBox.left + gridBox.width * (p.x - xOffset) / xTotal, | ||
| 70 | - gridBox.bottom + gridBox.height * (p.y - yOffset) / yTotal, | ||
| 71 | - ); | ||
| 72 | - } | ||
| 73 | - | ||
| 74 | - @override | ||
| 75 | void layout(Context context, PdfPoint size) { | 77 | void layout(Context context, PdfPoint size) { |
| 76 | style = Theme.of(context).defaultTextStyle.merge(textStyle); | 78 | style = Theme.of(context).defaultTextStyle.merge(textStyle); |
| 77 | font = style.font.getFont(context); | 79 | font = style.font.getFont(context); |
| 78 | 80 | ||
| 79 | - xAxisFontMetric = | ||
| 80 | - font.stringMetrics(xAxis.reduce(math.max).toStringAsFixed(1)) * | ||
| 81 | - (style.fontSize); | ||
| 82 | - yAxisFontMetric = | ||
| 83 | - font.stringMetrics(yAxis.reduce(math.max).toStringAsFixed(1)) * | ||
| 84 | - (style.fontSize); | 81 | + double xMaxWidth = 0; |
| 82 | + double xMaxHeight = 0; | ||
| 83 | + for (final double value in xAxis) { | ||
| 84 | + final PdfFontMetrics metrics = | ||
| 85 | + font.stringMetrics(xAxisFormat(value)) * style.fontSize; | ||
| 86 | + xMaxWidth = math.max(xMaxWidth, metrics.width); | ||
| 87 | + xMaxHeight = math.max(xMaxHeight, metrics.maxHeight); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + double yMaxWidth = 0; | ||
| 91 | + double yMaxHeight = 0; | ||
| 92 | + for (final double value in yAxis) { | ||
| 93 | + final PdfFontMetrics metrics = | ||
| 94 | + font.stringMetrics(yAxisFormat(value)) * style.fontSize; | ||
| 95 | + yMaxWidth = math.max(yMaxWidth, metrics.width); | ||
| 96 | + yMaxHeight = math.max(yMaxHeight, metrics.maxHeight); | ||
| 97 | + } | ||
| 85 | 98 | ||
| 86 | gridBox = PdfRect.fromLTRB( | 99 | gridBox = PdfRect.fromLTRB( |
| 87 | - yAxisFontMetric.width + xMargin, | ||
| 88 | - xAxisFontMetric.height + yMargin, | ||
| 89 | - size.x - xAxisFontMetric.width / 2, | ||
| 90 | - size.y - yAxisFontMetric.height / 2); | 100 | + yMaxWidth + xMargin, |
| 101 | + xMaxHeight + yMargin, | ||
| 102 | + size.x - xMaxWidth / 2, | ||
| 103 | + size.y - yMaxHeight / 2, | ||
| 104 | + ); | ||
| 91 | 105 | ||
| 92 | xOffset = xAxis.reduce(math.min); | 106 | xOffset = xAxis.reduce(math.min); |
| 93 | yOffset = yAxis.reduce(math.min); | 107 | yOffset = yAxis.reduce(math.min); |
| @@ -96,54 +110,136 @@ class LinearGrid extends ChartGrid { | @@ -96,54 +110,136 @@ class LinearGrid extends ChartGrid { | ||
| 96 | } | 110 | } |
| 97 | 111 | ||
| 98 | @override | 112 | @override |
| 99 | - void paintBackground(Context context, PdfPoint size) { | ||
| 100 | - xAxis.asMap().forEach((int i, double x) { | 113 | + PdfPoint tochart(PdfPoint p) { |
| 114 | + return PdfPoint( | ||
| 115 | + gridBox.left + gridBox.width * (p.x - xOffset) / xTotal, | ||
| 116 | + gridBox.bottom + gridBox.height * (p.y - yOffset) / yTotal, | ||
| 117 | + ); | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + double get xAxisOffset => gridBox.bottom; | ||
| 121 | + | ||
| 122 | + double get yAxisOffset => gridBox.left; | ||
| 123 | + | ||
| 124 | + void _drawAxis(Context context, PdfPoint size) { | ||
| 125 | + context.canvas | ||
| 126 | + ..moveTo(size.x, gridBox.bottom) | ||
| 127 | + ..lineTo(gridBox.left - xMargin / 2, gridBox.bottom) | ||
| 128 | + ..moveTo(gridBox.left, gridBox.bottom) | ||
| 129 | + ..lineTo(gridBox.left, size.y) | ||
| 130 | + ..setStrokeColor(color) | ||
| 131 | + ..setLineWidth(lineWidth) | ||
| 132 | + ..setLineCap(PdfLineCap.joinMiter) | ||
| 133 | + ..strokePath(); | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + void _drawYDivisions(Context context, PdfPoint size) { | ||
| 137 | + for (final double y in yAxis.sublist(1)) { | ||
| 138 | + final PdfPoint p = tochart(PdfPoint(0, y)); | ||
| 139 | + context.canvas.drawLine( | ||
| 140 | + gridBox.left, | ||
| 141 | + p.y, | ||
| 142 | + size.x, | ||
| 143 | + p.y, | ||
| 144 | + ); | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | + context.canvas | ||
| 148 | + ..setStrokeColor(separatorColor) | ||
| 149 | + ..setLineWidth(separatorLineWidth) | ||
| 150 | + ..setLineCap(PdfLineCap.joinMiter) | ||
| 151 | + ..strokePath(); | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + void _drawXDivisions(Context context, PdfPoint size) { | ||
| 155 | + for (final double x in xAxis.sublist(1)) { | ||
| 156 | + final PdfPoint p = tochart(PdfPoint(x, 0)); | ||
| 157 | + context.canvas.drawLine( | ||
| 158 | + p.x, | ||
| 159 | + size.y, | ||
| 160 | + p.x, | ||
| 161 | + gridBox.bottom, | ||
| 162 | + ); | ||
| 163 | + } | ||
| 164 | + | ||
| 165 | + context.canvas | ||
| 166 | + ..setStrokeColor(separatorColor) | ||
| 167 | + ..setLineWidth(separatorLineWidth) | ||
| 168 | + ..setLineCap(PdfLineCap.joinMiter) | ||
| 169 | + ..strokePath(); | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + void _drawYValues(Context context, PdfPoint size) { | ||
| 173 | + for (final double y in yAxis) { | ||
| 174 | + final String v = yAxisFormat(y); | ||
| 175 | + final PdfFontMetrics metrics = font.stringMetrics(v) * style.fontSize; | ||
| 176 | + final PdfPoint p = tochart(PdfPoint(0, y)); | ||
| 177 | + | ||
| 101 | context.canvas | 178 | context.canvas |
| 102 | ..setColor(style.color) | 179 | ..setColor(style.color) |
| 103 | ..drawString( | 180 | ..drawString( |
| 104 | style.font.getFont(context), | 181 | style.font.getFont(context), |
| 105 | style.fontSize, | 182 | style.fontSize, |
| 106 | - x.toStringAsFixed(1), | ||
| 107 | - gridBox.left + | ||
| 108 | - gridBox.width * i / (xAxis.length - 1) - | ||
| 109 | - xAxisFontMetric.width / 2, | ||
| 110 | - 0, | 183 | + v, |
| 184 | + gridBox.left - xMargin - metrics.width, | ||
| 185 | + p.y - (metrics.ascent + metrics.descent) / 2, | ||
| 111 | ); | 186 | ); |
| 112 | - }); | 187 | + } |
| 188 | + } | ||
| 189 | + | ||
| 190 | + void _drawXValues(Context context, PdfPoint size) { | ||
| 191 | + for (final double x in xAxis) { | ||
| 192 | + final String v = xAxisFormat(x); | ||
| 193 | + final PdfFontMetrics metrics = font.stringMetrics(v) * style.fontSize; | ||
| 194 | + final PdfPoint p = tochart(PdfPoint(x, 0)); | ||
| 113 | 195 | ||
| 114 | - for (double y in yAxis.where((double y) => y != yAxis.first)) { | ||
| 115 | - final double textWidth = | ||
| 116 | - (font.stringMetrics(y.toStringAsFixed(1)) * (style.fontSize)).width; | ||
| 117 | - final double yPos = gridBox.bottom + gridBox.height * y / yAxis.last; | ||
| 118 | context.canvas | 196 | context.canvas |
| 119 | ..setColor(style.color) | 197 | ..setColor(style.color) |
| 120 | ..drawString( | 198 | ..drawString( |
| 121 | style.font.getFont(context), | 199 | style.font.getFont(context), |
| 122 | style.fontSize, | 200 | style.fontSize, |
| 123 | - y.toStringAsFixed(1), | ||
| 124 | - xAxisFontMetric.width / 2 - textWidth / 2, | ||
| 125 | - yPos - font.ascent, | 201 | + v, |
| 202 | + p.x - metrics.width / 2, | ||
| 203 | + -metrics.descent, | ||
| 126 | ); | 204 | ); |
| 205 | + } | ||
| 206 | + } | ||
| 127 | 207 | ||
| 128 | - context.canvas.drawLine( | ||
| 129 | - gridBox.left, | ||
| 130 | - yPos + font.descent + font.ascent - separatorLineWidth / 2, | ||
| 131 | - gridBox.right, | ||
| 132 | - yPos + font.descent + font.ascent - separatorLineWidth / 2); | 208 | + @override |
| 209 | + void paintBackground(Context context, PdfPoint size) {} | ||
| 210 | + | ||
| 211 | + @override | ||
| 212 | + void paint(Context context, PdfPoint size) { | ||
| 213 | + if (drawXDivisions) { | ||
| 214 | + _drawXDivisions(context, size); | ||
| 133 | } | 215 | } |
| 134 | - context.canvas | ||
| 135 | - ..setStrokeColor(separatorColor) | ||
| 136 | - ..setLineWidth(separatorLineWidth) | ||
| 137 | - ..strokePath(); | 216 | + if (drawYDivisions) { |
| 217 | + _drawYDivisions(context, size); | ||
| 218 | + } | ||
| 219 | + } | ||
| 138 | 220 | ||
| 221 | + @override | ||
| 222 | + void paintForeground(Context context, PdfPoint size) { | ||
| 223 | + _drawAxis(context, size); | ||
| 224 | + _drawXValues(context, size); | ||
| 225 | + _drawYValues(context, size); | ||
| 226 | + } | ||
| 227 | + | ||
| 228 | + @override | ||
| 229 | + void clip(Context context, PdfPoint size) { | ||
| 139 | context.canvas | 230 | context.canvas |
| 140 | - ..setStrokeColor(color) | ||
| 141 | - ..setLineWidth(lineWidth) | ||
| 142 | - ..drawLine(gridBox.left, gridBox.bottom, gridBox.right, gridBox.bottom) | ||
| 143 | - ..drawLine(gridBox.left, gridBox.bottom, gridBox.left, gridBox.top) | ||
| 144 | - ..strokePath(); | 231 | + ..saveContext() |
| 232 | + ..drawRect( | ||
| 233 | + gridBox.left, | ||
| 234 | + gridBox.bottom, | ||
| 235 | + size.x - gridBox.left, | ||
| 236 | + size.y - gridBox.bottom, | ||
| 237 | + ) | ||
| 238 | + ..clipPath(); | ||
| 145 | } | 239 | } |
| 146 | 240 | ||
| 147 | @override | 241 | @override |
| 148 | - void paintForeground(Context context, PdfPoint size) {} | 242 | + void unClip(Context context, PdfPoint size) { |
| 243 | + context.canvas.restoreContext(); | ||
| 244 | + } | ||
| 149 | } | 245 | } |
-
Please register or login to post a comment