In This Topic
All content panels in Nevron Chart for .NET have an associated PaintCallback property, which you can initialize with your custom implementation of the INPaintCallback interface and perform custom painting before or after the panel content is painted. For the purpose of this topic we'll examine how to paint custom markers on a bar chart which will also show how to perform coordinate transformation in order to obtain the position of a certain datapoint on the screen.
Intercepting the panel AfterPaint event
To provide custom code to execute after the root panel is painted you should write code similar to:
C# |
Copy Code
|
...
NChart chart = chartControl.Charts[0];
chart.PaintCallback = new CustomPaintCallback();
...
public class CustomPaintCallback : INPaintCallback
{
...
public void OnAfterPaint(NPanel panel, NPanelPaintEventArgs eventArgs)
{
// do something in after paint
}
}
|
Visual Basic |
Copy Code
|
...
Dim chart As NChart = chartControl.Charts(0)
chart.PaintCallback = New CustomPaintCallback()
...
Public Class CustomPaintCallback
Implements INPaintCallback
...
Public Sub OnAfterPaint(ByVal panel As NPanel, ByVal eventArgs As NPanelPaintEventArgs) Handles INPaintCallback.OnAfterPaint
' do something in after paint
End Sub
End Sub
|
Painting using GDI+ device
After the event is intercepted you may draw on the chart canvas by converting the EventArgs argument to NPanelPaintEventArgs which has an associated GDI+ Graphics object. The following example creates a simple bar chart and draws an upward arrow on the biggest bar.
C# |
Copy Code
|
private void Form1_Load(object sender, System.EventArgs e)
{
NChart chart = chartControl.Charts[0];
chart.PaintCallback = new CustomPaintCallback();
NBarSeries bar = chart.Series.Add(SeriesType.Bar) as NBarSeries;
bar.Values.Add(10);
bar.Values.Add(20);
bar.Values.Add(30);
bar.Values.Add(25);
bar.DataLabelStyle.Visible = false;
chartControl.Refresh();
}
public class CustomPaintCallback : INPaintCallback
{
public void OnAfterPaint(NPanel panel, NPanelPaintEventArgs eventArgs)
{
// get chart and bar series from control
NChart chart = chartControl.Charts[0];
NBarSeries bar = chart.Series[0] as NBarSeries;
// find the biggest value double maxValue = (double)bar.Values[0];
int maxValueIndex = 0;
for (int i = 1; i < bar.Values.Count; i++)
{
if (maxValue < (double)bar.Values[i])
{
maxValue = (double)bar.Values[i];
maxValueIndex = i;
}
}
// transform coordinates
NScale2DToViewTransformation scale2DToViewTransformation = new NScale2DToViewTransformation(chartControl.View.Context, chart, (int)StandardAxis.PrimaryX, (int)StandardAxis.PrimaryY);
NPointF viewPoint = new NPointF();
scale2DToViewTransformation.Transform(new NVector2DD(maxValueIndex, (double)bar.Values[maxValueIndex]), ref viewPoint);
// create a path for arrow RectangleF arrowBounds = new RectangleF(viewPoint.X - 25, viewPoint.Y, 50, 50);
float arrowStubWidth = arrowBounds.Width * 30.0f / 100.0f;
float arrowHeadHeight = arrowBounds.Height * 30.0f / 100.0f;
PointF[] lines = new PointF[7];
lines[0].X = arrowBounds.Left + arrowBounds.Width / 2;
lines[0].Y = arrowBounds.Top;
lines[1].X = arrowBounds.Right;
lines[1].Y = arrowBounds.Top + arrowHeadHeight;
lines[2].X = arrowBounds.Right - (arrowBounds.Width - arrowStubWidth) / 2;
lines[2].Y = arrowBounds.Top + arrowHeadHeight;
lines[3].X = lines[2].X;
lines[3].Y = arrowBounds.Bottom;
lines[4].X = arrowBounds.Left + (arrowBounds.Width - arrowStubWidth) / 2;
lines[4].Y = arrowBounds.Bottom;
lines[5].X = lines[4].X;
lines[5].Y = arrowBounds.Top + arrowHeadHeight;
lines[6].X = arrowBounds.Left;
lines[6].Y = lines[1].Y;
// create a graphics path GraphicsPath path = new GraphicsPath();
path.AddLines(lines);
path.CloseAllFigures();
// obtain device Graphics graphics = eventArgs.Graphics.DeviceGraphics;
// create a brush and pen SolidBrush brush = new SolidBrush(Color.Red);
Pen pen = new Pen(Color.Black, 1);
// paint the arrow graphics.FillPath(brush, path);
graphics.DrawPath(pen, path);
// dispose objects path.Dispose();
brush.Dispose();
pen.Dispose();
}
}
|
Visual Basic |
Copy Code
|
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim chart As NCartesianChart = chartControl.Charts(0)
chart.PaintCallback = New CustomPaintCallback()
Dim bar As NBarSeries = chart.Series.Add(SeriesType.Bar)
bar.Values.Add(10)
bar.Values.Add(20)
bar.Values.Add(30)
bar.Values.Add(25)
bar.DataLabelStyle.Visible = False
chartControl.Refresh()
End Sub
Public Class CustomPaintCallback
Implements INPaintCallback
Public Sub OnAfterPaint(ByVal panel As NPanel, ByVal eventArgs As NPanelPaintEventArgs) Handles INPaintCallback.OnAfterPaint
' get chart and bar series from control
Dim chart As NCartesianChart = chartControl.Charts(0)
Dim bar As NBarSeries = chart.Series(0)
' find the biggest value
Dim maxValue As Double = CType(bar.Values(0), Double)
Dim maxValueIndex As Integer = 0
For i As Integer = 0 To bar.Values.Count - 1
If (maxValue < CType(bar.Values(i), Double)) Then
maxValue = CType(bar.Values(i), Double)
maxValueIndex = i
End If
Next
' transform coordinates
Dim scale2DToViewTransformation As New NScale2DToViewTransformation(chartControl.View.Context, chart, CType(StandardAxis.PrimaryX, Integer), CType(StandardAxis.PrimaryY, Integer))
Dim viewPoint As New NPointF
scale2DToViewTransformation.Transform(New NVector2DD(maxValueIndex, CType(bar.Values(maxValueIndex), Double)), viewPoint)
' create a path for arrow
Dim arrowBounds As RectangleF = New RectangleF(viewPoint.X - 25, viewPoint.Y, 50, 50)
Dim arrowStubWidth As Single = arrowBounds.Width * 30.0F / 100.0F
Dim arrowHeadHeight As Single = arrowBounds.Height * 30.0F / 100.0F
Dim lines(6) As PointF
lines(0).X = arrowBounds.Left + arrowBounds.Width / 2
lines(0).Y = arrowBounds.Top
lines(1).X = arrowBounds.Right
lines(1).Y = arrowBounds.Top + arrowHeadHeight
lines(2).X = arrowBounds.Right - (arrowBounds.Width - arrowStubWidth) / 2
lines(2).Y = arrowBounds.Top + arrowHeadHeight
lines(3).X = lines(2).X
lines(3).Y = arrowBounds.Bottom
lines(4).X = arrowBounds.Left + (arrowBounds.Width - arrowStubWidth) / 2
lines(4).Y = arrowBounds.Bottom
lines(5).X = lines(4).X
lines(5).Y = arrowBounds.Top + arrowHeadHeight
lines(6).X = arrowBounds.Left
lines(6).Y = lines(1).Y
' create a graphics path
Dim path As GraphicsPath = New GraphicsPath
path.AddLines(lines)
path.CloseAllFigures()
' obtain device
Dim graphics As Graphics = CType(e, NPanelPaintEventArgs).Graphics.DeviceGraphics
' create a brush and pen
Dim brush As New SolidBrush(Color.Red)
Dim pen As New Pen(Color.Black, 1)
' paint the arrow
graphics.FillPath(brush, path)
graphics.DrawPath(pen, path)
' dispose objects
path.Dispose()
brush.Dispose()
pen.Dispose()
End Sub
End Sub
|
Painting Using Nevron Device
You can also paint directly to the Nevron Device containing the GDI+ graphics object and take full advantage of its advanced presentation features.
The following code will paint the arrow with applied gradient and lighting image filter:
C# |
Copy Code
|
// obtain device
NGraphics graphics = ((NPanelPaintEventArgs)e).Graphics;
NGradientFillStyle gradient = new NGradientFillStyle(GradientStyle.Horizontal, GradientVariant.Variant1, Color.White, Color.Red);
gradient.ImageFiltersStyle.Filters.Add(new NLightingImageFilter());
NStrokeStyle stroke = new NStrokeStyle(1, Color.Black);
graphics.PaintPath(gradient, stroke, path);
|
Visual Basic |
Copy Code
|
' obtain device
Dim graphics As NGraphics = CType(e, NPanelPaintEventArgs).Graphics
Dim gradient As NGradientFillStyle = New NGradientFillStyle(GradientStyle.Horizontal, GradientVariant.Variant1, Color.White, Color.Red)
gradient.ImageFiltersStyle.Filters.Add(New NLightingImageFilter)
Dim stroke As NStrokeStyle = New NStrokeStyle(1, Color.Black)
graphics.PaintPath(gradient, stroke, path)
|
Related Examples
Windows Forms: Custom Painting\Custom Painting Using GDI+
Windows Forms: Custom Painting\Custom Painting Nevron Device
Web Forms: Custom Painting\Custom Painting Using GDI+
Web Forms: Custom Painting\Custom Painting Nevron Device