chart changes done

This commit is contained in:
venbaittech 2025-02-20 17:51:51 +05:30
parent 3cc3a9bcbd
commit 25eb1a06e9
4 changed files with 692 additions and 368 deletions

View File

@ -15,12 +15,12 @@ if (localPropertiesFile.exists()) {
def flutterVersionCode = localProperties.getProperty("flutter.versionCode") def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
if (flutterVersionCode == null) { if (flutterVersionCode == null) {
flutterVersionCode = "21" flutterVersionCode = "24"
} }
def flutterVersionName = localProperties.getProperty("flutter.versionName") def flutterVersionName = localProperties.getProperty("flutter.versionName")
if (flutterVersionName == null) { if (flutterVersionName == null) {
flutterVersionName = "1.0.20" flutterVersionName = "1.0.23"
} }
def keystorePropertiesFile = rootProject.file("key.properties") def keystorePropertiesFile = rootProject.file("key.properties")

View File

@ -80,7 +80,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
print(' bgColor $bgColor'); print(' bgColor $bgColor');
// fetchChartData(widget.dataSets); // fetchChartData(widget.dataSets);
checkIfBookmarked(); checkIfBookmarked();
locale = ref.read(localeProvider)?? const Locale('en'); locale = ref.read(localeProvider) ?? const Locale('en');
fetchChartData(widget.dataSets, locale?.languageCode ?? 'en').then((_) { fetchChartData(widget.dataSets, locale?.languageCode ?? 'en').then((_) {
if (_tabsData.isNotEmpty) { if (_tabsData.isNotEmpty) {
// Call onTabSelected for the first tab // Call onTabSelected for the first tab
@ -310,6 +310,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
), ),
); );
} }
//when the popup need for bookmark //when the popup need for bookmark
// void showAddBookmarkDialog() { // void showAddBookmarkDialog() {
// double myheight = MediaQuery.of(context).size.height; // double myheight = MediaQuery.of(context).size.height;
@ -398,15 +399,15 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// } // }
void showAddBookmarkDialog() { void showAddBookmarkDialog() {
addBookmark(); addBookmark();
ScaffoldMessenger.of(context).showSnackBar( // ScaffoldMessenger.of(context).showSnackBar(
SnackBar( // SnackBar(
content: Text( // content: Text(
'The bookmark is added successfully', // 'The bookmark is added successfully',
), // ),
backgroundColor: Colors.green, // backgroundColor: Colors.green,
duration: Duration(seconds: 2), // duration: Duration(seconds: 2),
), // ),
); // );
} }
void handleSkip() { void handleSkip() {
@ -539,9 +540,14 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? Color(0xFF7DAFBC):null, color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: null,
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Color(0xFF7DAFBC): Colors.white, width: 2.0), color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: Colors.white,
width: 2.0),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
@ -551,8 +557,13 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
if (locale.languageCode == 'ar') { if (locale.languageCode == 'ar') {
tutorialCoachMark.next(); tutorialCoachMark.next();
} else { } else {
ref.read(chartsTourProvider.notifier).state = true; ref
ref.read(previousHomeTourProvider.notifier).state = false; .read(chartsTourProvider.notifier)
.state = true;
ref
.read(previousHomeTourProvider
.notifier)
.state = false;
tutorialCoachMark.finish(); tutorialCoachMark.finish();
} }
}, },
@ -562,9 +573,14 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? null:Color(0xFF7DAFBC), color: locale.languageCode == 'ar'
? null
: Color(0xFF7DAFBC),
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Colors.white: Color(0xFF7DAFBC), width: 1), color: locale.languageCode == 'ar'
? Colors.white
: Color(0xFF7DAFBC),
width: 1),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
@ -572,8 +588,13 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
color: Colors.white), color: Colors.white),
onPressed: () { onPressed: () {
if (locale.languageCode == 'ar') { if (locale.languageCode == 'ar') {
ref.read(chartsTourProvider.notifier).state = true; ref
ref.read(previousHomeTourProvider.notifier).state = false; .read(chartsTourProvider.notifier)
.state = true;
ref
.read(previousHomeTourProvider
.notifier)
.state = false;
tutorialCoachMark.finish(); tutorialCoachMark.finish();
} else { } else {
tutorialCoachMark.next(); tutorialCoachMark.next();
@ -627,7 +648,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
text: AppLocalizations.of(context)!.bookMark, text: AppLocalizations.of(context)!.bookMark,
alignment: ContentAlign.bottom, alignment: ContentAlign.bottom,
gap: 53, gap: 53,
space: screenWidth*0.22, space: screenWidth * 0.22,
), ),
TargetContent( TargetContent(
align: ContentAlign.bottom, align: ContentAlign.bottom,
@ -682,18 +703,29 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? Color(0xFF7DAFBC):null, color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: null,
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Color(0xFF7DAFBC): Colors.white, width: 2.0), color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: Colors.white,
width: 2.0),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
icon: const Icon(Icons.arrow_back, icon: const Icon(
color: Colors.white,), Icons.arrow_back,
color: Colors.white,
),
onPressed: () { onPressed: () {
if (locale.languageCode == 'ar') { if (locale.languageCode == 'ar') {
ref.read(chartsTourProvider.notifier).state = true; ref
ref.read(scaffoldTourProvider.notifier).state = false; .read(chartsTourProvider.notifier)
.state = true;
ref
.read(scaffoldTourProvider.notifier)
.state = false;
tutorialCoachMark.finish(); tutorialCoachMark.finish();
} else { } else {
tutorialCoachMark.previous(); tutorialCoachMark.previous();
@ -705,23 +737,33 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? null:Color(0xFF7DAFBC), color: locale.languageCode == 'ar'
? null
: Color(0xFF7DAFBC),
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Colors.white: Color(0xFF7DAFBC), width: 1), color: locale.languageCode == 'ar'
? Colors.white
: Color(0xFF7DAFBC),
width: 1),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
icon: const Icon(Icons.arrow_forward, icon: const Icon(
color: Colors.white,), Icons.arrow_forward,
color: Colors.white,
),
onPressed: () { onPressed: () {
if (locale.languageCode == 'ar') { if (locale.languageCode == 'ar') {
tutorialCoachMark.previous(); tutorialCoachMark.previous();
} else { } else {
ref.read(chartsTourProvider.notifier).state = true; ref
ref.read(scaffoldTourProvider.notifier).state = false; .read(chartsTourProvider.notifier)
.state = true;
ref
.read(scaffoldTourProvider.notifier)
.state = false;
tutorialCoachMark.finish(); tutorialCoachMark.finish();
} }
}, },
), ),
), ),
@ -741,7 +783,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
align: ContentAlign.right, align: ContentAlign.right,
child: Container( child: Container(
width: screenWidth / 4, width: screenWidth / 4,
height: screenHeight*0.2, height: screenHeight * 0.2,
child: Stack( child: Stack(
children: [ children: [
Image.asset( Image.asset(
@ -770,7 +812,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
contents: [ contents: [
createTargetContent( createTargetContent(
text: AppLocalizations.of(context)!.bookMark, text: AppLocalizations.of(context)!.bookMark,
space:screenWidth*0.22, space: screenWidth * 0.22,
alignment: ContentAlign.bottom, alignment: ContentAlign.bottom,
gap: 53, gap: 53,
), ),
@ -827,18 +869,30 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? Color(0xFF7DAFBC):null, color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: null,
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Color(0xFF7DAFBC): Colors.white, width: 2.0,), color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: Colors.white,
width: 2.0,
),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
icon: const Icon(Icons.arrow_back, icon: const Icon(
color: Colors.white,), Icons.arrow_back,
color: Colors.white,
),
onPressed: () { onPressed: () {
if (locale.languageCode == 'ar') { if (locale.languageCode == 'ar') {
ref.read(chartsTourProvider.notifier).state = true; ref
ref.read(scaffoldTourProvider.notifier).state = false; .read(chartsTourProvider.notifier)
.state = true;
ref
.read(scaffoldTourProvider.notifier)
.state = false;
tutorialCoachMark.finish(); tutorialCoachMark.finish();
} else { } else {
tutorialCoachMark.next(); tutorialCoachMark.next();
@ -850,9 +904,15 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? null:Color(0xFF7DAFBC), color: locale.languageCode == 'ar'
? null
: Color(0xFF7DAFBC),
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Colors.white : Color(0xFF7DAFBC), width: 2.0,), color: locale.languageCode == 'ar'
? Colors.white
: Color(0xFF7DAFBC),
width: 2.0,
),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
@ -862,8 +922,12 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
if (locale.languageCode == 'ar') { if (locale.languageCode == 'ar') {
tutorialCoachMark.next(); tutorialCoachMark.next();
} else { } else {
ref.read(chartsTourProvider.notifier).state = true; ref
ref.read(scaffoldTourProvider.notifier).state = false; .read(chartsTourProvider.notifier)
.state = true;
ref
.read(scaffoldTourProvider.notifier)
.state = false;
tutorialCoachMark.finish(); tutorialCoachMark.finish();
} }
}, },
@ -885,7 +949,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
align: ContentAlign.right, align: ContentAlign.right,
child: SizedBox( child: SizedBox(
width: screenWidth / 4, width: screenWidth / 4,
height:screenHeight*0.2, height: screenHeight * 0.2,
child: Stack( child: Stack(
children: [ children: [
Image.asset( Image.asset(
@ -964,23 +1028,36 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? Color(0xFF7DAFBC):null, color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: null,
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Color(0xFF7DAFBC): Colors.white, width: 2.0,), color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: Colors.white,
width: 2.0,
),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
icon: const Icon(Icons.arrow_back, icon: const Icon(
color: Colors.white,), Icons.arrow_back,
color: Colors.white,
),
onPressed: () { onPressed: () {
if (locale.languageCode == 'ar') { if (locale.languageCode == 'ar') {
tutorialCoachMark.previous(); tutorialCoachMark.previous();
} else { } else {
ref.read(previousChartsTourProvider.notifier).state = true; ref
ref.read(previousHomeTourProvider.notifier).state = false; .read(previousChartsTourProvider
.notifier)
.state = true;
ref
.read(previousHomeTourProvider
.notifier)
.state = false;
tutorialCoachMark.finish(); tutorialCoachMark.finish();
} }
}, },
), ),
), ),
@ -988,18 +1065,31 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? null:Color(0xFF7DAFBC), color: locale.languageCode == 'ar'
? null
: Color(0xFF7DAFBC),
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Colors.white: Color(0xFF7DAFBC), width: 1), color: locale.languageCode == 'ar'
? Colors.white
: Color(0xFF7DAFBC),
width: 1),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
icon: const Icon(Icons.arrow_forward, icon: const Icon(
color: Colors.white,), Icons.arrow_forward,
color: Colors.white,
),
onPressed: () { onPressed: () {
if (locale.languageCode == 'ar') { if (locale.languageCode == 'ar') {
ref.read(previousChartsTourProvider.notifier).state = true; ref
ref.read(previousHomeTourProvider.notifier).state = false; .read(previousChartsTourProvider
.notifier)
.state = true;
ref
.read(previousHomeTourProvider
.notifier)
.state = false;
tutorialCoachMark.finish(); tutorialCoachMark.finish();
} else { } else {
tutorialCoachMark.previous(); tutorialCoachMark.previous();
@ -1217,6 +1307,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
for (var chart in data) { for (var chart in data) {
final groupBy = chart['group_by']; final groupBy = chart['group_by'];
List response = chart['response'] ?? []; List response = chart['response'] ?? [];
final chartHeading = chart['chart_heading'];
// Filter the response based on selected filters // Filter the response based on selected filters
var chartFilteredData = response.where((responseItem) { var chartFilteredData = response.where((responseItem) {
@ -1243,6 +1334,26 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
}); });
}).toList(); }).toList();
print('chartFilteredData- $chartFilteredData');
// If chartFilteredData is empty, print the message
if (chartFilteredData.isEmpty) {
if (kDebugMode) {
print(
"Selected year: ${selectedFilters.firstWhere((f) => f['filter_key'] == 'TIME_PERIOD', orElse: () => {
'filter_data': ['Unknown']
})['filter_data']} - No data for chart: : $chartHeading");
}
// Add the complete chart data to the filteredData list
filteredData.add({
...chart,
'response': response, // Return full unfiltered response
});
continue;
}
// If any data matches the filter, add the whole chart data object // If any data matches the filter, add the whole chart data object
// Add filtered chart only once // Add filtered chart only once
if (chartFilteredData.isNotEmpty && if (chartFilteredData.isNotEmpty &&
@ -1996,6 +2107,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
color: isBookmarked color: isBookmarked
? Colors.black ? Colors.black
: Colors.white, : Colors.white,
size: 23,
), ),
], ],
), ),
@ -2015,7 +2127,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
color: Colors.white, color: Colors.white,
), ),
), ),
SizedBox(width: 5), SizedBox(width: 6),
Stack( Stack(
children: [ children: [
// Image.asset( // Image.asset(
@ -2031,7 +2143,6 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// height: 24, // height: 24,
// ), // ),
SvgPicture.asset( SvgPicture.asset(
UaeNumbersAssetPath.share, UaeNumbersAssetPath.share,
semanticsLabel: 'share', semanticsLabel: 'share',
@ -2056,6 +2167,8 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
color: Colors.white, color: Colors.white,
), ),
), ),
SizedBox(width: 10),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
showRightSideModal( showRightSideModal(
@ -2233,9 +2346,11 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
right: 16.0, right: 16.0,
bottom: 1.0, bottom: 1.0,
top: 1.0), top: 1.0),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, // Move color inside BoxDecoration color: Colors
borderRadius: BorderRadius.circular(12), // Ensure border radius is applied .white, // Move color inside BoxDecoration
borderRadius: BorderRadius.circular(
12), // Ensure border radius is applied
), ),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -2280,20 +2395,22 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
const SizedBox(height: 5), const SizedBox(height: 5),
Flexible( Flexible(
fit: FlexFit.loose, fit: FlexFit.loose,
child: SizedBox( child: SizedBox(
height: 20.0, height: 20.0,
child: FittedBox( child: FittedBox(
child: Text( child: Text(
'(${response[0]['display_value'] ?? 'NA'})', '(${response[0]['display_value'] ?? 'NA'})',
// '(${data['firstYear'] ?? // '(${data['firstYear'] ??
// 'NA'} - ${data['lastYear'] ?? // 'NA'} - ${data['lastYear'] ??
// 'NA'})', // 'NA'})',
style: const TextStyle( style:
fontSize: 10, const TextStyle(
color: Colors.grey), fontSize: 10,
color: Colors
.grey),
),
), ),
), ),
),
), ),
const SizedBox(height: 1), const SizedBox(height: 1),
Flexible( Flexible(
@ -2302,20 +2419,60 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
height: 50.0, height: 50.0,
child: FittedBox( child: FittedBox(
fit: BoxFit.contain, fit: BoxFit.contain,
child: Text( child: Row(
response[0] children: [
['value'] ?? Text(
'NA', response[0][
// '${data['roundedAverage'] ?? 'value'] ??
// 'NA'}', 'NA',
style: // '${data['roundedAverage'] ??
const TextStyle( // 'NA'}',
fontSize: 20, style: TextStyle(
fontWeight: fontSize: 20,
FontWeight.w900, fontWeight:
color: Color( FontWeight
0xFF90B0D5), .w900,
), color: response[0]
[
'calculation'] ==
'different'
? _getColorFromHex(
response[0]
[
'font_color'])
: const Color(
0xFF90B0D5),
// color: Color(
// 0xFF90B0D5),
),
),
const SizedBox(
width:
1), // Space between text and icon
if (response[0][
'calculation'] ==
'different') ...[
if (response[0][
'font_color'] ==
'#D83731')
const Icon(
Icons
.arrow_downward,
color: Colors
.red,
size: 22)
else if (response[
0][
'font_color'] ==
'#11AF22')
const Icon(
Icons
.arrow_upward,
color: Colors
.green,
size: 22),
],
],
), ),
), ),
), ),
@ -2352,8 +2509,10 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
height: cardHeight, height: cardHeight,
padding: const EdgeInsets.all(10.0), padding: const EdgeInsets.all(10.0),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, // Move color inside BoxDecoration color: Colors
borderRadius: BorderRadius.circular(12), // Ensure border radius is applied .white, // Move color inside BoxDecoration
borderRadius: BorderRadius.circular(
12), // Ensure border radius is applied
), ),
child: Column( child: Column(
mainAxisSize: MainAxisSize mainAxisSize: MainAxisSize
@ -2424,12 +2583,18 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// data['lastYearValue']), // data['lastYearValue']),
// apiService.formatAmount( // apiService.formatAmount(
// data['lastYearValue']), // data['lastYearValue']),
style: const TextStyle( style: TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: fontWeight:
FontWeight.w900, FontWeight.w900,
color: color: response[0][
Color(0xFF90B0D5), 'calculation'] ==
'different'
? _getColorFromHex(
response[0][
'font_color'])
: const Color(
0xFF90B0D5),
), ),
), ),
), ),
@ -2452,12 +2617,18 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
'NA', 'NA',
// apiService.formatAmount( // apiService.formatAmount(
// data['secondLastYearValue']), // data['secondLastYearValue']),
style: const TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: fontWeight:
FontWeight.w600, FontWeight.w600,
color: color: response[1][
Color(0xFFD83731), 'calculation'] ==
'different'
? _getColorFromHex(
response[0][
'font_color'])
: const Color(
0xFFD83731),
), ),
), ),
), ),
@ -2487,47 +2658,48 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) { itemBuilder: (context, index) {
return Card( return Card(
margin: const EdgeInsets.all(10), margin: const EdgeInsets.all(10),
child: Container( child: Container(
decoration: BoxDecoration(
border: Border.all(
color: Color(
int.parse(
(chartScreenData[
'border_color'] ??
'#898C81')
.replaceFirst('#', '0xff'),
),
), // Border color
width: 1, // Border width
),
color: Colors.white,
borderRadius: BorderRadius.circular(
8), // Optional: Rounded corners
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
// ConstrainedBox
Container(
// constraints: const BoxConstraints(
// minHeight:
// 200, // Minimum height
// maxHeight:
// 400, // Maximum height
// ),
height: 350,
// child: buildChart(chartsData[index]),
decoration: BoxDecoration( child: ChartWidget(
border: Border.all( chartData:
color: Color(int.parse((chartScreenData[ chartsData[index]))
'border_color'] ?? '#898C81') ],
.replaceFirst('#', '0xff'),),), // Border color ),
width: 1, // Border width ),
), ));
color: Colors.white,
borderRadius: BorderRadius.circular(8), // Optional: Rounded corners
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
// ConstrainedBox
Container
(
// constraints: const BoxConstraints(
// minHeight:
// 200, // Minimum height
// maxHeight:
// 400, // Maximum height
// ),
height: 320,
// child: buildChart(chartsData[index]),
child: ChartWidget(
chartData:
chartsData[index]))
],
),
),
);
}, },
), ),
], ],
@ -2597,3 +2769,12 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
); );
} }
} }
// Function to convert hex color string to Color
Color _getColorFromHex(String hexColor) {
hexColor = hexColor.replaceFirst('#', '');
if (hexColor.length == 6) {
hexColor = 'FF$hexColor'; // Add alpha if not provided
}
return Color(int.parse(hexColor, radix: 16));
}

