Merge branch 'master' of http://34.17.52.180/Haroon6138/HMG_Patient_App_New into dev_sultan
						commit
						32c7608c83
					
				| @ -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)})'; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -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', | ||||||
|  |   ), | ||||||
|  | ]; | ||||||
					Loading…
					
					
				
		Reference in New Issue