Chart for .NET > User's Guide > Miscellaneous > Custom Painting |
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.
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 |
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 |
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) |
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