David PHAM-VAN

Implement PointDataSet for Chart

... ... @@ -96,11 +96,11 @@ Future<Uint8List> generateReport(
width: 15,
offset: -10,
borderColor: baseColor,
data: List<pw.LineChartValue>.generate(
data: List<pw.PointChartValue>.generate(
dataTable.length,
(i) {
final v = dataTable[i][2] as num;
return pw.LineChartValue(i.toDouble(), v.toDouble());
return pw.PointChartValue(i.toDouble(), v.toDouble());
},
),
),
... ... @@ -110,11 +110,11 @@ Future<Uint8List> generateReport(
width: 15,
offset: 10,
borderColor: PdfColors.amber,
data: List<pw.LineChartValue>.generate(
data: List<pw.PointChartValue>.generate(
dataTable.length,
(i) {
final v = dataTable[i][1] as num;
return pw.LineChartValue(i.toDouble(), v.toDouble());
return pw.PointChartValue(i.toDouble(), v.toDouble());
},
),
),
... ... @@ -138,11 +138,11 @@ Future<Uint8List> generateReport(
isCurved: true,
drawPoints: false,
color: baseColor,
data: List<pw.LineChartValue>.generate(
data: List<pw.PointChartValue>.generate(
dataTable.length,
(i) {
final v = dataTable[i][2] as num;
return pw.LineChartValue(i.toDouble(), v.toDouble());
return pw.PointChartValue(i.toDouble(), v.toDouble());
},
),
),
... ...
# Changelog
## 3.7.5
## 3.8.0
- Update xml dependency range
- Implement PointDataSet for Chart
## 3.7.4
... ...
... ... @@ -642,6 +642,11 @@ class SizedBox extends StatelessWidget {
: width = size?.x,
height = size?.y;
/// Creates a box whose width and height are equal.
SizedBox.square({this.child, double? dimension})
: width = dimension,
height = dimension;
/// If non-null, requires the child to have exactly this width.
final double? width;
... ...
... ... @@ -17,14 +17,15 @@
import '../../../pdf.dart';
import '../flex.dart';
import '../geometry.dart';
import '../page.dart';
import '../widget.dart';
import 'chart.dart';
import 'grid_cartesian.dart';
import 'line_chart.dart';
import 'point_chart.dart';
class BarDataSet extends Dataset {
class BarDataSet<T extends PointChartValue> extends PointDataSet<T> {
BarDataSet({
required this.data,
required List<T> data,
String? legend,
this.borderColor,
this.borderWidth = 1.5,
... ... @@ -35,16 +36,26 @@ class BarDataSet extends Dataset {
this.width = 10,
this.offset = 0,
this.axis = Axis.horizontal,
PdfColor? pointColor,
double pointSize = 3,
bool drawPoints = false,
BuildCallback? shape,
Widget Function(Context context, T value)? buildValue,
ValuePosition valuePosition = ValuePosition.auto,
}) : drawBorder = drawBorder ?? borderColor != null && color != borderColor,
assert((drawBorder ?? borderColor != null && color != borderColor) ||
drawSurface),
super(
legend: legend,
color: color,
color: pointColor ?? color,
data: data,
buildValue: buildValue,
drawPoints: drawPoints,
pointSize: pointSize,
shape: shape,
valuePosition: valuePosition,
);
final List<LineChartValue> data;
final bool drawBorder;
final PdfColor? borderColor;
final double borderWidth;
... ... @@ -58,7 +69,7 @@ class BarDataSet extends Dataset {
final Axis axis;
void _drawSurface(Context context, ChartGrid grid, LineChartValue value) {
void _drawSurface(Context context, ChartGrid grid, T value) {
switch (axis) {
case Axis.horizontal:
final y = (grid is CartesianGrid) ? grid.xAxisOffset : 0.0;
... ... @@ -128,4 +139,19 @@ class BarDataSet extends Dataset {
..strokePath();
}
}
@override
ValuePosition automaticValuePosition(
PdfPoint point,
PdfPoint size,
PdfPoint? previous,
PdfPoint? next,
) {
final pos = super.automaticValuePosition(point, size, previous, next);
if (pos == ValuePosition.right || pos == ValuePosition.left) {
return ValuePosition.top;
}
return pos;
}
}
... ...
... ... @@ -160,7 +160,9 @@ abstract class Dataset extends Widget {
void paintBackground(Context context) {}
Widget legendShape() {
void paintForeground(Context context) {}
Widget legendShape(Context context) {
return Container(
decoration: BoxDecoration(
color: color,
... ...
... ... @@ -116,5 +116,9 @@ class CartesianGrid extends ChartGrid {
context.canvas.restoreContext();
_xAxis.paint(context);
_yAxis.paint(context);
for (final dataSet in datasets) {
dataSet.paintForeground(context);
}
}
}
... ...
... ... @@ -56,7 +56,7 @@ class ChartLegend extends StatelessWidget {
width: style.fontSize,
height: style.fontSize,
margin: const EdgeInsets.only(right: 5),
child: dataset.legendShape(),
child: dataset.legendShape(context),
),
Text(
dataset.legend!,
... ...
... ... @@ -16,28 +16,31 @@
import '../../../pdf.dart';
import '../geometry.dart';
import '../page.dart';
import '../widget.dart';
import 'chart.dart';
import 'grid_cartesian.dart';
import 'point_chart.dart';
class LineChartValue extends ChartValue {
const LineChartValue(this.x, this.y);
final double x;
final double y;
PdfPoint get point => PdfPoint(x, y);
@Deprecated('Use PointChartValue')
class LineChartValue extends PointChartValue {
const LineChartValue(double x, double y) : super(x, y);
}
class LineDataSet extends Dataset {
class LineDataSet<T extends PointChartValue> extends PointDataSet<T> {
LineDataSet({
required this.data,
required List<T> data,
String? legend,
this.pointColor,
this.pointSize = 3,
PdfColor? pointColor,
double pointSize = 3,
PdfColor color = PdfColors.blue,
this.lineWidth = 2,
this.drawLine = true,
this.drawPoints = true,
this.lineColor,
bool drawPoints = true,
BuildCallback? shape,
Widget Function(Context context, T value)? buildValue,
ValuePosition valuePosition = ValuePosition.auto,
this.drawSurface = false,
this.surfaceOpacity = .2,
this.surfaceColor,
... ... @@ -46,19 +49,19 @@ class LineDataSet extends Dataset {
}) : assert(drawLine || drawPoints || drawSurface),
super(
legend: legend,
color: color,
color: pointColor ?? color,
data: data,
drawPoints: drawPoints,
pointSize: pointSize,
buildValue: buildValue,
shape: shape,
valuePosition: valuePosition,
);
final List<LineChartValue> data;
final bool drawLine;
final PdfColor? lineColor;
final double lineWidth;
final bool drawPoints;
final PdfColor? pointColor;
final double pointSize;
final bool drawSurface;
final PdfColor? surfaceColor;
final double surfaceOpacity;
... ... @@ -122,13 +125,6 @@ class LineDataSet extends Dataset {
context.canvas.lineTo(pf.x, y);
}
void _drawPoints(Context context, ChartGrid grid) {
for (final value in data) {
final p = grid.toChart(value.point);
context.canvas.drawEllipse(p.x, p.y, pointSize, pointSize);
}
}
@override
void paintBackground(Context context) {
if (data.isEmpty) {
... ... @@ -172,19 +168,46 @@ class LineDataSet extends Dataset {
_drawLine(context, grid, true);
context.canvas
..setStrokeColor(color)
..setStrokeColor(lineColor ?? color)
..setLineWidth(lineWidth)
..setLineCap(PdfLineCap.round)
..setLineJoin(PdfLineJoin.round)
..strokePath();
}
}
if (drawPoints) {
_drawPoints(context, grid);
@override
ValuePosition automaticValuePosition(
PdfPoint point,
PdfPoint size,
PdfPoint? previous,
PdfPoint? next,
) {
if (point.y - size.y - delta < box!.bottom) {
return ValuePosition.top;
}
context.canvas
..setColor(pointColor ?? color)
..fillPath();
if (previous != null &&
previous.y > point.y &&
next != null &&
next.y > point.y) {
return ValuePosition.bottom;
}
if (previous != null &&
previous.y < point.y &&
next != null &&
next.y > point.y) {
return ValuePosition.left;
}
if (previous != null &&
previous.y > point.y &&
next != null &&
next.y < point.y) {
return ValuePosition.right;
}
return super.automaticValuePosition(point, size, previous, next);
}
}
... ...
/*
* Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import '../../../pdf.dart';
import '../basic.dart';
import '../geometry.dart';
import '../page.dart';
import '../widget.dart';
import 'chart.dart';
enum ValuePosition { left, top, right, bottom, auto }
class PointChartValue extends ChartValue {
const PointChartValue(this.x, this.y);
final double x;
final double y;
PdfPoint get point => PdfPoint(x, y);
}
class PointDataSet<T extends PointChartValue> extends Dataset {
PointDataSet({
required this.data,
String? legend,
this.pointSize = 3,
PdfColor color = PdfColors.blue,
this.drawPoints = true,
this.shape,
this.buildValue,
this.valuePosition = ValuePosition.auto,
}) : super(
legend: legend,
color: color,
);
final List<T> data;
final bool drawPoints;
final double pointSize;
final BuildCallback? shape;
final Widget Function(Context context, T value)? buildValue;
final ValuePosition valuePosition;
double get delta => pointSize * .5;
@override
void layout(Context context, BoxConstraints constraints,
{bool parentUsesSize = false}) {
box = PdfRect.fromPoints(PdfPoint.zero, constraints.biggest);
}
ValuePosition automaticValuePosition(
PdfPoint point,
PdfPoint size,
PdfPoint? previous,
PdfPoint? next,
) {
// Usually on top, except on the edges
if (point.x - size.x / 2 < box!.left) {
return ValuePosition.right;
}
if (point.x + size.x / 2 > box!.right) {
return ValuePosition.left;
}
if (point.y + size.y + delta > box!.top) {
return ValuePosition.bottom;
}
return ValuePosition.top;
}
@override
void paintForeground(Context context) {
super.paintForeground(context);
if (data.isEmpty) {
return;
}
final grid = Chart.of(context).grid;
if (drawPoints) {
if (shape == null) {
for (final value in data) {
final p = grid.toChart(value.point);
context.canvas.drawEllipse(p.x, p.y, pointSize, pointSize);
}
context.canvas
..setColor(color)
..fillPath();
} else {
for (final value in data) {
final p = grid.toChart(value.point);
Widget.draw(
SizedBox.square(
dimension: pointSize * 2,
child: shape!(context),
),
offset: p,
alignment: Alignment.center,
context: context,
);
}
}
}
if (buildValue != null) {
PdfPoint? previous;
var index = 1;
for (final value in data) {
final p = grid.toChart(value.point);
final size = Widget.measure(
buildValue!(context, value),
context: context,
);
final PdfPoint offset;
var pos = valuePosition;
if (pos == ValuePosition.auto) {
final next =
index < data.length ? grid.toChart(data[index++].point) : null;
pos = automaticValuePosition(p, size, previous, next);
}
switch (pos) {
case ValuePosition.left:
offset = PdfPoint(p.x - size.x / 2 - pointSize - delta, p.y);
break;
case ValuePosition.top:
offset = PdfPoint(p.x, p.y + size.y / 2 + pointSize + delta);
break;
case ValuePosition.right:
offset = PdfPoint(p.x + size.x / 2 + pointSize + delta, p.y);
break;
case ValuePosition.bottom:
offset = PdfPoint(p.x, p.y - size.y / 2 - pointSize - delta);
break;
case ValuePosition.auto:
assert(false, 'We have an issue here');
offset = p;
break;
}
Widget.draw(
buildValue!(context, value),
offset: offset,
alignment: Alignment.center,
context: context,
);
previous = p;
}
}
}
@override
Widget legendShape(Context context) {
return shape == null ? super.legendShape(context) : shape!(context);
}
}
... ...
... ... @@ -29,6 +29,7 @@ export 'src/widgets/chart/grid_radial.dart';
export 'src/widgets/chart/legend.dart';
export 'src/widgets/chart/line_chart.dart';
export 'src/widgets/chart/pie_chart.dart';
export 'src/widgets/chart/point_chart.dart';
export 'src/widgets/clip.dart';
export 'src/widgets/container.dart';
export 'src/widgets/content.dart';
... ...
... ... @@ -3,7 +3,7 @@ description: A pdf producer for Dart. It can create pdf files for both web or fl
homepage: https://github.com/DavBfr/dart_pdf/tree/master/pdf
repository: https://github.com/DavBfr/dart_pdf
issue_tracker: https://github.com/DavBfr/dart_pdf/issues
version: 3.7.5
version: 3.8.0
environment:
sdk: ">=2.12.0 <3.0.0"
... ...
... ... @@ -39,10 +39,10 @@ void main() {
),
datasets: <Dataset>[
LineDataSet(
data: const <LineChartValue>[
LineChartValue(1, 1),
LineChartValue(2, 3),
LineChartValue(3, 7),
data: const <PointChartValue>[
PointChartValue(1, 1),
PointChartValue(2, 3),
PointChartValue(3, 7),
],
),
],
... ... @@ -60,10 +60,10 @@ void main() {
),
datasets: <Dataset>[
LineDataSet(
data: const <LineChartValue>[
LineChartValue(1, 1),
LineChartValue(2, 3),
LineChartValue(3, 7),
data: const <PointChartValue>[
PointChartValue(1, 1),
PointChartValue(2, 3),
PointChartValue(3, 7),
],
drawLine: false,
),
... ... @@ -81,10 +81,10 @@ void main() {
),
datasets: <Dataset>[
LineDataSet(
data: const <LineChartValue>[
LineChartValue(1, 1),
LineChartValue(2, 3),
LineChartValue(3, 7),
data: const <PointChartValue>[
PointChartValue(1, 1),
PointChartValue(2, 3),
PointChartValue(3, 7),
],
drawPoints: false,
),
... ... @@ -103,10 +103,10 @@ void main() {
),
datasets: <Dataset>[
LineDataSet(
data: const <LineChartValue>[
LineChartValue(1, 1),
LineChartValue(2, 3),
LineChartValue(3, 7),
data: const <PointChartValue>[
PointChartValue(1, 1),
PointChartValue(2, 3),
PointChartValue(3, 7),
],
drawLine: false,
pointColor: PdfColors.red,
... ... @@ -132,10 +132,10 @@ void main() {
),
datasets: <Dataset>[
LineDataSet(
data: const <LineChartValue>[
LineChartValue(1, 1),
LineChartValue(2, 3),
LineChartValue(3, 7),
data: const <PointChartValue>[
PointChartValue(1, 1),
PointChartValue(2, 3),
PointChartValue(3, 7),
],
),
],
... ... @@ -156,10 +156,10 @@ void main() {
LineDataSet(
drawPoints: false,
isCurved: true,
data: const <LineChartValue>[
LineChartValue(1, 1),
LineChartValue(3, 7),
LineChartValue(5, 3),
data: const <PointChartValue>[
PointChartValue(1, 1),
PointChartValue(3, 7),
PointChartValue(5, 3),
],
),
],
... ... @@ -179,10 +179,10 @@ void main() {
),
datasets: <Dataset>[
BarDataSet(
data: const <LineChartValue>[
LineChartValue(1, 1),
LineChartValue(2, 3),
LineChartValue(3, 7),
data: const <PointChartValue>[
PointChartValue(1, 1),
PointChartValue(2, 3),
PointChartValue(3, 7),
],
),
],
... ... @@ -201,10 +201,10 @@ void main() {
datasets: <Dataset>[
BarDataSet(
axis: Axis.vertical,
data: const <LineChartValue>[
LineChartValue(1, 1),
LineChartValue(2, 3),
LineChartValue(3, 7),
data: const <PointChartValue>[
PointChartValue(1, 1),
PointChartValue(2, 3),
PointChartValue(3, 7),
],
),
],
... ...