mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 15:17:31 +00:00
Implemented an initial version of AqiDistributionChart
.
This commit is contained in:
31
lib/pages/analytics/models/air_quality_data_model.dart
Normal file
31
lib/pages/analytics/models/air_quality_data_model.dart
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
class AirQualityDataModel {
|
||||||
|
const AirQualityDataModel({
|
||||||
|
required this.date,
|
||||||
|
this.aqi,
|
||||||
|
this.pm25,
|
||||||
|
this.pm10,
|
||||||
|
this.hcho,
|
||||||
|
this.tvoc,
|
||||||
|
this.co2,
|
||||||
|
});
|
||||||
|
|
||||||
|
final DateTime date;
|
||||||
|
final double? aqi;
|
||||||
|
final double? pm25;
|
||||||
|
final double? pm10;
|
||||||
|
final double? hcho;
|
||||||
|
final double? tvoc;
|
||||||
|
final double? co2;
|
||||||
|
|
||||||
|
static const Map<String, Color> metricColors = {
|
||||||
|
'aqi': ColorsManager.goodGreen,
|
||||||
|
'pm25': ColorsManager.moderateYellow,
|
||||||
|
'pm10': ColorsManager.poorOrange,
|
||||||
|
'hcho': ColorsManager.unhealthyRed,
|
||||||
|
'tvoc': ColorsManager.severePink,
|
||||||
|
'co2': ColorsManager.hazardousPurple,
|
||||||
|
};
|
||||||
|
}
|
@ -1,10 +1,205 @@
|
|||||||
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/analytics/models/air_quality_data_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/helpers/energy_management_charts_helper.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
class AqiDistributionChart extends StatelessWidget {
|
class AqiDistributionChart extends StatelessWidget {
|
||||||
const AqiDistributionChart({super.key});
|
const AqiDistributionChart({super.key, required this.chartData});
|
||||||
|
final List<AirQualityDataModel> chartData;
|
||||||
|
|
||||||
|
static const _rodStackItemsSpacing = 4;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const Placeholder();
|
return BarChart(
|
||||||
|
BarChartData(
|
||||||
|
alignment: BarChartAlignment.spaceAround,
|
||||||
|
barTouchData: _barTouchData(context),
|
||||||
|
titlesData: _titlesData(context),
|
||||||
|
gridData: EnergyManagementChartsHelper.gridData(
|
||||||
|
horizontalInterval: 100,
|
||||||
|
),
|
||||||
|
borderData: EnergyManagementChartsHelper.borderData(),
|
||||||
|
barGroups: _buildBarGroups(),
|
||||||
|
groupsSpace: 12,
|
||||||
|
),
|
||||||
|
duration: Duration.zero,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BarChartGroupData> _buildBarGroups() {
|
||||||
|
return List.generate(chartData.length, (index) {
|
||||||
|
final data = chartData[index];
|
||||||
|
final stackItems = <BarChartRodData>[];
|
||||||
|
double currentY = 0;
|
||||||
|
|
||||||
|
if (data.aqi != null) {
|
||||||
|
stackItems.add(
|
||||||
|
BarChartRodData(
|
||||||
|
fromY: currentY,
|
||||||
|
toY: currentY + data.aqi!,
|
||||||
|
color: AirQualityDataModel.metricColors['aqi']!,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
currentY += data.aqi! + _rodStackItemsSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.pm25 != null) {
|
||||||
|
stackItems.add(
|
||||||
|
BarChartRodData(
|
||||||
|
fromY: currentY,
|
||||||
|
toY: currentY + data.pm25!,
|
||||||
|
color: AirQualityDataModel.metricColors['pm25']!,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
currentY += data.pm25! + _rodStackItemsSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.pm10 != null) {
|
||||||
|
stackItems.add(
|
||||||
|
BarChartRodData(
|
||||||
|
fromY: currentY,
|
||||||
|
toY: currentY + data.pm10!,
|
||||||
|
color: AirQualityDataModel.metricColors['pm10']!,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
currentY += data.pm10! + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.hcho != null) {
|
||||||
|
stackItems.add(
|
||||||
|
BarChartRodData(
|
||||||
|
fromY: currentY,
|
||||||
|
toY: currentY + data.hcho!,
|
||||||
|
color: AirQualityDataModel.metricColors['hcho']!,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
currentY += data.hcho! + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.tvoc != null) {
|
||||||
|
stackItems.add(
|
||||||
|
BarChartRodData(
|
||||||
|
fromY: currentY,
|
||||||
|
toY: currentY + data.tvoc!,
|
||||||
|
color: AirQualityDataModel.metricColors['tvoc']!,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
currentY += data.tvoc! + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.co2 != null) {
|
||||||
|
stackItems.add(
|
||||||
|
BarChartRodData(
|
||||||
|
fromY: currentY,
|
||||||
|
toY: currentY + data.co2!,
|
||||||
|
color: AirQualityDataModel.metricColors['co2']!,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
currentY += data.co2! + 2;
|
||||||
|
}
|
||||||
|
return BarChartGroupData(
|
||||||
|
x: index,
|
||||||
|
barRods: stackItems,
|
||||||
|
groupVertically: true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
BarTouchData _barTouchData(BuildContext context) {
|
||||||
|
return BarTouchData(
|
||||||
|
touchTooltipData: BarTouchTooltipData(
|
||||||
|
getTooltipColor: (_) => ColorsManager.whiteColors,
|
||||||
|
tooltipBorder: const BorderSide(
|
||||||
|
color: ColorsManager.semiTransparentBlack,
|
||||||
|
),
|
||||||
|
tooltipRoundedRadius: 16,
|
||||||
|
tooltipPadding: const EdgeInsets.all(8),
|
||||||
|
getTooltipItem: (group, groupIndex, rod, rodIndex) {
|
||||||
|
final data = chartData[group.x.toInt()];
|
||||||
|
final stackItems = rod.rodStackItems;
|
||||||
|
|
||||||
|
return BarTooltipItem(
|
||||||
|
'${data.date.day}/${data.date.month}\n',
|
||||||
|
context.textTheme.bodyMedium!.copyWith(
|
||||||
|
color: ColorsManager.blackColor,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
children: stackItems.map((item) {
|
||||||
|
final metricName = AirQualityDataModel.metricColors.entries
|
||||||
|
.firstWhere((entry) => entry.value == item.color)
|
||||||
|
.key
|
||||||
|
.toUpperCase();
|
||||||
|
return TextSpan(
|
||||||
|
text: '$metricName: ${item.toY - item.fromY}\n',
|
||||||
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
|
color: ColorsManager.blackColor,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
FlTitlesData _titlesData(BuildContext context) {
|
||||||
|
final titlesData = EnergyManagementChartsHelper.titlesData(context);
|
||||||
|
|
||||||
|
return titlesData.copyWith(
|
||||||
|
bottomTitles: AxisTitles(
|
||||||
|
sideTitles: SideTitles(
|
||||||
|
showTitles: true,
|
||||||
|
getTitlesWidget: (value, meta) {
|
||||||
|
if (value.toInt() >= chartData.length) return const SizedBox.shrink();
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.only(top: 20.0),
|
||||||
|
child: Text(
|
||||||
|
chartData[value.toInt()].date.day.toString(),
|
||||||
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
|
color: ColorsManager.lightGreyColor,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
reservedSize: 32,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
leftTitles: titlesData.leftTitles.copyWith(
|
||||||
|
sideTitles: titlesData.leftTitles.sideTitles.copyWith(
|
||||||
|
reservedSize: 70,
|
||||||
|
getTitlesWidget: (value, meta) => Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.only(end: 12),
|
||||||
|
child: FittedBox(
|
||||||
|
alignment: AlignmentDirectional.centerStart,
|
||||||
|
fit: BoxFit.scaleDown,
|
||||||
|
child: Text(
|
||||||
|
value.toInt().toString(),
|
||||||
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
|
fontSize: 12,
|
||||||
|
color: ColorsManager.lightGreyColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/analytics/models/air_quality_data_model.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart.dart';
|
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart_title.dart';
|
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart_title.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
@ -13,15 +14,46 @@ class AqiDistributionChartBox extends StatelessWidget {
|
|||||||
decoration: subSectionContainerDecoration.copyWith(
|
decoration: subSectionContainerDecoration.copyWith(
|
||||||
borderRadius: BorderRadius.circular(30),
|
borderRadius: BorderRadius.circular(30),
|
||||||
),
|
),
|
||||||
child: const Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
AqiDistributionChartTitle(isLoading: false),
|
const AqiDistributionChartTitle(isLoading: false),
|
||||||
SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Divider(),
|
const Divider(),
|
||||||
SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Expanded(child: AqiDistributionChart()),
|
Expanded(
|
||||||
|
child: AqiDistributionChart(
|
||||||
|
chartData: [
|
||||||
|
AirQualityDataModel(
|
||||||
|
date: DateTime.now(),
|
||||||
|
aqi: 50,
|
||||||
|
pm25: 30,
|
||||||
|
pm10: 40,
|
||||||
|
co2: 120,
|
||||||
|
hcho: 10,
|
||||||
|
tvoc: 50,
|
||||||
|
),
|
||||||
|
AirQualityDataModel(
|
||||||
|
date: DateTime.now(),
|
||||||
|
aqi: 50,
|
||||||
|
pm25: 25,
|
||||||
|
pm10: 40,
|
||||||
|
co2: 120,
|
||||||
|
hcho: 10,
|
||||||
|
tvoc: 50,
|
||||||
|
),
|
||||||
|
AirQualityDataModel(
|
||||||
|
date: DateTime.now(),
|
||||||
|
aqi: 50,
|
||||||
|
pm25: 25,
|
||||||
|
pm10: 40,
|
||||||
|
co2: 120,
|
||||||
|
hcho: 10,
|
||||||
|
tvoc: 50,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user