Skip to content

Commit

Permalink
RadarChart draw functionality added to radar_chart_painter.dart
Browse files Browse the repository at this point in the history
  • Loading branch information
payam-zahedi committed Feb 18, 2021
1 parent a588c30 commit 0aa7e58
Show file tree
Hide file tree
Showing 6 changed files with 251 additions and 5 deletions.
2 changes: 1 addition & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ linter:
# the Dart Lint rules page to make maintenance easier
# https://github.com/dart-lang/linter/blob/master/example/all.yaml
- always_declare_return_types
- always_put_control_body_on_new_line
# - always_put_control_body_on_new_line
# - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219
- always_require_non_null_named_parameters
- annotate_overrides
Expand Down
2 changes: 2 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:example/radar_chart/radar_chart_page.dart';
import 'package:example/scatter_chart/scatter_chart_page.dart';
import 'package:flutter/material.dart';

Expand Down Expand Up @@ -42,6 +43,7 @@ class _MyHomePageState extends State<MyHomePage> {
body: SafeArea(
child: PageView(
children: <Widget>[
RadarChartPage(),
LineChartPage(),
BarChartPage(),
BarChartPage2(),
Expand Down
26 changes: 26 additions & 0 deletions example/lib/radar_chart/radar_chart_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'package:example/radar_chart/samples/radar_chart_sample1.dart';
import 'package:flutter/material.dart';

class RadarChartPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.grey,
padding: const EdgeInsets.all(28.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'RadarChart',
style: TextStyle(
color: Color(0xff333333),
fontSize: 32,
fontWeight: FontWeight.bold,
),
),
RadarChartSample(),
],
),
);
}
}
51 changes: 51 additions & 0 deletions example/lib/radar_chart/samples/radar_chart_sample1.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';

class RadarChartSample extends StatefulWidget {
@override
_RadarChartSampleState createState() => _RadarChartSampleState();
}

class _RadarChartSampleState extends State<RadarChartSample> {
@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1.3,
child: Card(
color: Colors.white,
child: RadarChart(
RadarChartData(
titleCount: 3,
fillColor: Colors.grey,
dataSets: showingDataSets(),
tickCount: 4,
getTitle: (index) => '$index + values',
),
),
),
);
}

List<RadarDataSet> showingDataSets() {
return [
RadarDataSet(
dataEntries: [
RadarEntry(value: 5),
RadarEntry(value: 1),
RadarEntry(value: 25),
],
strokeWidth: 3,
color: Colors.red,
),
RadarDataSet(
dataEntries: [
RadarEntry(value: 18),
RadarEntry(value: 20),
RadarEntry(value: 30),
],
strokeWidth: 3,
color: Colors.orange,
),
];
}
}
3 changes: 3 additions & 0 deletions lib/fl_chart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@ export 'src/chart/line_chart/line_chart.dart';
export 'src/chart/line_chart/line_chart_data.dart';
export 'src/chart/pie_chart/pie_chart.dart';
export 'src/chart/pie_chart/pie_chart_data.dart';
export 'src/chart/radar_chart/radar_chart.dart';
export 'src/chart/radar_chart/radar_chart_data.dart';
export 'src/chart/radar_chart/radar_chart_painter.dart';
export 'src/chart/scatter_chart/scatter_chart.dart';
export 'src/chart/scatter_chart/scatter_chart_data.dart';
172 changes: 168 additions & 4 deletions lib/src/chart/radar_chart/radar_chart_painter.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import 'dart:math' as math;
import 'dart:math' show pi, cos, sin;
import 'dart:developer';
import 'dart:math' show pi, cos, sin, min;
import 'dart:ui';

import 'package:fl_chart/src/chart/base/base_chart/base_chart_painter.dart';
import 'package:fl_chart/src/chart/radar_chart/radar_chart_data.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

