import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:pie_chart/pie_chart.dart'; class PieChartPainter extends CustomPainter { List _paintList = []; List _subParts; List _subTitles; double _total = 0; double _totalAngle = math.pi * 2; final TextStyle chartValueStyle; final Color chartValueBackgroundColor; final double initialAngle; final bool showValuesInPercentage; final bool showChartValues; final bool showChartValuesOutside; final int decimalPlaces; final bool showChartValueLabel; final ChartType chartType; final Function formatChartValues; final double strokeWidth; final bool selected; final List colorList; double _prevAngle = 0; final TextStyle sideTextStyle; PieChartPainter( double angleFactor, this.showChartValues, this.showChartValuesOutside, this.colorList, { this.chartValueStyle, this.chartValueBackgroundColor, List values, List titles, this.initialAngle, this.showValuesInPercentage, this.decimalPlaces, this.showChartValueLabel, this.chartType, this.formatChartValues, this.strokeWidth, this.selected = false, this.sideTextStyle, }) { for (int i = 0; i < values.length; i++) { final paint = Paint()..color = getColor(colorList, i); if (chartType == ChartType.ring) { paint.style = PaintingStyle.stroke; paint.strokeWidth = strokeWidth; } _paintList.add(paint); } _totalAngle = angleFactor * math.pi * 2; _subParts = values; _subTitles = titles; _total = values.fold(0, (v1, v2) => v1 + v2); } @override void paint(Canvas canvas, Size size) { final side = size.width < size.height ? size.width : size.height; _prevAngle = initialAngle * math.pi / 180; for (int i = 0; i < _subParts.length; i++) { canvas.drawArc( Rect.fromLTWH(0.0, 0.0, side, size.height), _prevAngle, (((_totalAngle) / _total) * _subParts[i]), chartType == ChartType.disc ? true : false, _paintList[i], ); final radius = showChartValuesOutside ? (side / 2) + 16 : side / 3; final x = (radius) * math.cos(_prevAngle + ((((_totalAngle) / _total) * _subParts[i]) / 2)); final y = (radius) * math.sin(_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); // final name = showValuesInPercentage // ? (((_subParts.elementAt(i) / _total) * 100) // .toStringAsFixed(this.decimalPlaces) + // '%') // : value; // final name = showValuesInPercentage ? (((_subParts.elementAt(i) / _total) * 100).toStringAsFixed(this.decimalPlaces) + '%') : _subTitles.elementAt(i); if (showChartValues) { final name = "${_subTitles[i]} " + (showValuesInPercentage ? (((_subParts.elementAt(i) / _total) * 100).toStringAsFixed(this.decimalPlaces) + '%') : value); var yLabel = y > size.width ? y + 40 : y + 10; var xLabel = (y > size.width ? x - y : x * 1.6) - 15; var yPopup = y - 8; if (_subParts[i] <= (_total / _subParts.length)) { yLabel = y + 8; xLabel *= 1.1; yPopup *= 1.25; } if (selected) _drawLabel(canvas, name, x, yPopup, side, true, statusColor: getColor(colorList, i)); _drawLabel(canvas, _subTitles[i], xLabel, yLabel, side + 8, false); } } _prevAngle = _prevAngle + (((_totalAngle) / _total) * _subParts[i]); } } void _drawLabel(Canvas canvas, String name, double x, double y, double side, bool withBackground, {Color statusColor = Colors.white}) { TextSpan span = TextSpan( style: withBackground ? chartValueStyle : sideTextStyle, text: name, ); TextPainter tp = TextPainter( text: span, textAlign: TextAlign.center, textDirection: TextDirection.ltr, ); tp.layout(); if (withBackground && showChartValueLabel) { //Draw text background box final rect = Rect.fromCenter( center: Offset((side / 2 + (x + 16)), (side / 2 + y)), width: tp.width + 45, height: tp.height + 16, ); final rect2 = Rect.fromCenter( center: Offset( (side / 2 + x) - ((tp.width - 16) / 2), (side / 2 + y) - ((tp.height - 16) / 2), ), width: 12, height: 12, ); final rRect = RRect.fromRectAndRadius(rect, const Radius.circular(8)); final rRect2 = RRect.fromRectAndRadius(rect2, const Radius.circular(1)); final paint = Paint() ..color = chartValueBackgroundColor ?? Colors.grey[200] ..style = PaintingStyle.fill; canvas.drawRRect(rRect, paint); canvas.drawRRect(rRect2, paint..color = statusColor); } //Finally paint the text above box tp.paint( canvas, Offset( (side / 2 + x) - ((tp.width - 50) / 2), (side / 2 + y) - ((tp.height) / 2), ), ); } @override bool shouldRepaint(PieChartPainter oldDelegate) => selected != oldDelegate.selected; }