Merge pull request 'functionality/graph' (#54) from functionality/graph into master

Reviewed-on: #54
pull/61/head
Haroon6138 1 month ago
commit d3978de92e

@ -0,0 +1,14 @@
///class used to provide value for the [DynamicResultChart] to plot the values
class DataPoint {
///values that is displayed on the graph and dot is plotted on this
final double value;
///label shown on the bottom of the graph
String label;
DataPoint(
{required this.value,
required this.label,
});
}

@ -0,0 +1,21 @@
import 'dart:ui' show Color;
class ThresholdRange {
final String label;
final double value;
final Color color;
final Color lineColor;
final String? actualValue;
ThresholdRange(
{required this.label,
required this.value,
required this.color,
required this.lineColor,
this.actualValue});
@override
String toString() {
return 'ThresholdRange(label: $label, value: $value, color: ${color.value.toRadixString(16)}, lineColor: ${lineColor.value.toRadixString(16)})';
}
}

@ -62,4 +62,7 @@ static const Color greyLightColor = Color(0xFFEFEFF0);
static const Color bottomNAVBorder = Color(0xFFEEEEEE);
static const Color quickLoginColor = Color(0xFF666666);
static const Color tooltipTextColor = Color(0xFF414D55);
static const Color graphGridColor = Color(0x4D18C273);
}

