I'm using charts_flutter library on one of my projects and I would like to display the data value on clicking on each Bar chart item. Is it possible?
var data = [
new ClicksPerYear('2016', 12, Colors.red),
new ClicksPerYear('2017', 42, Colors.blue),
new ClicksPerYear('2018', counter, Colors.green),
];
var series = [
new charts.Series(
id: 'Clicks',
data: data,
domainFn: (ClicksPerYear clickData, _) => clickData.year,
measureFn: (ClicksPerYear clickData, _) => clickData.clicks,
colorFn: (ClicksPerYear clickData, _) => clickData.color,
)
];
var barChart = new charts.BarChart(
series,
animate: true,
);
Found a solution from Github issues
https://github.com/google/charts/issues/58
To get the value use SelectionModelConfig.changedListener.
Extend the CircleSymbolRenderer (for LinePointHighlighter.symbolRenderer) and overridden the paint method. Inside you can draw custom objects relative to the selected point.
Maybe in the future the authors will make this easier but for now you use this method to modify rendering process of the selected point in any way you need (using ChartCanvas methods)
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart';
import 'package:charts_flutter/src/text_element.dart';
import 'package:charts_flutter/src/text_style.dart' as style;
class Chart extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LineChart(
_createSampleData(),
behaviors: [
LinePointHighlighter(
symbolRenderer: CustomCircleSymbolRenderer()
)
],
selectionModels: [
SelectionModelConfig(
changedListener: (SelectionModel model) {
if(model.hasDatumSelection)
print(model.selectedSeries[0].measureFn(model.selectedDatum[0].index));
}
)
],
);
}
List<Series<LinearSales, int>> _createSampleData() {
final data = [
new LinearSales(0, 5),
new LinearSales(1, 25),
new LinearSales(2, 100),
new LinearSales(3, 75),
];
return [
new Series<LinearSales, int>(
id: 'Sales',
colorFn: (_, __) => MaterialPalette.blue.shadeDefault,
domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.sales,
data: data,
)
];
}
}
class CustomCircleSymbolRenderer extends CircleSymbolRenderer {
@override
void paint(ChartCanvas canvas, Rectangle<num> bounds, {List<int> dashPattern, Color fillColor, Color strokeColor, double strokeWidthPx}) {
super.paint(canvas, bounds, dashPattern: dashPattern, fillColor: fillColor, strokeColor: strokeColor, strokeWidthPx: strokeWidthPx);
canvas.drawRect(
Rectangle(bounds.left - 5, bounds.top - 30, bounds.width + 10, bounds.height + 10),
fill: Color.white
);
var textStyle = style.TextStyle();
textStyle.color = Color.black;
textStyle.fontSize = 15;
canvas.drawText(
TextElement("1", style: textStyle),
(bounds.left).round(),
(bounds.top - 28).round()
);
}
}
class LinearSales {
final int year;
final int sales;
LinearSales(this.year, this.sales);
}
There were some errors when using the ChartCanvas method above the modified corrected version of this code is:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart';
// import 'package:charts_flutter/src/chart_canvas.dart' as eos;
import 'package:charts_flutter/src/text_element.dart' as TextElement;
import 'package:charts_flutter/src/text_style.dart' as style;
class Chart extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LineChart(
_createSampleData(),
behaviors: [
LinePointHighlighter(
symbolRenderer: CustomCircleSymbolRenderer()
)
],
selectionModels: [
SelectionModelConfig(
changedListener: (SelectionModel model) {
if(model.hasDatumSelection)
print(model.selectedSeries[0].measureFn(model.selectedDatum[0].index));
}
)
],
);
}
List<Series<LinearSales, int>> _createSampleData() {
final data = [
new LinearSales(0, 5),
new LinearSales(1, 25),
new LinearSales(2, 100),
new LinearSales(3, 75),
];
return [
new Series<LinearSales, int>(
id: 'Sales',
colorFn: (_, __) => MaterialPalette.blue.shadeDefault,
domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.sales,
data: data,
)
];
}
}
class CustomCircleSymbolRenderer extends CircleSymbolRenderer {
@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,fillPattern: fillPattern, strokeColor: strokeColor, strokeWidthPx: strokeWidthPx);
canvas.drawRect(
Rectangle(bounds.left - 5, bounds.top - 30, bounds.width + 10, bounds.height + 10),
fill: Color.white
);
var textStyle = style.TextStyle();
textStyle.color = Color.black;
textStyle.fontSize = 15;
canvas.drawText(
TextElement.TextElement("1", style: textStyle),
(bounds.left).round(),
(bounds.top - 28).round()
);
}
}
class LinearSales {
final int year;
final int sales;
LinearSales(this.year, this.sales);
}
I think you are searching for selection model, here is a bit of code which make event happened when you touch in chart:
selectionModels: [
new charts.SelectionModelConfig(
changedListener: (SelectionModel model) {
print( model.selectedSeries[0].measureFn(
model.selectedDatum[0].index);
}
)
],
A newer version of what the top answer recommends, with an example that works out of the box is here: https://github.com/google/charts/issues/58#issuecomment-1023006331
In a nutshell, you'll define the behaviour of the chart like this:
Widget build(BuildContext context) {
return new charts.LineChart(seriesList,
animate: animate,
defaultRenderer: new charts.LineRendererConfig(includePoints: true),
behaviors: [
charts.LinePointHighlighter(
////////////////////// notice ////////////////////////////
symbolRenderer: TextSymbolRenderer(() => Random().nextInt(100).toString()),
////////////////////// notice ////////////////////////////
),
],
);
}
And define the TextSymbolRenderer like this:
import 'dart:math';
import 'package:charts_flutter/flutter.dart';
import 'package:charts_flutter/src/text_style.dart' as style;
import 'package:charts_flutter/src/text_element.dart' as element;
import 'package:flutter/material.dart';
typedef GetText = String Function();
class TextSymbolRenderer extends CircleSymbolRenderer {
TextSymbolRenderer(this.getText, {this.marginBottom = 8, this.padding = const EdgeInsets.all(8)});
final GetText getText;
final double marginBottom;
final EdgeInsets padding;
@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, fillPattern: fillPattern, strokeColor: strokeColor, strokeWidthPx: strokeWidthPx);
style.TextStyle textStyle = style.TextStyle();
textStyle.color = Color.black;
textStyle.fontSize = 15;
element.TextElement textElement = element.TextElement(getText.call(), style: textStyle);
double width = textElement.measurement.horizontalSliceWidth;
double height = textElement.measurement.verticalSliceWidth;
double centerX = bounds.left + bounds.width / 2;
double centerY = bounds.top + bounds.height / 2 - marginBottom - (padding.top + padding.bottom);
canvas.drawRRect(
Rectangle(
centerX - (width / 2) - padding.left,
centerY - (height / 2) - padding.top,
width + (padding.left + padding.right),
height + (padding.top + padding.bottom),
),
fill: Color.white,
radius: 16,
roundTopLeft: true,
roundTopRight: true,
roundBottomRight: true,
roundBottomLeft: true,
);
canvas.drawText(
textElement,
(centerX - (width / 2)).round(),
(centerY - (height / 2)).round(),
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With