-
Notifications
You must be signed in to change notification settings - Fork 906
Description
Use case
I want to reverse the label order without reversing the circles ( my chart ) order. I tried a few things and nothing worked out so I am not entirely sure if this is possible or not.
Proposal
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:intl/intl.dart';
class OverviewPage extends StatefulWidget {
const OverviewPage({Key? key}) : super(key: key);
@OverRide
_OverviewPageState createState() => _OverviewPageState();
}
class _OverviewPageState extends State {
bool showTotalActivityTime = false;
@OverRide
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'Overview',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
centerTitle: true,
automaticallyImplyLeading: false, // Removes the go back arrow
),
body: Center(
child: Column(
children: [
ElevatedButton(
onPressed: () {
setState(() {
showTotalActivityTime = !showTotalActivityTime;
});
},
child: Text(showTotalActivityTime ? 'Show Activity Counts' : 'Show Total Activity Time'),
),
Expanded(
child: FutureBuilder<List>(
future: showTotalActivityTime ? fetchTotalActivityTime() : fetchActivityCounts(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return SizedBox(
height: 300, // Adjust height as needed
width: double.infinity, // Take full width
child: SfCircularChart(
legend: Legend(isVisible: true, position: LegendPosition.right), // Move legend to the right
series: [
RadialBarSeries<ChartData, String>(
dataSource: snapshot.data!,
xValueMapper: (ChartData data, _) => data.category,
yValueMapper: (ChartData data, _) => data.value,
dataLabelMapper: (ChartData data, _) => data.formattedTime,
dataLabelSettings: const DataLabelSettings(isVisible: true),
// Adjust the thickness of the circle lines
trackBorderWidth: 2, // Adjust this value to make the circle lines thinner or thicker
// Adjust the space between each circle
gap: '17%', // Adjust this value to add space between the circles
// Adjust the thickness of the circles
innerRadius: '10%', // Adjust this value to make the circles thinner or thicker
)
],
),
);
}
},
),
),
],
),
),
);
}
Future<List> fetchActivityCounts() async {
final userUID = FirebaseAuth.instance.currentUser?.uid;
if (userUID != null) {
final now = DateTime.now();
final currentMonthYear = DateFormat('MM-yyyy').format(now);
final querySnapshot = await FirebaseFirestore.instance
.collection('users')
.doc(userUID)
.collection(currentMonthYear)
.where('ActivityName', isNotEqualTo: null)
.where('ActivityName', isNotEqualTo: 'placeholder')
.get();
if (querySnapshot.docs.isEmpty) {
// Return example chart data if no records are found
return generateExampleChartData();
}
// Aggregate count of records for each activity
Map<String, int> activityCounts = {};
for (var doc in querySnapshot.docs) {
final activityName = doc['ActivityName'] as String;
activityCounts[activityName] = (activityCounts[activityName] ?? 0) + 1;
}
// Convert to ChartData objects
List<ChartData> chartData = [];
activityCounts.forEach((activity, count) {
final formattedTime = '$count $activity records';
chartData.add(ChartData(activity, count.toDouble(), formattedTime));
});
// Sort the chartData list by value in descending order
chartData.sort((a, b) => b.value.compareTo(a.value));
// Get only the first 5 elements
chartData = chartData.take(5).toList();
// Reverse the list so that the biggest count is first
chartData = chartData.reversed.toList();
return chartData;
}
return [];
}
Future<List> fetchTotalActivityTime() async {
final userUID = FirebaseAuth.instance.currentUser?.uid;
if (userUID != null) {
final now = DateTime.now();
final currentMonthYear = DateFormat('MM-yyyy').format(now);
final querySnapshot = await FirebaseFirestore.instance
.collection('users')
.doc(userUID)
.collection(currentMonthYear)
.where('ActivityName', isNotEqualTo: null)
.where('ActivityName', isNotEqualTo: 'placeholder')
.get();
if (querySnapshot.docs.isEmpty) {
// Return example chart data if no records are found
return generateExampleChartData();
}
// Aggregate total activity time for each activity
Map<String, double> activityTimes = {};
for (var doc in querySnapshot.docs) {
final activityName = doc['ActivityName'] as String;
final activityTimeRaw = doc['ActivityTime'] as String;
double activityTime = parseActivityTime(activityTimeRaw);
// Convert time from minutes to hours
double activityTimeInHours = activityTime / 60.0;
activityTimes[activityName] = (activityTimes[activityName] ?? 0) + activityTimeInHours;
}
// Convert to ChartData objects
List<ChartData> chartData = [];
activityTimes.forEach((activity, time) {
final hours = time.floor();
final minutes = ((time - hours) * 60).toInt();
final formattedTime = '$hours hours $minutes minutes';
chartData.add(ChartData(activity, time, formattedTime));
});
// Sort the chartData list by value in descending order
chartData.sort((a, b) => b.value.compareTo(a.value));
// Get only the first 5 elements
chartData = chartData.take(5).toList();
// Reverse the list so that the biggest time is first
chartData = chartData.reversed.toList();
return chartData;
}
return [];
}
List generateExampleChartData() {
// Example data
List exampleData = [
ChartData('Example 1', 3, '3 records'),
ChartData('Example 2', 5, '5 records'),
ChartData('Example 3', 10, '10 records'),
ChartData('Example 4', 15, '15 records'),
ChartData('Example 5', 20, '20 records'),
];
return exampleData;
}
double parseActivityTime(String activityTime) {
// Initialize total time in minutes
double totalMinutes = 0.0;
// Use regular expressions to extract the values
final hoursRegex = RegExp(r'(\d+)\s*hours?');
final minutesRegex = RegExp(r'(\d+)\s*mins?');
final hoursMatch = hoursRegex.firstMatch(activityTime);
final minutesMatch = minutesRegex.firstMatch(activityTime);
if (hoursMatch != null) {
totalMinutes += double.parse(hoursMatch.group(1)!) * 60;
}
if (minutesMatch != null) {
totalMinutes += double.parse(minutesMatch.group(1)!);
}
return totalMinutes;
}
}
class ChartData {
ChartData(this.category, this.value, this.formattedTime);
final String category;
final double value;
final String formattedTime;
}