@ -0,0 +1,287 @@
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:hmg_patient_app_new/core/common_models/data_points.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
///
/// CustomGraph(dataPoints: sampleData, scrollDirection: Axis.horizontal,height: 200,maxY: 100, maxX:2.5,
/// leftLabelFormatter: (value){
/// Widget buildLabel(String label) {
/// return Padding(
/// padding: const EdgeInsets.only(right: 8),
/// child: Text(
/// label,
/// style: TextStyle(
/// fontSize: 8.fSize, color: AppColors.textColor,
/// fontFamily:
/// FontUtils.getFontFamilyForLanguage(false)
/// ),
/// textAlign: TextAlign.right,
/// ),
/// );
/// }
/// switch (value.toInt()) {
///
/// case 20:
/// return buildLabel("Critical Low");
/// case 40:
/// return buildLabel("Low");
/// case 60:
/// return buildLabel("Normal");
/// case 80:
/// return buildLabel("High");
/// case 100:
/// return buildLabel("Critical High");
/// }
/// return const SizedBox.shrink();
/// },
///
/// ),
class CustomGraph extends StatelessWidget {
final List<DataPoint> dataPoints;
final double? width;
final double height;
final double? maxY;
final double? maxX;
final Color spotColor;
final Color graphColor;
final Color graphShadowColor;
final Color graphGridColor;
final Color bottomLabelColor;
final double? bottomLabelSize;
final FontWeight? bottomLabelFontWeight;
///creates the left label and provide it to the chart as it will be used by other part of the application so the label will be different for every chart
final Widget Function(double value) leftLabelFormatter;
final Axis scrollDirection;
final bool showBottomTitleDates;
final bool isFullScreeGraph;
const CustomGraph({
super.key,
required this.dataPoints,
required this.leftLabelFormatter,
this.width,
required this.scrollDirection,
required this.height,
this.maxY,
this.maxX,
this.showBottomTitleDates = true,
this.isFullScreeGraph = false,
this.spotColor = AppColors.bgGreenColor,
this.graphColor = AppColors.bgGreenColor,
this.graphShadowColor = AppColors.graphGridColor,
this.graphGridColor = AppColors.graphGridColor,
this.bottomLabelColor = AppColors.textColor,
this.bottomLabelFontWeight = FontWeight.w500,
this.bottomLabelSize,
});
@override
Widget build(BuildContext context) {
// var maxY = 0.0;
double interval = 20;
if ((maxY ?? 0) > 10 && (maxY ?? 0) <= 20) {
interval = 2;
} else if ((maxY ?? 0) > 5 && (maxY ?? 0) <= 10) {
interval = 1;
} else if ((maxY ?? 0) >= 0 && (maxY ?? 0) <= 5) {
interval = .4;
}
return Material(
color: Colors.white,
child: SizedBox(
width: width,
height: height,
child: Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8),
child: LineChart(
LineChartData(
minY: 0,
maxY:
((maxY?.ceilToDouble() ?? 0.0) + interval).floorToDouble(),
// minX: dataPoints.first.labelValue - 1,
maxX: maxX,
minX: -0.2,
lineTouchData: LineTouchData(
getTouchLineEnd: (_, __) => 0,
getTouchedSpotIndicator: (barData, indicators) {
// Only show custom marker for touched spot
return indicators.map((int index) {
return TouchedSpotIndicatorData(
FlLine(color: Colors.transparent),
FlDotData(
show: true,
getDotPainter: (spot, percent, barData, idx) {
return FlDotCirclePainter(
radius: 8,
color: spotColor,
strokeWidth: 2,
strokeColor: Colors.white,
);
},
),
);
}).toList();
},
enabled: true,
touchTooltipData: LineTouchTooltipData(
getTooltipColor: (_) => Colors.white,
getTooltipItems: (touchedSpots) {
if (touchedSpots.isEmpty) return [];
// Only show tooltip for the first touched spot, hide others
return touchedSpots.map((spot) {
if (spot == touchedSpots.first) {
final dataPoint = dataPoints[spot.x.toInt()];
return LineTooltipItem(
// '${dataPoint.label} ${spot.y.toStringAsFixed(2)}',
'${dataPoint.value} ',
TextStyle(
color: Colors.black,
fontSize: 12.fSize,
fontWeight: FontWeight.w500),
);
}
return null; // hides the rest
}).toList();
},
),
),
titlesData: FlTitlesData(
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 77,
interval: .1, // Let fl_chart handle it
getTitlesWidget: (value, _) {
return leftLabelFormatter(value);
},
),
),
bottomTitles: AxisTitles(
axisNameSize: 60,
sideTitles: SideTitles(
showTitles: showBottomTitleDates,
reservedSize: 50,
getTitlesWidget: (value, _) {
if ((value.toDouble() >= 0) &&
(value.toDouble() < (maxX ?? dataPoints.length))) {
var label = dataPoints[value.toInt()].label;
return buildBottomLabel(label);
}
return const SizedBox.shrink();
},
interval: 1, // ensures 1:1 mapping with spots
),
),
topTitles: AxisTitles(),
rightTitles: AxisTitles(),
),
borderData: FlBorderData(
show: true,
border: const Border(
bottom: BorderSide.none,
left: BorderSide(color: Colors.grey, width: .5),
right: BorderSide.none,
top: BorderSide.none,
),
),
lineBarsData: _buildColoredLineSegments(dataPoints),
gridData: FlGridData(
show: true,
drawVerticalLine: false,
horizontalInterval: 20,
checkToShowHorizontalLine: (value) =>
value >= 0 && value <= 100,
getDrawingHorizontalLine: (value) {
return FlLine(
color: AppColors.graphGridColor,
strokeWidth: 1,
dashArray: [5, 5],
);
},
),
),
),
),
));
}
List<LineChartBarData> _buildColoredLineSegments(List<DataPoint> dataPoints) {
final List<FlSpot> allSpots = dataPoints.asMap().entries.map((entry) {
return FlSpot(entry.key.toDouble(), entry.value.value);
}).toList();
var data = [
LineChartBarData(
spots: allSpots,
isCurved: true,
isStrokeCapRound: true,
isStrokeJoinRound: true,
barWidth: 4,
gradient: LinearGradient(
colors: [graphColor, graphColor],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
dotData: FlDotData(
show: false,
),
belowBarData: BarAreaData(
show: true,
gradient: LinearGradient(
colors: [
graphShadowColor,
Colors.transparent,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
)
];
return data;
}
// Widget buildLabel(String label) {
// return Padding(
// padding: const EdgeInsets.only(right: 8),
// child: Text(
// label,
// style: TextStyle(
// fontSize: leftLabelSize ?? 8.fSize, color: leftLabelColor),
// textAlign: TextAlign.right,
// ),
// );
// }
Widget buildBottomLabel(String label) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
label,
style: TextStyle(
fontSize: bottomLabelSize ?? 8.fSize, color: bottomLabelColor),
),
);
}
}
final List<DataPoint> sampleData = [
DataPoint(
value: 20,
label: 'Jan 2024',
),
DataPoint(
value: 36,
label: 'Feb 2024',
),
DataPoint(
value: 80,
label: 'This result',
),
];

@ -55,7 +55,7 @@ dependencies:
uuid: ^4.5.1
health: ^13.1.3
# health: 12.0.1
fl_chart: ^1.0.0
fl_chart: ^1.1.1
geolocator: ^14.0.2
dropdown_search: ^6.0.2
google_maps_flutter: ^2.12.3

Loading…
Cancel
Save