Forked from cirediew/single_bundle_symbol_renderer.dart
Created
January 30, 2021 18:41
-
-
Save ARIFCSE10/080c57a6bf901b695ca8912126a55b44 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:math' show Rectangle; | |
import 'package:my_app/database/database.dart'; | |
import 'package:my_app/util/chart/tooltip_data.dart'; | |
import 'package:charts_flutter/flutter.dart' | |
show | |
CircleSymbolRenderer, | |
Color, | |
SelectionModel, | |
ChartCanvas, | |
FillPatternType; | |
import 'package:charts_flutter/src/text_element.dart'; // ignore: implementation_imports | |
import 'package:charts_flutter/src/text_style.dart'; // ignore: implementation_imports | |
import 'package:equatable/equatable.dart'; | |
import 'package:meta/meta.dart'; | |
class SingleBundleSymbolRenderer extends CircleSymbolRenderer | |
with EquatableMixin { | |
final Color textColor; | |
final Color backgroundColor; | |
final Color strokeColor; | |
final EnergyAssetCategory category; | |
final TooltipData tooltipData; | |
final SelectionModel<DateTime> model; | |
final int horizontalMargin; | |
final int verticalMargin; | |
final int bottomPadding; | |
final int textSize; | |
final double textScaleFactor; | |
final TextStyle textStyle; | |
SingleBundleSymbolRenderer({ | |
@required this.model, | |
@required this.tooltipData, | |
@required this.textColor, | |
@required this.backgroundColor, | |
@required this.strokeColor, | |
this.category, | |
this.horizontalMargin = 4, | |
this.verticalMargin = 7, | |
this.bottomPadding = 4, | |
this.textSize = 14, | |
this.textScaleFactor = 1.0, | |
bool isSolid = true, | |
}) : textStyle = TextStyle() | |
..color = textColor | |
..fontSize = textSize, | |
super(isSolid: isSolid); | |
@override | |
bool shouldRepaint(SingleBundleSymbolRenderer oldRenderer) => | |
this != oldRenderer; | |
@override | |
List<Object> get props => [ | |
model, | |
tooltipData, | |
textColor, | |
backgroundColor, | |
strokeColor, | |
category, | |
horizontalMargin, | |
verticalMargin, | |
bottomPadding, | |
textSize, | |
textScaleFactor, | |
isSolid, | |
textStyle, | |
]; | |
@override | |
void paint( | |
ChartCanvas canvas, | |
Rectangle<num> bounds, { | |
List<int> dashPattern, | |
Color fillColor, | |
FillPatternType fillPattern, | |
Color strokeColor, | |
double strokeWidthPx, | |
}) { | |
super.paint( | |
canvas, | |
bounds, | |
dashPattern: dashPattern, | |
fillColor: fillColor, | |
strokeColor: strokeColor, | |
strokeWidthPx: strokeWidthPx, | |
); | |
if (tooltipData.dateIsInFuture) { | |
return; | |
} | |
TextElement textElement = category != null | |
? TextElement( | |
'${tooltipData.formattedIndex}\n' | |
'${category.title}: ${tooltipData.formattedValue}', | |
style: textStyle, | |
textScaleFactor: tooltipData.textScaleFactor, | |
) | |
: TextElement( | |
'${tooltipData.formattedIndex}\n' | |
'${tooltipData.formattedValue}', | |
style: textStyle, | |
textScaleFactor: tooltipData.textScaleFactor, | |
); | |
final offsetX = bounds.left - | |
(textElement.measurement.horizontalSliceWidth * | |
(tooltipData.index / | |
((tooltipData.size - 1 == 0 ? 1 : tooltipData.size - 1)))); | |
final offsetY = bounds.top - | |
textElement.measurement.verticalSliceWidth - | |
verticalMargin; | |
canvas.drawRect( | |
Rectangle( | |
offsetX - horizontalMargin, | |
offsetY - verticalMargin - bottomPadding, | |
textElement.measurement.horizontalSliceWidth + horizontalMargin * 2, | |
textElement.measurement.verticalSliceWidth + verticalMargin * 2, | |
), | |
fill: backgroundColor, | |
stroke: strokeColor, | |
strokeWidthPx: 1, | |
); | |
canvas.drawText( | |
textElement, | |
offsetX.toInt(), | |
offsetY.toInt() - bottomPadding, | |
); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:my_app/database/database.dart'; | |
import 'package:my_app/util/extensions/iterable.ext.dart'; //used for firstOrNull | |
import 'package:my_app/util/number_formatter.dart'; | |
import 'package:charts_flutter/flutter.dart'; | |
import 'package:equatable/equatable.dart'; | |
import 'package:flutter/cupertino.dart'; | |
import 'package:intl/intl.dart'; | |
class TooltipData with EquatableMixin { | |
num value = 0; | |
String formattedValue = ''; | |
String formattedIndex = ''; | |
int index = 0; | |
int size = 0; | |
int fractionDigits = 2; | |
bool dateIsInFuture = false; | |
int textSize = 14; | |
double textScaleFactor = 1.0; | |
NumberFormat format = NumberFormat.decimalPattern('en'); | |
TooltipData({ | |
this.value, | |
this.formattedValue, | |
this.formattedIndex, | |
this.index, | |
this.size, | |
this.fractionDigits, | |
}); | |
@override | |
List get props => [ | |
value, | |
formattedValue, | |
formattedIndex, | |
index, | |
size, | |
fractionDigits, | |
dateIsInFuture, | |
textSize, | |
textScaleFactor, | |
]; | |
void updateFromModel( | |
BuildContext context, { | |
SelectionModel<DateTime> selectionModel, | |
EnergyAssetCategory category, | |
DateFormat dateFormat, | |
double textScaleFactor, | |
}) { | |
value = selectionModel.selectedSeries.firstOrNull?.measureFn( | |
selectionModel.selectedDatum.firstOrNull?.index, | |
); | |
format = decimalFormat( | |
decimalDigits: fractionDigits ?? category.fractionDigits, | |
); | |
formattedValue = '${format.format(value)} ${category.suffix}'; | |
final date = selectionModel.selectedSeries.firstOrNull?.domainFn( | |
selectionModel.selectedDatum.firstOrNull?.index, | |
); | |
dateIsInFuture = date?.isAfter(DateTime.now()) ?? false; | |
formattedIndex = dateFormat.format(date); | |
index = selectionModel.selectedDatum.firstOrNull?.index; | |
size = selectionModel.selectedSeries.firstOrNull?.data?.length; | |
this.textScaleFactor = textScaleFactor; | |
} | |
@override | |
String toString() => 'TooltipData{' | |
'hash: $hashCode, ' | |
'value: $value, ' | |
'formattedValue: $formattedValue, ' | |
'formattedIndex: $formattedIndex, ' | |
'index: $index, ' | |
'size: $size, ' | |
'dateIsInFuture: $dateIsInFuture}'; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:my_app/database/data_classes/bundle_chart_data.dart'; | |
import 'package:my_app/database/database.dart'; | |
import 'package:my_app/util/chart/chart_util.dart'; | |
import 'package:my_app/util/chart/custom_date_time_factory.dart'; | |
import 'package:my_app/util/chart/single_bundle_symbol_renderer.dart'; | |
import 'package:my_app/util/chart/tooltip_data.dart'; | |
import 'package:charts_common/common.dart' show SymbolRenderer; | |
import 'package:charts_flutter/flutter.dart'; | |
import 'package:equatable/equatable.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:intl/intl.dart'; | |
class YearChart extends StatefulWidget { | |
final EnergyAssetCategory category; | |
final List<Series<ChartDataPoint, DateTime>> seriesList; | |
const YearChart(this.seriesList, this.category); | |
@override | |
_YearChartState createState() => _YearChartStateState(); | |
} | |
class _YearChartState extends State<YearChart> { | |
SelectionModel<DateTime> _selectionModel; | |
TooltipData _tooltipData; | |
MarginSpec _marginSpec; | |
@override | |
void initState() { | |
super.initState(); | |
_tooltipData = TooltipData(fractionDigits: 0); | |
_marginSpec = MarginSpec.fromPercent( | |
minPercent: 5, | |
maxPercent: 50, | |
); | |
} | |
@override | |
Widget build(BuildContext context) { | |
final Color textColor = | |
ColorUtil.fromDartColor(Theme.of(context).colorScheme.onSurface); | |
final textScaleFactor = MediaQuery.textScaleFactorOf(context); | |
if (_tooltipData.textScaleFactor != textScaleFactor) { | |
_tooltipData.textScaleFactor = textScaleFactor; | |
} | |
return TimeSeriesChart( | |
widget.seriesList, | |
layoutConfig: LayoutConfig( | |
leftMarginSpec: _marginSpec, | |
topMarginSpec: MarginSpec.fromPercent( | |
minPercent: 10, | |
maxPercent: 50, | |
), | |
rightMarginSpec: MarginSpec.defaultSpec, | |
bottomMarginSpec: _marginSpec, | |
), | |
defaultRenderer: | |
BarRendererConfig<DateTime>(groupingType: BarGroupingType.stacked), | |
dateTimeFactory: | |
CustomDateTimeFactory(Localizations.localeOf(context).languageCode), | |
primaryMeasureAxis: NumericAxisSpec( | |
showAxisLine: false, | |
renderSpec: SmallTickRendererSpec<num>( | |
labelStyle: TextStyleSpec( | |
color: textColor, | |
fontSize: (ChartUtil.defaultLabelSize * textScaleFactor).round()), | |
), | |
), | |
domainAxis: DateTimeAxisSpec( | |
renderSpec: SmallTickRendererSpec<DateTime>( | |
labelStyle: TextStyleSpec( | |
color: textColor, | |
fontSize: (ChartUtil.defaultLabelSize * textScaleFactor).round()), | |
), | |
tickFormatterSpec: const AutoDateTimeTickFormatterSpec( | |
minute: ChartUtil.emptyFormatterSpec, | |
hour: ChartUtil.emptyFormatterSpec, | |
day: ChartUtil.emptyFormatterSpec, | |
month: ChartUtil.monthFormatterSpec, | |
year: ChartUtil.yearFormatterSpec, | |
), | |
), | |
behaviors: [ | |
SelectNearest(), | |
DomainHighlighter(), | |
CustomLinePointHighlighter( | |
symbolRenderer: SingleBundleSymbolRenderer( | |
model: _selectionModel, | |
tooltipData: _tooltipData, | |
textColor: textColor, | |
textScaleFactor: textScaleFactor, | |
backgroundColor: ColorUtil.fromDartColor( | |
Theme.of(context).canvasColor, | |
), | |
strokeColor: ColorUtil.fromDartColor( | |
widget.category.getColor(), | |
), | |
), | |
drawFollowLinesAcrossChart: true, | |
showVerticalFollowLine: LinePointHighlighterFollowLineType.none, | |
showHorizontalFollowLine: LinePointHighlighterFollowLineType.all, | |
defaultRadiusPx: 0, | |
), | |
], | |
selectionModels: [ | |
SelectionModelConfig( | |
changedListener: (SelectionModel<DateTime> model) { | |
if (model != null && model.hasAnySelection) { | |
_tooltipData.updateFromModel(context, | |
selectionModel: model, | |
category: widget.category, | |
dateFormat: DateFormat.MMMM(), | |
textScaleFactor: textScaleFactor); | |
} | |
}, | |
), | |
], | |
); | |
} | |
} | |
///Overridden class because [symbolRenderer] is missing from equals and hashcode in [LinePointHighlighter] | |
class CustomLinePointHighlighter extends LinePointHighlighter | |
with EquatableMixin { | |
CustomLinePointHighlighter({ | |
SelectionModelType selectionModelType, | |
double defaultRadiusPx, | |
double radiusPaddingPx, | |
LinePointHighlighterFollowLineType showHorizontalFollowLine, | |
LinePointHighlighterFollowLineType showVerticalFollowLine, | |
List<int> dashPattern, | |
bool drawFollowLinesAcrossChart, | |
SymbolRenderer symbolRenderer, | |
}) : super( | |
selectionModelType: selectionModelType, | |
defaultRadiusPx: defaultRadiusPx, | |
radiusPaddingPx: radiusPaddingPx, | |
showHorizontalFollowLine: showHorizontalFollowLine, | |
showVerticalFollowLine: showVerticalFollowLine, | |
dashPattern: dashPattern, | |
drawFollowLinesAcrossChart: drawFollowLinesAcrossChart, | |
symbolRenderer: symbolRenderer, | |
); | |
@override | |
List<Object> get props => [ | |
selectionModelType, | |
defaultRadiusPx, | |
radiusPaddingPx, | |
showHorizontalFollowLine, | |
showVerticalFollowLine, | |
dashPattern, | |
drawFollowLinesAcrossChart, | |
symbolRenderer, | |
]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment