Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question / Need help #2136

Open
Welnnys opened this issue Oct 17, 2024 · 6 comments
Open

Question / Need help #2136

Welnnys opened this issue Oct 17, 2024 · 6 comments
Labels
charts Charts component waiting for customer response Cannot make further progress until the customer responds.

Comments

@Welnnys
Copy link

Welnnys commented Oct 17, 2024

Is there a way to reverse the order of the labels on the right side without reversing the order of the circles and if possible to also keep the default legend icons (those little clickable circles)?

// overview_model.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:intl/intl.dart';

class OverviewModel {
final String userUID;

OverviewModel(this.userUID);

Future<List> fetchActivityCounts() async {
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 generateExampleChartData();
}

Map<String, int> activityCounts = {};
for (var doc in querySnapshot.docs) {
  final activityName = doc['ActivityName'] as String;
  activityCounts[activityName] = (activityCounts[activityName] ?? 0) + 1;
}

List<ChartData> chartData = [];
activityCounts.forEach((activity, count) {
  final formattedTime = '$count $activity records';
  chartData.add(ChartData(activity, count.toDouble(), formattedTime));
});

chartData.sort((a, b) => b.value.compareTo(a.value));
chartData = chartData.take(5).toList();
chartData = chartData.reversed.toList();

return chartData;

}

Future<List> fetchTotalActivityTime() async {
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 generateExampleChartData();
}

Map<String, double> activityTimes = {};
for (var doc in querySnapshot.docs) {
  final activityName = doc['ActivityName'] as String;
  final int activityTime = doc['ActivityTime'] as int;
  double activityTimeInHours = activityTime / 60.0;

  activityTimes[activityName] =
      (activityTimes[activityName] ?? 0) + activityTimeInHours;
}

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));
});

chartData.sort((a, b) => b.value.compareTo(a.value));
chartData = chartData.take(5).toList();
chartData = chartData.reversed.toList();

return chartData;

}

Future<List<Map<String, dynamic>>> fetchPersonalBestActivities(
List sortedActivityTypes) async {
List allActivityTypes = [
'Running',
'Cycling',
'Walking',
'Swimming',
'Volleyball',
'Bouldering',
'Football',
'Basketball',
'Fitness',
];

List<Map<String, dynamic>> allActivities = [];
for (String activityType in allActivityTypes) {
  final querySnapshot = await FirebaseFirestore.instance
      .collection('users')
      .doc(userUID)
      .collection(activityType)
      .orderBy('steps', descending: true)
      .limit(1)
      .get();

  if (querySnapshot.docs.isNotEmpty) {
    final bestActivity = querySnapshot.docs.first.data();
    bestActivity['docId'] = querySnapshot.docs.first.id;
    bestActivity['activityType'] = activityType;
    allActivities.add(bestActivity);
  }
}

List<Map<String, dynamic>> chartActivities = [];
List<Map<String, dynamic>> nonChartActivities = [];

for (var activity in allActivities) {
  if (sortedActivityTypes.contains(activity['activityType'])) {
    chartActivities.add(activity);
  } else {
    nonChartActivities.add(activity);
  }
}

chartActivities.sort((a, b) {
  String typeA = a['activityType'];
  String typeB = b['activityType'];
  return sortedActivityTypes
      .indexOf(typeA)
      .compareTo(sortedActivityTypes.indexOf(typeB));
});

chartActivities = chartActivities.reversed.toList();

return [...chartActivities, ...nonChartActivities];

}

List generateExampleChartData() {
List exampleData = [
ChartData('Example 1', 3, 'No Data'),
ChartData('Example 2', 5, 'No Data'),
ChartData('Example 3', 10, 'No Data'),
ChartData('Example 4', 15, 'No Data'),
ChartData('Example 5', 20, 'No Data'),
];

return exampleData;

}
}

class ChartData {
ChartData(this.category, this.value, this.formattedTime);
final String category;
final double value;
final String formattedTime;
}


// overview_page.dart

import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:sporti_angel_kolev/models/overview_model.dart';
import 'package:sporti_angel_kolev/controllers/overview_controller.dart';
import 'package:sporti_angel_kolev/common/activity_list_widget.dart';
import 'package:sporti_angel_kolev/common/profile_picture.dart';
import 'package:sporti_angel_kolev/common/user_information.dart';

class OverviewPage extends StatefulWidget {
const OverviewPage({super.key});

@OverRide
_OverviewPageState createState() => _OverviewPageState();
}

