mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-15 01:35:25 +00:00
Merge pull request #176 from SyncrowIOT/SP-1510-FE-Build-Occupancy-Bar-Chart-Monthly-Consumption-View
Sp 1510 fe build occupancy bar chart monthly consumption view
This commit is contained in:
@ -0,0 +1,144 @@
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/analytics/models/occupacy.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 OccupancyChart extends StatelessWidget {
|
||||
const OccupancyChart({required this.chartData, super.key});
|
||||
|
||||
final List<Occupacy> chartData;
|
||||
|
||||
static const _chartWidth = 16.0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BarChart(
|
||||
BarChartData(
|
||||
maxY: 1.0,
|
||||
gridData: EnergyManagementChartsHelper.gridData().copyWith(
|
||||
checkToShowHorizontalLine: (value) => true,
|
||||
horizontalInterval: 0.25,
|
||||
),
|
||||
borderData: EnergyManagementChartsHelper.borderData(),
|
||||
barTouchData: _barTouchData(context),
|
||||
titlesData: _titlesData(context),
|
||||
barGroups: List.generate(chartData.length, (index) {
|
||||
final actual = chartData[index];
|
||||
return BarChartGroupData(
|
||||
x: index,
|
||||
barsSpace: 0,
|
||||
groupVertically: true,
|
||||
barRods: [
|
||||
BarChartRodData(
|
||||
toY: 1.0,
|
||||
fromY: double.parse(actual.occupancy) + 0.025,
|
||||
color: ColorsManager.graysColor,
|
||||
width: _chartWidth,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
BarChartRodData(
|
||||
toY: double.parse(actual.occupancy),
|
||||
color: ColorsManager.vividBlue.withValues(alpha: 0.8),
|
||||
width: _chartWidth,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
BarTouchData _barTouchData(BuildContext context) {
|
||||
return BarTouchData(
|
||||
touchTooltipData: BarTouchTooltipData(
|
||||
getTooltipColor: (touchTooltipItem) => ColorsManager.whiteColors,
|
||||
tooltipBorder: const BorderSide(
|
||||
color: ColorsManager.semiTransparentBlack,
|
||||
),
|
||||
tooltipRoundedRadius: 16,
|
||||
tooltipPadding: const EdgeInsets.all(8),
|
||||
getTooltipItem: (group, groupIndex, rod, rodIndex) => getTooltipItem(
|
||||
context: context,
|
||||
group: group,
|
||||
groupIndex: groupIndex,
|
||||
rod: rod,
|
||||
rodIndex: rodIndex,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
BarTooltipItem? getTooltipItem({
|
||||
required BuildContext context,
|
||||
required BarChartGroupData group,
|
||||
required int groupIndex,
|
||||
required BarChartRodData rod,
|
||||
required int rodIndex,
|
||||
}) {
|
||||
final data = chartData;
|
||||
|
||||
final month = double.parse(data[group.x.toInt()].occupancy).toStringAsFixed(2);
|
||||
|
||||
return BarTooltipItem(
|
||||
month,
|
||||
context.textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.blackColor,
|
||||
fontSize: 14,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FlTitlesData _titlesData(BuildContext context) {
|
||||
final titlesData = EnergyManagementChartsHelper.titlesData(
|
||||
context,
|
||||
leftTitlesInterval: 250,
|
||||
);
|
||||
|
||||
final leftTitles = titlesData.leftTitles.copyWith(
|
||||
sideTitles: titlesData.leftTitles.sideTitles.copyWith(
|
||||
reservedSize: 70,
|
||||
interval: 0.25,
|
||||
getTitlesWidget: (value, meta) => Padding(
|
||||
padding: const EdgeInsetsDirectional.only(end: 12),
|
||||
child: FittedBox(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Text(
|
||||
'${(value * 100).toStringAsFixed(0)}%',
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
fontSize: 12,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final bottomTitles = AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: true,
|
||||
getTitlesWidget: (value, _) => FittedBox(
|
||||
alignment: AlignmentDirectional.bottomCenter,
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Text(
|
||||
(value + 1).toString(),
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
color: ColorsManager.greyColor,
|
||||
fontSize: 8,
|
||||
),
|
||||
),
|
||||
),
|
||||
reservedSize: 36,
|
||||
),
|
||||
);
|
||||
|
||||
return titlesData.copyWith(
|
||||
leftTitles: leftTitles,
|
||||
bottomTitles: bottomTitles,
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/analytics/modules/analytics/widgets/analytics_date_filter_button.dart';
|
||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/chart_title.dart';
|
||||
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy/occupancy_bloc.dart';
|
||||
import 'package:syncrow_web/pages/analytics/modules/occupancy/widgets/occupancy_chart.dart';
|
||||
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class OccupancyChartBox extends StatelessWidget {
|
||||
const OccupancyChartBox({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<OccupancyBloc, OccupancyState>(
|
||||
builder: (context, state) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(30),
|
||||
decoration: containerWhiteDecoration,
|
||||
child: Column(
|
||||
spacing: 20,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AnalyticsErrorWidget(state.errorMessage),
|
||||
const Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: FittedBox(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
fit: BoxFit.scaleDown,
|
||||
child: ChartTitle(title: Text('Occupancy')),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Expanded(
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: AnalyticsDateFilterButton(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(height: 0),
|
||||
Expanded(child: OccupancyChart(chartData: state.chartData)),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class OccupancyEndSideBar extends StatelessWidget {
|
||||
const OccupancyEndSideBar({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: subSectionContainerDecoration.copyWith(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
padding: const EdgeInsetsDirectional.all(32),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildHeader(context),
|
||||
Text(
|
||||
'Device ID:',
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
SelectableText(
|
||||
(const Uuid().v4()),
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
color: ColorsManager.blackColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 50),
|
||||
const Placeholder(fallbackHeight: 150),
|
||||
const SizedBox(height: 50),
|
||||
const Expanded(child: Placeholder()),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeader(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
child: SelectableText(
|
||||
'Presnce Sensor',
|
||||
style: context.textTheme.headlineSmall?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
color: ColorsManager.vividBlue.withValues(alpha: 0.6),
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
const Expanded(
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
// child: PowerClampEnergyDataDeviceDropdown(),
|
||||
child: Placeholder(fallbackHeight: 30),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user