How to Highlight Data Points in .NET MAUI Toolkit Cartesian Charts?
The .NET MAUI Toolkit Cartesian Charts offers sophisticated customization capabilities for enhancing data visualization and user interaction. While the standard GetDataPoints(Rect) method of the Cartesian series retrieves data points within a rectangular region, this article demonstrates how to extend this functionality to highlight data points within a circular region.
Step 1: Create the Circle Selection Behavior Class
Create an extension class inherited from the ChartInteractiveBehavior class to handle the custom touch interactions on the chart. Define fields for storing the center coordinates and radius of the circle, and a flag to indicate when the circle should be shown. Implement the IDrawable interface to draw the selection circle. Override the OnTouchDown, OnTouchMove, and OnTouchUp methods to manage the drawing and selection process.
OnTouchDown Method: Capture the initial touch point when the user touches down on the chart. This point will serve as the center of the selection circle. The coordinates are adjusted to account for the chart’s SeriesBounds.
OnTouchMove Method: Calculate and update the radius of the selection circle dynamically based on the distance between the center point and the current touch position.
OnTouchUp Method: Finalize the circle dimensions and identify data points that fall within the circular region. This is a two-step process:
- First, create a bounding rectangle for the circle and use the GetDataPoints method to retrieve potential data points.
- Then, apply the Euclidean distance formula to each point to determine if it truly falls within the circle.
- Finally, update the SelectedIndexes property of ChartSelectionBehavior with the indexes of the selected points.
Here’s the complete code for the circle selection behavior:
public class CircleDataPointSelector : ChartInteractiveBehavior, IDrawable, INotifyPropertyChanged
{
private float CenterX;
private float CenterY;
private float radius = 0;
private bool showCircle = false;
public GraphicsView Graphics { get; set; }
public void Draw(ICanvas canvas, RectF dirtyRect)
{
canvas.StrokeColor = Colors.Red;
canvas.StrokeSize = 2;
canvas.FillColor = Colors.Red.WithAlpha(0.2f);
// Draw circle from center with diameter as width/height
canvas.DrawEllipse(CenterX - radius, CenterY - radius, radius * 2, radius * 2);
}
protected override void OnTouchDown(ChartBase chart, float pointX, float pointY)
{
var seriesBounds = chart.SeriesBounds;
CenterX = (float)(pointX - seriesBounds.Left);
CenterY = (float)(pointY - seriesBounds.Top);
radius = 0;
showCircle = true;
Graphics.Invalidate();
}
protected override void OnTouchMove(ChartBase chart, float pointX, float pointY)
{
if (showCircle)
{
var seriesBounds = chart.SeriesBounds;
// Calculate radius using exact code from clipboard
float dx = (float)(pointX - seriesBounds.Left - CenterX);
float dy = (float)(pointY - seriesBounds.Top - CenterY);
radius = (float)Math.Sqrt(dx * dx + dy * dy);
Graphics.Invalidate();
}
}
protected override void OnTouchUp(ChartBase chart, float pointX, float pointY)
{
if (chart is SfCartesianChart cartesianChart)
{
var viewModel = chart.BindingContext as ScatterSeriesViewModel;
// Create bounding rect for the circle in chart coordinates.
var boundingRect = new Rect(
CenterX - radius,
CenterY - radius,
radius * 2,
radius * 2
);
var selectedIndexes = new List<int>();
foreach (var series in cartesianChart.Series)
{
if (series is ScatterSeries scatterSeries)
{
var rectanglePoints = scatterSeries.GetDataPoints(boundingRect);
if (rectanglePoints != null && viewModel != null)
{
for (int i = 0; i < viewModel.Data.Count; i++)
{
var point = viewModel.Data[i];
if (rectanglePoints.Contains(point))
{
var xAxis = cartesianChart.XAxes[0];
var yAxis = cartesianChart.YAxes[0];
// Convert data coordinates to pixel coordinates
double pixelX = xAxis.ValueToPoint(point.XValue);
double pixelY = yAxis.ValueToPoint(point.YValue);
// Calculate distance from center to this point
double distance = Math.Sqrt(
Math.Pow(pixelX - CenterX, 2) +
Math.Pow(pixelY - CenterY, 2));
// If distance is less than radius, point is in circle
if (distance <= radius)
{
selectedIndexes.Add(i);
}
}
}
scatterSeries.SelectionBehavior.SelectedIndexes = selectedIndexes;
}
}
}
}
showCircle = false;
Graphics.Invalidate();
}
}
Step 2: Assign the Circle Selection Behavior to the Chart
Assign the CircleDataPointSelector class to the InteractiveBehavior property of the SfCartesianChart. Define the GraphicsView in the PlotAreaBackgroundView to handle custom drawing of the selection circle.
<chart:SfCartesianChart>
<chart:SfCartesianChart.PlotAreaBackgroundView>
<GraphicsView Drawable="{x:Reference InteractionExt}" x:Name="graphicsView"
InputTransparent="True"
ZIndex="1"/>
</chart:SfCartesianChart.PlotAreaBackgroundView>
<chart:SfCartesianChart.InteractiveBehavior>
<local:CircleDataPointSelector x:Name="InteractionExt"
Graphics="{x:Reference graphicsView}"/>
</chart:SfCartesianChart.InteractiveBehavior>
<chart:SfCartesianChart.Series>
<chart:ScatterSeries ItemsSource="{Binding Data}"
XBindingPath="XValue"
YBindingPath="YValue"
PointHeight ="8" PointWidth="8" >
<chart:ScatterSeries.SelectionBehavior>
<chart:DataPointSelectionBehavior Type="Multiple"
SelectionBrush="#3652AD"/>
</chart:ScatterSeries.SelectionBehavior>
</chart:ScatterSeries>
</chart:SfCartesianChart.Series>
</chart:SfCartesianChart>
Download the complete sample from GitHub.
Output
Conclusion:
I hope you enjoyed learning how to highlight data points within a circular region in .NET MAUI Toolkit Cartesian Charts.
You can refer to our .NET MAUI Chart’s feature tour page to learn about its other groundbreaking feature representations. You can also explore our .NET MAUI Toolkit Chart documentation to understand how to present and manipulate data.
For current customers, check out our .NET MAUI from the License and Downloads page. If you are new to Syncfusion®, try our 30-day free trial to check out our .NET MAUI Chart and other .NET MAUI components.
Please let us know in the following comments section if you have any queries or require clarifications. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!