class _OverviewPageState extends State {
bool showTotalActivityTime = true;
late OverviewController _controller;

@OverRide
void initState() {
super.initState();
final userUID = UserInformation().userUID;
_controller = OverviewController(OverviewModel(userUID));
}

@OverRide
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
surfaceTintColor: Colors.white,
title: const Text(
'Overview',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
centerTitle: true,
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
actions: const [ProfilePicture()],
),
body: Center(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: ElevatedButton(
onPressed: () {
setState(() {
showTotalActivityTime = !showTotalActivityTime;
});
},
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
vertical: 15.0, horizontal: 30.0),
backgroundColor: Colors.redAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
elevation: 5,
shadowColor: Colors.black,
),
child: Text(
showTotalActivityTime
? 'Monthly Activity Count'
: 'Monthly Total Activity Time',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
Expanded(
child: Column(
children: [
Flexible(
child: FutureBuilder<List>(
future: showTotalActivityTime
? _controller.fetchTotalActivityTime()
: _controller.fetchActivityCounts(),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation(
Colors.red)));
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
final chartData = snapshot.data ?? [];

                      List<String> sortedActivityTypes =
                          chartData.map((data) => data.category).toList();

                      return Column(
                        children: [
                          SfCircularChart(
                            centerX: '130',
                            legend: const Legend(
                                isVisible: true,
                                position: LegendPosition.right),
                            series: <CircularSeries>[
                              RadialBarSeries<ChartData, String>(
                                dataSource: chartData,
                                xValueMapper: (ChartData data, _) =>
                                    data.category,
                                yValueMapper: (ChartData data, _) =>
                                    data.value,
                                dataLabelMapper: (ChartData data, _) =>
                                    data.formattedTime,
                                dataLabelSettings: const DataLabelSettings(
                                    isVisible: true),
                                trackBorderWidth: 2,
                                gap: '17%',
                                innerRadius: '10%',
                              ),
                            ],
                          ),
                          Expanded(
                            child: SingleChildScrollView(
                              child: ActivityListWidget(
                                fetchActivities: () =>
                                    _controller.fetchPersonalBestActivities(
                                        sortedActivityTypes),
                                onActivityDeleted: () {
                                  setState(() {});
                                },
                                centerEmptyMessage: false,
                              ),
                            ),
                          ),
                        ],
                      );
                    }
                  },
                ),
              ),
            ],
          ),
        ),
      ],
    ),
  ),
);

}
}

image

@VijayakumarMariappan VijayakumarMariappan added charts Charts component open Open labels Oct 18, 2024
@Welnnys
Copy link
Author

Welnnys commented Oct 30, 2024

Can I please get a response :/?

@Welnnys
Copy link
Author

Welnnys commented Nov 4, 2024

Hello :/, it's been 3 weeks

@ThilipChandru
Copy link
Collaborator

ThilipChandru commented Nov 8, 2024

Hi @Welnnys,

We have analyzed you query and you can achieve your requirement by using LegendItemBuilder. However by reversing the text alone in legend does not reflect in chart segment when click on respective legend item. We have shared code snippet and sample for your reference.

Code Snippet:

@override
  Widget build(BuildContext context) {
    // Reverse the chart data only for the legend
    List<_ChartData> reversedChartData = List.from(chartData.reversed);

    return Scaffold(
      body: SfCircularChart(
        ……………….
          // Customizing the legend to show in reversed order
         legendItemBuilder: (String name, dynamic series, dynamic point, int index) {
            final ChartPoint _point = point as ChartPoint; 
            // Define colors for each category in reversed order
            final Color color = index == 0
                ? Colors.blue
                : index == 1
                    ? Colors.green
                    : Colors.red;

            return Container(
              padding: const EdgeInsets.all(4),
              child: Row(
                children: [
                  // Circular shape icon with custom color
                  Container(
                    width: 10,
                    height: 10,
                    decoration: BoxDecoration(
                      shape: BoxShape.circle,
                      color: color,
                    ),
                  ),
                  const SizedBox(width: 8),
                  // Display the reversed label
                  Text(reversedChartData[index].x),
                ],
              ),
            );
          },
…………….

Screenshot:
image

For more information, kindly refer to the following UG,
UG link: https://help.syncfusion.com/flutter/circular-charts/legend#legend-item-template

Sample : gh_2136.zip

Regards,
Thilip Chandru.

@Welnnys
Copy link
Author

Welnnys commented Nov 8, 2024

And there is no way to make it reflect the chart?

@Welnnys
Copy link
Author

Welnnys commented Nov 8, 2024

and to have the default legend icons aswell

@LavanyaGowtham2021 LavanyaGowtham2021 added waiting for customer response Cannot make further progress until the customer responds. and removed open Open labels Nov 10, 2024
@Welnnys
Copy link
Author

Welnnys commented Nov 11, 2024

I have already responded, I am waiting for you to respond

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
charts Charts component waiting for customer response Cannot make further progress until the customer responds.
Projects
None yet
Development

No branches or pull requests

4 participants