There are times when we run into a scenario in which we need point selection on a chart. Luckily, RadChart for WPF and Silverlight already has this feature - but what if you need to find the closest point to where you selected on a chart? And what if you have multiple chart series that you are doing this with? Normally, this would be a bit of a challenge as this involves figuring out where the user clicked, what is around it, etc.
Luckily for us, we have charting wizards like Manol Donev on our team and an aggressive release cycle here at Telerik.
The solution that can be downloaded at the bottom relies upon the latest internal builds release of RadChart for WPF due to some new PointMark properties that were recently added to the control. But of course, we're all developers here, so let me show you some code and break down what we are doing to accomplish this task.
The first thing we need to do is to grab the pointmarks that are present in RadChart. We get here by subscribing to the RadChart.ItemClick event, giving us all the event parameters required for the following bit of code. Then, we simply use a little linq to grab a collection of PointMark items:
// Grab all pointmarks within the RadChart default ChartArea
var pointMarks = RadChart1.DefaultView.ChartArea
Once we have a list of PointMarks, the next step is to figure out which one has been selected. This is where our new properties from the latest internal build come into play:
PointMark pointMark1 = pointMarks.Where(x => x.DataContext == e.DataPoint).SingleOrDefault();
PointMark pointMark2 =
(e.ItemIndex < e.DataSeries.Count - 1)
pointMark2 = pointMarks.Where(x => x.DataContext == e.DataSeries[e.DataSeries.IndexOf(e.DataPoint) + 1]).SingleOrDefault();
In a more readable format, we set our first PointMark to be the only point in which the datapoint of the selected point (e.DataPoint) matches the datacontext of a pointmark in the collection. The next step is a little trickier, but entirely possible thanks to the new additions in the LIB release. To break the statement down, if the selected pointmark is not the last one in the given dataseries, we grab the pointmark whose datacontext equals that of the next in the series after the first datapoint. Complex to look at, yes, but works like a charm. :)
The next step is to examine which point our mouse has clicked closest to between the two selected points. To accomplish this, we grab points based on the position of the two pointmark items and do a quick comparison on the X values, since this will tell us which pointmark the click was closest to:
Point point1 = e.MouseData.GetPosition(pointMark1);
Point point2 = e.MouseData.GetPosition(pointMark2);
(Math.Abs(point1.X) <= Math.Abs(point2.X))
.highlightedPointMark = pointMark1;
.highlightedPointMark = pointMark2;
And last but certainly not least, you see the HighlightPointMark method being called. This (along with the corresponding method to clear highlighting) both take advantage of the rich API exposed by RadChart to modify pointmarks on the fly:
.highlightedPointMark.Shape = MarkerShape.Triangle;
.highlightedPointMark.Shape = MarkerShape.Circle;
And the end result? Looks something like this:
Pretty cool, right? :)
Remember to thank Manol for the base of this (to which I added the multi-series support and this stellar blog post to share it with the world) and his awesome work on RadChart (along with the rest of the team), and stay tuned for more tips from the support trenches.
Download the full source code for this example, complete with comments, right here.
Evan Hutnick works as a Developer Evangelist for Telerik specializing in Silverlight and WPF in addition to being a Microsoft MVP for Silverlight. After years as a development enthusiast in .Net technologies, he has been able to excel in XAML development helping to provide samples and expertise in these cutting edge technologies. You can find him on Twitter @EvanHutnick.
Copyright © 2016, Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
Progress, Telerik, and certain product names used herein are trademarks or registered trademarks of Progress Software Corporation and/or one of its subsidiaries or affiliates in the U.S. and/or other countries. See Trademarks or appropriate markings.