charts
This commit is contained in:
parent
4917749f65
commit
d1bcedd4fe
@ -1764,18 +1764,21 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
.expand((item) => item)
|
.expand((item) => item)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
for (var item in filterData) {
|
print("FilteringDAtss START1 - $filterData");
|
||||||
if (item['filter_key'] == 'TIME_PERIOD') {
|
print('TABId1 - $tabId');
|
||||||
// Convert the values to integers, sort them, and convert back to strings
|
// for (var item in filterData) {
|
||||||
List<int> timePeriodData = item['filter_data']
|
// if (item['filter_key'] == 'TIME_PERIOD') {
|
||||||
.map<int>((e) => int.parse(e.toString())) // Convert to int
|
// // Convert the values to integers, sort them, and convert back to strings
|
||||||
.toList();
|
// List<int> timePeriodData = item['filter_data']
|
||||||
timePeriodData.sort((a, b) => a.compareTo(b)); // Sort numerically
|
// .map<int>((e) => int.parse(e.toString())) // Convert to int
|
||||||
|
// .toList();
|
||||||
// Optionally, convert sorted integers back to strings if necessary
|
// timePeriodData.sort((a, b) => a.compareTo(b)); // Sort numerically
|
||||||
item['filter_data'] = timePeriodData.map((e) => e.toString()).toList();
|
//
|
||||||
}
|
// // 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");
|
print("TABFiltered Data: $filterData");
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -2112,6 +2115,8 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
// width: 24,
|
// width: 24,
|
||||||
// height: 24,
|
// height: 24,
|
||||||
// ),
|
// ),
|
||||||
|
|
||||||
|
|
||||||
SvgPicture.asset(
|
SvgPicture.asset(
|
||||||
UaeNumbersAssetPath.share,
|
UaeNumbersAssetPath.share,
|
||||||
semanticsLabel: 'share',
|
semanticsLabel: 'share',
|
||||||
|
|||||||
@ -494,6 +494,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
colorIndex % uniqueColorsLine_trend_2.length];
|
colorIndex % uniqueColorsLine_trend_2.length];
|
||||||
colorIndex++;
|
colorIndex++;
|
||||||
}
|
}
|
||||||
|
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>)
|
||||||
@ -511,6 +512,8 @@ class ChartWidget extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print('LnTrnd1.2');
|
||||||
|
|
||||||
// Find the maximum year and calculate the range for the last 5 years
|
// Find the maximum year and calculate the range for the last 5 years
|
||||||
int maxYear = years.reduce((a, b) => a > b ? a : b);
|
int maxYear = years.reduce((a, b) => a > b ? a : b);
|
||||||
int minYear = maxYear - 5;
|
int minYear = maxYear - 5;
|
||||||
@ -521,16 +524,82 @@ class ChartWidget extends StatelessWidget {
|
|||||||
int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
|
int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
|
||||||
return year >= minYear && year <= maxYear;
|
return year >= minYear && year <= maxYear;
|
||||||
}).toList();
|
}).toList();
|
||||||
|
print('LnTrnd2');
|
||||||
|
|
||||||
Set<double> uniqueXValues = filteredData
|
// Set<double> uniqueXValues = filteredData
|
||||||
.map<double>(
|
// .map<double>(
|
||||||
(entry) => double.parse(entry['ObsKey']['TIME_PERIOD']))
|
// (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();
|
.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
|
// Generate line bars for the chart
|
||||||
List<LineChartBarData> lineBars =
|
List<LineChartBarData> lineBars =
|
||||||
lineBarsData(filteredData, groupByValues, groupByKey);
|
lineBarsData(filteredData, groupByValues, groupByKey);
|
||||||
|
|
||||||
|
|
||||||
|
print('LnTrnd3');
|
||||||
|
|
||||||
return Column(children: [
|
return Column(children: [
|
||||||
Text(
|
Text(
|
||||||
chartData['chart_heading'] ?? '', // Chart title from data
|
chartData['chart_heading'] ?? '', // Chart title from data
|
||||||
@ -555,11 +624,16 @@ class ChartWidget extends StatelessWidget {
|
|||||||
child: LineChart(LineChartData(
|
child: LineChart(LineChartData(
|
||||||
lineTouchData: lineTouchData1(),
|
lineTouchData: lineTouchData1(),
|
||||||
gridData: gridData(),
|
gridData: gridData(),
|
||||||
titlesData: titlesData1(uniqueXValues),
|
// titlesData: titlesData1(uniqueXValues),
|
||||||
|
titlesData: titlesData1(uniqueXValuesProcessed),
|
||||||
borderData: borderData(),
|
borderData: borderData(),
|
||||||
lineBarsData: lineBars,
|
lineBarsData: lineBars,
|
||||||
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),
|
||||||
|
// maxX: uniqueXValuesProcessed.reduce((a, b) => a > b ? a : b),
|
||||||
))),
|
))),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
@ -1061,19 +1135,45 @@ class ChartWidget extends StatelessWidget {
|
|||||||
String cropKey = chartData['chart_type_json']['x_sub_group'];
|
String cropKey = chartData['chart_type_json']['x_sub_group'];
|
||||||
// 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']) {
|
|
||||||
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)) {
|
if (groupedCrops.containsKey(cropType)) {
|
||||||
groupedCrops[cropType]!.add(crop);
|
groupedCrops[cropType] = (groupedCrops[cropType]! + [crop]).toSet().toList();
|
||||||
} else {
|
} else {
|
||||||
groupedCrops[cropType] = [crop];
|
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: [
|
return Column(children: [
|
||||||
Text(
|
Text(
|
||||||
chartData['chart_heading'] ?? '', // Chart title from data
|
chartData['chart_heading'] ?? '', // Chart title from data
|
||||||
@ -1189,7 +1289,8 @@ class ChartWidget extends StatelessWidget {
|
|||||||
} else {
|
} else {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// print('groupedCrops1: $groupedCrops - $rodIndex');
|
// print('groupedCrops1: $groupedCrops - $rodIndex');
|
||||||
@ -1754,6 +1855,34 @@ class ChartWidget extends StatelessWidget {
|
|||||||
return lineBars;
|
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,
|
List<LineChartBarData> lineBarsData(List<dynamic> filteredData,
|
||||||
Set<String> groupByValues, String groupByKey) {
|
Set<String> groupByValues, String groupByKey) {
|
||||||
List<LineChartBarData> lineBars = [];
|
List<LineChartBarData> lineBars = [];
|
||||||
@ -1779,14 +1908,66 @@ class ChartWidget extends StatelessWidget {
|
|||||||
print('Group-Color Map: $groupColorMap');
|
print('Group-Color Map: $groupColorMap');
|
||||||
// Iterate through each group and generate line data
|
// Iterate through each group and generate line data
|
||||||
for (String group in groupByValues) {
|
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
|
List<FlSpot> spots = filteredData
|
||||||
.where((entry) => entry['ObsKey'][groupByKey] == group)
|
.where((entry) => entry['ObsKey'][groupByKey] == group)
|
||||||
.map<FlSpot>((entry) {
|
.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']);
|
double yValue = double.parse(entry['ObsValue']['Value']);
|
||||||
return FlSpot(xValue, yValue);
|
return FlSpot(xValue, yValue);
|
||||||
}).toList();
|
}).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
|
// Add a line for this group
|
||||||
lineBars.add(
|
lineBars.add(
|
||||||
LineChartBarData(
|
LineChartBarData(
|
||||||
@ -1830,6 +2011,13 @@ class ChartWidget extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FlTitlesData titlesData1(Set<double> xValues) {
|
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(
|
return FlTitlesData(
|
||||||
leftTitles: AxisTitles(
|
leftTitles: AxisTitles(
|
||||||
sideTitles: SideTitles(
|
sideTitles: SideTitles(
|
||||||
@ -1840,7 +2028,7 @@ 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 >= 1000000) {
|
||||||
formattedValue = '${(value / 1000000).toStringAsFixed(0)}M';
|
formattedValue = '${(value / 1000000).toStringAsFixed(0)}M';
|
||||||
} else if (value >= 1000) {
|
} else if (value >= 1000) {
|
||||||
@ -1857,7 +2045,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
// Update the last formatted value for the next comparison
|
// Update the last formatted value for the next comparison
|
||||||
_lastFormattedValue = formattedValue;
|
_lastFormattedValue = formattedValue;
|
||||||
|
|
||||||
print('formattedValueLine - $formattedValue');
|
// print('formattedValueLine - $formattedValue');
|
||||||
return Text(formattedValue, style: TextStyle(fontSize: 10));
|
return Text(formattedValue, style: TextStyle(fontSize: 10));
|
||||||
}
|
}
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
@ -1872,9 +2060,19 @@ class ChartWidget extends StatelessWidget {
|
|||||||
bottomTitles: AxisTitles(
|
bottomTitles: AxisTitles(
|
||||||
sideTitles: SideTitles(
|
sideTitles: SideTitles(
|
||||||
showTitles: true,
|
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) {
|
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(
|
return Transform.rotate(
|
||||||
angle: -0.5, // Slight rotation to improve readability
|
angle: -0.5, // Slight rotation to improve readability
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user