flutter-examples
flutter-examples copied to clipboard
[SFCartesianChart] make possible to return null with builder in DataLabelSettings
Hello, I don't know if this is possible or not, but I was committed with a task to build a Cartesian chart to show only 2 labels in the chart, but for some reason, when the point where one of the labels to show is close enough to the top or bottom limits, sometimes it disappears. I noticed that this is happening also when there was not enough space between the 'showing' labels and the 'not showing/empty' labels. Here is the code of the SFCartesianChart
with the logic to show the 2 labels only and some screenshots of what im getting right now and what is expected to achieve. The reason of this issue is to know if its possible to return null for those 'empty labels' and with that, freeing space for the labels that need it, but only on the builder, since here is where the custom labels can be achieved.
SizedBox(
height: 220,
child: SfCartesianChart(
key: Key('SmartSfCartesianChart'),
margin: EdgeInsets.zero,
plotAreaBorderColor: Colors.transparent,
primaryXAxis: CategoryAxis(
isVisible: false,
labelPlacement: LabelPlacement.onTicks,
edgeLabelPlacement: EdgeLabelPlacement.hide,
majorGridLines: const MajorGridLines(color: Colors.transparent),
axisLine: const AxisLine(width: 0),
minorGridLines: const MinorGridLines(color: Colors.transparent)),
primaryYAxis: CategoryAxis(
isVisible: false,
visibleMinimum: minLabel! - (minLabel! * 0.065),
visibleMaximum: maxLabel! * 1.065,
maximumLabels: 1,
labelPlacement: LabelPlacement.onTicks,
majorGridLines: const MajorGridLines(color: Colors.transparent),
axisLine: const AxisLine(width: 0),
minorGridLines: const MinorGridLines(color: Colors.transparent)),
// Enable tooltip on initState
tooltipBehavior: _tooltipBehavior,
series: <LineSeries<CoinPerformanceData, String>>[
LineSeries<CoinPerformanceData, String>(
color: Colors.blue,
name: 'USD Value',
dataSource: coinPerformanceData,
xValueMapper: (CoinPerformanceData d, _) {
return d.valueX;
},
yValueMapper: (CoinPerformanceData d, _) {
return d.valueY;
},
// Enable data label
dataLabelSettings: DataLabelSettings(
labelAlignment: ChartDataLabelAlignment.auto,
// ignore: implicit_dynamic_parameter
builder: (data, point, series, pointIndex, seriesIndex) {
final coinPerformanceDataValue = data as CoinPerformanceData;
if (coinPerformanceDataValue.valueY == maxLabel &&
!maxApplied) {
maxApplied = true;
return Padding(
padding: const EdgeInsets.only(top: 0),
child:
Text(
smartNumberize(
number: coinPerformanceDataValue.valueY,
isMoney: true),
style: Theme.of(context)
.textTheme
.bodyText2!
.copyWith(fontSize: 10)),
);
}
if (coinPerformanceDataValue.valueY == minLabel &&
!minApplied) {
minApplied = true;
return Padding(
padding: const EdgeInsets.only(bottom: 0),
child:
Text(
smartNumberize(
number: coinPerformanceDataValue.valueY,
isMoney: true),
style: Theme.of(context)
.textTheme
.bodyText2!
.copyWith(fontSize: 10)),
);
}
return Text('',
style: Theme.of(context)
.textTheme
.bodyText2!
.copyWith(fontSize: 10));
},
isVisible: true))
]));
Here is a data set where the chart only shows 1 of the 2 labels
{
"2022-04-24 19:00": 39704.0,
"2022-04-24 20:00": 39501.0,
"2022-04-24 21:00": 39625.0,
"2022-04-24 22:00": 39548.0,
"2022-04-24 23:00": 39451.0,
"2022-04-25 00:00": 38868.0,
"2022-04-25 01:00": 39102.0,
"2022-04-25 02:00": 39086.0,
"2022-04-25 03:00": 39246.0,
"2022-04-25 04:00": 39143.0,
"2022-04-25 05:00": 38968.0,
"2022-04-25 06:00": 38643.0,
"2022-04-25 07:00": 38458.86,
"2022-04-25 08:00": 38416.0,
"2022-04-25 09:00": 38578.0,
"2022-04-25 10:00": 38437.0,
"2022-04-25 11:00": 38828.0,
"2022-04-25 12:00": 38807.0,
"2022-04-25 13:00": 38735.0,
"2022-04-25 14:00": 39061.0,
"2022-04-25 15:00": 38977.0,
"2022-04-25 16:00": 39470.0,
"2022-04-25 17:00": 39394.0
}
Here is the class that im using on the chart
class CoinPerformanceData {
CoinPerformanceData({
this.valueX,
this.valueY,
});
String? valueX;
double? valueY;
}
And these are some variables that are being used in the SFCartesianChart
that need to be stablished to work
// This is a helper function for number formatting used in our code
String smartNumberize(
{double? number,
bool isMoney = false,
bool? isSimple = false,
bool? dynamicDecimals = false,
int? decimalDigits = 1}) {
if (number == null) {
return 'N/A';
}
if (isMoney) {
return NumberFormat.simpleCurrency(
decimalDigits: dynamicDecimals! ? (number < 0.01 ? 6 : 2) : 2)
.format(number);
} else if (isSimple!) {
return NumberFormat.decimalPattern().format(number);
} else {
return NumberFormat.decimalPercentPattern(decimalDigits: decimalDigits)
.format(number);
}
}
// These are set before the build method
bool minApplied = false;
bool maxApplied = false;
double? minLabel;
double? maxLabel;
List<CoinPerformanceData> coinPerformanceData = [];
// This is only for this issue, since the data set is fetched from backend,
// use it with the previous data set provided for testing
Map<String, dynamic> dataSet = {};
// This is set on initState in my project
dataSet.forEach((key, value) {
final valueY = value as double;
minLabel = minLabel != null
? minLabel! > valueY
? valueY
: minLabel
: valueY;
maxLabel = maxLabel != null
? maxLabel! < valueY
? valueY
: maxLabel
: valueY;
coinPerformanceData.add(CoinPerformanceData(
valueX: key,
valueY: valueY,
));
});
I noticed that this problem can be solved by giving more height to the SizedBox
that contains the chart, but is not possible due to UI/UX rules that we have for the project.
Image references:
What im getting in some charts
What im expecting to get in all charts
Hi @starfoxcom,
On checking your scenario with the provided code snippet and replication information, we would like to let you know that the last data label which is getting hiding is due to the data label text / widget being too long and it flows outside the plot area and also collides with the other empty string data labels before the last point internally and this is the current default behavior in our chart widget. However, for this scenario you can render the last points data label text/ widget using the annotation feature available in our chart widget and setting necessary padding in order to align as per your requirement. We have also modified the provided code snippet to achieve the same and also attached the sample below for your reference.
Sample: datalabelminmax.zip
For further information on the annotation feature, please check the user guide below. https://help.syncfusion.com/flutter/cartesian-charts/annotations
Regards, Sriram Kiran
Hello, I tested the code snippet provided on my project, and its working really well, just with some issues found:
I tried to use the onDataLabelRender
to render only the labels that match the indexes of the two labels that I want, but the problem is that these are still hiding when the data set is kind of big.
References when the amount of data points are not a problem:
References when the amount of data points are a problem:
With the previous mentioned, I decided to go with the annotation option, which worked really well too, since this one will always show no matter what, but the position is absolute, so if the widget is kind of off from the edges, it has to be replaced. I know that it can be achieved with padding, but the problem here is that it cannot be a fixed number, since the points in the chart can vary, so I want to know if there's a way to get the exact position in pixels of these annotations to modify its padding according to it, since with that its possible to replace the widget by knowing the boxConstraints of the chart, then getting the size of the widget in pixels and get the position of it and calculate if the widget itself is out of bounds .
References of the charts where the annotations are quite off the chart area or even completely out of it:
Hi @starfoxcom,
As we stated earlier empty string data label region may collide with the label you have rendered using onDataLabelRender callback. So, we have considered this as a bug, and we will fix this and roll out in our next weekly patch release. That would be expected on 10th May 2022. We appreciate your patience until then.
Regards, Yuvaraj.
Hi @starfoxcom,
Thanks for your patience. We are glad to let you know that the reported issue regarding data labels getting hidden when adjacent labels have empty strings has been fixed and rolled out in our SP release. To resolve the issue at your end kindly upgrade the chart package to the latest version mentioned below.
Version: https://pub.dev/packages/syncfusion_flutter_charts/versions/20.1.55
Regards, Yuvaraj.