From d1bcedd4fe7b1136765b1730015b72f1eb259b42 Mon Sep 17 00:00:00 2001 From: venbaittech Date: Tue, 18 Feb 2025 09:33:59 +0530 Subject: [PATCH] charts --- .../Screens/charts/screens/chart_screen.dart | 33 ++- .../Screens/charts/widgets/chart_widget.dart | 240 ++++++++++++++++-- 2 files changed, 238 insertions(+), 35 deletions(-) diff --git a/lib/presentation/Screens/charts/screens/chart_screen.dart b/lib/presentation/Screens/charts/screens/chart_screen.dart index bd464ca9..e994896b 100644 --- a/lib/presentation/Screens/charts/screens/chart_screen.dart +++ b/lib/presentation/Screens/charts/screens/chart_screen.dart @@ -1764,18 +1764,21 @@ class _ChartScreen1State extends ConsumerState { .expand((item) => item) .toList(); - for (var item in filterData) { - if (item['filter_key'] == 'TIME_PERIOD') { - // Convert the values to integers, sort them, and convert back to strings - List timePeriodData = item['filter_data'] - .map((e) => int.parse(e.toString())) // Convert to int - .toList(); - timePeriodData.sort((a, b) => a.compareTo(b)); // Sort numerically - - // Optionally, convert sorted integers back to strings if necessary - item['filter_data'] = timePeriodData.map((e) => e.toString()).toList(); - } - } + print("FilteringDAtss START1 - $filterData"); + print('TABId1 - $tabId'); + // for (var item in filterData) { + // if (item['filter_key'] == 'TIME_PERIOD') { + // // Convert the values to integers, sort them, and convert back to strings + // List timePeriodData = item['filter_data'] + // .map((e) => int.parse(e.toString())) // Convert to int + // .toList(); + // timePeriodData.sort((a, b) => a.compareTo(b)); // Sort numerically + // + // // Optionally, convert sorted integers back to strings if necessary + // item['filter_data'] = timePeriodData.map((e) => e.toString()).toList(); + // } + // } + print('TABId - $tabId'); print("TABFiltered Data: $filterData"); setState(() { @@ -2112,6 +2115,8 @@ class _ChartScreen1State extends ConsumerState { // width: 24, // height: 24, // ), + + SvgPicture.asset( UaeNumbersAssetPath.share, semanticsLabel: 'share', @@ -2625,7 +2630,7 @@ class _ChartScreen1State extends ConsumerState { onTap: () { setState(() { _activeTabIndex = _tabsData.indexOf(tab); - }); + }); _scrollToIndex(_activeTabIndex); onTabSelected(tab['id']!); }, @@ -2647,4 +2652,4 @@ class _ChartScreen1State extends ConsumerState { ), ); } -} +} \ No newline at end of file diff --git a/lib/presentation/Screens/charts/widgets/chart_widget.dart b/lib/presentation/Screens/charts/widgets/chart_widget.dart index 57c3690a..3cf031dd 100644 --- a/lib/presentation/Screens/charts/widgets/chart_widget.dart +++ b/lib/presentation/Screens/charts/widgets/chart_widget.dart @@ -494,6 +494,7 @@ class ChartWidget extends StatelessWidget { colorIndex % uniqueColorsLine_trend_2.length]; colorIndex++; } + print('LnTrnd1'); // Extract all years from the chart data List years = (chartData['response'] as List) @@ -511,6 +512,8 @@ class ChartWidget extends StatelessWidget { ); } + print('LnTrnd1.2'); + // Find the maximum year and calculate the range for the last 5 years int maxYear = years.reduce((a, b) => a > b ? a : b); int minYear = maxYear - 5; @@ -521,16 +524,82 @@ class ChartWidget extends StatelessWidget { int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0; return year >= minYear && year <= maxYear; }).toList(); + print('LnTrnd2'); - Set uniqueXValues = filteredData - .map( - (entry) => double.parse(entry['ObsKey']['TIME_PERIOD'])) + // Set uniqueXValues = filteredData + // .map( + // (entry) => double.parse(entry['ObsKey']['TIME_PERIOD'])) + // .toSet(); + + + Set uniqueXValues = filteredData + .map((entry) { + String? timePeriod = entry['ObsKey']['TIME_PERIOD']; // Nullable String + // print('TIME_PERIOD- $timePeriod'); + + if (timePeriod == null) { + print('TIME_PERIOD is null'); + return ''; // Or handle the null case appropriately + } + + // Check format using regex + if (RegExp(r'^\d{4}$').hasMatch(timePeriod)) { + print('Year format detected: $timePeriod'); + return timePeriod; // Year only + } else if (RegExp(r'^\d{4}-\d{2}$').hasMatch(timePeriod)) { + print('Year-Month format detected: $timePeriod'); + return timePeriod; // Year-Month + } else if (RegExp(r'^\d{4}-[A-Za-z]{3}$').hasMatch(timePeriod)) { + print('Year-MonthAbbr format detected: $timePeriod'); + return timePeriod; // Year-MonthAbbr + } else { + print('Unknown format: $timePeriod'); + return timePeriod; // Keep it as is + } + }) .toSet(); + print("Unique X Values: $uniqueXValues"); + + double parseTimePeriod(String timePeriod) { + // Match formats + if (RegExp(r'^\d{4}$').hasMatch(timePeriod)) { + return double.parse(timePeriod); // Year-only (2019 → 2019.0) + } else if (RegExp(r'^\d{4}-\d{2}$').hasMatch(timePeriod)) { + return double.parse(timePeriod.replaceAll('-', '.')); // Year-Month (2019-11 → 2019.11) + } else if (RegExp(r'^\d{4}-[A-Za-z]{3}$').hasMatch(timePeriod)) { + // Year-MonthAbbr (2019-Nov) + Map monthMap = { + 'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, + 'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8, + 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12 + }; + + List parts = timePeriod.split('-'); + int month = 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"); + } + + Set uniqueXValuesProcessed = uniqueXValues + .where((value) => value.isNotEmpty) // Remove any empty strings + .map(parseTimePeriod) + .toSet(); + print('Processed X Values: $uniqueXValuesProcessed'); + + + + print('LnTrnd2.1'); + // Generate line bars for the chart List lineBars = lineBarsData(filteredData, groupByValues, groupByKey); + + print('LnTrnd3'); + return Column(children: [ Text( chartData['chart_heading'] ?? '', // Chart title from data @@ -555,12 +624,17 @@ class ChartWidget extends StatelessWidget { child: LineChart(LineChartData( lineTouchData: lineTouchData1(), gridData: gridData(), - titlesData: titlesData1(uniqueXValues), + // titlesData: titlesData1(uniqueXValues), + titlesData: titlesData1(uniqueXValuesProcessed), borderData: borderData(), lineBarsData: lineBars, - minX: uniqueXValues.reduce((a, b) => a < b ? a : b), - maxX: 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), + + + // minX: uniqueXValuesProcessed.reduce((a, b) => a < b ? a : b), + // maxX: uniqueXValuesProcessed.reduce((a, b) => a > b ? a : b), + ))), Padding( padding: const EdgeInsets.all(8.0), child: Wrap( @@ -641,7 +715,7 @@ class ChartWidget extends StatelessWidget { // Generate line bars for the chart List lineBars = lineBarsData(filteredData, groupByValues, groupByKey); - + return Column(children: [ Text( chartData['chart_heading'] ?? '', // Chart title from data @@ -1061,19 +1135,45 @@ class ChartWidget extends StatelessWidget { String cropKey = chartData['chart_type_json']['x_sub_group']; // Group crops by CROP_TYPE Map> groupedCrops = {}; + + int touchedGroupIndex = -1; // Iterate over the chartData to group crops by CROP_TYPE - for (var item in chartData['response']) { - String crop, cropType; - crop = item['ObsKey'][cropKey]; - cropType = item['ObsKey'][groupByKey]; + + + for (var item in chartData['response']) { + + // print("MultiBArRaw item: $item"); + + String crop = item['ObsKey'][cropKey]; + String cropType = item['ObsKey'][groupByKey]; + + // Use a Set to avoid duplicates if (groupedCrops.containsKey(cropType)) { - groupedCrops[cropType]!.add(crop); + groupedCrops[cropType] = (groupedCrops[cropType]! + [crop]).toSet().toList(); } else { groupedCrops[cropType] = [crop]; } } + + print('Unique groupedCrops: $groupedCrops'); + + // for (var item in chartData['response']) { + // String crop, cropType; + // crop = item['ObsKey'][cropKey]; + // cropType = item['ObsKey'][groupByKey]; + // + // if (groupedCrops.containsKey(cropType)) { + // groupedCrops[cropType]!.add(crop); + // } else { + // groupedCrops[cropType] = [crop]; + // } + // } + // + // print('groupedCropsflmutli- $groupedCrops'); + + return Column(children: [ Text( chartData['chart_heading'] ?? '', // Chart title from data @@ -1189,7 +1289,8 @@ class ChartWidget extends StatelessWidget { } else { print( '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; } // print('groupedCrops1: $groupedCrops - $rodIndex'); @@ -1754,6 +1855,34 @@ class ChartWidget extends StatelessWidget { return lineBars; } + + /// Function to parse TIME_PERIOD into a EXACT value + double parseTimePeriod(String timePeriod) { + // Match formats + if (RegExp(r'^\d{4}$').hasMatch(timePeriod)) { + // Format: Year-only (e.g., "2020") + return double.parse(timePeriod); // Year as a double (2020 → 2020.0) + } else if (RegExp(r'^\d{4}-\d{2}$').hasMatch(timePeriod)) { + // Format: Year-Month (e.g., "2020-10") + return double.parse(timePeriod.replaceAll('-', '.')); // Convert "2020-10" → 2020.10 + } else if (RegExp(r'^\d{4}-[A-Za-z]{3}$').hasMatch(timePeriod)) { + // Format: Year-MonthAbbr (e.g., "2020-Oct") + Map monthMap = { + 'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, + 'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8, + 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12 + }; + + List parts = timePeriod.split('-'); + int month = monthMap[parts[1]] ?? 1; // Default to January if unknown + return double.parse('${parts[0]}.$month'); // Convert "2020-Oct" → 2020.10 + } + + // Throw an error for unsupported formats + throw FormatException("Invalid TIME_PERIOD format: $timePeriod"); + } + + List lineBarsData(List filteredData, Set groupByValues, String groupByKey) { List lineBars = []; @@ -1779,14 +1908,66 @@ class ChartWidget extends StatelessWidget { print('Group-Color Map: $groupColorMap'); // Iterate through each group and generate line data for (String group in groupByValues) { + print('lineGrp1'); + + // List spots = filteredData + // .where((entry) => entry['ObsKey'][groupByKey] == group) + // .map((entry) { + // print("FindTimePeriod"); + // print(entry['ObsKey'][groupByKey]); + // double xValue = double.parse(entry['ObsKey']['TIME_PERIOD']); + // double yValue = double.parse(entry['ObsValue']['Value']); + // return FlSpot(xValue, yValue); + // }).toList(); + + // List spots = filteredData + // .where((entry) => entry['ObsKey'][groupByKey] == group) + // .map((entry) { + // String timePeriod = entry['ObsKey']['TIME_PERIOD']; + // print("FindTimePeriod: $timePeriod"); + // + // double xValue = parseTimePeriodToDouble(timePeriod); // Convert to double for graph plotting + // double yValue = double.parse(entry['ObsValue']['Value']); + // print('TimePeriod: $timePeriod, xValue: $xValue, yValue: $yValue'); + // + // return FlSpot(xValue, yValue); + // }).toList(); + List spots = filteredData .where((entry) => entry['ObsKey'][groupByKey] == group) .map((entry) { - double xValue = double.parse(entry['ObsKey']['TIME_PERIOD']); + String timePeriod = entry['ObsKey']['TIME_PERIOD']; + print("FindTimePeriod: $timePeriod"); + + // Use the timePeriod directly as a string for x-axis + double xValue = parseTimePeriod(timePeriod); double yValue = double.parse(entry['ObsValue']['Value']); return FlSpot(xValue, yValue); }).toList(); + print('spots - $spots'); + + + + + // List spots = filteredData + // .where((entry) => entry['ObsKey'][groupByKey] == group) + // .map((entry) { + // String timePeriod = entry['ObsKey']['TIME_PERIOD']; + // List parts = timePeriod.split('-'); // Split "2017-01" into ["2017", "01"] + // + // double year = double.parse(parts[0]); // Convert "2017" to 2017.0 + // double month = double.parse(parts[1]) / 12; // Convert "01" to 1/12 + // + // double xValue = year + month; // E.g., "2017-06" becomes 2017.5 + // double yValue = double.parse(entry['ObsValue']['Value']); + // + // return FlSpot(xValue, yValue); + // }).toList(); + + + + print('lineGrp2'); // Add a line for this group lineBars.add( LineChartBarData( @@ -1830,6 +2011,13 @@ class ChartWidget extends StatelessWidget { } FlTitlesData titlesData1(Set xValues) { + + print('tileDATa1xvalue - $xValues'); + + double findClosest(double value, Set values) { + return values.reduce((a, b) => (value - a).abs() < (value - b).abs() ? a : b); + } + return FlTitlesData( leftTitles: AxisTitles( sideTitles: SideTitles( @@ -1840,7 +2028,7 @@ class ChartWidget extends StatelessWidget { String formattedValue; 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) { formattedValue = '${(value / 1000000).toStringAsFixed(0)}M'; } else if (value >= 1000) { @@ -1857,7 +2045,7 @@ class ChartWidget extends StatelessWidget { // Update the last formatted value for the next comparison _lastFormattedValue = formattedValue; - print('formattedValueLine - $formattedValue'); + // print('formattedValueLine - $formattedValue'); return Text(formattedValue, style: TextStyle(fontSize: 10)); } return const SizedBox.shrink(); @@ -1872,9 +2060,19 @@ class ChartWidget extends StatelessWidget { bottomTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, - interval: 10, // Ensure each year is shown only once + interval: null, + // interval: 10, // Ensure each year is shown only once getTitlesWidget: (value, meta) { - if (xValues.contains(value)) { + + print('BtmTiles :-$value'); + print('BtmTilesmeta :-$meta'); + // if (xValues.contains(value)) + double closestValue = findClosest(value, xValues); + if ((closestValue - value).abs() < 0.15) + { + + print("Bottomtiles"); + print(value); return Transform.rotate( angle: -0.5, // Slight rotation to improve readability child: Text( @@ -2207,7 +2405,7 @@ double calculateBarWidth(BuildContext context, int totalBars) { barWidth = availableWidth; } - // Optional: Add a minimum width constraint if needed + // Optional: Add a minimum width constraint if needed double minWidth = 10.0; // Example minimum width if (barWidth < minWidth) { barWidth = minWidth; @@ -2222,4 +2420,4 @@ class ChartData { final DateTime? xDateTime; ChartData({this.x, required this.y, this.xDateTime}); -} +} \ No newline at end of file