diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f19aed88..bd577ce1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.7 +* added ExtraLinesData in the LineChartData to draw extra horizontal and vertical lines on LineChart +* added BelowSpotsLine in the BlowBarData to draw lines from spot to the bottom of chart on LineChart + ## 0.0.6 * fixed charts repainting bug, #16 diff --git a/README.md b/README.md index aed8d6c2d..6c1b3fe8d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![pub package](https://img.shields.io/pub/v/fl_chart.svg)](https://pub.dartlang.org/packages/fl_chart) -[![APK](https://img.shields.io/badge/APK-Demo-brightgreen.svg)](https://github.com/imaNNeoFighT/fl_chart/raw/master/repo_files/fl_chart_samples_0.0.1.apk) +[![APK](https://img.shields.io/badge/APK-Demo-brightgreen.svg)](https://github.com/imaNNeoFighT/fl_chart/raw/master/repo_files/fl_chart_samples_0.0.7.apk) ![FL Chart Logo](https://github.com/imaNNeoFighT/fl_chart/raw/master/repo_files/images/landing_logo.jpg) @@ -36,7 +36,7 @@ Thank you all! ```kotlin dependencies: - fl_chart: ^0.0.6 + fl_chart: ^0.0.7 ``` diff --git a/example/lib/line_chart/samples/line_chart_sample3.dart b/example/lib/line_chart/samples/line_chart_sample3.dart index 4e118676e..7cc010e92 100644 --- a/example/lib/line_chart/samples/line_chart_sample3.dart +++ b/example/lib/line_chart/samples/line_chart_sample3.dart @@ -5,103 +5,146 @@ class LineChartSample3 extends StatelessWidget { @override Widget build(BuildContext context) { - return SizedBox( - width: 300, - height: 140, - child: FlChart( - chart: LineChart( - LineChartData( - lineBarsData: [ - LineChartBarData( - spots: [ - FlSpot(0, 1.3), - FlSpot(1, 1), - FlSpot(2, 1.8), - FlSpot(3, 1.5), - FlSpot(4, 2.2), - FlSpot(5, 1.8), - FlSpot(6, 3), - ], - isCurved: false, - barWidth: 4, - colors: [ - Colors.orange, + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Text('Average Line', + style: TextStyle(color: Colors.green, fontWeight: FontWeight.bold, fontSize: 16),), + const Text(' and ', + style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 16),), + const Text('Indiactors', + style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold, fontSize: 16),), + ], + ), + const SizedBox(height: 18,), + SizedBox( + width: 300, + height: 140, + child: FlChart( + chart: LineChart( + LineChartData( + extraLinesData: ExtraLinesData( + showVerticalLines: true, + verticalLines: [ + VerticalLine( + y: 1.8, + color: Colors.green.withOpacity(0.7), + strokeWidth: 4, + ), + ] + + ), + lineBarsData: [ + LineChartBarData( + spots: [ + FlSpot(0, 1.3), + FlSpot(1, 1), + FlSpot(2, 1.8), + FlSpot(3, 1.5), + FlSpot(4, 2.2), + FlSpot(5, 1.8), + FlSpot(6, 3), + ], + isCurved: false, + barWidth: 4, + colors: [ + Colors.orange, + ], + belowBarData: BelowBarData( + show: true, + colors: [ + Colors.orange.withOpacity(0.5), + Colors.orange.withOpacity(0.0), + ], + gradientColorStops: [0.5, 1.0], + gradientFrom: Offset(0, 0), + gradientTo: Offset(0, 1), + belowSpotsLine: BelowSpotsLine( + show: true, + flLineStyle: const FlLine( + color: Colors.blue, + strokeWidth: 2, + ), + checkToShowSpotBelowLine: (spot) { + if (spot.x == 0 || spot.x == 6) { + return false; + } + + return true; + } + ) + ), + dotData: FlDotData( + show: true, + dotColor: Colors.deepOrange, + dotSize: 6, + checkToShowDot: (spot) { + return spot.x != 0 && spot.x != 6; + }), + ), ], - belowBarData: BelowBarData( + minY: 0, + gridData: FlGridData( show: true, - colors: [ - Colors.orange.withOpacity(0.5), - Colors.orange.withOpacity(0.0), - ], - gradientColorStops: [0.5, 1.0], - gradientFrom: Offset(0, 0), - gradientTo: Offset(0, 1), + drawHorizontalGrid: true, + drawVerticalGrid: true, ), - dotData: FlDotData( + titlesData: FlTitlesData( show: true, - dotColor: Colors.deepOrange, - dotSize: 6, - checkToShowDot: (spot) { - return spot.x != 0 && spot.x != 6; - }), - ), - ], - minY: 0, - gridData: FlGridData( - show: true, - drawHorizontalGrid: true, - drawVerticalGrid: true, - ), - titlesData: FlTitlesData( - show: true, - getHorizontalTitles: (value) { - switch (value.toInt()) { - case 0: - return 'Sat'; + getHorizontalTitles: (value) { + switch (value.toInt()) { + case 0: + return 'Sat'; - case 1: - return 'Sun'; + case 1: + return 'Sun'; - case 2: - return 'Mon'; + case 2: + return 'Mon'; - case 3: - return 'Tue'; + case 3: + return 'Tue'; - case 4: - return 'Wed'; + case 4: + return 'Wed'; - case 5: - return 'Thu'; + case 5: + return 'Thu'; - case 6: - return 'Fri'; - } + case 6: + return 'Fri'; + } - return ''; - }, - getVerticalTitles: (value) { - switch (value.toInt()) { - case 0: - return ""; - case 1: - return "1k colories"; - case 2: - return "2k colories"; - case 3: - return "3k colories"; - } + return ''; + }, + getVerticalTitles: (value) { + switch (value.toInt()) { + case 0: + return ""; + case 1: + return "1k colories"; + case 2: + return "2k colories"; + case 3: + return "3k colories"; + } - return ""; - }, - horizontalTitlesTextStyle: TextStyle( - color: Colors.deepOrange, - fontWeight: FontWeight.bold, + return ""; + }, + horizontalTitlesTextStyle: TextStyle( + color: Colors.deepOrange, + fontWeight: FontWeight.bold, + ), + verticalTitlesTextStyle: TextStyle(color: Colors.black, fontSize: 10)), ), - verticalTitlesTextStyle: TextStyle(color: Colors.black, fontSize: 10)), + ), ), ), - ), + ], ); } diff --git a/lib/src/chart/base/axis_chart/axis_chart_data.dart b/lib/src/chart/base/axis_chart/axis_chart_data.dart index a3d9e00bb..5b4ffd8f4 100644 --- a/lib/src/chart/base/axis_chart/axis_chart_data.dart +++ b/lib/src/chart/base/axis_chart/axis_chart_data.dart @@ -83,4 +83,17 @@ class FlGridData { this.verticalGridLineWidth = 0.5, this.checkToShowVerticalGrid = showAllGrids, }); +} + + +/// This class can be used wherever we want draw a straight line, +/// and contains visual properties +class FlLine { + final Color color; + final double strokeWidth; + + const FlLine({ + this.color = Colors.black, + this.strokeWidth = 2, + }); } \ No newline at end of file diff --git a/lib/src/chart/line_chart/line_chart_data.dart b/lib/src/chart/line_chart/line_chart_data.dart index 6f38dad96..a8b9ac693 100644 --- a/lib/src/chart/line_chart/line_chart_data.dart +++ b/lib/src/chart/line_chart/line_chart_data.dart @@ -10,10 +10,12 @@ import 'package:flutter/material.dart'; class LineChartData extends AxisChartData { final List lineBarsData; final FlTitlesData titlesData; + final ExtraLinesData extraLinesData; LineChartData({ this.lineBarsData = const [], this.titlesData = const FlTitlesData(), + this.extraLinesData = const ExtraLinesData(), FlGridData gridData = const FlGridData(), FlBorderData borderData, double minX, @@ -168,12 +170,40 @@ class BelowBarData { /// stop points of the gradient. final List gradientColorStops; + + /// holds data for drawing a line from each spot the the bottom of the chart + final BelowSpotsLine belowSpotsLine; + const BelowBarData({ this.show = true, this.colors = const [Colors.blueGrey], this.gradientFrom = const Offset(0, 0), this.gradientTo = const Offset(1, 0), this.gradientColorStops, + this.belowSpotsLine = const BelowSpotsLine(), + }); +} + + +typedef CheckToShowSpotBelowLine = bool Function(FlSpot spot); + +bool showAllSpotsBelowLine(FlSpot spot) { + return true; +} + +class BelowSpotsLine { + final bool show; + + /// determines style of the line + final FlLine flLineStyle; + + /// a function to determine whether to show or hide the below line on the given spot + final CheckToShowSpotBelowLine checkToShowSpotBelowLine; + + const BelowSpotsLine({ + this.show = false, + this.flLineStyle = const FlLine(), + this.checkToShowSpotBelowLine = showAllSpotsBelowLine, }); } @@ -200,4 +230,45 @@ class FlDotData { this.dotSize = 4.0, this.checkToShowDot = showAllDots, }); +} + + +/// horizontal lines draw from bottom to top of the chart, +/// and the x is dynamic +class HorizontalLine extends FlLine { + final double x; + HorizontalLine({ + this.x, + Color color = Colors.black, + double strokeWidth = 2, + }) : super(color: color, strokeWidth: strokeWidth); +} + +/// vertical lines draw from left to right of the chart +/// and the y is dynamic +class VerticalLine extends FlLine { + final double y; + VerticalLine({ + this.y, + Color color = Colors.black, + double strokeWidth = 2, + }) : super(color: color, strokeWidth: strokeWidth); +} + +/// we use ExtraLinesData to draw straight horizontal and vertical lines, +/// for example if you want show the average values of the y axis, +/// you can calculate the average and draw a vertical line by setting the y. +class ExtraLinesData { + final bool showHorizontalLines; + final List horizontalLines; + + final bool showVerticalLines; + final List verticalLines; + + const ExtraLinesData({ + this.showHorizontalLines = false, + this.horizontalLines = const [], + this.showVerticalLines = false, + this.verticalLines = const [], + }); } \ No newline at end of file diff --git a/lib/src/chart/line_chart/line_chart_painter.dart b/lib/src/chart/line_chart/line_chart_painter.dart index 743f5150e..e6c837683 100644 --- a/lib/src/chart/line_chart/line_chart_painter.dart +++ b/lib/src/chart/line_chart/line_chart_painter.dart @@ -14,7 +14,8 @@ class LineChartPainter extends AxisChartPainter { /// [belowBarPaint] is responsible to fill the below space of our bar line /// [dotPaint] is responsible to draw dots on spot points /// [clearAroundBorderPaint] is responsible to clip the border - Paint barPaint, belowBarPaint, dotPaint, clearAroundBorderPaint; + Paint barPaint, belowBarPaint, belowBarLinePaint, + dotPaint, clearAroundBorderPaint, extraLinesPaint; LineChartPainter( this.data, @@ -24,6 +25,9 @@ class LineChartPainter extends AxisChartPainter { belowBarPaint = Paint()..style = PaintingStyle.fill; + belowBarLinePaint = Paint() + ..style = PaintingStyle.stroke; + dotPaint = Paint() ..style = PaintingStyle.fill; @@ -31,6 +35,9 @@ class LineChartPainter extends AxisChartPainter { ..style = PaintingStyle.stroke ..color = const Color(0x000000000) ..blendMode = BlendMode.dstIn; + + extraLinesPaint = Paint() + ..style = PaintingStyle.stroke; } @override @@ -58,6 +65,8 @@ class LineChartPainter extends AxisChartPainter { } drawTitles(canvas, viewSize); + + drawExtraLines(canvas, viewSize); } void drawBarLine(Canvas canvas, Size viewSize, LineChartBarData barData) { @@ -184,6 +193,32 @@ class LineChartPainter extends AxisChartPainter { } canvas.drawPath(belowBarPath, belowBarPaint); + + + /// draw below spots line + if (barData.belowBarData.belowSpotsLine != null) { + for (FlSpot spot in barData.spots) { + if (barData.belowBarData.belowSpotsLine.show && + barData.belowBarData.belowSpotsLine.checkToShowSpotBelowLine(spot)) { + final Offset from = Offset( + getPixelX(spot.x, chartViewSize), + getPixelY(spot.y, chartViewSize), + ); + + final double bottomPadding = getExtraNeededVerticalSpace() - getTopOffsetDrawSize(); + final Offset to = Offset( + getPixelX(spot.x, chartViewSize), + viewSize.height - bottomPadding, + ); + + belowBarLinePaint.color = barData.belowBarData.belowSpotsLine.flLineStyle.color; + belowBarLinePaint.strokeWidth = + barData.belowBarData.belowSpotsLine.flLineStyle.strokeWidth; + + canvas.drawLine(from, to, belowBarLinePaint); + } + } + } } void drawBar(Canvas canvas, Size viewSize, Path barPath, LineChartBarData barData) { @@ -317,6 +352,46 @@ class LineChartPainter extends AxisChartPainter { } } + void drawExtraLines(Canvas canvas, Size viewSize) { + if (data.extraLinesData == null) { + return; + } + + final Size chartUsableSize = getChartUsableDrawSize(viewSize); + + if (data.extraLinesData.showHorizontalLines) { + for (HorizontalLine line in data.extraLinesData.horizontalLines) { + + final double topChartPadding = getTopOffsetDrawSize(); + final Offset from = Offset(getPixelX(line.x, chartUsableSize), topChartPadding); + + final double bottomChartPadding = getExtraNeededVerticalSpace() - getTopOffsetDrawSize(); + final Offset to = Offset(getPixelX(line.x, chartUsableSize), viewSize.height - bottomChartPadding); + + extraLinesPaint.color = line.color; + extraLinesPaint.strokeWidth = line.strokeWidth; + + canvas.drawLine(from, to, extraLinesPaint); + } + } + + if (data.extraLinesData.showVerticalLines) { + for (VerticalLine line in data.extraLinesData.verticalLines) { + + final double leftChartPadding = getLeftOffsetDrawSize(); + final Offset from = Offset(leftChartPadding, getPixelY(line.y, chartUsableSize)); + + final double rightChartPadding = getExtraNeededHorizontalSpace() - getLeftOffsetDrawSize(); + final Offset to = Offset(viewSize.width - rightChartPadding, getPixelY(line.y, chartUsableSize)); + + extraLinesPaint.color = line.color; + extraLinesPaint.strokeWidth = line.strokeWidth; + + canvas.drawLine(from, to, extraLinesPaint); + } + } + } + /// We add our needed horizontal space to parent needed. /// we have some titles that maybe draw in the left side of our chart, /// then we should draw the chart a with some left space, @@ -362,4 +437,5 @@ class LineChartPainter extends AxisChartPainter { @override bool shouldRepaint(LineChartPainter oldDelegate) => oldDelegate.data != this.data; + } diff --git a/pubspec.yaml b/pubspec.yaml index 636b988e7..795381fa8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: fl_chart description: A powerful Flutter chart library, currently supporting Line Chart, Bar Chart and Pie Chart. -version: 0.0.6 +version: 0.0.7 author: Iman Khoshabi homepage: https://github.com/imaNNeoFighT/fl_chart diff --git a/repo_files/documentations/base_chart.md b/repo_files/documentations/base_chart.md index 52507b804..a96324d8f 100644 --- a/repo_files/documentations/base_chart.md +++ b/repo_files/documentations/base_chart.md @@ -53,3 +53,11 @@ |:-------|:----------|:------------| |x|represents x on the coordinate system (x starts from left)|null| |y|represents y on the coordinate system (y starts from bottom)|null| + + + +### FlLine +|propName|Description|default valkue| +|:-------|:----------|:------------| +|color|determines the color of line|Colors.black| +|strokeWidth|determines the stroke width of the line|2| diff --git a/repo_files/documentations/line_chart.md b/repo_files/documentations/line_chart.md index f2a6490bc..5dacbf98b 100644 --- a/repo_files/documentations/line_chart.md +++ b/repo_files/documentations/line_chart.md @@ -18,6 +18,7 @@ FlChart( |:---------------|:---------------|:-------| |lineBarsData| list of [LineChartBarData ](#LineChartBarData ) to show the chart's lines, they stack and be drawn on top of each other|[]| |titlesData| check the [FlTitlesData](base_chart.md#FlTitlesData)| FlTitlesData()| +|extraLinesData| [ExtraLinesData](#ExtraLinesData) object to hold drawing details of extra horizontal and vertical lines. |gridData| check the [FlGridData](base_chart.md#FlGridData)|FlGridData()| |borderData| check the [FlBorderData](base_chart.md#FlBorderData)|FlBorderData()| |minX| gets minimum x of x axis, if null, value will read from the input lineBars |null| @@ -50,6 +51,15 @@ FlChart( |gradientFrom|determines start of the gradient, each number should be between 0 and 1, [Read More](https://api.flutter.dev/flutter/dart-ui/Gradient/Gradient.linear.html)|Offset(0, 0)| |gradientTo|determines end of the gradient, each number should be between 0 and 1, [Read More](https://api.flutter.dev/flutter/dart-ui/Gradient/Gradient.linear.html)|Offset(1, 0)| |gradientColorStops|gets the stop positions of the gradient color, [Read More](https://api.flutter.dev/flutter/dart-ui/Gradient/Gradient.linear.html)|null| +|belowSpotsLine| draw a line from each spot to the bottom of the chart|[BelowSpotsLine](#BelowSpotsLine)()| + + +### BelowSpotsLine +|PropName|Description|default value| +|:-------|:----------|:------------| +|show|determines show or hide the below spots line|true| +|flLineStyle|a [FlLine](base_chart.md#FlLine) object that determines style of the line|[Colors.blueGrey]| +|checkToShowSpotBelowLine|a function to determine whether to show or hide the below line on the given spot|showAllSpotsBelowLine| ### FlDotData @@ -60,6 +70,32 @@ FlChart( |dotSize|size of showing dot|4.0| |checkToShowDot|a function to determine whether to show or hide the dot on the given spot|showAllDots| + +### HorizontalLine +|PropName|Description|default value| +|:-------|:----------|:------------| +|x|draw straight line from bottom to top of the chart with dynamic x value|null| +|color|color of the line|Colors.black| +|strokeWidth|strokeWidth of the line|2| + + +### VerticalLine +|PropName|Description|default value| +|:-------|:----------|:------------| +|x|draw straight line from left to right of the chart with dynamic y value|null| +|color|color of the line|Colors.black| +|strokeWidth|strokeWidth of the line|2| + + +### ExtraLinesData +|PropName|Description|default value| +|:-------|:----------|:------------| +|showHorizontalLines|determines to show or hide the horizontal lines|false| +|horizontalLines|list of [HorizontalLine](#HorizontalLine) to draw on the chart|[]| +|showVerticalLines|determines to show or hide the vertical lines|false| +|verticalLines|list of [VerticalLine](#VerticalLine) to draw on the chart|[]| + + ### some samples ---- ##### Sample 1 ([Source Code](/example/lib/line_chart/samples/line_chart_sample1.dart)) diff --git a/repo_files/fl_chart_samples_0.0.1.apk b/repo_files/fl_chart_samples_0.0.7.apk similarity index 73% rename from repo_files/fl_chart_samples_0.0.1.apk rename to repo_files/fl_chart_samples_0.0.7.apk index 8f1ad2bab..5a3599154 100644 Binary files a/repo_files/fl_chart_samples_0.0.1.apk and b/repo_files/fl_chart_samples_0.0.7.apk differ diff --git a/repo_files/images/line_chart/line_chart_sample_3.png b/repo_files/images/line_chart/line_chart_sample_3.png index 4359780c2..29809656b 100644 Binary files a/repo_files/images/line_chart/line_chart_sample_3.png and b/repo_files/images/line_chart/line_chart_sample_3.png differ