/// <summary>
        /// Gets a closed polygon version of the specified drawing points.
        /// </summary>
        /// <param name="surface">The target surface.</param>
        /// <param name="points">The drawing points.</param>
        /// <returns></returns>
        protected virtual IEnumerable <PointF> GetFillPoints(IGraphSurface <TDataSeries> surface, IEnumerable <PointF> points)
        {
            List <PointF> closed = points.ToList();

            closed.Add(new PointF(points.Last().X, surface.GetSize().Width));
            closed.Add(new PointF(0, surface.GetSize().Height));
            return(closed.ToArray());
        }
        /// <summary>
        /// Draws the specified data series points on the target surface.
        /// </summary>
        /// <param name="surface">The target graph surface.</param>
        /// <param name="series">The instance of the current rendered data series.</param>
        /// <param name="points">The collection of the current data series drawing points.</param>
        /// <param name="index">The index of the current data series within the collection of data series.</param>
        /// <param name="count">The length of the data series collection.</param>
        public override void Draw(IGraphSurface <TDataSeries> surface, TDataSeries series, IEnumerable <PointF> points, int index, int count)
        {
            if (series.UseFill)
            {
                surface.FillSeries(series, GetFillPoints(surface, points));
            }

            surface.DrawSeries(series, points);
        }
        /// <summary>
        /// Called when the surface has changed.
        /// </summary>
        /// <param name="previous">The previous.</param>
        /// <param name="surface">The surface.</param>
        protected virtual void OnSurfaceChanged(IGraphSurface <TDataSeries> previous, IGraphSurface <TDataSeries> surface)
        {
            if (previous != null)
            {
                previous.SurfaceSizeChanged -= Surface_SurfaceSizeChanged;
                previous.ZoomRectChanged    -= Surface_ZoomRectChanged;
            }

            if (surface != null)
            {
                surface.SurfaceSizeChanged += Surface_SurfaceSizeChanged;
                surface.ZoomRectChanged    += Surface_ZoomRectChanged;
            }
        }
        /// <summary>
        /// Arranges the series of data points and returns a series of drawing points.
        /// </summary>
        /// <param name="surface">The target graph surface.</param>
        /// <param name="series">The instance of the current rendered data series.</param>
        /// <param name="range">Instance of graph range.</param>
        /// <param name="xx">Collection of x coordinates.</param>
        /// <param name="yy">Collection of y coordinates.</param>
        /// <param name="minimumX">The minimum x coordinates value.</param>
        /// <param name="maximumX">The maximum x coordinates value.</param>
        /// <param name="minimumY">The minimum y coordinates value.</param>
        /// <param name="maximumY">The maximum y coordinates value.</param>
        /// <returns></returns>
        public override IEnumerable <PointF> Render(IGraphSurface <TDataSeries> surface, TDataSeries series, IGraphRange range, List <GraphDataPoint> xx, List <GraphDataPoint> yy, GraphDataPoint minimumX, GraphDataPoint maximumX, GraphDataPoint minimumY, GraphDataPoint maximumY)
        {
            var dxList = xx.Select(x => x.ComputeRelativePosition(minimumX, maximumX)).ToList();
            var dyList = yy.Select(x => x.ComputeRelativePosition(minimumY, maximumY)).ToList();

            if (maximumX - minimumX > range.MaximumX)
            {
                var offset = ((maximumX - minimumX) - range.MaximumX) + minimumX;

                for (int i = 0; i < xx.Count; i++)
                {
                    if (xx[i] < offset)
                    {
                        xx.RemoveAt(i);
                        yy.RemoveAt(i);
                        i--;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            List <PointF> points = new List <PointF>();

            for (int i = 0; i < dxList.Count; i++)
            {
                float image_x = ConvertXValueToRendererValue(surface, dxList[i]);
                float image_y = (float)Math.Min(ConvertYValueToRendererValue(surface, dyList[i]), surface.GetSize().Height - 2);

                PointF point = new PointF(image_x, image_y);
                points.Add(point);
            }

            return(points);
        }
 /// <summary>
 /// Draws the specified data series points on the target surface.
 /// </summary>
 /// <param name="surface">The target graph surface.</param>
 /// <param name="series">The instance of the current rendered data series.</param>
 /// <param name="points">The collection of the current data series drawing points.</param>
 /// <param name="index">The index of the current data series within the collection of data series.</param>
 /// <param name="count">The length of the data series collection.</param>
 public abstract void Draw(IGraphSurface <TDataSeries> surface, TDataSeries series, IEnumerable <PointF> points, int index, int count);
 /// <summary>
 /// Arranges the series of data points and returns a series of drawing points.
 /// </summary>
 /// <param name="surface">The target graph surface.</param>
 /// <param name="series">The instance of the current rendered data series.</param>
 /// <param name="range">Instance of graph range.</param>
 /// <param name="xx">Collection of x coordinates.</param>
 /// <param name="yy">Collection of y coordinates.</param>
 /// <param name="minimumX">The minimum x coordinates value.</param>
 /// <param name="maximumX">The maximum x coordinates value.</param>
 /// <param name="minimumY">The minimum y coordinates value.</param>
 /// <param name="maximumY">The maximum y coordinates value.</param>
 /// <returns></returns>
 public abstract IEnumerable <PointF> Render(IGraphSurface <TDataSeries> surface, TDataSeries series, IGraphRange range, List <GraphDataPoint> xx, List <GraphDataPoint> yy, GraphDataPoint minimumX, GraphDataPoint maximumX, GraphDataPoint minimumY, GraphDataPoint maximumY);
 /// <summary>
 /// Converts the specified relative y position to a graph surface absolute position.
 /// </summary>
 /// <param name="surface">The surface.</param>
 /// <param name="y">The relative y position.</param>
 /// <returns></returns>
 protected virtual float ConvertYValueToRendererValue(IGraphSurface <TDataSeries> surface, double y)
 {
     return((float)(surface.GetSize().Height - (y * surface.GetSize().Height / 100)));
 }
 /// <summary>
 /// Converts the specified relative x position to a graph surface absolute position.
 /// </summary>
 /// <param name="surface">The target surface.</param>
 /// <param name="x">The relative x position.</param>
 /// <returns></returns>
 protected virtual float ConvertXValueToRendererValue(IGraphSurface <TDataSeries> surface, double x)
 {
     return((float)(x * surface.GetSize().Width / 100));
 }