@ -6,14 +6,26 @@ import 'package:intl/intl.dart';
class DynamicResultChart extends StatelessWidget {
final List < DataPoint > dataPoints ;
final List < ThresholdRange > thresholds ;
final double ? width ;
final double height ;
final double ? maxX ;
final Axis scrollDirection ;
final bool isFullScreenGraph ;
const DynamicResultChart (
{ super . key , required this . dataPoints , required this . thresholds } ) ;
{ super . key , required this . dataPoints , required this . thresholds ,required this . width , required this . scrollDirection , required this . height , this . maxX , this . isFullScreenGraph = false }) ;
@ override
Widget build ( BuildContext context ) {
final minY = thresholds . first . value ;
final maxY = thresholds . last . value + 1 ;
var minY = 0.0 ;
var maxY = 0.0 ;
if ( thresholds . isNotEmpty ) {
print ( " the thresholds are $ thresholds " ) ;
minY = thresholds . first . value ;
maxY = thresholds . last . value + 1 ;
} else {
return SizedBox . shrink ( ) ;
}
final spots = dataPoints . asMap ( ) . entries . map ( ( entry ) {
return FlSpot ( entry . key . toDouble ( ) , entry . value . value ) ;
@ -24,130 +36,127 @@ class DynamicResultChart extends StatelessWidget {
return Material (
color: Colors . white ,
child: SizedBox (
height: MediaQuery . sizeOf ( context ) . height / 4 ,
child: SingleChildScrollView (
scrollDirection: Axis . horizontal ,
child: SizedBox (
width: MediaQuery . sizeOf ( context ) . width - 77 ,
child: Padding (
padding: const EdgeInsets . only ( top: 8.0 , bottom: 8 ) ,
child: LineChart (
LineChartData (
minY: minY ,
maxY: maxY ,
minX: dataPoints . first . labelValue - 1 ,
maxX: dataPoints . first . labelValue + 1 ,
lineTouchData:
LineTouchData ( touchTooltipData: LineTouchTooltipData (
getTooltipItems: ( touchedSpots ) {
if ( touchedSpots . isEmpty ) return [ ] ;
width: width ,
height: height ,
child: Padding (
padding: const EdgeInsets . only ( top: 8.0 , bottom: 8 ) ,
child: LineChart (
LineChartData (
minY: minY ,
maxY: maxY ,
minX: dataPoints . first . labelValue - 1 ,
maxX: maxX ,
lineTouchData:
LineTouchData ( touchTooltipData: LineTouchTooltipData (
getTooltipItems: ( touchedSpots ) {
if ( touchedSpots . isEmpty ) return [ ] ;
/ / Only show tooltip for the first touched spot , hide others
return touchedSpots . map ( ( spot ) {
if ( spot = = touchedSpots . first ) {
return LineTooltipItem (
' ${ spot . y } ' ,
const TextStyle ( color: Colors . white ) ,
) ;
}
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 , _ ) {
/ / print ( " the value is ======== ${ value } " ) ;
/ / 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 ) } ' ,
const TextStyle ( color: Colors . white ) ,
) ;
}
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 , _ ) {
/ / print ( " the value is ======== ${ value } " ) ;
/ / Compare with 2 - decimal precision to avoid close duplicates
final matchingThreshold = thresholds . firstWhere (
( t ) = >
t . value . toStringAsFixed ( 1 ) = =
value . toStringAsFixed ( 1 ) ,
orElse: ( ) = > ThresholdRange (
label: ' ' ,
value: 0 ,
color: Colors . transparent ,
lineColor: Colors . transparent ) ,
) ;
/ / Compare with 2 - decimal precision to avoid close duplicates
final matchingThreshold = thresholds . firstWhere (
( t ) = >
t . value . toStringAsFixed ( 1 ) = =
value . toStringAsFixed ( 1 ) ,
orElse: ( ) = > ThresholdRange (
label: ' ' ,
value: 0 ,
color: Colors . transparent ,
lineColor: Colors . transparent ) ,
) ;
var actualValue = ( matchingThreshold . actualValue ! =
null )
? " ${ TranslationBase . of ( context ) . getTranslation ( matchingThreshold . label ) } ( ${ matchingThreshold . actualValue } ) "
: ' ${ TranslationBase . of ( context ) . getTranslation ( matchingThreshold . label ) } ' ;
if ( matchingThreshold . label . isNotEmpty ) {
return Text (
actualValue ,
style: const TextStyle ( fontSize: 10 ) ,
) ;
}
return const SizedBox . shrink ( ) ;
} ,
) ,
) ,
bottomTitles: AxisTitles (
axisNameSize: 60 ,
sideTitles: SideTitles (
showTitles: true ,
reservedSize: 50 ,
getTitlesWidget: ( value , _ ) {
if ( value . toInt ( ) > = 0 & &
value . toInt ( ) < dataPoints . length ) {
var label = dataPoints [ value . toInt ( ) ] . label ;
if ( dataPoints [ value . toInt ( ) ] . isStringResource ) {
label = TranslationBase . of ( context )
. getTranslation (
dataPoints [ value . toInt ( ) ] . label ) ;
}
var actualValue = ( matchingThreshold . actualValue ! =
null )
? " ${ TranslationBase . of ( context ) . getTranslation ( matchingThreshold . label ) } ( ${ matchingThreshold . actualValue } ) "
: ' ${ TranslationBase . of ( context ) . getTranslation ( matchingThreshold . label ) } ' ;
if ( matchingThreshold . label . isNotEmpty ) {
return Text (
actualValue ,
style: const TextStyle ( fontSize: 10 ) ,
) ;
}
return const SizedBox . shrink ( ) ;
} ,
) ,
) ,
bottomTitles: AxisTitles (
axisNameSize: 60 ,
sideTitles: SideTitles (
showTitles: ! isFullScreenGraph ,
reservedSize: 50 ,
getTitlesWidget: ( value , _ ) {
if ( value . toInt ( ) > = 0 & &
value . toInt ( ) < dataPoints . length ) {
var label = dataPoints [ value . toInt ( ) ] . label ;
if ( dataPoints [ value . toInt ( ) ] . isStringResource ) {
label = TranslationBase . of ( context )
. getTranslation (
dataPoints [ value . toInt ( ) ] . label ) ;
}
return Padding (
padding: const EdgeInsets . only ( top: 8.0 ) ,
child: Text (
label ,
style: const TextStyle ( fontSize: 12 ) ,
) ,
) ;
}
return const SizedBox . shrink ( ) ;
} ,
interval: 1 , / / ensures 1 : 1 mapping with spots
return Padding (
padding: EdgeInsetsDirectional . only ( top: 8.0 , ) ,
child: Text (
label ,
style: const TextStyle ( fontSize: 12 ) ,
) ,
) ,
topTitles: AxisTitles ( ) ,
rightTitles: AxisTitles ( ) ,
) ,
borderData: FlBorderData ( show: false ) ,
lineBarsData:
_buildColoredLineSegments ( dataPoints , thresholds ) ,
gridData: FlGridData ( show: false ) ,
extraLinesData: ExtraLinesData (
horizontalLines: thresholds . map ( ( t ) {
return HorizontalLine (
y: t . value ,
color: t . lineColor ,
strokeWidth: 2 ,
/ / label: HorizontalLineLabel (
/ / show: true ,
/ / alignment: Alignment . centerLeft ,
/ / style: const TextStyle ( fontSize: 10 ) ,
/ / labelResolver: ( _ ) = > ' ${ t . label } ( ${ t . value . toStringAsFixed ( 2 ) } ) ' ,
/ / ) ,
) ;
} ) . toList ( ) ,
) ,
rangeAnnotations: RangeAnnotations (
horizontalRangeAnnotations: _buildRangeShades ( thresholds ) ,
) ,
) ,
) ;
}
return const SizedBox . shrink ( ) ;
} ,
interval: 1 , / / ensures 1 : 1 mapping with spots
) ,
) ,
topTitles: AxisTitles ( ) ,
rightTitles: AxisTitles ( ) ,
) ,
borderData: FlBorderData ( show: false ) ,
lineBarsData:
_buildColoredLineSegments ( dataPoints , thresholds ) ,
gridData: FlGridData ( show: false ) ,
extraLinesData: ExtraLinesData (
horizontalLines: thresholds . map ( ( t ) {
return HorizontalLine (
y: t . value ,
color: t . lineColor ,
strokeWidth: 2 ,
/ / label: HorizontalLineLabel (
/ / show: true ,
/ / alignment: Alignment . centerLeft ,
/ / style: const TextStyle ( fontSize: 10 ) ,
/ / labelResolver: ( _ ) = > ' ${ t . label } ( ${ t . value . toStringAsFixed ( 2 ) } ) ' ,
/ / ) ,
) ;
} ) . toList ( ) ,
) ,
rangeAnnotations: RangeAnnotations (
horizontalRangeAnnotations: _buildRangeShades ( thresholds ) ,
) ,
) ,
) ) ;
) ,
) ,
) ) ;
}
List < LineChartBarData > _buildColoredLineSegments (
@ -186,12 +195,13 @@ class DynamicResultChart extends StatelessWidget {
}
/ / Add dot markers separately so they are on top
final List < FlSpot > allSpots = dataPoints . asMap ( ) . entries . map ( ( entry ) {
return FlSpot ( entry . key . toDouble ( ) , entry . value . value ) ;
} ) . toList ( ) ;
print ( " the spots are $ allSpots " ) ;
return [
var data = [
. . . segments ,
LineChartBarData (
spots: allSpots ,
@ -212,6 +222,10 @@ class DynamicResultChart extends StatelessWidget {
) ,
)
] ;
var max = LineChartHelper . calculateMaxAxisValues ( data ) . maxX ;
print ( " the maxX is the -------> $ max " ) ;
return data ;
}
List < HorizontalRangeAnnotation > _buildRangeShades (
@ -226,6 +240,8 @@ class DynamicResultChart extends StatelessWidget {
}
return ranges ;
}
}
final List < DataPoint > sampleData = [