charts
This commit is contained in:
parent
4917749f65
commit
d1bcedd4fe
@ -1764,18 +1764,21 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
||||
.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<int> timePeriodData = item['filter_data']
|
||||
.map<int>((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<int> timePeriodData = item['filter_data']
|
||||
// .map<int>((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<ChartScreen1> {
|
||||
// width: 24,
|
||||
// height: 24,
|
||||
// ),
|
||||
|
||||
|
||||
SvgPicture.asset(
|
||||
UaeNumbersAssetPath.share,
|
||||
semanticsLabel: 'share',
|
||||
@ -2625,7 +2630,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_activeTabIndex = _tabsData.indexOf(tab);
|
||||
});
|
||||
});
|
||||
_scrollToIndex(_activeTabIndex);
|
||||
onTabSelected(tab['id']!);
|
||||
},
|
||||
@ -2647,4 +2652,4 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -494,6 +494,7 @@ class ChartWidget extends StatelessWidget {
|
||||
colorIndex % uniqueColorsLine_trend_2.length];
|
||||
colorIndex++;
|
||||
}
|
||||
print('LnTrnd1');
|
||||
|
||||
// Extract all years from the chart data
|
||||
List<int> years = (chartData['response'] as List<dynamic>)
|
||||
@ -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<double> uniqueXValues = filteredData
|
||||
.map<double>(
|
||||
(entry) => double.parse(entry['ObsKey']['TIME_PERIOD']))
|
||||
// Set<double> uniqueXValues = filteredData
|
||||
// .map<double>(
|
||||
// (entry) => double.parse(entry['ObsKey']['TIME_PERIOD']))
|
||||
// .toSet();
|
||||
|
||||
|
||||
Set<String> uniqueXValues = filteredData
|
||||
.map<String>((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<String, int> 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<String> 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<double> 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<LineChartBarData> 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<LineChartBarData> 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<String, List<String>> 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<String, int> 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<String> 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<LineChartBarData> lineBarsData(List<dynamic> filteredData,
|
||||
Set<String> groupByValues, String groupByKey) {
|
||||
List<LineChartBarData> 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<FlSpot> spots = filteredData
|
||||
// .where((entry) => entry['ObsKey'][groupByKey] == group)
|
||||
// .map<FlSpot>((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<FlSpot> spots = filteredData
|
||||
// .where((entry) => entry['ObsKey'][groupByKey] == group)
|
||||
// .map<FlSpot>((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<FlSpot> spots = filteredData
|
||||
.where((entry) => entry['ObsKey'][groupByKey] == group)
|
||||
.map<FlSpot>((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<FlSpot> spots = filteredData
|
||||
// .where((entry) => entry['ObsKey'][groupByKey] == group)
|
||||
// .map<FlSpot>((entry) {
|
||||
// String timePeriod = entry['ObsKey']['TIME_PERIOD'];
|
||||
// List<String> 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<double> xValues) {
|
||||
|
||||
print('tileDATa1xvalue - $xValues');
|
||||
|
||||
double findClosest(double value, Set<double> 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});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user