Attaching Elements to Data Points
In previous sections, we discussed how you can customize the appearance of data series and individual data points. We also discussed how you can add data labels and tooltips to charts.
In some cases, however, you may need to add custom elements and position them relative to specific data points. For example, the Google Financials site displays charts with labels attached to specific data points. The labels relate the data points to significant news that affected the values on the chart.
This can be done easily with C1Chart using the PointFromData method. This method converts a specific point from chart coordinates to client coordinates, which you can use to position elements over the chart.
For example:
// Custom elements used to indicate maximum and minimum values
Ellipse _minMark, _maxMark;
// Create chart and initialize custom elements
void CustomElementChart()
{
// Create chart as usual
BuildSalesPerRegionChart(ChartType.LineSymbols);
// Create min/max custom elements
_minMark = new Ellipse()
_minMark.Width = _minMark.Height = 45;
_minMark.Stroke = new SolidColorBrush(Colors.Blue);
_minMark.Fill = new SolidColorBrush(Color.FromArgb(64, 0, 0, 255));
_maxMark = new Ellipse()
_maxMark.Width = _maxMark.Height = 45;
_maxMark.Stroke = new SolidColorBrush(Colors.Red);
_maxMark.Fill = new SolidColorBrush(Color.FromArgb(64, 255, 0, 0));
// Add custom elements to the chart
_c1Chart.View.Children.Add(_minMark);
_c1Chart.View.Children.Add(_maxMark);
// Reposition custom elements when chart layout changes
_c1Chart.LayoutUpdated += _c1Chart_LayoutUpdated;
}
The code starts by creating a chart as usual. Then it creates two Ellipse elements that will be used to indicate the minimum and maximum values on the chart. The custom elements are added to the View canvas. Finally, the code adds an event handler to the chart's LayoutUpdated event. The event handler is responsible for positioning the custom elements over data points on the chart whenever the chart layout changes (for example, when the chart is resized).
Here is the code for the event handler:
void _c1Chart_LayoutUpdated(object sender, EventArgs e)
{
// Find minimum and maximum values
int imax = 0, imin = 0;
double ymin = double.MaxValue, ymax = double.MinValue;
foreach (DataSeries ds in _c1Chart.Data.Children)
{
double[] values = ds.ValuesSource as double[];
for (int i = 0; i < values.Length; i++)
{
if (values[i] > ymax)
{
ymax = values[i];
imax = i;
}
if (values[i] < ymin)
{
ymin = values[i];
imin = i;
}
}
}
// Position custom element over minimum
Point ptMin = _c1Chart.View.PointFromData(new Point(imin, ymin));
Canvas.SetLeft(_minMark, ptMin.X - _minMark.Width / 2);
Canvas.SetTop(_minMark, ptMin.Y - _minMark.Height / 2);
// Position custom element over maximum
Point ptMax = _c1Chart.View.PointFromData(new Point(imax, ymax));
Canvas.SetLeft(_maxMark, ptMax.X - _maxMark.Width / 2);
Canvas.SetTop(_maxMark, ptMax.Y - _maxMark.Height / 2);
}
The event handler starts by scanning all the data series to find the maximum and minimum values on the chart and their index along the X axis.
Once these values have been found, the event handler calls the PointFromData method to convert the data coordinates into pixel coordinates within the chart's plot area. Finally, it calls the SetLeft and SetTop methods to position the custom elements so the center of the ellipses coincides with the point on the chart.
The result looks like the image below:
The red marker is positioned over the maximum value and the blue over the minimum. The position of the markers is updated automatically when the chart is resized.