import 'package:charts_flutter/flutter.dart' as charts; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import '../model/product_model.dart'; typedef void ProductClick(DateTime date, Map measures); class ProductsChart extends StatelessWidget { static final numberFormatter = new NumberFormat("#,###"); final ChartData chartData; final ProductClick productClick; const ProductsChart(this.chartData, {Key key, this.productClick}) : super(key: key); factory ProductsChart.fromModel(ProductModel productModel, {ProductClick productClick}) { return new ProductsChart(_createData(productModel), productClick: productClick); } static ChartData _createData(ProductModel productModel) { List> list = []; var min = 9999, max = 0; productModel.products.forEach((p) { List data = []; if (p.priceHistory != null) { var dateKeys = {}; p.priceHistory.entries.forEach((e) { dateKeys[DateTime.parse(e.key)] = e.value; }); var sortedKeys = dateKeys.keys.toList()..sort((a, b) => b.compareTo(a)); sortedKeys.forEach((k) { var v = dateKeys[k]; data.add(new TimeSeriesSales(k, v)); if (v < min) min = v; if (v > max) max = v; }); } list.add(new charts.Series( id: p.name, colorFn: (_, __) => charts.ColorUtil.fromDartColor(Color(p.color)), domainFn: (TimeSeriesSales sales, _) => sales.time, measureFn: (TimeSeriesSales sales, _) => sales.sales, data: data, labelAccessorFn: (TimeSeriesSales series, _) => '${numberFormatter.format(series.sales)}', measureFormatterFn: (TimeSeriesSales series, _) => (n) => "s", )); }); var chartData = ChartData(list, min, max); return chartData; } @override Widget build(BuildContext context) { return charts.TimeSeriesChart( chartData.seriesList, animate: true, defaultRenderer: new charts.LineRendererConfig( includePoints: true, ), primaryMeasureAxis: new charts.NumericAxisSpec( tickProviderSpec: new charts.BasicNumericTickProviderSpec( zeroBound: false, desiredTickCount: 10), renderSpec: new charts.GridlineRendererSpec( lineStyle: charts.LineStyleSpec( dashPattern: [4, 4], ))), selectionModels: [ new charts.SelectionModelConfig( type: charts.SelectionModelType.info, updatedListener: _onSelectionChanged, ) ], ); } _onSelectionChanged(charts.SelectionModel model) { final selectedDatum = model.selectedDatum; if (selectedDatum.isNotEmpty) { var _time = selectedDatum.first.datum.time; Map _measures = {}; selectedDatum.forEach((charts.SeriesDatum datumPair) { _measures[datumPair.series.displayName] = datumPair.datum.sales; }); if (productClick != null) { productClick(_time, _measures); } } } } class TimeSeriesSales { final DateTime time; final int sales; TimeSeriesSales(this.time, this.sales); } class ChartData { final List seriesList; final num min, max; ChartData(this.seriesList, this.min, this.max); }