Chart for .NET / User's Guide / Interactivity / Hit Testing

In This Topic
Hit Testing
In This Topic
The ability to determine the chart object at given window coordinates is an essential functionality build in Nevron Chart for Windows Forms. This feature is called "hit testing" and allows you to build advanced interactive applications.

You perform hit testing by calling the HitTest function of the NChartControl class. It accepts two parameters specifying a point in window coordinates. The function returns an object of type NHitTestResult containing information about the underlying chart object. The following code for example intercepts the mouse click event and obtains a NHitTestResult object for the chart object laying under the mouse:

C#
Copy Code
private void Form_Load(object sender, System.EventArgs e)
{
 chartControl.MouseDown += new System.Windows.Forms.MouseEventHandler(OnMouseDown);
}

.....

public void OnMouseDown(object sender, MouseEventArgs e)
{
 NHitTestResult hitTestResult = chartControl.HitTest(e.X, e.Y);

 if (hitTestResult.ChartElement == ChartElement.ControlBackground)
 {
  // the user clicked on the chart control background.
 }
}
Visual Basic
Copy Code
Private Sub NMouseEventsUC_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
 AddHandler chartControl.MouseDown, AddressOf chartControl_MouseDown
End Sub 'NMouseEventsUC_Load

.......

Private Sub chartControl_MouseDown(ByVal sender As Object, ByVal e As System.EventArgs)
 Dim hitTestResult As NHitTestResult = chartControl.HitTest(e.X, e.Y)

 if hitTestResult.ChartElement = ChartElement.ControlBackground then
  ' the user clicked on the chart control background.
 end if
End Sub

The most important property of the NHitTestResult object is the ChartElement property. It describes the type of the chart element at the given window coordinates. Depending on the chart element type some of the properties of the NHitTestResult referencing objects may be null (Nothing in VB .NET), similarly properties specifying indexes in some of the chart collections may be -1. The following table shows how the properties depend on the ChartElement property:

Property Description Valid for chart elements
Object A refence to a chart element. Valid for all chart elements except ChartElement.Nothing.
Chart Returns a reference to the NChart object containing the located object.

Valid when the ChartElement is contained within a chart (DataPoint, SurfaceDataPoint, Axis, AxisStripe, AxisConstLine, Axis, ChartWall etc.)

ChartWall Returns a reference to a NChartWall object. Valid only when ChartElement is set to ChartWall.
Series Returns a reference to the NSeriesBase object containing the located data item. Valid when ChartElement is ChartElement.SurfaceDataPoint or ChartElement.DataPoint.
DataPointIndex Returns the index of the data point in the NSeries Values collection. Valid only when ChartElement is set to DataPoint.
Axis Returns a reference to a NAxis object. Valid when ChartElement is Axis or AxisStripe, AxisConstLine or AxisCustomLabel.
AxisStripe Returns a reference to a NAxisStripe object. Valid only when ChartElement is set to AxisStripe.
Legend Returns a reference to a NLegend object Valid only when ChertElement is set to Legend, LegendDataItem, LegendHeader or LegendFooter.
LegendDataItem Returns a reference to NLegendItemCellData object. Valid only when ChartElement is set to LegendDataItem.
Label Returns a reference to a NLabel object. Valid only when ChartElement is set to Label.
Watermark Returns a reference to a NWatermark object. Valid only when ChartElement is set to Watermark.

Now lets see how this works in practice. The following example creates an interactive pie chart that allows the user to click on the pie slices. When a pie is clicked it will be detached from the pie center:

