How to set different border radius for each Rect series data points by extending the implementation of Cartesian charts (SfCartesianChart) ?
In this article, we described how to set different border radius for each chart Rect series data points using extendibility (inheritance) in Cartesian chart.
Flutter Cartesian Chart widget provides support for extending chart series, allowing you to override methods and properties for customization purposes. Extendibility or inheritance is defined as the process of deriving properties and characteristics from another class. It provides the ability to create a new class from an existing class, enabling you to use the properties and characteristics of the existing class. By using the onCreateRenderer property available in the chart, you can create a custom chart series renderer using extendibility and return that series renderer to this property so that application-level series rendering customizations will be reflected in the chart.
Follow these instructions to set different border radius values for each series data point using extendibility:
Step 1: First, create a new class CustomColumnSeriesRenderer extending ColumnSeriesRenderer class.
// Custom column series renderer created class CustomColumnSeriesRenderer<T, D> extends ColumnSeriesRenderer<T, D> { CustomColumnSeriesRenderer(); }
Step 2: Create another custom painter class CustomColumnSeriesPainter extending ColumnSegment class and then override the createSegment() method in the previously created CustomColumnSeriesRenderer class and return the CustomColumnSeriesPainter class inside that method.
class CustomColumnSeriesRenderer<T, D> extends ColumnSeriesRenderer<T, D> { CustomColumnSeriesRenderer(); @override ColumnSegment<T, D> createSegment() { // Custom segment painter returned return CustomChartPainter(); } } // Initialized custom cegment painter for customizing each segments of the chart series class CustomColumnSeriesPainter<T, D> extends ColumnSegment<T, D> { }
Step 3: Inside the CustomColumnSeriesPainter class, create temporary Rect variable for storing the values of the segmentRect property of the ColumnSegment class. This property holds the rect values of each column segment that is to be painted in the chart.
class CustomColumSeriesPainter<T, D> extends ColumnSegment<T, D> { late Rect rect; }
After that, override the onPaint() method of the ColumnSegment, in which each column segment properties can be customized. Here, we have modified two different border radii for the column segments based on their y values. For setting the border radii for each segment inside the onPaint() method, you can use the RRect.fromRectAndCorners() method to specify radius for the each segment rect’s corners and assign the result RRect value to the segmentRect property itself.
We use the currentSegmentIndex property’s value to parse using the chart data source for setting the border radius.
class CustomColumnSeriesPainter<T, D> extends ColumnSegment<T, D> { // Initialized a temporary rect to store the segment rect of each column late Rect rect; @override void onPaint(Canvas canvas) { // Stored the segment rect in the temporary rect variable rect = segmentRect!.outerRect; // Here, if the value is above 35, the bottom corner parts of the column segment will be rounded. if (chartData[currentSegmentIndex].sales > 35) { // Modified the radius of the segment rect corners using RRect.fromRectAndCorners method. segmentRect = RRect.fromRectAndCorners(rect, bottomLeft: Radius.circular(25), bottomRight: Radius.circular(25)); // Here, if the value is below 35, the top corner parts of the column segment will be rounded. } else if (chartData[currentSegmentIndex].sales < 35) { segmentRect = RRect.fromRectAndCorners(rect, topLeft: Radius.circular(25), topRight: Radius.circular(25)); } // You can set the radius values as per your wish using the necessary parameters (such as topLeft, // topRight, bottomRight, bottomLeft) of the RRect.fromRectAndCorners method. // Called the superclass method and properties for column segment rendering. super.onPaint(canvas); } }
Step 4: Initialize the chart data source globally and then initialize the SfCartesianChart with all the required properties and finally return the CustomColumSeriesRenderer class to the onCreateRenderer property of the chart series.
// Initialize the chart's data source globally. List<_SalesData> chartData = <_SalesData>[ _SalesData('Jan', 36), _SalesData('Feb', 28), _SalesData('Mar', 34), _SalesData('Apr', 32), _SalesData('May', 40) ]; // State class that holds the chart widget class _MyHomePageState extends State<_MyHomePage> { @override Widget build(BuildContext context) { return Scaffold( body: SfCartesianChart( primaryXAxis: CategoryAxis(), series: <ColumnSeries<_SalesData, String>>[ ColumnSeries<_SalesData, String>( // Property with which the overriding is done in the chart. onCreateRenderer: (ChartSeries<dynamic, dynamic> series) { // returned the custom series renderer return CustomColumnSeriesRenderer(); }, dataSource: chartData, xValueMapper: (_SalesData sales, _) => sales.year, yValueMapper: (_SalesData sales, _) => sales.sales, // Enable data label dataLabelSettings: DataLabelSettings(isVisible: true)) ]), ); } }
Screenshots
Border radius customization using extendibility
For more information on onCreateRenderer property, please click here.