New to Telerik UI for WinFormsStart a free 30-day trial

How to create sine wave using RadChartView spline AreaSeries

Updated over 6 months ago

Environment

Product VersionProductAuthor
2022.2.511RadChartView for WinFormsDinko 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:

C#

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.

C#

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.

C#

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);
}

In this article
EnvironmentDescriptionSolution
Not finding the help you need?
Contact Support