View File

@ -1,3 +1,4 @@
import 'dart:convert';
import 'dart:math'; import 'dart:math';
import 'package:fl_chart/fl_chart.dart'; import 'package:fl_chart/fl_chart.dart';
@ -48,8 +49,11 @@ class ChartWidget extends StatelessWidget {
List<PieChartSectionData> parsePieChartData( List<PieChartSectionData> parsePieChartData(
dynamic chartData, dynamic chartData,
double totalValue, double totalValue,
// String totalValue,
int? touchedIndex, int? touchedIndex,
) { ) {
debugPrint('Chart Data: ${jsonEncode(chartData)}');
return chartData['response'] return chartData['response']
.asMap() .asMap()
.entries .entries
@ -69,27 +73,54 @@ class ChartWidget extends StatelessWidget {
// Handle different types: int, double, and String // Handle different types: int, double, and String
double value = 0.0; double value = 0.0;
if (data['ObsValue']['Value'] is String) { var rawValue = data['ObsValue']['Value'];
value = double.tryParse(data['ObsValue']['Value']) ?? 0.0; // Parse string to double
} else if (data['ObsValue']['Value'] is int) { print('Raw Value: $rawValue (Type: ${rawValue.runtimeType})');
value = (data['ObsValue']['Value'] as int).toDouble(); // Convert int to double
} else if (data['ObsValue']['Value'] is double) { if (rawValue is String) {
value = data['ObsValue']['Value']; // Already a double value = double.tryParse(rawValue) ?? 0.0;
} else if (rawValue is int) {
value = rawValue.toDouble();
} else if (rawValue is double) {
value = rawValue;
} else {
print('Unexpected Type for ObsValue[Value]: ${rawValue.runtimeType}');
} }
print('piePArse1 - $value'); // if (data['ObsValue']['Value'] is String) {
double percentage = (value / totalValue) * 100; // value = double.tryParse(data['ObsValue']['Value']) ?? 0.0; // Parse string to double
// } else if (data['ObsValue']['Value'] is int) {
// value = (data['ObsValue']['Value'] as int).toDouble(); // Convert int to double
// } else if (data['ObsValue']['Value'] is double) {
// value = data['ObsValue']['Value']; // Already a double
// }
print('piePArse1 - $value');
// double percentage = (value / totalValue) * 100;
double percentage = (totalValue > 0) ? (value / totalValue) * 100 : 0.0;
if (kDebugMode) {
print('percentage- $percentage');
print('Total Value: $totalValue');
}
debugPrint('debug Total Value- $totalValue');
debugPrint('debug percentage- $percentage');
bool isTouched = index == touchedIndex; bool isTouched = index == touchedIndex;
return PieChartSectionData( return PieChartSectionData(
value: value, value: value,
color: Colors.primaries[index % Colors.primaries.length], color: Colors.primaries[index % Colors.primaries.length],
title: '${percentage.toStringAsFixed(1)}%', title: '${percentage.toStringAsFixed(1)}%',
radius: isTouched ? 60 : 50, // Increase size when touched radius: isTouched ? 60 : 50,
// Increase size when touched
titleStyle: TextStyle( titleStyle: TextStyle(
fontSize: isTouched ? 12 : 10, fontSize: isTouched ? 12 : 10,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.white, color: Colors.black,
// color: Colors.white,
), ),
titlePositionPercentageOffset: 1.3,
); );
}).toList(); }).toList();
} }
@ -116,21 +147,33 @@ class ChartWidget extends StatelessWidget {
), ),
SizedBox(width: 8), SizedBox(width: 8),
TooltipTheme( TooltipTheme(
data: TooltipThemeData( data: TooltipThemeData(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.blueGrey[800], // Change background color color: Colors.blueGrey[800], // Change background color
borderRadius: BorderRadius.circular(8), // Optional: rounded corners borderRadius:
), BorderRadius.circular(8), // Optional: rounded corners
textStyle: TextStyle(color: Colors.white), // Change text color ),
), textStyle: TextStyle(color: Colors.white), // Change text color
child: Tooltip(
message: title, // Full text on hover
child: Text(
shortTitle,
style: TextStyle(fontSize: 12),
overflow: TextOverflow.ellipsis, // Ensures text doesn't overflow
), ),
),), child: Tooltip(
message: title, // Full text on hover
child: ConstrainedBox(
// Constrain width to allow wrapping
constraints: BoxConstraints(maxWidth: 100),
child: Text(
title,
style: TextStyle(
fontSize: 12,
),
softWrap: true,
maxLines: 2,
overflow:
TextOverflow.ellipsis, // Ensures text doesn't overflow
),
),
),
),
SizedBox(width: 5),
], ],
); );
}).toList(); }).toList();
@ -152,6 +195,8 @@ class ChartWidget extends StatelessWidget {
return Center(child: Text('No chart data available')); return Center(child: Text('No chart data available'));
} }
print(chartData['chart_type_json']['TIME_PERIOD']);
String groupByKey = chartData['group_by'] ?? ''; String groupByKey = chartData['group_by'] ?? '';
print('groupByKey $groupByKey'); print('groupByKey $groupByKey');
Set<String> groupByValues = extractGroupByValues(chartData, groupByKey); Set<String> groupByValues = extractGroupByValues(chartData, groupByKey);
@ -242,13 +287,28 @@ class ChartWidget extends StatelessWidget {
), ),
); );
case 'pie_chart': case 'pie_chart':
double totalValue = chartData['response'] double totalValue = chartData['response'].map<double>((entry) {
.map<double>((entry) {
var value = entry['ObsValue']['Value']; var value = entry['ObsValue']['Value'];
print('Processing value: $value, type: ${value.runtimeType}'); // Debug each value print(
return value is int ? value.toDouble() : value is String ? double.tryParse(value) ?? 0.0 : 0.0; 'Processing value: $value, type: ${value.runtimeType}'); // Debug each value
}) print(value is int
.fold(0.0, (prev, element) => prev + element); ? value.toDouble()
: value is String
? double.tryParse(value) ?? 0.0
: 0.0);
return (value is num)
? value.toDouble()
: value is String
? double.tryParse(value) ?? 0.0
: 0.0;
}).fold(0.0, (prev, element) => prev + element);
// List<String> totalValues = chartData['response']
// .map<String>((entry) {
// var value = entry['ObsValue']['Value'];
// print('Processing value: $value, type: ${value.runtimeType}'); // Debug each value
//
// return value.toString(); // Convert to string
// }).fold(0.0, (prev, element) => prev + element);
ValueNotifier<int?> touchedIndex = ValueNotifier(null); ValueNotifier<int?> touchedIndex = ValueNotifier(null);
@ -263,7 +323,7 @@ class ChartWidget extends StatelessWidget {
), ),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
SizedBox(height: 5), SizedBox(height: 15),
Text( Text(
chartData['chart_sub_heading'] ?? '', chartData['chart_sub_heading'] ?? '',
style: TextStyle( style: TextStyle(
@ -272,8 +332,7 @@ class ChartWidget extends StatelessWidget {
), ),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
SizedBox(height: 40), SizedBox(height: 70),
Expanded( Expanded(
child: ValueListenableBuilder<int?>( child: ValueListenableBuilder<int?>(
valueListenable: touchedIndex, valueListenable: touchedIndex,
@ -299,30 +358,33 @@ class ChartWidget extends StatelessWidget {
), ),
), ),
); );
}, },
), ),
), ),
SizedBox(height:60), SizedBox(height: 65),
Flexible( Flexible(
// child: SingleChildScrollView(
// scrollDirection: Axis.horizontal,
//
child: SingleChildScrollView( child: SingleChildScrollView(
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
child: Container( child: Container(
// constraints: constraints:
// BoxConstraints(minHeight: 5), // Allow dynamic height BoxConstraints(minHeight: 3), // Allow dynamic height
child: Padding( child: Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: 0.0, right: 0.0, bottom: 8.0, top: 20.0), left: 0.0, right: 0.0, bottom: 8.0, top: 20.0),
child: Wrap( child: Wrap(
// spacing: 12, spacing: 12,
// runSpacing: 8, runSpacing: 8,
children: children:
generateIndicators(chartData, chartData['group_by']), generateIndicators(chartData, chartData['group_by']),
), ),
), ),
), ),
), ),
// ),
), ),
], ],
); );
@ -372,11 +434,11 @@ class ChartWidget extends StatelessWidget {
fitInsideHorizontally: true, fitInsideHorizontally: true,
fitInsideVertically: true, fitInsideVertically: true,
// tooltipPadding: const EdgeInsets.all(8), // tooltipPadding: const EdgeInsets.all(8),
tooltipPadding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8), // Optional tooltipPadding: const EdgeInsets.symmetric(
horizontal: 4, vertical: 8), // Optional
tooltipHorizontalAlignment: FLHorizontalAlignment.left, tooltipHorizontalAlignment: FLHorizontalAlignment.left,
tooltipMargin: 16, tooltipMargin: 16,
getTooltipItem: getTooltipItem:
(groupData, groupIndex, rodData, rodIndex) { (groupData, groupIndex, rodData, rodIndex) {
// Get the list of group names dynamically // Get the list of group names dynamically
@ -534,7 +596,7 @@ class ChartWidget extends StatelessWidget {
colorIndex % uniqueColorsLine_trend_2.length]; colorIndex % uniqueColorsLine_trend_2.length];
colorIndex++; colorIndex++;
} }
print('LnTrnd1'); print('LnTrnd1');
// Extract all years from the chart data // Extract all years from the chart data
List<int> years = (chartData['response'] as List<dynamic>) List<int> years = (chartData['response'] as List<dynamic>)
@ -571,10 +633,9 @@ class ChartWidget extends StatelessWidget {
// (entry) => double.parse(entry['ObsKey']['TIME_PERIOD'])) // (entry) => double.parse(entry['ObsKey']['TIME_PERIOD']))
// .toSet(); // .toSet();
Set<String> uniqueXValues = filteredData.map<String>((entry) {
Set<String> uniqueXValues = filteredData String? timePeriod =
.map<String>((entry) { entry['ObsKey']['TIME_PERIOD']; // Nullable String
String? timePeriod = entry['ObsKey']['TIME_PERIOD']; // Nullable String
print('TIME_PERIOD- $timePeriod'); print('TIME_PERIOD- $timePeriod');
if (timePeriod == null) { if (timePeriod == null) {
@ -596,8 +657,7 @@ class ChartWidget extends StatelessWidget {
print('Unknown format: $timePeriod'); print('Unknown format: $timePeriod');
return timePeriod; // Keep it as is return timePeriod; // Keep it as is
} }
}) }).toSet();
.toSet();
print("Unique X Values: $uniqueXValues"); print("Unique X Values: $uniqueXValues");
@ -606,18 +666,30 @@ class ChartWidget extends StatelessWidget {
if (RegExp(r'^\d{4}$').hasMatch(timePeriod)) { if (RegExp(r'^\d{4}$').hasMatch(timePeriod)) {
return double.parse(timePeriod); // Year-only (2019 2019.0) return double.parse(timePeriod); // Year-only (2019 2019.0)
} else if (RegExp(r'^\d{4}-\d{2}$').hasMatch(timePeriod)) { } else if (RegExp(r'^\d{4}-\d{2}$').hasMatch(timePeriod)) {
return double.parse(timePeriod.replaceAll('-', '.')); // Year-Month (2019-11 2019.11) return double.parse(timePeriod.replaceAll(
'-', '.')); // Year-Month (2019-11 2019.11)
} else if (RegExp(r'^\d{4}-[A-Za-z]{3}$').hasMatch(timePeriod)) { } else if (RegExp(r'^\d{4}-[A-Za-z]{3}$').hasMatch(timePeriod)) {
// Year-MonthAbbr (2019-Nov) // Year-MonthAbbr (2019-Nov)
Map<String, int> monthMap = { Map<String, int> monthMap = {
'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'Jan': 1,
'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8, 'Feb': 2,
'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12 'Mar': 3,
'Apr': 4,
'May': 5,
'Jun': 6,
'Jul': 7,
'Aug': 8,
'Sep': 9,
'Oct': 10,
'Nov': 11,
'Dec': 12
}; };
List<String> parts = timePeriod.split('-'); List<String> parts = timePeriod.split('-');
int month = monthMap[parts[1]] ?? 1; // Default to January if unknown int month =
return double.parse('${parts[0]}.$month'); // Convert to format (2019-Nov 2019.11) monthMap[parts[1]] ?? 1; // Default to January if unknown
return double.parse(
'${parts[0]}.$month'); // Convert to format (2019-Nov 2019.11)
} }
throw FormatException("Invalid TIME_PERIOD format: $timePeriod"); throw FormatException("Invalid TIME_PERIOD format: $timePeriod");
@ -629,15 +701,12 @@ class ChartWidget extends StatelessWidget {
.toSet(); .toSet();
print('Processed X Values: $uniqueXValuesProcessed'); print('Processed X Values: $uniqueXValuesProcessed');
print('LnTrnd2.1'); print('LnTrnd2.1');
// Generate line bars for the chart // Generate line bars for the chart
List<LineChartBarData> lineBars = List<LineChartBarData> lineBars =
lineBarsData(filteredData, groupByValues, groupByKey); lineBarsData(filteredData, groupByValues, groupByKey);
print('LnTrnd3'); print('LnTrnd3');
return Column(children: [ return Column(children: [
@ -671,10 +740,9 @@ class ChartWidget extends StatelessWidget {
// minX: uniqueXValues.reduce((a, b) => a < b ? a : b), // minX: uniqueXValues.reduce((a, b) => a < b ? a : b),
// maxX: uniqueXValues.reduce((a, b) => a > b ? a : b), // maxX: uniqueXValues.reduce((a, b) => a > b ? a : b),
// minX: uniqueXValuesProcessed.reduce((a, b) => a < b ? a : b),
// minX: uniqueXValuesProcessed.reduce((a, b) => a < b ? a : b), // maxX: uniqueXValuesProcessed.reduce((a, b) => a > b ? a : b),
// maxX: uniqueXValuesProcessed.reduce((a, b) => a > b ? a : b), ))),
))),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Wrap( child: Wrap(
@ -924,11 +992,61 @@ class ChartWidget extends StatelessWidget {
List<String> xAxisData = []; List<String> xAxisData = [];
List<double> yAxisData = []; List<double> yAxisData = [];
var xadditionalgrp = chartData['chart_type_json']['additional_x_group'];
print('xadditionalgrp-$xadditionalgrp');
for (var entry in chartData['response']) { for (var entry in chartData['response']) {
var xValue = entry['ObsKey'][groupByKey]; var xValue = entry['ObsKey'][groupByKey];
var xTimePeriod = entry['ObsKey']['TIME_PERIOD'];
var yValue = entry['ObsValue']['Value']; var yValue = entry['ObsValue']['Value'];
var xadditionalgroup =
chartData['chart_type_json']['additional_x_group'];
print('chartData response: ${chartData['response']}');
print('xValue-$xValue');
print('Xadditionalt-$xTimePeriod');
print('xadditionalgroup-$xadditionalgroup');
print('yValue-$yValue');
if (xadditionalgrp == 'TIME_PERIOD') {
chartData['response'].sort((a, b) {
// Convert TIME_PERIOD to int for proper sorting
int timeA =
int.tryParse(a['ObsKey']['TIME_PERIOD'].toString()) ?? 0;
int timeB =
int.tryParse(b['ObsKey']['TIME_PERIOD'].toString()) ?? 0;
// Extract QUARTER and convert "Q1", "Q2", etc. to numeric values
int quarterA = int.tryParse(
a['ObsKey']['QUARTER'].toString().replaceAll('Q', '')) ??
0;
int quarterB = int.tryParse(
b['ObsKey']['QUARTER'].toString().replaceAll('Q', '')) ??
0;
// First, sort by TIME_PERIOD. If equal, sort by QUARTER
if (timeA != timeB) {
return timeA.compareTo(timeB);
} else {
return quarterA.compareTo(quarterB);
}
});
}
// if (xValue != null && yValue != null) {
// xAxisData.add(xValue.toString());
// yAxisData.add(double.tryParse(yValue.toString()) ?? 0.0);
// }
if (xValue != null && yValue != null) { if (xValue != null && yValue != null) {
xAxisData.add(xValue.toString()); // Check if additional_x_group is "Timeperiod" and concatenate
String xLabel = xValue.toString();
if (xadditionalgroup == 'TIME_PERIOD' && xTimePeriod != null) {
xLabel = '$xTimePeriod-$xValue'; // Format: Label (TimePeriod)
}
xAxisData.add(xLabel);
yAxisData.add(double.tryParse(yValue.toString()) ?? 0.0); yAxisData.add(double.tryParse(yValue.toString()) ?? 0.0);
} }
} }
@ -959,7 +1077,7 @@ class ChartWidget extends StatelessWidget {
maxY: yAxisData.isNotEmpty maxY: yAxisData.isNotEmpty
? yAxisData.reduce((a, b) => a > b ? a : b) * 1.2 ? yAxisData.reduce((a, b) => a > b ? a : b) * 1.2
: 10, : 10,
// barTouchData: BarTouchData(enabled: true), // barTouchData: BarTouchData(enabled: true),
barTouchData: BarTouchData( barTouchData: BarTouchData(
enabled: true, enabled: true,
handleBuiltInTouches: true, handleBuiltInTouches: true,
@ -1004,7 +1122,8 @@ class ChartWidget extends StatelessWidget {
: title; : title;
return Padding( return Padding(
padding: const EdgeInsets.only(top: 8.0,left: 25.0), padding:
const EdgeInsets.only(top: 8.0, left: 55.0),
child: SizedBox( child: SizedBox(
width: 60, // Limit width to force wrapping width: 60, // Limit width to force wrapping
child: Transform.rotate( child: Transform.rotate(
@ -1012,36 +1131,43 @@ class ChartWidget extends StatelessWidget {
angle: -1.5, angle: -1.5,
child: TooltipTheme( child: TooltipTheme(
data: TooltipThemeData( data: TooltipThemeData(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.blueGrey[800], // Change background color color: Colors.blueGrey[
borderRadius: BorderRadius.circular(8), // Optional: rounded corners 800], // Change background color
), borderRadius: BorderRadius.circular(
textStyle: TextStyle(color: Colors.white), // Change text color 8), // Optional: rounded corners
), ),
textStyle: TextStyle(
color: Colors
.white), // Change text color
),
child: TooltipTheme( child: TooltipTheme(
data: TooltipThemeData( data: TooltipThemeData(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.blueGrey[800], // Change background color color: Colors.blueGrey[
borderRadius: BorderRadius.circular(8), // Optional: rounded corners 800], // Change background color
borderRadius: BorderRadius.circular(
8), // Optional: rounded corners
),
textStyle: TextStyle(
color: Colors
.white), // Change text color
),
child: Tooltip(
message: title,
child: Text(
// title,
displayTitle,
softWrap: true,
style: TextStyle(
fontSize: 10,
),
overflow: TextOverflow.ellipsis,
), ),
textStyle: TextStyle(color: Colors.white), // Change text color
), ),
child: Tooltip(
message: title,
child: Text(
// title,
displayTitle,
softWrap: true,
style: TextStyle(fontSize: 10,),
overflow: TextOverflow.ellipsis,
),),
), ),
), ),
))); )));
} }
return Container(); return Container();
@ -1111,102 +1237,104 @@ class ChartWidget extends StatelessWidget {
SizedBox(height: 10), SizedBox(height: 10),
// Chart // Chart
Expanded( Expanded(
child: BarChart( child: BarChart(
BarChartData( BarChartData(
alignment: BarChartAlignment.spaceAround, alignment: BarChartAlignment.spaceAround,
maxY: yAxisData.isNotEmpty maxY: yAxisData.isNotEmpty
? yAxisData.reduce((a, b) => a > b ? a : b) * 1.2 ? yAxisData.reduce((a, b) => a > b ? a : b) * 1.2
: 10, : 10,
rotationQuarterTurns: rotationTurns, rotationQuarterTurns: rotationTurns,
barTouchData: BarTouchData( barTouchData: BarTouchData(
enabled: true, enabled: true,
handleBuiltInTouches: true, handleBuiltInTouches: true,
touchTooltipData: BarTouchTooltipData( touchTooltipData: BarTouchTooltipData(
fitInsideHorizontally: true, fitInsideHorizontally: true,
fitInsideVertically: true, fitInsideVertically: true,
tooltipPadding: const EdgeInsets.all(8), tooltipPadding: const EdgeInsets.all(8),
tooltipMargin: 16, tooltipMargin: 16,
getTooltipItem: (group, groupIndex, rod, rodIndex) { getTooltipItem: (group, groupIndex, rod, rodIndex) {
return BarTooltipItem( return BarTooltipItem(
'${rod.toY.toStringAsFixed(1)}', '${rod.toY.toStringAsFixed(1)}',
const TextStyle(color: Colors.white), const TextStyle(color: Colors.white),
);
},
),
),
titlesData: FlTitlesData(
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: false,
interval: (yAxisData.isNotEmpty
? yAxisData.reduce((a, b) => a > b ? a : b) / 5
: 1),
getTitlesWidget: (value, meta) {
return Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Text('${value.toInt()}'),
); );
}, },
reservedSize: 60,
), ),
), ),
bottomTitles: AxisTitles( titlesData: FlTitlesData(
sideTitles: SideTitles( leftTitles: AxisTitles(
showTitles: true, sideTitles: SideTitles(
getTitlesWidget: (value, meta) { showTitles: false,
if (value.toInt() < xAxisData.length) { interval: (yAxisData.isNotEmpty
? yAxisData.reduce((a, b) => a > b ? a : b) / 5
: 1),
getTitlesWidget: (value, meta) {
return Padding( return Padding(
padding: const EdgeInsets.only(top: 8.0), padding: const EdgeInsets.only(right: 8.0),
child: Transform.rotate( child: Text('${value.toInt()}'),
angle: -1.58, );
// angle: -45 * },
// (3.1415927 / 180), // Rotating by -45 degrees reservedSize: 60,
alignment: Alignment.center, ),
child: Center( ),
child: SizedBox( bottomTitles: AxisTitles(
width: 100, sideTitles: SideTitles(
child: Text( showTitles: true,
xAxisData[value.toInt()], getTitlesWidget: (value, meta) {
style: const TextStyle(fontSize: 12), if (value.toInt() < xAxisData.length) {
softWrap: true, return Padding(
maxLines: 3, padding: const EdgeInsets.only(top: 8.0),
child: Transform.rotate(
angle: -1.58,
// angle: -45 *
// (3.1415927 / 180), // Rotating by -45 degrees
alignment: Alignment.center,
child: Center(
child: SizedBox(
width: 100,
child: Text(
xAxisData[value.toInt()],
style: const TextStyle(fontSize: 12),
softWrap: true,
maxLines: 3,
),
), ),
), ),
), ),
), );
); }
} return Container();
return Container(); },
}, reservedSize: 85,
reservedSize: 85, ),
),
topTitles: AxisTitles(
sideTitles:
SideTitles(showTitles: false), // Hide top titles
),
rightTitles: AxisTitles(
sideTitles:
SideTitles(showTitles: false), // Hide right titles
), ),
), ),
topTitles: AxisTitles( gridData: FlGridData(show: false),
sideTitles: SideTitles(showTitles: false), // Hide top titles borderData: FlBorderData(show: false),
), barGroups: List.generate(
rightTitles: AxisTitles( xAxisData.length,
sideTitles: (index) => BarChartGroupData(
SideTitles(showTitles: false), // Hide right titles x: index,
), barRods: [
), BarChartRodData(
gridData: FlGridData(show: false), toY: yAxisData[index],
borderData: FlBorderData(show: false), color: Colors.blueAccent,
barGroups: List.generate( borderRadius: BorderRadius.circular(4),
xAxisData.length, width: 20,
(index) => BarChartGroupData( ),
x: index, ],
barRods: [ ),
BarChartRodData(
toY: yAxisData[index],
color: Colors.blueAccent,
borderRadius: BorderRadius.circular(4),
width: 20,
),
],
), ),
), ),
), ),
)) ),
]); ]);
case 'fl_multi_bar': case 'fl_multi_bar':
double _calculateChartWidth(dynamic chartData) { double _calculateChartWidth(dynamic chartData) {
@ -1218,14 +1346,10 @@ class ChartWidget extends StatelessWidget {
// Group crops by CROP_TYPE // Group crops by CROP_TYPE
Map<String, List<String>> groupedCrops = {}; Map<String, List<String>> groupedCrops = {};
int touchedGroupIndex = -1; int touchedGroupIndex = -1;
// Iterate over the chartData to group crops by CROP_TYPE // Iterate over the chartData to group crops by CROP_TYPE
for (var item in chartData['response']) { for (var item in chartData['response']) {
print("MultiBArRaw item: $item"); print("MultiBArRaw item: $item");
String crop = item['ObsKey'][cropKey]; String crop = item['ObsKey'][cropKey];
@ -1233,7 +1357,8 @@ class ChartWidget extends StatelessWidget {
// Use a Set to avoid duplicates // Use a Set to avoid duplicates
if (groupedCrops.containsKey(cropType)) { if (groupedCrops.containsKey(cropType)) {
groupedCrops[cropType] = (groupedCrops[cropType]! + [crop]).toSet().toList(); groupedCrops[cropType] =
(groupedCrops[cropType]! + [crop]).toSet().toList();
} else { } else {
groupedCrops[cropType] = [crop]; groupedCrops[cropType] = [crop];
} }
@ -1255,7 +1380,6 @@ class ChartWidget extends StatelessWidget {
// //
// print('groupedCropsflmutli- $groupedCrops'); // print('groupedCropsflmutli- $groupedCrops');
return Center( return Center(
child: Column(children: [ child: Column(children: [
Text( Text(
@ -1286,8 +1410,8 @@ class ChartWidget extends StatelessWidget {
child: BarChart( child: BarChart(
BarChartData( BarChartData(
alignment: BarChartAlignment.spaceAround, alignment: BarChartAlignment.spaceAround,
maxY: maxY: _calculateMaxY(
_calculateMaxY(chartData), // Dynamically calculate max Y chartData), // Dynamically calculate max Y
barGroups: _buildHorizontalRotateBarGroups( barGroups: _buildHorizontalRotateBarGroups(
chartData, groupByValues), // Build bar groups chartData, groupByValues), // Build bar groups
titlesData: FlTitlesData( titlesData: FlTitlesData(
@ -1310,27 +1434,31 @@ class ChartWidget extends StatelessWidget {
return Padding( return Padding(
padding: const EdgeInsets.only(top: 8.0), padding: const EdgeInsets.only(top: 8.0),
child: SizedBox( child: SizedBox(
width: 60, // Limit width to force wrapping width:
60, // Limit width to force wrapping
child: Transform.rotate( child: Transform.rotate(
angle: -0.5, angle: -0.5,
child: TooltipTheme( child: TooltipTheme(
data: TooltipThemeData( data: TooltipThemeData(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.blueGrey[800], // Change background color color: Colors.blueGrey[
borderRadius: BorderRadius.circular(8), // Optional: rounded corners 800], // Change background color
), borderRadius: BorderRadius.circular(
textStyle: TextStyle(color: Colors.white), // Change text color 8), // Optional: rounded corners
), ),
child: Tooltip( textStyle: TextStyle(
message: title, color: Colors
child: Text( .white), // Change text color
displayTitle,
softWrap: true,
// style: TextStyle(backgroundColor: Colors.blueGrey[800]),
overflow: TextOverflow.ellipsis,
)),
), ),
child: Tooltip(
message: title,
child: Text(
displayTitle,
softWrap: true,
// style: TextStyle(backgroundColor: Colors.blueGrey[800]),
overflow: TextOverflow.ellipsis,
)),
),
))); )));
// return Transform.rotate( // return Transform.rotate(
// angle: // angle:
@ -1353,7 +1481,8 @@ class ChartWidget extends StatelessWidget {
borderData: FlBorderData(show: false), borderData: FlBorderData(show: false),
barTouchData: BarTouchData( barTouchData: BarTouchData(
touchTooltipData: BarTouchTooltipData( touchTooltipData: BarTouchTooltipData(
tooltipHorizontalAlignment: FLHorizontalAlignment.center, tooltipHorizontalAlignment:
FLHorizontalAlignment.center,
tooltipRoundedRadius: 8, tooltipRoundedRadius: 8,
fitInsideHorizontally: fitInsideHorizontally:
true, // Ensure it fits within the screen true, // Ensure it fits within the screen
@ -1371,7 +1500,8 @@ class ChartWidget extends StatelessWidget {
groupByValues.elementAt(groupIndex); groupByValues.elementAt(groupIndex);
// Fetch the crop for the current group from groupedCrops // Fetch the crop for the current group from groupedCrops
String cropType = groupByValues.elementAt(groupIndex); String cropType =
groupByValues.elementAt(groupIndex);
print('GrpcropType: $cropType'); print('GrpcropType: $cropType');
// String crop = groupedCrops[cropType]![rodIndex]; // String crop = groupedCrops[cropType]![rodIndex];
@ -1384,7 +1514,9 @@ class ChartWidget extends StatelessWidget {
print( print(
'Crop is null or index out of bounds for cropType: $cropType and rodIndex: $rodIndex'); 'Crop is null or index out of bounds for cropType: $cropType and rodIndex: $rodIndex');
// crop = cropType; // Fallback to cropType // crop = cropType; // Fallback to cropType
crop = (crops != null && crops.isNotEmpty) ? crops.first : cropType; crop = (crops != null && crops.isNotEmpty)
? crops.first
: cropType;
} }
// print('groupedCrops1: $groupedCrops - $rodIndex'); // print('groupedCrops1: $groupedCrops - $rodIndex');
@ -1431,7 +1563,8 @@ class ChartWidget extends StatelessWidget {
response != null && response != null &&
response.spot != null) { response.spot != null) {
// setState(() { // setState(() {
touchedGroupIndex = response.spot!.touchedBarGroupIndex; touchedGroupIndex =
response.spot!.touchedBarGroupIndex;
// }); // });
} else { } else {
// setState(() { // setState(() {
@ -1950,7 +2083,6 @@ class ChartWidget extends StatelessWidget {
return lineBars; return lineBars;
} }
/// Function to parse TIME_PERIOD into a EXACT value /// Function to parse TIME_PERIOD into a EXACT value
double parseTimePeriod(String timePeriod) { double parseTimePeriod(String timePeriod) {
// Match formats // Match formats
@ -1959,13 +2091,23 @@ class ChartWidget extends StatelessWidget {
return double.parse(timePeriod); // Year as a double (2020 2020.0) return double.parse(timePeriod); // Year as a double (2020 2020.0)
} else if (RegExp(r'^\d{4}-\d{2}$').hasMatch(timePeriod)) { } else if (RegExp(r'^\d{4}-\d{2}$').hasMatch(timePeriod)) {
// Format: Year-Month (e.g., "2020-10") // Format: Year-Month (e.g., "2020-10")
return double.parse(timePeriod.replaceAll('-', '.')); // Convert "2020-10" 2020.10 return double.parse(
timePeriod.replaceAll('-', '.')); // Convert "2020-10" 2020.10
} else if (RegExp(r'^\d{4}-[A-Za-z]{3}$').hasMatch(timePeriod)) { } else if (RegExp(r'^\d{4}-[A-Za-z]{3}$').hasMatch(timePeriod)) {
// Format: Year-MonthAbbr (e.g., "2020-Oct") // Format: Year-MonthAbbr (e.g., "2020-Oct")
Map<String, int> monthMap = { Map<String, int> monthMap = {
'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'Jan': 1,
'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8, 'Feb': 2,
'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12 'Mar': 3,
'Apr': 4,
'May': 5,
'Jun': 6,
'Jul': 7,
'Aug': 8,
'Sep': 9,
'Oct': 10,
'Nov': 11,
'Dec': 12
}; };
List<String> parts = timePeriod.split('-'); List<String> parts = timePeriod.split('-');
@ -1977,7 +2119,6 @@ class ChartWidget extends StatelessWidget {
throw FormatException("Invalid TIME_PERIOD format: $timePeriod"); throw FormatException("Invalid TIME_PERIOD format: $timePeriod");
} }
List<LineChartBarData> lineBarsData(List<dynamic> filteredData, List<LineChartBarData> lineBarsData(List<dynamic> filteredData,
Set<String> groupByValues, String groupByKey) { Set<String> groupByValues, String groupByKey) {
List<LineChartBarData> lineBars = []; List<LineChartBarData> lineBars = [];
@ -2042,9 +2183,6 @@ class ChartWidget extends StatelessWidget {
print('spots - $spots'); print('spots - $spots');
// List<FlSpot> spots = filteredData // List<FlSpot> spots = filteredData
// .where((entry) => entry['ObsKey'][groupByKey] == group) // .where((entry) => entry['ObsKey'][groupByKey] == group)
// .map<FlSpot>((entry) { // .map<FlSpot>((entry) {
@ -2060,8 +2198,6 @@ class ChartWidget extends StatelessWidget {
// return FlSpot(xValue, yValue); // return FlSpot(xValue, yValue);
// }).toList(); // }).toList();
print('lineGrp2'); print('lineGrp2');
// Add a line for this group // Add a line for this group
lineBars.add( lineBars.add(
@ -2106,11 +2242,11 @@ class ChartWidget extends StatelessWidget {
} }
FlTitlesData titlesData1(Set<double> xValues) { FlTitlesData titlesData1(Set<double> xValues) {
print('tileDATa1xvalue - $xValues'); print('tileDATa1xvalue - $xValues');
double findClosest(double value, Set<double> values) { double findClosest(double value, Set<double> values) {
return values.reduce((a, b) => (value - a).abs() < (value - b).abs() ? a : b); return values
.reduce((a, b) => (value - a).abs() < (value - b).abs() ? a : b);
} }
return FlTitlesData( return FlTitlesData(
@ -2123,8 +2259,14 @@ class ChartWidget extends StatelessWidget {
String formattedValue; String formattedValue;
if (value % 10 == 0) { if (value % 10 == 0) {
// Check if the value is in the millions or thousands range // Check if the value is in the millions or thousands range
if (value >= 1000000) {
if (value >= 1000000000000) {
formattedValue =
'${(value / 1000000000000).toStringAsFixed(0)}T';
} else if (value >= 1000000000) {
formattedValue = '${(value / 1000000000).toStringAsFixed(0)}B';
} else if (value >= 1000000) {
formattedValue = '${(value / 1000000).toStringAsFixed(0)}M'; formattedValue = '${(value / 1000000).toStringAsFixed(0)}M';
} else if (value >= 1000) { } else if (value >= 1000) {
formattedValue = '${(value / 1000).toStringAsFixed(0)}k'; formattedValue = '${(value / 1000).toStringAsFixed(0)}k';
@ -2158,21 +2300,22 @@ class ChartWidget extends StatelessWidget {
interval: null, interval: null,
// interval: 10, // Ensure each year is shown only once // interval: 10, // Ensure each year is shown only once
getTitlesWidget: (value, meta) { getTitlesWidget: (value, meta) {
print('BtmTiles :-$value'); print('BtmTiles :-$value');
print('BtmTilesmeta :-$meta'); print('BtmTilesmeta :-$meta');
// if (xValues.contains(value)) // if (xValues.contains(value))
double closestValue = findClosest(value, xValues); double closestValue = findClosest(value, xValues);
if ((closestValue - value).abs() < 0.15) if ((closestValue - value).abs() < 0.15) {
{
print("Bottomtiles"); print("Bottomtiles");
print(value); print(value);
return Transform.rotate( return Padding(
angle: -0.5, // Slight rotation to improve readability padding: const EdgeInsets.only(top: 1.1),
child: Text( child: Transform.rotate(
value.toInt().toString(), angle: 0.0,
style: TextStyle(color: Colors.black, fontSize: 12), // angle: -0.5, // Slight rotation to improve readability
child: Text(
value.toInt().toString(),
style: TextStyle(color: Colors.black, fontSize: 12),
),
), ),
); );
} else { } else {

View File

@ -1,7 +1,7 @@
name: uae_stat name: uae_stat
description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness." description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness."
publish_to: "none" publish_to: "none"
version: 1.0.20+21 version: 1.0.23+24
environment: environment:
sdk: ">=3.2.3 <4.0.0" sdk: ">=3.2.3 <4.0.0"