How to create sine wave using RadChartView spline AreaSeries
Environment
| Product Version | Product | Author |
|---|---|---|
| 2022.2.511 | RadChartView for WinForms | Dinko Krastev |
Description
To create sine wave using AreaSeries we can use a custom renderer. The CartesianRenderer is responsible for painting the area for each of your data points.

Solution
The starting point of the article is to create a CustomCartesianRenderer class that inherits CartesianRenderer and overrides the Initialize method. This method creates and arranges draw parts responsible for the rendering of each RadChartView segment. After calling the base method, the DrawParts collection contains objects that know how to draw axes, labels, series etc. The particular draw part you would like to replace is of type AreaSeriesDrawPart. Your code should be like the following:
public class CustomCartesianRenderer : CartesianRenderer
{
public CustomCartesianRenderer(CartesianArea area)
: base(area)
{ }
protected override void Initialize()
{
base.Initialize();
for (int i = 0; i < this.DrawParts.Count; i++)
{
AreaSeriesDrawPart areaPart = this.DrawParts[i] as AreaSeriesDrawPart;
if (areaPart != null)
{
this.DrawParts[i] = new CustomAreaSeriesDrawPart((AreaSeries)areaPart.Element, this);
}
}
}
}
Now we need to create our custom AreaSeriesDrawPart class. In the custom class we can override the DrawArea() in which we can create custom logic to calculate the area of each segment.
public class CustomAreaSeriesDrawPart : AreaSeriesDrawPart
{
public CustomAreaSeriesDrawPart(AreaSeries series, IChartRenderer renderer)
: base(series, renderer)
{ }
protected override void DrawArea()
{
CartesianRenderer renderer = (CartesianRenderer)this.Renderer;
AreaSeries area = this.Element as AreaSeries;
Graphics graphics = renderer.Graphics;
RadGdiGraphics radGraphics = new RadGdiGraphics(graphics);
RectangleF rect = ChartRenderer.ToRectangleF(this.Element.Model.LayoutSlot);
RectangleF clipRect = (RectangleF)renderer.Area
.GetType()
.GetMethod("GetCartesianClipRect", BindingFlags.Instance | BindingFlags.NonPublic)
.Invoke(renderer.Area, new object[]{});
PointF topLeft = new PointF(clipRect.X, clipRect.Y);
PointF topRight = new PointF(clipRect.Right - 1, clipRect.Y);
PointF lowerRight = new PointF(clipRect.Right - 1, clipRect.Bottom - 1);
PointF lowerLeft = new PointF(clipRect.X, clipRect.Bottom - 1);
List<PointF[]> allPoints = GetPointsPositionsArrays();
foreach (PointF[] points in allPoints)
{
if (points.Length < 2)
{
continue;
}
GraphicsPath fillPath = this.GetLinePaths(points);
if (fillPath == null)
{
continue;
}
if (this.Element.View.GetArea<CartesianArea>().Orientation == System.Windows.Forms.Orientation.Vertical)
{
if (area.VerticalAxis.IsInverse)
{
fillPath.AddLine(points[points.Length - 1], new PointF(points[points.Length - 1].X, topRight.Y));
fillPath.AddLine(topRight, topLeft);
fillPath.AddLine(new PointF(points[0].X, topLeft.Y), points[0]);
}
else
{
fillPath.AddLine(points[points.Length - 1], new PointF(points[points.Length - 1].X, points[0].Y));
}
}
else
{
if (area.HorizontalAxis.IsInverse)
{
fillPath.AddLine(points[points.Length - 1], topRight);
fillPath.AddLine(topRight, lowerRight);
fillPath.AddLine(lowerRight, points[0]);
}
else
{
fillPath.AddLine(points[points.Length - 1], topLeft);
fillPath.AddLine(topLeft, lowerLeft);
fillPath.AddLine(lowerLeft, points[0]);
}
}
FillPrimitiveImpl fill = new FillPrimitiveImpl(this.Element, null);
fill.PaintFill(radGraphics, fillPath, clipRect);
GraphicsPath borderPath = new GraphicsPath();
AreaSeries series = (AreaSeries)this.Element;
borderPath = new GraphicsPath();
if (series.StrokeMode == AreaSeriesStrokeMode.All ||
series.StrokeMode == AreaSeriesStrokeMode.AllButPlotLine ||
series.StrokeMode == AreaSeriesStrokeMode.LeftAndPoints ||
series.StrokeMode == AreaSeriesStrokeMode.LeftLine)
{
if (this.Element.View.GetArea<CartesianArea>().Orientation == System.Windows.Forms.Orientation.Vertical)
{
if (area.VerticalAxis.IsInverse)
{
borderPath.AddLine(topLeft, points[0]);
}
else
{
borderPath.AddLine(lowerLeft, points[0]);
}
}
else
{
if (area.HorizontalAxis.IsInverse)
{
borderPath.AddLine(lowerRight, points[0]);
}
else
{
borderPath.AddLine(lowerLeft, points[0]);
}
}
}
if (series.StrokeMode == AreaSeriesStrokeMode.All ||
series.StrokeMode == AreaSeriesStrokeMode.AllButPlotLine ||
series.StrokeMode == AreaSeriesStrokeMode.LeftAndPoints ||
series.StrokeMode == AreaSeriesStrokeMode.Points ||
series.StrokeMode == AreaSeriesStrokeMode.RightAndPoints)
{
GraphicsPath path = GetLinePaths(points);
if (path != null)
{
borderPath.AddPath(path, true);
}
}
if (series.StrokeMode == AreaSeriesStrokeMode.All ||
series.StrokeMode == AreaSeriesStrokeMode.AllButPlotLine ||
series.StrokeMode == AreaSeriesStrokeMode.RightAndPoints ||
series.StrokeMode == AreaSeriesStrokeMode.RightLine)
{
if (this.Element.View.GetArea<CartesianArea>().Orientation == System.Windows.Forms.Orientation.Vertical)
{
if (area.VerticalAxis.IsInverse)
{
borderPath.AddLine(points[points.Length - 1], topRight);
}
else
{
borderPath.AddLine(points[points.Length - 1], lowerRight);
}
}
else
{
if (area.HorizontalAxis.IsInverse)
{
borderPath.AddLine(points[points.Length - 1], topRight);
}
else
{
borderPath.AddLine(points[points.Length - 1], topLeft);
}
}
}
if (series.StrokeMode == AreaSeriesStrokeMode.All ||
series.StrokeMode == AreaSeriesStrokeMode.PlotLine)
{
if (this.Element.View.GetArea<CartesianArea>().Orientation == System.Windows.Forms.Orientation.Vertical)
{
if (area.VerticalAxis.IsInverse)
{
borderPath.AddLine(topRight, topLeft);
}
else
{
borderPath.AddLine(lowerRight, lowerLeft);
}
}
else
{
if (area.HorizontalAxis.IsInverse)
{
borderPath.AddLine(topRight, lowerRight);
}
else
{
borderPath.AddLine(lowerLeft, topLeft);
}
}
}
BorderPrimitiveImpl border = new BorderPrimitiveImpl(this.Element, null);
border.PaintBorder(radGraphics, null, borderPath, rect);
if (series.Image != null)
{
graphics.SetClip(fillPath);
ImagePrimitiveImpl image = new ImagePrimitiveImpl(series);
image.PaintImage(radGraphics, series.Image, clipRect, series.ImageLayout, series.ImageAlignment, series.ImageOpacity, false);
graphics.ResetClip();
}
}
}
}
What's left is to apply the custom renderer to the RadChartView and add spline AreaSeries with our data.
public Form1()
{
InitializeComponent();
this.radChartView1.CreateRenderer += radChartView1_CreateRenderer;
AreaSeries areaSeries = new AreaSeries();
areaSeries.Spline = true;
for (int x = 0; x < 60; x++)
{
areaSeries.DataPoints.Add(1 + 1 * Math.Sin(x / Math.PI), x);
}
this.radChartView1.Series.Add(areaSeries);
CategoricalAxis horizontalAxis = areaSeries.HorizontalAxis as CategoricalAxis;
horizontalAxis.StartPositionAxis = areaSeries.VerticalAxis;
horizontalAxis.StartPositionValue = 1;
}
private void radChartView1_CreateRenderer(object sender, ChartViewCreateRendererEventArgs e)
{
e.Renderer = new CustomCartesianRenderer(e.Area as CartesianArea);
}