I have confused with working of flutter_graph. I want to two help yu guys.
I trying to make datetetime charts using charts_flutter package.
I want to make x-axis value 1-2-2018 format instead of oct-2017(this is default style). I want to update all x-values tp dd-MM-YYY style. How to do that,.
2)I want to make update domainAxis in charts.DateTimeAxisSpec viewport. How to update start and end properity in correct format? i actually iam using API value. so its not static, its dynamic, its changes all time. so how to update viewport in properly.
I am stucking in this two things. here i am sharing the model one code. Please add your things.
class LineChart extends StatefulWidget {
final List<LineChartModel> firstGraph;
const LineChart({
Key? key,
required this.firstGraph,
}) : super(key: key);
#override
State<LineChart> createState() => _LineChartState();
}
class _LineChartState extends State<LineChart> {
//late AnalyticsNotifier noti;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
List<charts.Series<LineChartModel, DateTime>> series = [
charts.Series<LineChartModel, DateTime>(
id: 'Graph1',
colorFn: (_, __) => charts.MaterialPalette.deepOrange.shadeDefault,
domainFn: (LineChartModel sales, _) => sales.date,
measureFn: (LineChartModel sales, _) => sales.count,
data: widget.firstGraph,
),
];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: charts.TimeSeriesChart(
series,
animate: true,
behaviors: [
charts.SlidingViewport(),
charts.PanAndZoomBehavior(),
charts.ChartTitle('Day',
behaviorPosition: charts.BehaviorPosition.bottom,
titleStyleSpec: const charts.TextStyleSpec(fontSize: 15),
titleOutsideJustification:
charts.OutsideJustification.middleDrawArea),
charts.ChartTitle('Count of observations',
behaviorPosition: charts.BehaviorPosition.start,
titleStyleSpec: const charts.TextStyleSpec(fontSize: 15),
titleOutsideJustification:
charts.OutsideJustification.middleDrawArea),
],
dateTimeFactory: const charts.LocalDateTimeFactory(),
domainAxis: charts.DateTimeAxisSpec(//how to add this one in proper.
viewport: charts.DateTimeExtents(
start: widget.firstGraph.first.date,
end: widget.firstGraph[5].date,
),
renderSpec: const charts.SmallTickRendererSpec(
labelCollisionOffsetFromAxisPx: 35,
labelCollisionRotation: -80,
// Tick and Label styling here.
labelStyle: charts.TextStyleSpec(
fontSize: 12, // size in Pts.
fontFamily: 'Montserrat',
color: charts.MaterialPalette.black,
),
)),
primaryMeasureAxis: const charts.NumericAxisSpec(
//viewport: charts.NumericExtents(0, 10),
renderSpec: charts.GridlineRendererSpec(
// Tick and Label styling here.
labelStyle: charts.TextStyleSpec(
fontSize: 9, // size in Pts.
fontFamily: 'Montserrat',
color: charts.MaterialPalette.black,
),
),
),
defaultRenderer: charts.LineRendererConfig(
includeArea: true,
includeLine: true,
areaOpacity: 0.25,
includePoints: true,
layoutPaintOrder: 1,
radiusPx: 3,
roundEndCaps: false,
strokeWidthPx: 1,
),
),
)
],
);
}
}
class LineChartModel {
final DateTime date;
final int count;
LineChartModel(
this.date,
this.count,
);
}
Related
So I am stuck into trying to paint the different value for a selected line in a time series chart. soo basically what I am trying to achieve is show the comparison on the values inside the series of the chart. I will upload some code and embed the deployed link for the sample program. this was done using dart and flutter
This is the code that is responsible for the series inside the chart:
List<charts.Series<StockSeries, DateTime>> series = [
charts.Series(
id: "strategyReturns",
data: chartData,
domainFn: (StockSeries series, _) => series.date,
measureFn: (StockSeries series, _) => series.strategyReturns,
colorFn: (StockSeries series, _) => series.strategyReturnsColor),
charts.Series(
id: "pSEiReturns",
data: chartData,
domainFn: (StockSeries series, _) => series.date,
measureFn: (StockSeries series, _) => series.pSEiReturns,
colorFn: (StockSeries series, _) => series.pSEiReturnsColor),
];
this is the code that is responsible for drawing the chart and here also is where I think the problem is:
return Container(
height: 500,
padding: const EdgeInsets.all(25),
child: Card(
child: Padding(
padding: const EdgeInsets.all(9.0),
child: Column(children: <Widget>[
Text(
"Chart",
style: Theme.of(context).textTheme.bodyText2,
),
Expanded(
child: charts.TimeSeriesChart(
series,
animate: true,
defaultRenderer: charts.LineRendererConfig(),
dateTimeFactory: const charts.LocalDateTimeFactory(),
behaviors: [
charts.SeriesLegend(),
charts.SlidingViewport(),
charts.PanAndZoomBehavior(),
charts.LinePointHighlighter(
symbolRenderer: CustomCircleSymbolRenderer(),
)
],
selectionModels: [
charts.SelectionModelConfig(
changedListener: (charts.SelectionModel model) {
if (model.hasDatumSelection) {
final value = model.selectedSeries[0]
.measureFn(model.selectedDatum[0].index);
CustomCircleSymbolRenderer.value =
value.toString(); // paints the tapped value
}
})
],
domainAxis: charts.DateTimeAxisSpec(
tickProviderSpec: const charts.DayTickProviderSpec(
increments: [15]), // View in increments of 30 days
viewport: charts.DateTimeExtents(
start: DateTime(
chartData.last.date.year,
chartData.last.date.month - 3,
chartData.last.date
.day), // Start Date 6 months before current date
end: DateTime(chartData.last.date.year,
chartData.last.date.month + 1, chartData.last.date.day),
),
),
primaryMeasureAxis: charts.NumericAxisSpec(
viewport: const charts.NumericExtents(-30, 30),
tickFormatterSpec:
charts.BasicNumericTickFormatterSpec.fromNumberFormat(
NumberFormat("#.##")),
tickProviderSpec: const charts.BasicNumericTickProviderSpec(
zeroBound: false, dataIsInWholeNumbers: false)),
))
]),
),
),
);
I pasted the whole part of the chart code. But the one responsible for painting the values are this part of the code
symbolRenderer: CustomCircleSymbolRenderer(),
)
],
selectionModels: [
charts.SelectionModelConfig(
changedListener: (charts.SelectionModel model) {
if (model.hasDatumSelection) {
final value = model.selectedSeries[0]
.measureFn(model.selectedDatum[0].index);
CustomCircleSymbolRenderer.value =
value.toString(); // paints the tapped value
}
})
and this part is responsible on painting a rectangle when you click a part of the graph and this is where the value comes from:
void paint(charts.ChartCanvas canvas, Rectangle<num> bounds,
{List<int>? dashPattern,
charts.Color? fillColor,
charts.FillPatternType? fillPattern,
charts.Color? strokeColor,
double? strokeWidthPx}) {
super.paint(canvas, bounds,
dashPattern: dashPattern,
fillColor: fillColor,
fillPattern: fillPattern,
strokeColor: strokeColor,
strokeWidthPx: strokeWidthPx);
canvas.drawRect(
Rectangle(bounds.left - 5, bounds.top - 30, bounds.width + 10,
bounds.height + 10),
fill: charts.Color.white);
var textStyle = style.TextStyle();
textStyle.color = charts.Color.black;
textStyle.fontSize = 15;
canvas.drawText(charts_text.TextElement("$value", style: textStyle),
(bounds.left).round(), (bounds.top - 28).round());
image:
here is the sample of the problem. in the chart it paints -7.317 which is the value of the red dot, what I want to achieve is if I tap on the red dot it will show -7.317 and also show the value of the green dot which should be -1.46 and vice versa
if you are willing to help I can explain it more in depth through meeting. I will also post the deployed version for you to try out the graph. link: https://knndeploy.herokuapp.com/#/
I am Creating a ScatterPlot chart based on the data in which I will show TimeStamp on the domain Axis(X-Axis). I have already built Bar and TimeSeries chart successfully. In case of ScatterPlot, it takes Series<T,D> D as num. I tried using epoch time but not getting much further as it should show time and also not able to add viewPort if iN terms of int only. Below is what I have tried.
Creating Series :
List<charts.Series<ValueAtTime, int>> _getScatterPlotSeries() {
List<charts.Series<ValueAtTime, int>> chartsSeriesList = [];
chartsSeriesList = _ccdList
.map((ccd) => charts.Series<ValueAtTime, int>(
id: ccd.dataType,
data: ccd.data,
domainFn: (datum, _) => DateTime.parse(datum.date).millisecond,
measureFn: (datum, _) => datum.value,
colorFn: (datum, _) =>
charts.ColorUtil.fromDartColor(datum.color),
strokeWidthPxFn: (datum, _) => 2.0,
))
.toList();
var lineData = [
ValueAtTime(
date: _ccdList.first.data.first.date,
value: _ccdList.first.data.first.value,
color: Colors.red,
),
ValueAtTime(
date: _ccdList.last.data.last.date,
value: _ccdList.last.data.last.value,
color: Colors.blue,
),
];
chartsSeriesList.add(
charts.Series(
id: 'Line',
data: lineData,
domainFn: (datum, _) => DateTime.parse(datum.date).second,
measureFn: (datum, _) => datum.value,
colorFn: (datum, _) => charts.ColorUtil.fromDartColor(datum.color),
)..setAttribute(charts.rendererIdKey, 'customLine'),
);
return chartsSeriesList;
}
Then while setting up the Chart :
Container(
color: Colors.white,
height: 350,
width: double.infinity,
child: charts.ScatterPlotChart(
_getScatterPlotSeries(),
animate: true,
domainAxis: charts.NumericAxisSpec(
renderSpec: charts.SmallTickRendererSpec(
labelStyle: charts.TextStyleSpec(
fontSize: 10,
color: charts.ColorUtil.fromDartColor(Colors.black),
),
),
),
// defaultRenderer: ,
customSeriesRenderers: [
charts.LineRendererConfig(
customRendererId: 'customLine',
layoutPaintOrder:
charts.LayoutViewPaintOrder.point + 1,
),
],
behaviors: [
charts.SeriesLegend(
cellPadding: const EdgeInsets.all(2),
showMeasures: true,
position: charts.BehaviorPosition.top,
desiredMaxColumns: 5,
),
charts.ChartTitle(
'Real-time scatter plot for Meter ${meter.meterName}',
behaviorPosition: charts.BehaviorPosition.top,
titleOutsideJustification:
charts.OutsideJustification.middleDrawArea,
innerPadding: 2,
titleStyleSpec: charts.TextStyleSpec(
fontSize: 14,
color: charts.ColorUtil.fromDartColor(Colors.black),
),
),
charts.ChartTitle(
'Values',
behaviorPosition: charts.BehaviorPosition.start,
titleOutsideJustification:
charts.OutsideJustification.middleDrawArea,
innerPadding: 2,
titleStyleSpec: charts.TextStyleSpec(
fontSize: 14,
color: charts.ColorUtil.fromDartColor(Colors.black),
),
),
charts.ChartTitle(
'Time',
behaviorPosition: charts.BehaviorPosition.bottom,
titleOutsideJustification:
charts.OutsideJustification.middleDrawArea,
innerPadding: 2,
titleStyleSpec: charts.TextStyleSpec(
fontSize: 14,
color: charts.ColorUtil.fromDartColor(Colors.black),
),
),
charts.SlidingViewport(),
charts.PanAndZoomBehavior(),
],
selectionModels: [
charts.SelectionModelConfig(
changedListener: (charts.SelectionModel model) {
AppConstants.logger({
model.selectedSeries[0]
.measureFn(model.selectedDatum[0].index)
});
},
),
],
),
),
I think the chart may be plotting points at the proper place but I want to show the time at the bottom. The problem is, that It takes Numerical Axis Spec only and also how can I format shown milliseconds if I want to.
How can I set the range in x axis in charts_flutter? My data sample is like (5000, 5.0),(5001, 25.2),(5002, 100.5),(5003, 75.8).
My code is
/// Example of a simple line chart.
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:flutter/material.dart';
class SimpleLineChart extends StatelessWidget {
final List<charts.Series> seriesList;
final bool animate;
SimpleLineChart(this.seriesList, {this.animate});
/// Creates a [LineChart] with sample data and no transition.
factory SimpleLineChart.withSampleData() {
return SimpleLineChart(
_createSampleData(),
// Disable animations for image tests.
animate: false,
);
}
#override
Widget build(BuildContext context) {
return Container(
height: 300,
// decoration: const BoxDecoration(color: Color(0xff232d37)),
width: double.infinity,
padding:
const EdgeInsets.only(right: 18.0, left: 12.0, top: 24, bottom: 12),
child: charts.LineChart(seriesList, animate: animate),
);
}
/// Create one series with sample hard coded data.
static List<charts.Series<LinearSales, int>> _createSampleData() {
final data = [
LinearSales(5000, 5.0),
LinearSales(5001, 25.2),
LinearSales(5002, 100.5),
LinearSales(5003, 75.8),
];
return [
charts.Series<LinearSales, int>(
id: 'Sales',
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
domainFn: (LinearSales sales, _) {
return sales.year;
},
measureFn: (LinearSales sales, _) {
return sales.sales;
},
data: data,
domainLowerBoundFn: (s, _) => 5000,
domainUpperBoundFn: (s, _) => 5010,
)
];
}
}
/// Sample linear data type.
class LinearSales {
final int year;
final double sales;
LinearSales(this.year, this.sales);
}
The charts looks like
It shows a straight line but I want x axis to start at 5000 and end on 5010. I tried setting it in
domainLowerBoundFn and domainUpperBoundFn but it still starts at 0. How do I fix it?
Ref: Charts Flutter Gallery
You can set domainAxis.
How about this?
child: charts.LineChart(
seriesList,
animate: animate,
domainAxis: const charts.NumericAxisSpec(
tickProviderSpec:
charts.BasicNumericTickProviderSpec(zeroBound: false),
viewport: charts.NumericExtents(5000.0, 5005.0),
),
),
or this?
child: charts.LineChart(
seriesList,
animate: animate,
domainAxis: const charts.NumericAxisSpec(
tickProviderSpec:
charts.BasicNumericTickProviderSpec(zeroBound: false),
),
),
You can use the next code for Y-axis:
primaryMeasureAxis: charts.NumericAxisSpec(
tickProviderSpec:
charts.BasicNumericTickProviderSpec(desiredTickCount: 3)),
Full example looks like:
ScatterPlotChart(
[seriesDistorted],
animate: true,
domainAxis: const NumericAxisSpec(
tickProviderSpec: BasicNumericTickProviderSpec(
// Vertical axis every 2 ticks from 0 to 10
dataIsInWholeNumbers: true,
zeroBound: false,
desiredTickCount: 6),
),
primaryMeasureAxis: const NumericAxisSpec(
tickProviderSpec: BasicNumericTickProviderSpec(desiredTickCount: 6)),
);
I am trying to change my Y-axis label from number like 60,000 to 60k. Currently, I am using Charts_Flutter dependency.
Here is how my graph looks like:
And here is how my code looks like:
child: charts.TimeSeriesChart(
series,
animate: true,
domainAxis: new charts.DateTimeAxisSpec(
tickFormatterSpec: new charts.AutoDateTimeTickFormatterSpec(
day: new charts.TimeFormatterSpec(
format: 'dd',
transitionFormat: 'dd MMM',
),
),
),
primaryMeasureAxis: new charts.NumericAxisSpec(
renderSpec: new charts.GridlineRendererSpec(
// Tick and Label styling here.
labelStyle: new charts.TextStyleSpec(
fontSize: 10, // size in Pts.
color: charts.MaterialPalette.black
),
)
),
defaultRenderer: charts.LineRendererConfig(
includeArea: true,
includeLine: true,
includePoints: true,
strokeWidthPx: 0.5,
radiusPx: 1.5
),
dateTimeFactory: const charts.LocalDateTimeFactory(),
behaviors: [
charts.PanAndZoomBehavior(),
charts.SelectNearest(
eventTrigger: charts.SelectionTrigger.tap
),
charts.LinePointHighlighter(
symbolRenderer: CustomCircleSymbolRenderer(size: size),
),
],
selectionModels: [
charts.SelectionModelConfig(
type: charts.SelectionModelType.info,
changedListener: (charts.SelectionModel model) {
if(model.hasDatumSelection) {
final tankVolumeValue = model.selectedSeries[0].measureFn(model.selectedDatum[0].index).round();
final dateValue = model.selectedSeries[0].domainFn(model.selectedDatum[0].index);
CustomCircleSymbolRenderer.value = '$dateValue \n $tankVolumeValue L';
}
})
]),
),
);
Any idea on how to change the label is welcome.
With charts_flutter you can specify a NumberFormat using their BasicNumericTickFormatterSpec class (which... doesn't seem basic at all).
Then supply this formatter class to your chart
Below I've used NumberFormat.compact() which would turn 60,000 into 60K.
/// Formatter for Y-axis numbers using [NumberFormat] compact
///
/// Used in the [NumericAxisSpec] below.
final myNumericFormatter =
BasicNumericTickFormatterSpec.fromNumberFormat(
NumberFormat.compact() // ← your format goes here
);
return TimeSeriesChart(seriesList,
animate: animate,
// Use myNumericFormatter on the primaryMeasureAxis
primaryMeasureAxis: NumericAxisSpec(
tickFormatterSpec: myNumericFormatter // ← pass your formatter here
),
Here's a full running example using the above:
import 'package:charts_flutter/flutter.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class ChartFormatPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Chart Format'),
),
body: Center(
child: ChartCustomYAxis.withSampleData(),
)
);
}
}
class ChartCustomYAxis extends StatelessWidget {
final List<Series> seriesList;
final bool animate;
ChartCustomYAxis(this.seriesList, {this.animate});
/// Creates a [TimeSeriesChart] with sample data and no transition.
factory ChartCustomYAxis.withSampleData() {
return ChartCustomYAxis(
_createSampleData(),
// Disable animations for image tests.
animate: false,
);
}
#override
Widget build(BuildContext context) {
/// Formatter for Y-axis numbers using [NumberFormat] compact
///
/// Used in the [NumericAxisSpec] below.
final myNumericFormatter =
BasicNumericTickFormatterSpec.fromNumberFormat(
NumberFormat.compact() // ← your format goes here
);
return TimeSeriesChart(seriesList,
animate: animate,
// Use myNumericFormatter on the primaryMeasureAxis
primaryMeasureAxis: NumericAxisSpec(
tickFormatterSpec: myNumericFormatter // ← pass your formatter here
),
/// Customizes the date tick formatter. It will print the day of month
/// as the default format, but include the month and year if it
/// transitions to a new month.
///
/// minute, hour, day, month, and year are all provided by default and
/// you can override them following this pattern.
domainAxis: DateTimeAxisSpec(
tickFormatterSpec: AutoDateTimeTickFormatterSpec(
day: TimeFormatterSpec(
format: 'd', transitionFormat: 'MM/dd/yyyy'))));
}
/// Create one series with sample hard coded data.
static List<Series<MyRow, DateTime>> _createSampleData() {
final data = [
MyRow(DateTime(2017, 9, 25), 6000),
MyRow(DateTime(2017, 9, 26), 8000),
MyRow(DateTime(2017, 9, 27), 6000),
MyRow(DateTime(2017, 9, 28), 9000),
MyRow(DateTime(2017, 9, 29), 11000),
MyRow(DateTime(2017, 9, 30), 15000),
MyRow(DateTime(2017, 10, 01), 25000),
MyRow(DateTime(2017, 10, 02), 33000),
MyRow(DateTime(2017, 10, 03), 27000),
MyRow(DateTime(2017, 10, 04), 31000),
MyRow(DateTime(2017, 10, 05), 23000),
];
return [
Series<MyRow, DateTime>(
id: 'Cost',
domainFn: (MyRow row, _) => row.timeStamp,
measureFn: (MyRow row, _) => row.cost,
data: data,
)
];
}
}
/// Sample time series data type.
class MyRow {
final DateTime timeStamp;
final int cost;
MyRow(this.timeStamp, this.cost);
}
The above example was stolen from here and modified to show NumberFormat.compact.
I have been working with the online gallery of Flutter charts (https://google.github.io/charts/flutter/gallery.html) but I'm struggling to add a title for x & y axis values.
Can somebody help me or tell me how to add the labels to the graph?
Its possible using behaviors property, check the code
var chart = charts.LineChart(seriesList,
behaviors: [
new charts.ChartTitle('Dimension',
behaviorPosition: charts.BehaviorPosition.bottom,
titleStyleSpec: chartsCommon.TextStyleSpec(fontSize: 11),
titleOutsideJustification:
charts.OutsideJustification.middleDrawArea),
new charts.ChartTitle('Dose, mg',
behaviorPosition: charts.BehaviorPosition.start,
titleStyleSpec: chartsCommon.TextStyleSpec(fontSize: 11),
titleOutsideJustification:
charts.OutsideJustification.middleDrawArea)
],
defaultRenderer: new charts.LineRendererConfig(includePoints: true));
Source https://google.github.io/charts/flutter/example/behaviors/chart_title
use the 'behavior' list for set title of chart
Widget build(BuildContext context) {
return new charts.LineChart(
seriesList,
animate: animate,
behaviors: [
new charts.ChartTitle('Top title text',
subTitle: 'Top sub-title text',
behaviorPosition: charts.BehaviorPosition.top,
titleOutsideJustification: charts.OutsideJustification.start,
innerPadding: 18),
new charts.ChartTitle('Bottom title text',
behaviorPosition: charts.BehaviorPosition.bottom,
titleOutsideJustification:
charts.OutsideJustification.middleDrawArea),
new charts.ChartTitle('Start title',
behaviorPosition: charts.BehaviorPosition.start,
titleOutsideJustification:
charts.OutsideJustification.middleDrawArea),
new charts.ChartTitle('End title',
behaviorPosition: charts.BehaviorPosition.end,
titleOutsideJustification:
charts.OutsideJustification.middleDrawArea),
],
);
}
You can do it by using behaviors using line annotations iterating your list data and make a new LineAnnotationSegment array but you should be aware that some titles may overlap when the next time point is very close.
final data = [
LinearPrices(DateTime(2020, 9, 19), 5),
LinearPrices(DateTime(2020, 9, 26), 15),
LinearPrices(DateTime(2020, 10, 3), 20),
LinearPrices(DateTime(2020, 10, 10), 17),
];
#override
Widget build(BuildContext context) {
return charts.TimeSeriesChart(seriesList, animate: false, behaviors: [
charts.RangeAnnotation( data.map((e) => charts.LineAnnotationSegment(
e.timestamp, charts.RangeAnnotationAxisType.domain,
middleLabel: '\$${e.price}')).toList()),
]);
}
Nevertheless you can use a callback to paint when the user clicks the line by painting either a custom text at the bottom or as a custom label using behaviors like this:
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:intl/intl.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
final data = [
LinearPrices(DateTime(2020, 9, 19), 5),
LinearPrices(DateTime(2020, 9, 26), 15),
LinearPrices(DateTime(2020, 10, 3), 20),
LinearPrices(DateTime(2020, 10, 10), 17),
];
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Chart'),
),
body: ChartPricesItem(data),
));
}
}
class ChartPricesItem extends StatefulWidget {
final List<LinearPrices> data;
ChartPricesItem(this.data);
static List<charts.Series<LinearPrices, DateTime>> _createSeries(
List<LinearPrices> data) {
return [
charts.Series<LinearPrices, DateTime>(
id: 'Prices',
colorFn: (_, __) => charts.MaterialPalette.deepOrange.shadeDefault,
domainFn: (LinearPrices sales, _) => sales.timestamp,
measureFn: (LinearPrices sales, _) => sales.price,
data: data,
)
];
}
#override
_ChartPricesItemState createState() => _ChartPricesItemState();
}
class _ChartPricesItemState extends State<ChartPricesItem> {
DateTime _time;
double _price;
// Listens to the underlying selection changes, and updates the information relevant
void _onSelectionChanged(charts.SelectionModel model) {
final selectedDatum = model.selectedDatum;
DateTime time;
double price;
// We get the model that updated with a list of [SeriesDatum] which is
// simply a pair of series & datum.
if (selectedDatum.isNotEmpty) {
time = selectedDatum.first.datum.timestamp;
price = selectedDatum.first.datum.price;
}
// Request a build.
setState(() {
_time = time;
_price = price;
});
}
#override
Widget build(BuildContext context) {
final simpleCurrencyFormatter =
charts.BasicNumericTickFormatterSpec.fromNumberFormat(
NumberFormat.compactSimpleCurrency());
var behaviors;
// Check if the user click over the line.
if (_time != null && _price != null) {
behaviors = [
charts.RangeAnnotation([
charts.LineAnnotationSegment(
_time,
charts.RangeAnnotationAxisType.domain,
labelDirection: charts.AnnotationLabelDirection.horizontal,
labelPosition: charts.AnnotationLabelPosition.margin,
labelStyleSpec:
charts.TextStyleSpec(fontWeight: FontWeight.bold.toString()),
middleLabel: '\$$_price',
),
]),
];
}
var chart = charts.TimeSeriesChart(
ChartPricesItem._createSeries(widget.data),
animate: false,
// Include timeline points in line
defaultRenderer: charts.LineRendererConfig(includePoints: true),
selectionModels: [
charts.SelectionModelConfig(
type: charts.SelectionModelType.info,
changedListener: _onSelectionChanged,
)
],
// This is the part where you paint label when you click over the line.
behaviors: behaviors,
// Sets up a currency formatter for the measure axis.
primaryMeasureAxis: charts.NumericAxisSpec(
tickFormatterSpec: simpleCurrencyFormatter,
tickProviderSpec:
charts.BasicNumericTickProviderSpec(zeroBound: false)),
/// Customizes the date tick formatter. It will print the day of month
/// as the default format, but include the month and year if it
/// transitions to a new month.
///
/// minute, hour, day, month, and year are all provided by default and
/// you can override them following this pattern.
domainAxis: charts.DateTimeAxisSpec(
tickFormatterSpec: charts.AutoDateTimeTickFormatterSpec(
day: charts.TimeFormatterSpec(
format: 'd', transitionFormat: 'dd/MM/yyyy'),
minute: charts.TimeFormatterSpec(
format: 'mm', transitionFormat: 'dd/MM/yyyy HH:mm'))),
);
var chartWidget = Padding(
padding: EdgeInsets.all(16),
child: SizedBox(
height: 200.0,
child: chart,
),
);
final children = <Widget>[chartWidget];
// If there is a selection, then include the details.
if (_time != null) {
children.add(Padding(
padding: EdgeInsets.only(top: 4.0),
child: Text(DateFormat('dd/MM/yyyy hh:mm').format(_time),
style: Theme.of(context).textTheme.bodyText1)));
}
return SingleChildScrollView(
child: Column(
children: <Widget>[
const SizedBox(height: 8),
Text("Product Prices", style: Theme.of(context).textTheme.headline5),
Column(children: children),
],
),
);
}
}
/// Sample linear data type.
class LinearPrices {
final DateTime timestamp;
final double price;
LinearPrices(this.timestamp, this.price);
}
This is the result: