diff --git a/lib/src/chart_painter.dart b/lib/src/chart_painter.dart index 29011dc..ba9f088 100644 --- a/lib/src/chart_painter.dart +++ b/lib/src/chart_painter.dart @@ -1,14 +1,15 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; -import 'package:pie_chart/pie_chart.dart'; + +import '../pie_chart.dart'; class PieChartPainter extends CustomPainter { - List _paintList = []; + final List _paintList = []; late List _subParts; List? _subTitles; double _total = 0; - double _totalAngle = math.pi * 2; + final double _totalAngle = math.pi * 2; final TextStyle? chartValueStyle; final Color? chartValueBackgroundColor; @@ -23,6 +24,7 @@ class PieChartPainter extends CustomPainter { final Function? formatChartValues; final double? strokeWidth; final Color? emptyColor; + final double border; double _prevAngle = 0; @@ -44,13 +46,15 @@ class PieChartPainter extends CustomPainter { this.formatChartValues, this.strokeWidth, this.emptyColor, + this.border = .05, }) { _total = values.fold(0, (v1, v2) => v1 + v2); - for (int i = 0; i < values.length; i++) { + for (var i = 0; i < values.length; i++) { final paint = Paint()..color = getColor(colorList, i); if (chartType == ChartType.ring) { - paint.style = PaintingStyle.stroke; - paint.strokeWidth = strokeWidth!; + paint + ..style = PaintingStyle.stroke + ..strokeWidth = strokeWidth!; } _paintList.add(paint); } @@ -64,48 +68,48 @@ class PieChartPainter extends CustomPainter { if (_total == 0) { final paint = Paint()..color = emptyColor!; if (chartType == ChartType.ring) { - paint.style = PaintingStyle.stroke; - paint.strokeWidth = strokeWidth!; + paint + ..style = PaintingStyle.stroke + ..strokeWidth = strokeWidth!; } canvas.drawArc( - new Rect.fromLTWH(0.0, 0.0, side, size.height), + Rect.fromLTWH(0, 0, side, size.height), _prevAngle, 360, - chartType == ChartType.disc ? true : false, + chartType == ChartType.disc, paint, ); } else { - _prevAngle = this.initialAngle! * math.pi / 180; - for (int i = 0; i < _subParts.length; i++) { + _prevAngle = initialAngle! * math.pi / 180; + final gap = _subParts.isNotEmpty ? border : 0; + for (var i = 0; i < _subParts.length; i++) { canvas.drawArc( - new Rect.fromLTWH(0.0, 0.0, side, size.height), + Rect.fromLTWH(0, 0, side, size.height), _prevAngle, - (((_totalAngle) / _total) * _subParts[i]), - chartType == ChartType.disc ? true : false, + ((_totalAngle / _total) * _subParts[i]) - gap, + chartType == ChartType.disc, _paintList[i], ); final radius = showChartValuesOutside ? (side / 2) + 16 : side / 3; - final x = (radius) * + final x = radius * math.cos( - _prevAngle + ((((_totalAngle) / _total) * _subParts[i]) / 2)); - final y = (radius) * + _prevAngle + (((_totalAngle / _total) * _subParts[i]) / 2)); + final y = radius * math.sin( - _prevAngle + ((((_totalAngle) / _total) * _subParts[i]) / 2)); + _prevAngle + (((_totalAngle / _total) * _subParts[i]) / 2)); if (_subParts.elementAt(i).toInt() != 0) { final value = formatChartValues != null ? formatChartValues!(_subParts.elementAt(i)) - : _subParts.elementAt(i).toStringAsFixed(this.decimalPlaces!); + : _subParts.elementAt(i).toStringAsFixed(decimalPlaces!); if (showChartValues) { final name = showValuesInPercentage! - ? (((_subParts.elementAt(i) / _total) * 100) - .toStringAsFixed(this.decimalPlaces!) + - '%') + ? ('${((_subParts.elementAt(i) / _total) * 100).toStringAsFixed(decimalPlaces!)}%') : value; _drawName(canvas, name, x, y, side); } } - _prevAngle = _prevAngle + (((_totalAngle) / _total) * _subParts[i]); + _prevAngle = _prevAngle + ((_totalAngle / _total) * _subParts[i]); } } @@ -119,25 +123,24 @@ class PieChartPainter extends CustomPainter { } void _drawName(Canvas canvas, String? name, double x, double y, double side) { - TextSpan span = TextSpan( + final span = TextSpan( style: chartValueStyle, text: name, ); - TextPainter tp = TextPainter( + final tp = TextPainter( text: span, textAlign: TextAlign.center, textDirection: TextDirection.ltr, - ); - tp.layout(); + )..layout(); if (showChartValueLabel!) { //Draw text background box final rect = Rect.fromCenter( - center: Offset((side / 2 + x), (side / 2 + y)), + center: Offset(side / 2 + x, side / 2 + y), width: tp.width + 6, height: tp.height + 4, ); - final rRect = RRect.fromRectAndRadius(rect, Radius.circular(4)); + final rRect = RRect.fromRectAndRadius(rect, const Radius.circular(4)); final paint = Paint() ..color = chartValueBackgroundColor ?? Colors.grey[200]! ..style = PaintingStyle.fill; @@ -146,7 +149,7 @@ class PieChartPainter extends CustomPainter { //Finally paint the text above box tp.paint( canvas, - new Offset( + Offset( (side / 2 + x) - (tp.width / 2), (side / 2 + y) - (tp.height / 2), ), diff --git a/lib/src/legend.dart b/lib/src/legend.dart index 8a0a311..e8cebaf 100644 --- a/lib/src/legend.dart +++ b/lib/src/legend.dart @@ -6,12 +6,18 @@ class Legend extends StatelessWidget { required this.color, required this.style, required this.legendShape, + required this.titleRowWidth, + this.legendHeight = 8, + this.legendWidth = 8, }); final String title; final Color color; final TextStyle style; final BoxShape legendShape; + final double titleRowWidth; + final double legendHeight; + final double legendWidth; @override Widget build(BuildContext context) { @@ -21,8 +27,8 @@ class Legend extends StatelessWidget { children: [ Container( margin: EdgeInsets.symmetric(vertical: 2.0), - height: 20.0, - width: 18.0, + height: legendHeight, + width: legendWidth, decoration: BoxDecoration( shape: legendShape, color: color, @@ -31,12 +37,12 @@ class Legend extends StatelessWidget { SizedBox( width: 8.0, ), - Flexible( - fit: FlexFit.loose, + SizedBox( + width: titleRowWidth, child: Text( title, style: style, - softWrap: true, + overflow: TextOverflow.ellipsis, ), ), SizedBox( diff --git a/lib/src/legend_options.dart b/lib/src/legend_options.dart index f3d1737..4d9b711 100644 --- a/lib/src/legend_options.dart +++ b/lib/src/legend_options.dart @@ -8,6 +8,8 @@ class LegendOptions { final TextStyle legendTextStyle; final BoxShape legendShape; final LegendPosition legendPosition; + final double width; + final double height; const LegendOptions({ this.showLegends = true, @@ -15,5 +17,7 @@ class LegendOptions { this.legendTextStyle = defaultLegendStyle, this.legendShape = BoxShape.circle, this.legendPosition = LegendPosition.right, + this.width = 18, + this.height = 20, }); } diff --git a/lib/src/pie_chart.dart b/lib/src/pie_chart.dart index 61511b7..1c8ddd7 100644 --- a/lib/src/pie_chart.dart +++ b/lib/src/pie_chart.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:pie_chart/pie_chart.dart'; -import 'package:pie_chart/src/chart_values_options.dart'; +import '../pie_chart.dart'; import 'chart_painter.dart'; +import 'chart_values_options.dart'; import 'legend.dart'; import 'utils.dart'; @@ -11,7 +11,7 @@ enum LegendPosition { top, bottom, left, right } enum ChartType { disc, ring } class PieChart extends StatefulWidget { - PieChart({ + const PieChart({ required this.dataMap, this.chartType = ChartType.disc, this.chartRadius, @@ -25,9 +25,11 @@ class PieChart extends StatefulWidget { this.legendOptions = const LegendOptions(), this.chartValuesOptions = const ChartValuesOptions(), this.emptyColor = Colors.grey, + this.border = .05, Key? key, }) : super(key: key); + final double border; final Map dataMap; final ChartType chartType; final double? chartRadius; @@ -50,23 +52,23 @@ class _PieChartState extends State with SingleTickerProviderStateMixin { late Animation animation; AnimationController? controller; - double _animFraction = 0.0; + double _animFraction = 0; List? legendTitles; late List legendValues; void initLegends() { - this.legendTitles = widget.dataMap.keys.toList(growable: false); + legendTitles = widget.dataMap.keys.toList(growable: false); } void initValues() { - this.legendValues = widget.dataMap.values.toList(growable: false); + legendValues = widget.dataMap.values.toList(growable: false); } void initData() { assert( - widget.dataMap != null && widget.dataMap.isNotEmpty, - "dataMap passed to pie chart cant be null or empty", + widget.dataMap.isNotEmpty, + 'dataMap passed to pie chart cant be null or empty', ); initLegends(); initValues(); @@ -77,7 +79,7 @@ class _PieChartState extends State super.initState(); initData(); controller = AnimationController( - duration: widget.animationDuration ?? Duration(milliseconds: 800), + duration: widget.animationDuration ?? const Duration(milliseconds: 800), vsync: this, ); final Animation curve = CurvedAnimation( @@ -97,7 +99,7 @@ class _PieChartState extends State Widget _getChart() { return Flexible( child: LayoutBuilder( - builder: (_, c) => Container( + builder: (_, c) => SizedBox( height: widget.chartRadius != null ? c.maxWidth < widget.chartRadius! ? c.maxWidth @@ -125,8 +127,9 @@ class _PieChartState extends State formatChartValues: widget.formatChartValues, strokeWidth: widget.ringStrokeWidth, emptyColor: widget.emptyColor, + border: widget.border, ), - child: AspectRatio(aspectRatio: 1), + child: const AspectRatio(aspectRatio: 1), ), ), ), @@ -162,7 +165,8 @@ class _PieChartState extends State ); case LegendPosition.left: return Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _getLegend( padding: EdgeInsets.only( @@ -199,43 +203,49 @@ class _PieChartState extends State } } - _getLegend({EdgeInsets? padding}) { + Widget _getLegend({EdgeInsets? padding}) { if (widget.legendOptions.showLegends) { - return Padding( - padding: padding!, - child: Wrap( - direction: widget.legendOptions.showLegendsInRow - ? Axis.horizontal - : Axis.vertical, - runSpacing: 8, - crossAxisAlignment: WrapCrossAlignment.start, - children: legendTitles! - .map( - (item) => Legend( - title: item, - color: getColor( - widget.colorList, - legendTitles!.indexOf(item), - ), - style: widget.legendOptions.legendTextStyle, - legendShape: widget.legendOptions.legendShape, - ), - ) - .toList(), + return Flexible( + child: LayoutBuilder( + builder: (_, c) { + return Padding( + padding: padding!, + child: Wrap( + direction: widget.legendOptions.showLegendsInRow + ? Axis.horizontal + : Axis.vertical, + runSpacing: 8, + children: legendTitles! + .map( + (item) => Legend( + title: item, + legendHeight: widget.legendOptions.height, + legendWidth: widget.legendOptions.width, + titleRowWidth: c.maxWidth, + color: getColor( + widget.colorList, + legendTitles!.indexOf(item), + ), + style: widget.legendOptions.legendTextStyle, + legendShape: widget.legendOptions.legendShape, + ), + ) + .toList(), + ), + ); + }, ), ); - } else - return SizedBox( - height: 0, - width: 0, - ); + } else { + return const SizedBox(); + } } @override Widget build(BuildContext context) { return Container( alignment: Alignment.center, - padding: EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: _getPieChart(), ); }