Search code examples
c#.netsilverlightchartssilverlight-toolkit

Select the nearest point in a Silverlight Toolkit chart


I have a LineSeries chart. By series.IsSelectionEnabled = true; when I move the mouse over the points, I can select that node. But how can I do it when the mouse is not exactly over the point but when it's near it (above or under)? Thanks.

PS: One more thing. How can I change the color of the column when the mouse is over it so the user can tell which one of the columns he/she is going to select.


Solution

  • I have created the example of the chart with the single LineSeries. You can click anywhere at the plot and the nearest point will be selected.

    XAML (Change the ItemsSource property and other properties to yours):

        <Charting:Chart MouseLeftButtonDown="Chart_MouseLeftButtonDown">
            <Charting:Chart.Series>
                <Charting:LineSeries IsSelectionEnabled="True" ItemsSource="..." ... />
            </Charting:Chart.Series>
        </Charting:Chart>
    

    Code-behind:

        private void Chart_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var chart = sender as Chart;
            //In my example the line series is the first item of the chart series
            var line = (LineSeries)chart.Series[0];
    
            //Find the nearest point on the LineSeries
            var newPoint = e.GetPosition(line);
            var selectIndex = this.FindNearestPointIndex(line.Points, newPoint);
    
            if (selectIndex != null)
            {
                //Select a real item from the items source
                var source = line.ItemsSource as IList;
                line.SelectedItem = source[selectIndex.Value];
            }
        }
    
        private int? FindNearestPointIndex(PointCollection points, Point newPoint)
        {
            if (points == null || !points.Any())
                return null;
    
            //c^2 = a^2+b^2
            Func<Point, Point, double> getLength = (p1, p2) => Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));
    
            //Create the collection of points with more information
            var items = points.Select((p,i) => new { Point = p, Length = getLength(p, newPoint), Index = i });
            var minLength = items.Min(item => item.Length);
    
            //Uncomment if it is necessary to have some kind of sensitive area
            //if (minLength > 50)
            //    return null;
    
            //The index of the point with min distance to the new point
            return items.First(item => item.Length == minLength).Index;
        }
    

    As I said this chart will select the nearest point even if you click at a great distance away from any chart point. If it isn't intended behavior, you can uncomment these lines and set any number in pixels:

    //Uncomment if it is necessary to have some kind of sensitive area
    if (minLength > 50)
        return null;
    

    I have written comments, but if something isn't clear you can ask and I will explain.