|
|
|
|
@ -3,40 +3,43 @@ 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';
|
|
|
|
|
/// A customizable line graph widget using `fl_chart`.
|
|
|
|
|
///
|
|
|
|
|
/// 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()) {
|
|
|
|
|
/// Displays a line chart with configurable axis labels, colors, and data points.
|
|
|
|
|
/// Useful for visualizing time series or other sequential data.
|
|
|
|
|
///
|
|
|
|
|
/// 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();
|
|
|
|
|
/// },
|
|
|
|
|
/// **Parameters:**
|
|
|
|
|
/// - [dataPoints]: List of `DataPoint` objects to plot.
|
|
|
|
|
/// - [leftLabelFormatter]: Function to build left axis labels.
|
|
|
|
|
/// - [bottomLabelFormatter]: Function to build bottom axis labels.
|
|
|
|
|
/// - [width]: Optional width of the chart.
|
|
|
|
|
/// - [height]: Required height of the chart.
|
|
|
|
|
/// - [maxY], [maxX], [minX]: Axis bounds.
|
|
|
|
|
/// - [spotColor]: Color of the touched spot marker.
|
|
|
|
|
/// - [graphColor]: Color of the line.
|
|
|
|
|
/// - [graphShadowColor]: Color of the area below the line.
|
|
|
|
|
/// - [graphGridColor]: Color of the grid lines.
|
|
|
|
|
/// - [bottomLabelColor]: Color of bottom axis labels.
|
|
|
|
|
/// - [bottomLabelSize]: Font size for bottom axis labels.
|
|
|
|
|
/// - [bottomLabelFontWeight]: Font weight for bottom axis labels.
|
|
|
|
|
/// - [leftLabelInterval]: Interval between left axis labels.
|
|
|
|
|
/// - [leftLabelReservedSize]: Reserved space for left axis labels.
|
|
|
|
|
/// - [scrollDirection]: Axis direction for scrolling.
|
|
|
|
|
/// - [showBottomTitleDates]: Whether to show bottom axis labels.
|
|
|
|
|
/// - [isFullScreeGraph]: Whether the graph is fullscreen.
|
|
|
|
|
/// - [makeGraphBasedOnActualValue]: Use `actualValue` for plotting.
|
|
|
|
|
///
|
|
|
|
|
/// ),
|
|
|
|
|
/// Example usage:
|
|
|
|
|
/// ```dart
|
|
|
|
|
/// CustomGraph(
|
|
|
|
|
/// dataPoints: sampleData,
|
|
|
|
|
/// leftLabelFormatter: (value) => ...,
|
|
|
|
|
/// bottomLabelFormatter: (value, dataPoints) => ...,
|
|
|
|
|
/// height: 200,
|
|
|
|
|
/// scrollDirection: Axis.horizontal,
|
|
|
|
|
/// maxY: 100,
|
|
|
|
|
/// maxX: 2.5,
|
|
|
|
|
/// )
|
|
|
|
|
class CustomGraph extends StatelessWidget {
|
|
|
|
|
final List<DataPoint> dataPoints;
|
|
|
|
|
final double? width;
|
|
|
|
|
@ -51,6 +54,8 @@ class CustomGraph extends StatelessWidget {
|
|
|
|
|
final Color bottomLabelColor;
|
|
|
|
|
final double? bottomLabelSize;
|
|
|
|
|
final FontWeight? bottomLabelFontWeight;
|
|
|
|
|
final double? leftLabelInterval;
|
|
|
|
|
final double? leftLabelReservedSize;
|
|
|
|
|
|
|
|
|
|
///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) leftLabelFormatter;
|
|
|
|
|
@ -60,6 +65,7 @@ class CustomGraph extends StatelessWidget {
|
|
|
|
|
final Axis scrollDirection;
|
|
|
|
|
final bool showBottomTitleDates;
|
|
|
|
|
final bool isFullScreeGraph;
|
|
|
|
|
final bool makeGraphBasedOnActualValue;
|
|
|
|
|
|
|
|
|
|
const CustomGraph({
|
|
|
|
|
super.key,
|
|
|
|
|
@ -79,6 +85,9 @@ class CustomGraph extends StatelessWidget {
|
|
|
|
|
this.bottomLabelColor = AppColors.textColor,
|
|
|
|
|
this.bottomLabelFontWeight = FontWeight.w500,
|
|
|
|
|
this.bottomLabelSize,
|
|
|
|
|
this.leftLabelInterval,
|
|
|
|
|
this.leftLabelReservedSize,
|
|
|
|
|
this.makeGraphBasedOnActualValue = false,
|
|
|
|
|
required this.bottomLabelFormatter,
|
|
|
|
|
this.minX,
|
|
|
|
|
});
|
|
|
|
|
@ -87,13 +96,7 @@ class CustomGraph extends StatelessWidget {
|
|
|
|
|
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(
|
|
|
|
|
@ -102,11 +105,11 @@ class CustomGraph extends StatelessWidget {
|
|
|
|
|
child: LineChart(
|
|
|
|
|
LineChartData(
|
|
|
|
|
minY: 0,
|
|
|
|
|
maxY:
|
|
|
|
|
((maxY?.ceilToDouble() ?? 0.0) + interval).floorToDouble(),
|
|
|
|
|
// maxY: ((maxY?.ceilToDouble() ?? 0.0) + interval).floorToDouble(),
|
|
|
|
|
maxY: maxY,
|
|
|
|
|
// minX: dataPoints.first.labelValue - 1,
|
|
|
|
|
maxX: maxX,
|
|
|
|
|
minX: minX ??-0.2,
|
|
|
|
|
minX: minX ,
|
|
|
|
|
lineTouchData: LineTouchData(
|
|
|
|
|
getTouchLineEnd: (_, __) => 0,
|
|
|
|
|
getTouchedSpotIndicator: (barData, indicators) {
|
|
|
|
|
@ -140,7 +143,7 @@ class CustomGraph extends StatelessWidget {
|
|
|
|
|
|
|
|
|
|
return LineTooltipItem(
|
|
|
|
|
// '${dataPoint.label} ${spot.y.toStringAsFixed(2)}',
|
|
|
|
|
'${dataPoint.actualValue} ${dataPoint.displayTime}',
|
|
|
|
|
'${dataPoint.value} - ${dataPoint.actualValue} - ${dataPoint.displayTime}',
|
|
|
|
|
TextStyle(
|
|
|
|
|
color: Colors.black,
|
|
|
|
|
fontSize: 12.fSize,
|
|
|
|
|
@ -156,8 +159,8 @@ class CustomGraph extends StatelessWidget {
|
|
|
|
|
leftTitles: AxisTitles(
|
|
|
|
|
sideTitles: SideTitles(
|
|
|
|
|
showTitles: true,
|
|
|
|
|
reservedSize: 77,
|
|
|
|
|
interval: .1, // Let fl_chart handle it
|
|
|
|
|
reservedSize: leftLabelReservedSize??80,
|
|
|
|
|
interval: leftLabelInterval ?? .1, // Let fl_chart handle it
|
|
|
|
|
getTitlesWidget: (value, _) {
|
|
|
|
|
return leftLabelFormatter(value);
|
|
|
|
|
},
|
|
|
|
|
@ -190,12 +193,12 @@ class CustomGraph extends StatelessWidget {
|
|
|
|
|
gridData: FlGridData(
|
|
|
|
|
show: true,
|
|
|
|
|
drawVerticalLine: false,
|
|
|
|
|
horizontalInterval: 20,
|
|
|
|
|
// horizontalInterval: 40,
|
|
|
|
|
checkToShowHorizontalLine: (value) =>
|
|
|
|
|
value >= 0 && value <= 100,
|
|
|
|
|
getDrawingHorizontalLine: (value) {
|
|
|
|
|
return FlLine(
|
|
|
|
|
color: AppColors.graphGridColor,
|
|
|
|
|
color: graphGridColor,
|
|
|
|
|
strokeWidth: 1,
|
|
|
|
|
dashArray: [5, 5],
|
|
|
|
|
);
|
|
|
|
|
@ -208,7 +211,9 @@ class CustomGraph extends StatelessWidget {
|
|
|
|
|
|
|
|
|
|
List<LineChartBarData> _buildColoredLineSegments(List<DataPoint> dataPoints) {
|
|
|
|
|
final List<FlSpot> allSpots = dataPoints.asMap().entries.map((entry) {
|
|
|
|
|
return FlSpot(entry.key.toDouble(), entry.value.value);
|
|
|
|
|
double value = (makeGraphBasedOnActualValue)?double.tryParse(entry.value.actualValue)??0.0:entry.value.value;
|
|
|
|
|
debugPrint("the value is $value");
|
|
|
|
|
return FlSpot(entry.key.toDouble(), value);
|
|
|
|
|
}).toList();
|
|
|
|
|
|
|
|
|
|
var data = [
|
|
|
|
|
|