const defaultGraphColors = [
Expand All @@ -15,16 +16,179 @@ const defaultGraphColors = [

class RadarChartPainter extends BaseChartPainter<RadarChartData>
with TouchHandler<RadarTouchResponse> {
final Paint _outlinePaint, _backgroundPaint, _tickPaint;
final TextPainter _ticksTextPaint;

//ToDo(payam) : add touchHandle function here
RadarChartPainter(
RadarChartData data,
RadarChartData targetData, {
double textScale,
}) : super(data, targetData, textScale: textScale);
}) : _backgroundPaint = Paint()
..color = data.fillColor
..style = PaintingStyle.fill
..isAntiAlias = true,
_outlinePaint = Paint()
..color = data.borderData.border.top.color
..style = PaintingStyle.stroke
..strokeWidth = data.borderData.border.top.width
..isAntiAlias = true,
_ticksTextPaint = TextPainter(),
_tickPaint = Paint()
..color = Colors.blue
..style = PaintingStyle.stroke
..strokeWidth = 2
..isAntiAlias = true,
super(data, targetData, textScale: textScale);

@override
void paint(Canvas canvas, Size size) {}
void paint(Canvas canvas, Size size) {
drawTicks(size, canvas);
drawGrids(size, canvas);
drawTitles(size, canvas);
drawDataSets(size, canvas);
}

void drawTicks(Size size, Canvas canvas) {
final centerX = size.width / 2.0;
final centerY = size.height / 2.0;
final centerOffset = Offset(centerX, centerY);

/// controls Radar chart size
final radius = min(centerX, centerY) * 0.7;

//draw radar background
canvas.drawCircle(centerOffset, radius, _backgroundPaint);
//draw radar border
canvas.drawCircle(centerOffset, radius, _outlinePaint);

final dataSetMaxValue = data.maxEntry.value;
final dataSetMinValue = data.minEntry.value;
final tickSpace = (dataSetMaxValue - dataSetMinValue) / data.tickCount;

final ticks = <double>[];

for (var tick = dataSetMinValue; tick <= dataSetMaxValue; tick = tick + tickSpace)
ticks.add(tick);

final tickDistance = radius / (ticks.length);

log('ticks: ${ticks.toString()}');

ticks.sublist(0, ticks.length - 1).asMap().forEach((index, tick) {
final tickRadius = tickDistance * (index + 1);
canvas.drawCircle(centerOffset, tickRadius, _tickPaint);
_ticksTextPaint
..text = TextSpan(
text: tick.toString(),
style: const TextStyle(fontSize: 10, color: Colors.black),
)
..textDirection = TextDirection.ltr
..layout(minWidth: 0, maxWidth: size.width)
..paint(canvas, Offset(centerX + 5, centerY - tickRadius - 12));
});
}

void drawGrids(Size size, Canvas canvas) {
final centerX = size.width / 2.0;
final centerY = size.height / 2.0;
final centerOffset = Offset(centerX, centerY);

/// controls Radar chart size
final radius = min(centerX, centerY) * 0.7;

final angle = (2 * pi) / data.titleCount;

//drawing grids
for (int index = 0; index < data.titleCount; index++) {
final endX = centerX + radius * cos(angle * index - pi / 2);
final endY = centerY + radius * sin(angle * index - pi / 2);

final gridOffset = Offset(endX, endY);

canvas.drawLine(centerOffset, gridOffset, _tickPaint);
}
}

void drawTitles(Size size, Canvas canvas) {
if (data?.getTitle == null) return;

final centerX = size.width / 2.0;
final centerY = size.height / 2.0;

/// controls Radar chart size
final radius = min(centerX, centerY) * 0.7;

final angle = (2 * pi) / data.titleCount;

for (int index = 0; index < data.titleCount; index++) {
final title = data?.getTitle(index);
const style = TextStyle(fontSize: 14, color: Colors.red);
final xAngle = cos(angle * index - pi / 2);
final yAngle = sin(angle * index - pi / 2);

final span = TextSpan(text: title, style: style);
final TextPainter tp = TextPainter(
text: span,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
textScaleFactor: textScale,
);

tp.layout();
canvas.save();
const threshold = 1.15;
final featureOffset = Offset(
centerX + threshold * radius * xAngle,
centerY + threshold * radius * yAngle,
);
canvas.translate(featureOffset.dx, featureOffset.dy);
canvas.rotate(angle * index);

tp.paint(canvas, Offset.zero - Offset(tp.width / 2, tp.height / 2));
canvas.restore();
}
}

void drawDataSets(Size size, Canvas canvas) {
final centerX = size.width / 2.0;
final centerY = size.height / 2.0;

/// controls Radar chart size
final radius = min(centerX, centerY) * 0.7;

data.dataSets.asMap().forEach((index, graph) {
final graphPaint = Paint()
..color = graph.color.withOpacity(0.3)
..style = PaintingStyle.fill;

final graphOutlinePaint = Paint()
..color = graph.color
..style = PaintingStyle.stroke
..strokeWidth = 2.0
..isAntiAlias = true;

final scale = radius / data.maxEntry.value;
final scaledPoint = scale * graph.dataEntries.first.value;
final angle = (2 * pi) / data.titleCount;
final path = Path();

path.moveTo(centerX, centerY - scaledPoint);

graph.dataEntries.asMap().forEach((index, point) {
if (index == 0) return;
final xAngle = cos(angle * index - pi / 2);
final yAngle = sin(angle * index - pi / 2);
final scaledPoint = scale * point.value;

path.lineTo(centerX + scaledPoint * xAngle, centerY + scaledPoint * yAngle);
});

path.close();
canvas.drawPath(path, graphPaint);
canvas.drawPath(path, graphOutlinePaint);
});
}

@override
bool shouldRepaint(RadarChartPainter oldDelegate) {
Expand Down

0 comments on commit 0aa7e58

Please sign in to comment.