C#
Copy Code
private void Form1_Load(object sender, System.EventArgs e)
{
 chartControl.Charts.Clear();
 NPieChart pieChart = new NPieChart();
 chartControl.Charts.Add(pieChart);

 // create a pie series
 NPieSeries pie = (NPieSeries)pieChart.Series.Add(SeriesType.Pie);

 // add some data
 pie.AddDataPoint(new NDataPoint(12, "Cars", new NColorFillStyle(Color.FromArgb(56, 89, 150))));
 pie.AddDataPoint(new NDataPoint(42, "Trains", new NColorFillStyle(Color.DarkGreen)));
 pie.AddDataPoint(new NDataPoint(56, "Airplanes", new NColorFillStyle(Color.DarkGoldenrod)));
 pie.AddDataPoint(new NDataPoint(23, "Buses", new NColorFillStyle(Color.DarkRed)));

 // set pie detachments to zero
 for(int i = 0; i < pie.Values.Count; i++)
 {
  pie.Detachments.Add(0);
 }

 // subscribe for mouse down
 chartControl.MouseDown += new MouseEventHandler(ChartControl_MouseDown);
 chartControl.Refresh();
}

private void ChartControl_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
 if (e.Button != MouseButtons.Left)
  return;

 // perform hit test
 NHitTestResult hitTestResult = chartControl.HitTest(e.X, e.Y);

 // if this is a data point (pie slice) = detach it
 if (hitTestResult.ChartElement == ChartElement.DataPoint)
 {
  NPieSeries pie = hitTestResult.Series as NPieSeries;
  // remove detachments
  for (int i = 0; i < pie.Detachments.Count; i++)
  {
       pie.Detachments[i] = 0.0f;
  }

  // detach current slice
  pie.Detachments[hitTestResult.DataPointIndex] = 5.0f;
  chartControl.Refresh();
 }
}
Visual Basic
Copy Code
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Dim chart As New NPieChart
    chartControl.Charts.Clear()
    chartControl.Charts.Add(chart)

    ' create a pie series
    Dim pie As NPieSeries = chart.Series.Add(SeriesType.Pie)

    ' add some data
    pie.AddDataPoint(New NDataPoint(12, "Cars", New NColorFillStyle(Color.FromArgb(56, 89, 150))))
    pie.AddDataPoint(New NDataPoint(42, "Trains", New NColorFillStyle(Color.DarkGreen)))
    pie.AddDataPoint(New NDataPoint(56, "Airplanes", New NColorFillStyle(Color.DarkGoldenrod)))
    pie.AddDataPoint(New NDataPoint(23, "Buses", New NColorFillStyle(Color.DarkRed)))

    ' set pie detachments to zero
    For i As Integer = 0 To pie.Values.Count - 1
        pie.Detachments.Add(0)
    Next i

    ' subscribe for mouse down
    AddHandler chartControl.MouseDown, AddressOf ChartControl_MouseDown
    chartControl.Refresh()
End Sub

Private Sub ChartControl_MouseDown(ByVal sender As Object, ByVal e As 
System.Windows.Forms.MouseEventArgs)
    If Not (e.Button = MouseButtons.Left) Then
        Return
    End If

    ' perform hit test
    Dim hitTestResult As NHitTestResult = chartControl.HitTest(e.X, e.Y)

    ' if this is a data point (pie slice) = detach it
    If hitTestResult.ChartElement = ChartElement.DataPoint Then
        Dim pie As NPieSeries = CType(hitTestResult.Series, NPieSeries)

        ' remove detachments
        For i As Integer = 0 To pie.Detachments.Count - 1
            pie.Detachments(i) = 0.0
        Next i

        ' detach current slice
        pie.Detachments(hitTestResult.DataPointIndex) = 5.0
        chartControl.Refresh()
    End If
End Sub

Now lets investigate what happens in ChartControl_MouseDown function. The code first checks whether the user clicked on a data point object - if not it does not do anything. If yes it obtains a reference to the NPieSeries collection by using the properties in the NHitTest result object:

C#
Copy Code
NPieSeries pie = (NPieSeries)(hitTestResult.Series);
Visual Basic
Copy Code
Dim pie As NPieSeries = CType(hitTestResult.Series, NPieSeries)
this ensures that we'll access the proper series in case the control displays multiple charts or multiple series in a chart. Finally it uses the DataPointIndex property to modify the detachment for the clicked pie.
See Also