public void RenderRect(OxyRect bounds, OxyColor fill, OxyColor borderColor, double borderThickness)
        {
            var border = new[]
                             {
                                 new ScreenPoint(bounds.Left, bounds.Top), new ScreenPoint(bounds.Right, bounds.Top),
                                 new ScreenPoint(bounds.Right, bounds.Bottom), new ScreenPoint(bounds.Left, bounds.Bottom),
                                 new ScreenPoint(bounds.Left, bounds.Top)
                             };

            rc.DrawPolygon(border, fill, borderColor, borderThickness, null, true);
        }
        /// <summary>
        /// Draws an ellipse.
        /// </summary>
        /// <param name="rect">The rectangle.</param>
        /// <param name="fill">The fill color.</param>
        /// <param name="stroke">The stroke color.</param>
        /// <param name="thickness">The thickness.</param>
        public override void DrawEllipse(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness)
        {
            var isStroked = stroke.IsVisible() && thickness > 0;
            var isFilled = fill.IsVisible();
            if (!isStroked && !isFilled)
            {
                return;
            }

            double y = this.doc.PageHeight - rect.Bottom;
            if (isStroked)
            {
                this.SetLineWidth(thickness);
                this.doc.SetColor(stroke);
                if (isFilled)
                {
                    this.doc.SetFillColor(fill);
                    this.doc.DrawEllipse(rect.Left, y, rect.Width, rect.Height, true);
                }
                else
                {
                    this.doc.DrawEllipse(rect.Left, y, rect.Width, rect.Height);
                }
            }
            else
            {
                this.doc.SetFillColor(fill);
                this.doc.FillEllipse(rect.Left, y, rect.Width, rect.Height);
            }
        }
 /// <summary>
 /// The Sutherland-Hodgman polygon clipping algorithm.
 /// </summary>
 /// <remarks>
 /// See http://ezekiel.vancouver.wsu.edu/~cs442/lectures/clip/clip/index.html
 /// </remarks>
 /// <param name="bounds">
 /// The bounds.
 /// </param>
 /// <param name="v">
 /// The polygon points.
 /// </param>
 /// <returns>
 /// The clipped points.
 /// </returns>
 public static List<ScreenPoint> ClipPolygon(OxyRect bounds, IList<ScreenPoint> v)
 {
     List<ScreenPoint> p1 = ClipOneAxis(bounds, RectangleEdge.Left, v);
     List<ScreenPoint> p2 = ClipOneAxis(bounds, RectangleEdge.Right, p1);
     List<ScreenPoint> p3 = ClipOneAxis(bounds, RectangleEdge.Top, p2);
     return ClipOneAxis(bounds, RectangleEdge.Bottom, p3);
 }
        /// <summary>
        /// Draws an ellipse.
        /// </summary>
        /// <param name="rect">The rectangle.</param>
        /// <param name="fill">The fill color.</param>
        /// <param name="stroke">The stroke color.</param>
        /// <param name="thickness">The thickness.</param>
        public override void DrawEllipse(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness)
        {
            var isStroked = stroke.IsVisible() && thickness > 0;

            if (fill.IsVisible())
            {
                if (!isStroked)
                {
                    this.g.SmoothingMode = SmoothingMode.HighQuality;
                }

                this.g.FillEllipse(this.GetCachedBrush(fill), (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height);
            }

            if (!isStroked)
            {
                return;
            }

            using (var pen = this.GetCachedPen(stroke, thickness))
            {
                this.g.SmoothingMode = SmoothingMode.HighQuality;
                this.g.DrawEllipse(pen, (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height);
            }
        }
        /// <summary>
        /// Clips to one axis.
        /// </summary>
        /// <param name="bounds">The bounds.</param>
        /// <param name="edge">The edge.</param>
        /// <param name="v">The points of the polygon.</param>
        /// <returns>The clipped points.</returns>
        private static List<ScreenPoint> ClipOneAxis(OxyRect bounds, RectangleEdge edge, IList<ScreenPoint> v)
        {
            if (v.Count == 0)
            {
                return new List<ScreenPoint>();
            }

            var polygon = new List<ScreenPoint>(v.Count);

            var s = v[v.Count - 1];

            for (int i = 0; i < v.Count; ++i)
            {
                var p = v[i];
                bool pin = IsInside(bounds, edge, p);
                bool sin = IsInside(bounds, edge, s);

                if (sin && pin)
                {
                    // case 1: inside -> inside
                    polygon.Add(p);
                }
                else if (sin)
                {
                    // case 2: inside -> outside
                    polygon.Add(LineIntercept(bounds, edge, s, p));
                }
                else if (!pin)
                {
                    // case 3: outside -> outside
                    // emit nothing
                }
                else
                {
                    // case 4: outside -> inside
                    polygon.Add(LineIntercept(bounds, edge, s, p));
                    polygon.Add(p);
                }

                s = p;
            }

            return polygon;
        }
        /// <summary>
        /// Draws the ellipse.
        /// </summary>
        /// <param name="rect">The rect.</param>
        /// <param name="fill">The fill.</param>
        /// <param name="stroke">The stroke.</param>
        /// <param name="thickness">The thickness.</param>
        public override void DrawEllipse(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness)
        {
            if (fill != null)
            {
                this.g.FillEllipse(
                    this.ToBrush(fill), (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height);
            }

            if (stroke == null || thickness <= 0)
            {
                return;
            }

            using (var pen = new Pen(this.ToColor(stroke), (float)thickness))
            {
                this.g.SmoothingMode = SmoothingMode.HighQuality;
                this.g.DrawEllipse(pen, (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height);
            }
        }
 /// <summary>
 /// Draws the rectangle as an aliased polygon.
 /// (makes sure pixel alignment is the same as for lines)
 /// </summary>
 /// <param name="rc">
 /// The render context.
 /// </param>
 /// <param name="rect">
 /// The rectangle.
 /// </param>
 /// <param name="fill">
 /// The fill.
 /// </param>
 /// <param name="stroke">
 /// The stroke.
 /// </param>
 /// <param name="thickness">
 /// The thickness.
 /// </param>
 public static void DrawRectangleAsPolygon(
     this IRenderContext rc, OxyRect rect, OxyColor fill, OxyColor stroke, double thickness)
 {
     var sp0 = new ScreenPoint(rect.Left, rect.Top);
     var sp1 = new ScreenPoint(rect.Right, rect.Top);
     var sp2 = new ScreenPoint(rect.Right, rect.Bottom);
     var sp3 = new ScreenPoint(rect.Left, rect.Bottom);
     rc.DrawPolygon(new[] { sp0, sp1, sp2, sp3 }, fill, stroke, thickness, null, OxyPenLineJoin.Miter, true);
 }
 /// <summary>
 /// Renders the plot with the specified rendering context within the given rectangle.
 /// </summary>
 /// <param name="rc">The rendering context.</param>
 /// <param name="rect">The plot bounds.</param>
 void IPlotModel.Render(IRenderContext rc, OxyRect rect)
 {
     this.RenderOverride(rc, rect);
 }
 /// <summary>
 /// Renders the (smoothed) line.
 /// </summary>
 /// <param name="rc">
 /// The render context.
 /// </param>
 /// <param name="clippingRect">
 /// The clipping rect.
 /// </param>
 /// <param name="pointsToRender">
 /// The points to render.
 /// </param>
 protected virtual void RenderSmoothedLine(IRenderContext rc, OxyRect clippingRect, IList<ScreenPoint> pointsToRender)
 {
     rc.DrawClippedLine(
         pointsToRender,
         clippingRect,
         this.MinimumSegmentLength * this.MinimumSegmentLength,
         this.GetSelectableColor(this.ActualColor),
         this.StrokeThickness,
         this.ActualLineStyle,
         this.LineJoin,
         false);
 }
 /// <summary>
 /// Renders the legend symbol for the line series on the
 /// specified rendering context.
 /// </summary>
 /// <param name="rc">
 /// The rendering context.
 /// </param>
 /// <param name="legendBox">
 /// The bounding rectangle of the legend box.
 /// </param>
 public override void RenderLegend(IRenderContext rc, OxyRect legendBox)
 {
     double xmid = (legendBox.Left + legendBox.Right) / 2;
     double ymid = (legendBox.Top + legendBox.Bottom) / 2;
     var pts = new[] { new ScreenPoint(legendBox.Left, ymid), new ScreenPoint(legendBox.Right, ymid) };
     rc.DrawLine(pts, this.GetSelectableColor(this.ActualColor), this.StrokeThickness, LineStyleHelper.GetDashArray(this.ActualLineStyle));
     var midpt = new ScreenPoint(xmid, ymid);
     rc.DrawMarker(
         midpt,
         legendBox,
         this.MarkerType,
         this.MarkerOutline,
         this.MarkerSize,
         this.MarkerFill,
         this.MarkerStroke,
         this.MarkerStrokeThickness);
 }
        /// <summary>
        ///     Gets the point on the series that is nearest the specified point.
        /// </summary>
        /// <param name="point">The point.</param>
        /// <param name="interpolate">
        ///     Interpolate the series if this flag is set to <c>true</c>.
        /// </param>
        /// <returns>A TrackerHitResult for the current hit.</returns>
        public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate)
        {
            foreach (var v in this.Values)
            {
                if (double.IsNaN(v) || v < this.XAxis.ActualMinimum || v > this.XAxis.ActualMaximum)
                {
                    continue;
                }

                double x = this.XAxis.Transform(v);
                var r = new OxyRect(
                    x - this.symbolSize.Width / 2,
                    this.symbolPosition - this.symbolSize.Height,
                    this.symbolSize.Width,
                    this.symbolSize.Height);
                if (r.Contains(point))
                {
                    var text = StringHelper.Format(this.ActualCulture, this.TrackerFormatString, null, this.Title, v);

                    return new TrackerHitResult(
                        this,
                        new DataPoint(v, double.NaN),
                        new ScreenPoint(x, this.symbolPosition - this.symbolSize.Height)) { Text = text };
                }
            }

            return null;
        }
        /// <summary>
        /// The draw rectangle.
        /// </summary>
        /// <param name="rect">
        /// The rect.
        /// </param>
        /// <param name="fill">
        /// The fill.
        /// </param>
        /// <param name="stroke">
        /// The stroke.
        /// </param>
        /// <param name="thickness">
        /// The thickness.
        /// </param>
        public override void DrawRectangle(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness)
        {
            if (fill != null)
            {
                this.g.FillRectangle(
                    this.ToBrush(fill), (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height);
            }

            if (stroke == null || thickness <= 0)
            {
                return;
            }

            var pen = new Pen(this.ToColor(stroke), (float)thickness);
            this.g.DrawRectangle(pen, (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height);
        }
 /// <summary>
 /// Fills a rectangle at the specified position.
 /// </summary>
 /// <param name="rc">The render context.</param>
 /// <param name="rectangle">The rectangle.</param>
 /// <param name="fill">The fill color.</param>
 public static void FillRectangle(this IRenderContext rc, OxyRect rectangle, OxyColor fill)
 {
     rc.DrawRectangle(rectangle, fill, OxyColors.Undefined, 0d);
 }
Exemple #14
0
        /// <summary>
        /// Renders the Series on the specified rendering context.
        /// </summary>
        /// <param name="rc">
        /// The rendering context.
        /// </param>
        /// <param name="model">
        /// The model.
        /// </param>
        public override void Render(IRenderContext rc, PlotModel model)
        {
            this.ActualMinimumBarRectangles = new List <OxyRect>();
            this.ActualMaximumBarRectangles = new List <OxyRect>();

            if (this.ValidItems.Count == 0)
            {
                return;
            }

            var clippingRect   = this.GetClippingRect();
            var categoryAxis   = this.GetCategoryAxis();
            var actualBarWidth = this.GetActualBarWidth();

            for (var i = 0; i < this.ValidItems.Count; i++)
            {
                var item = this.ValidItems[i];

                var categoryIndex = item.GetCategoryIndex(i);

                var baseValue = double.IsNaN(item.BaseValue) ? this.BaseValue : item.BaseValue;

                var p0 = this.Transform(item.Minimum, categoryIndex - 0.5 + categoryAxis.BarOffset[categoryIndex]);
                var p1 = this.Transform(
                    item.Maximum, categoryIndex - 0.5 + categoryAxis.BarOffset[categoryIndex] + actualBarWidth);
                var p2 = this.Transform(baseValue, categoryIndex - 0.5 + categoryAxis.BarOffset[categoryIndex]);
                p2.X = (int)p2.X;

                var minimumRectangle = OxyRect.Create(p0.X, p0.Y, p2.X, p1.Y);
                var maximumRectangle = OxyRect.Create(p2.X, p0.Y, p1.X, p1.Y);

                this.ActualMinimumBarRectangles.Add(minimumRectangle);
                this.ActualMaximumBarRectangles.Add(maximumRectangle);

                rc.DrawClippedRectangleAsPolygon(
                    minimumRectangle,
                    clippingRect,
                    item.MinimumColor ?? this.ActualMinimumFillColor,
                    this.StrokeColor,
                    this.StrokeThickness);
                rc.DrawClippedRectangleAsPolygon(
                    maximumRectangle,
                    clippingRect,
                    item.MaximumColor ?? this.ActualMaximumFillColor,
                    this.StrokeColor,
                    this.StrokeThickness);

                if (this.MinimumLabelFormatString != null)
                {
                    var s = StringHelper.Format(
                        this.ActualCulture,
                        this.MinimumLabelFormatString,
                        this.GetItem(this.ValidItemsIndexInversion[i]),
                        item.Minimum);
                    var pt = new ScreenPoint(
                        minimumRectangle.Left - this.LabelMargin, (minimumRectangle.Top + minimumRectangle.Bottom) / 2);

                    rc.DrawClippedText(
                        clippingRect,
                        pt,
                        s,
                        this.ActualTextColor,
                        this.ActualFont,
                        this.ActualFontSize,
                        this.ActualFontWeight,
                        0,
                        HorizontalTextAlign.Right,
                        VerticalTextAlign.Middle);
                }

                if (this.MaximumLabelFormatString != null)
                {
                    var s = StringHelper.Format(
                        this.ActualCulture,
                        this.MaximumLabelFormatString,
                        this.GetItem(this.ValidItemsIndexInversion[i]),
                        item.Maximum);
                    var pt = new ScreenPoint(
                        maximumRectangle.Right + this.LabelMargin, (maximumRectangle.Top + maximumRectangle.Bottom) / 2);

                    rc.DrawClippedText(
                        clippingRect,
                        pt,
                        s,
                        this.ActualTextColor,
                        this.ActualFont,
                        this.ActualFontSize,
                        this.ActualFontWeight,
                        0,
                        HorizontalTextAlign.Left,
                        VerticalTextAlign.Middle);
                }
            }
        }
 /// <summary>
 /// Sets the clipping rectangle.
 /// </summary>
 /// <param name="clippingRect">The clipping rectangle.</param>
 /// <returns>
 ///   <c>true</c> if the clip rectangle was set.
 /// </returns>
 public override bool SetClip(OxyRect clippingRect)
 {
     return(this.rc.SetClip(clippingRect));
 }
        /// <summary>
        /// Calculates the plot area (subtract padding, title size and outside legends)
        /// </summary>
        /// <param name="rc">The rendering context.</param>
        private void UpdatePlotArea(IRenderContext rc)
        {
            var plotArea = new OxyRect(
                this.PlotBounds.Left + this.Padding.Left,
                this.PlotBounds.Top + this.Padding.Top,
                Math.Max(0, this.Width - this.Padding.Left - this.Padding.Right),
                Math.Max(0, this.Height - this.Padding.Top - this.Padding.Bottom));

            var titleSize = this.MeasureTitles(rc);

            if (titleSize.Height > 0)
            {
                var titleHeight = titleSize.Height + this.TitlePadding;
                plotArea = new OxyRect(plotArea.Left, plotArea.Top + titleHeight, plotArea.Width, Math.Max(0, plotArea.Height - titleHeight));
            }

            plotArea = plotArea.Deflate(this.ActualPlotMargins);

            if (this.IsLegendVisible)
            {
                // Make space for legends

                OxySize maxLegendSize = new OxySize(0, 0);
                double  legendMargin  = 0;
                // first run Outside Left-Side legends
                foreach (var legend in this.Legends.Where(l =>
                                                          l.LegendPlacement == LegendPlacement.Outside && (l.IsLegendVisible &&
                                                                                                           (l.LegendPosition == LegendPosition.LeftTop || l.LegendPosition == LegendPosition.LeftMiddle || l.LegendPosition == LegendPosition.LeftBottom))))
                {
                    // Find the available size for the legend box
                    var availableLegendWidth  = plotArea.Width;
                    var availableLegendHeight = double.IsNaN(legend.LegendMaxHeight) ?
                                                plotArea.Height : Math.Min(plotArea.Height, legend.LegendMaxHeight);

                    var lsiz = legend.GetLegendSize(rc, new OxySize(availableLegendWidth, availableLegendHeight));
                    legend.LegendSize = lsiz;
                    maxLegendSize     = new OxySize(maxLegendSize.Width > lsiz.Width ? maxLegendSize.Width : lsiz.Width, maxLegendSize.Height > lsiz.Height ? maxLegendSize.Height : lsiz.Height);

                    if (legend.LegendMargin > legendMargin)
                    {
                        legendMargin = legend.LegendMargin;
                    }
                }

                // Adjust the plot area after the size of the legend has been calculated
                if (maxLegendSize.Width > 0 || maxLegendSize.Height > 0)
                {
                    plotArea = new OxyRect(plotArea.Left + maxLegendSize.Width + legendMargin, plotArea.Top, Math.Max(0, plotArea.Width - (maxLegendSize.Width + legendMargin)), plotArea.Height);
                }

                maxLegendSize = new OxySize(0, 0);
                legendMargin  = 0;
                // second run Outside Right-Side legends
                foreach (var legend in this.Legends.Where(l =>
                                                          l.LegendPlacement == LegendPlacement.Outside && (l.IsLegendVisible &&
                                                                                                           (l.LegendPosition == LegendPosition.RightTop || l.LegendPosition == LegendPosition.RightMiddle || l.LegendPosition == LegendPosition.RightBottom))))
                {
                    // Find the available size for the legend box
                    var availableLegendWidth  = plotArea.Width;
                    var availableLegendHeight = double.IsNaN(legend.LegendMaxHeight) ?
                                                plotArea.Height : Math.Min(plotArea.Height, legend.LegendMaxHeight);

                    var lsiz = legend.GetLegendSize(rc, new OxySize(availableLegendWidth, availableLegendHeight));
                    legend.LegendSize = lsiz;
                    maxLegendSize     = new OxySize(maxLegendSize.Width > lsiz.Width ? maxLegendSize.Width : lsiz.Width, maxLegendSize.Height > lsiz.Height ? maxLegendSize.Height : lsiz.Height);

                    if (legend.LegendMargin > legendMargin)
                    {
                        legendMargin = legend.LegendMargin;
                    }
                }

                // Adjust the plot area after the size of the legend has been calculated
                if (maxLegendSize.Width > 0 || maxLegendSize.Height > 0)
                {
                    plotArea = new OxyRect(plotArea.Left, plotArea.Top, Math.Max(0, plotArea.Width - (maxLegendSize.Width + legendMargin)), plotArea.Height);
                }

                maxLegendSize = new OxySize(0, 0);
                legendMargin  = 0;
                // third run Outside Top legends
                foreach (var legend in this.Legends.Where(l =>
                                                          l.LegendPlacement == LegendPlacement.Outside && (l.IsLegendVisible &&
                                                                                                           (l.LegendPosition == LegendPosition.TopLeft || l.LegendPosition == LegendPosition.TopCenter || l.LegendPosition == LegendPosition.TopRight))))
                {
                    // Find the available size for the legend box
                    var availableLegendWidth  = plotArea.Width;
                    var availableLegendHeight = double.IsNaN(legend.LegendMaxHeight) ?
                                                plotArea.Height : Math.Min(plotArea.Height, legend.LegendMaxHeight);

                    var lsiz = legend.GetLegendSize(rc, new OxySize(availableLegendWidth, availableLegendHeight));
                    legend.LegendSize = lsiz;
                    maxLegendSize     = new OxySize(maxLegendSize.Width > lsiz.Width ? maxLegendSize.Width : lsiz.Width, maxLegendSize.Height > lsiz.Height ? maxLegendSize.Height : lsiz.Height);

                    if (legend.LegendMargin > legendMargin)
                    {
                        legendMargin = legend.LegendMargin;
                    }
                }

                // Adjust the plot area after the size of the legend has been calculated
                if (maxLegendSize.Width > 0 || maxLegendSize.Height > 0)
                {
                    plotArea = new OxyRect(plotArea.Left, plotArea.Top + maxLegendSize.Height + legendMargin, plotArea.Width, Math.Max(0, plotArea.Height - (maxLegendSize.Height + legendMargin)));
                }

                maxLegendSize = new OxySize(0, 0);
                legendMargin  = 0;
                // fourth run Outside Bottom legends
                foreach (var legend in this.Legends.Where(l =>
                                                          l.LegendPlacement == LegendPlacement.Outside && (l.IsLegendVisible &&
                                                                                                           (l.LegendPosition == LegendPosition.BottomLeft || l.LegendPosition == LegendPosition.BottomCenter || l.LegendPosition == LegendPosition.BottomRight))))
                {
                    // Find the available size for the legend box
                    var availableLegendWidth  = plotArea.Width;
                    var availableLegendHeight = double.IsNaN(legend.LegendMaxHeight) ?
                                                plotArea.Height : Math.Min(plotArea.Height, legend.LegendMaxHeight);

                    var lsiz = legend.GetLegendSize(rc, new OxySize(availableLegendWidth, availableLegendHeight));
                    legend.LegendSize = lsiz;
                    maxLegendSize     = new OxySize(maxLegendSize.Width > lsiz.Width ? maxLegendSize.Width : lsiz.Width, maxLegendSize.Height > lsiz.Height ? maxLegendSize.Height : lsiz.Height);

                    if (legend.LegendMargin > legendMargin)
                    {
                        legendMargin = legend.LegendMargin;
                    }
                }

                // Adjust the plot area after the size of the legend has been calculated
                if (maxLegendSize.Width > 0 || maxLegendSize.Height > 0)
                {
                    plotArea = new OxyRect(plotArea.Left, plotArea.Top, plotArea.Width, Math.Max(0, plotArea.Height - (maxLegendSize.Height + legendMargin)));
                }

                // Finally calculate size of inside legends
                foreach (var legend in this.Legends.Where(l => l.LegendPlacement == LegendPlacement.Inside && l.IsLegendVisible))
                {
                    // Find the available size for the legend box
                    var availableLegendWidth  = plotArea.Width;
                    var availableLegendHeight = double.IsNaN(legend.LegendMaxHeight) ?
                                                plotArea.Height : Math.Min(plotArea.Height, legend.LegendMaxHeight);

                    if (legend.LegendPlacement == LegendPlacement.Inside)
                    {
                        availableLegendWidth  -= legend.LegendMargin * 2;
                        availableLegendHeight -= legend.LegendMargin * 2;
                    }

                    legend.LegendSize = legend.GetLegendSize(rc, new OxySize(availableLegendWidth, availableLegendHeight));
                }
            }

            // Ensure the plot area is valid
            if (plotArea.Height < 0)
            {
                plotArea = new OxyRect(plotArea.Left, plotArea.Top, plotArea.Width, 1);
            }

            if (plotArea.Width < 0)
            {
                plotArea = new OxyRect(plotArea.Left, plotArea.Top, 1, plotArea.Height);
            }

            this.PlotArea        = plotArea;
            this.PlotAndAxisArea = plotArea.Inflate(this.ActualPlotMargins);

            switch (this.TitleHorizontalAlignment)
            {
            case TitleHorizontalAlignment.CenteredWithinView:
                this.TitleArea = new OxyRect(
                    this.PlotBounds.Left,
                    this.PlotBounds.Top + this.Padding.Top,
                    this.Width,
                    titleSize.Height + (this.TitlePadding * 2));
                break;

            default:
                this.TitleArea = new OxyRect(
                    this.PlotArea.Left,
                    this.PlotBounds.Top + this.Padding.Top,
                    this.PlotArea.Width,
                    titleSize.Height + (this.TitlePadding * 2));
                break;
            }

            // Calculate the legend area for each legend.
            foreach (var l in this.Legends)
            {
                l.LegendArea = l.GetLegendRectangle(l.LegendSize);
            }
        }
        /// <summary>
        /// Renders the plot with the specified rendering context.
        /// </summary>
        /// <param name="rc">The rendering context.</param>
        /// <param name="rect">The plot bounds.</param>
        protected virtual void RenderOverride(IRenderContext rc, OxyRect rect)
        {
            lock (this.SyncRoot)
            {
                try
                {
                    if (this.lastPlotException != null)
                    {
                        // There was an exception during plot model update.
                        // This could happen when OxyPlot is given invalid input data.
                        // The client application should be responsible for handling this.
                        // If the client application submitted invalid data, show the exception message and stack trace.
                        var errorMessage = string.Format(
                            "An exception of type {0} was thrown when updating the plot model.\r\n{1}",
                            this.lastPlotException.GetType(),
                            this.lastPlotException.GetBaseException().StackTrace);
                        this.RenderErrorMessage(rc, string.Format("OxyPlot exception: {0}", this.lastPlotException.Message), errorMessage);
                        return;
                    }

                    if (this.RenderingDecorator != null)
                    {
                        rc = this.RenderingDecorator(rc);
                    }

                    this.PlotBounds = rect;

                    this.ActualPlotMargins =
                        new OxyThickness(
                            double.IsNaN(this.PlotMargins.Left) ? 0 : this.PlotMargins.Left,
                            double.IsNaN(this.PlotMargins.Top) ? 0 : this.PlotMargins.Top,
                            double.IsNaN(this.PlotMargins.Right) ? 0 : this.PlotMargins.Right,
                            double.IsNaN(this.PlotMargins.Bottom) ? 0 : this.PlotMargins.Bottom);

                    foreach (var l in this.Legends)
                    {
                        l.EnsureLegendProperties();
                    }

                    while (true)
                    {
                        this.UpdatePlotArea(rc);
                        this.UpdateAxisTransforms();
                        this.UpdateIntervals();

                        if (!this.AdjustPlotMargins(rc))
                        {
                            break;
                        }
                    }

                    if (this.PlotType == PlotType.Cartesian)
                    {
                        this.EnforceCartesianTransforms();
                        this.UpdateIntervals();
                    }

                    foreach (var a in this.Axes)
                    {
                        a.ResetCurrentValues();
                    }

                    this.RenderBackgrounds(rc);
                    this.RenderAnnotations(rc, AnnotationLayer.BelowAxes);
                    this.RenderAxes(rc, AxisLayer.BelowSeries);
                    this.RenderAnnotations(rc, AnnotationLayer.BelowSeries);
                    this.RenderSeries(rc);
                    this.RenderAnnotations(rc, AnnotationLayer.AboveSeries);
                    this.RenderTitle(rc);
                    this.RenderBox(rc);
                    this.RenderAxes(rc, AxisLayer.AboveSeries);

                    if (this.IsLegendVisible)
                    {
                        this.RenderLegends(rc);
                    }
                }
                catch (Exception exception)
                {
                    // An exception was raised during rendering. This should not happen...
                    var errorMessage = string.Format(
                        "An exception of type {0} was thrown when rendering the plot model.\r\n{1}",
                        exception.GetType(),
                        exception.GetBaseException().StackTrace);
                    this.lastPlotException = exception;
                    this.RenderErrorMessage(rc, string.Format("OxyPlot exception: {0}", exception.Message), errorMessage);
                }
                finally
                {
                    // Clean up unused images
                    rc.CleanUp();
                }
            }
        }
        /// <summary>
        /// Calculates the clipped version of a rectangle.
        /// </summary>
        /// <param name="rect">
        /// The rectangle to clip.
        /// </param>
        /// <param name="clippingRectangle">
        /// The clipping rectangle.
        /// </param>
        /// <returns>
        /// The clipped rectangle, or null if the rectangle is outside the clipping area.
        /// </returns>
        private static OxyRect? ClipRect(OxyRect rect, OxyRect clippingRectangle)
        {
            if (rect.Right < clippingRectangle.Left)
            {
                return null;
            }

            if (rect.Left > clippingRectangle.Right)
            {
                return null;
            }

            if (rect.Top > clippingRectangle.Bottom)
            {
                return null;
            }

            if (rect.Bottom < clippingRectangle.Top)
            {
                return null;
            }

            if (rect.Right > clippingRectangle.Right)
            {
                rect.Right = clippingRectangle.Right;
            }

            if (rect.Left < clippingRectangle.Left)
            {
                rect.Width = rect.Right - clippingRectangle.Left;
                rect.Left = clippingRectangle.Left;
            }

            if (rect.Top < clippingRectangle.Top)
            {
                rect.Height = rect.Bottom - clippingRectangle.Top;
                rect.Top = clippingRectangle.Top;
            }

            if (rect.Bottom > clippingRectangle.Bottom)
            {
                rect.Bottom = clippingRectangle.Bottom;
            }

            if (rect.Width <= 0 || rect.Height <= 0)
            {
                return null;
            }

            return rect;
        }
 /// <summary>
 /// Renders the icon on the specified render context.
 /// </summary>
 /// <param name="rc">The render context.</param>
 /// <param name="size">The size.</param>
 public override void Render(IRenderContext rc, double size)
 {
     var m = size * 0.05;
     var rect = new OxyRect(m, m, size - m * 2, size - m * 2);
     rc.DrawEllipse(rect, OxyColors.Black, OxyColors.Black, 0);
     rc.DrawText(new ScreenPoint(size * 0.52, size * 0.32), "XY", OxyColors.White, "Arial", size * 0.25, FontWeights.Bold, 0, HorizontalAlignment.Center, VerticalAlignment.Middle);
     rc.DrawText(new ScreenPoint(size * 0.52, size * 0.64), "PLOT", OxyColors.White, "Arial", size * 0.25, FontWeights.Bold, 0, HorizontalAlignment.Center, VerticalAlignment.Middle);
 }
        /// <summary>
        /// Renders the point labels.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="clippingRect">The clipping rect.</param>
        protected void RenderPointLabels(IRenderContext rc, OxyRect clippingRect)
        {
            int index = -1;

            foreach (var point in this.Points)
            {
                index++;

                if (!this.IsValidPoint(point, this.XAxis, this.YAxis))
                {
                    continue;
                }

                var pt = this.XAxis.Transform(point.X, point.Y, this.YAxis);
                pt.Y -= this.LabelMargin;

                if (!clippingRect.Contains(pt))
                {
                    continue;
                }

                var s = StringHelper.Format(
                    this.ActualCulture, this.LabelFormatString, this.GetItem(index), point.X, point.Y);

#if SUPPORTLABELPLACEMENT
                switch (this.LabelPlacement)
                {
                case LabelPlacement.Inside:
                    pt = new ScreenPoint(rect.Right - this.LabelMargin, (rect.Top + rect.Bottom) / 2);
                    ha = HorizontalTextAlign.Right;
                    break;

                case LabelPlacement.Middle:
                    pt = new ScreenPoint((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2);
                    ha = HorizontalTextAlign.Center;
                    break;

                case LabelPlacement.Base:
                    pt = new ScreenPoint(rect.Left + this.LabelMargin, (rect.Top + rect.Bottom) / 2);
                    ha = HorizontalTextAlign.Left;
                    break;

                default:         // Outside
                    pt = new ScreenPoint(rect.Right + this.LabelMargin, (rect.Top + rect.Bottom) / 2);
                    ha = HorizontalTextAlign.Left;
                    break;
                }
#endif

                rc.DrawClippedText(
                    clippingRect,
                    pt,
                    s,
                    this.ActualTextColor,
                    this.ActualFont,
                    this.ActualFontSize,
                    this.ActualFontWeight,
                    0,
                    HorizontalTextAlign.Center,
                    VerticalTextAlign.Bottom);
            }
        }
 public void ShowZoomRectangle(OxyRect r)
 {
     zoomRectangle = new Rectangle((int)r.Left, (int)r.Top, (int)r.Width, (int)r.Height);
     Invalidate();
 }
        /// <summary>
        /// Calculates the plot area (subtract padding, title size and outside legends)
        /// </summary>
        /// <param name="rc">
        /// The rendering context.
        /// </param>
        private void UpdatePlotArea(IRenderContext rc)
        {
            var plotArea = new OxyRect(
                this.Padding.Left,
                this.Padding.Top,
                this.Width - this.Padding.Left - this.Padding.Right,
                this.Height - this.Padding.Top - this.Padding.Bottom);

            var titleSize = this.MeasureTitles(rc);

            if (titleSize.Height > 0)
            {
                double titleHeight = titleSize.Height + this.TitlePadding;
                plotArea.Height -= titleHeight;
                plotArea.Top    += titleHeight;
            }

            plotArea.Top    += this.ActualPlotMargins.Top;
            plotArea.Height -= this.ActualPlotMargins.Top;

            plotArea.Height -= this.ActualPlotMargins.Bottom;

            plotArea.Left  += this.ActualPlotMargins.Left;
            plotArea.Width -= this.ActualPlotMargins.Left;

            plotArea.Width -= this.ActualPlotMargins.Right;

            // Find the available size for the legend box
            double availableLegendWidth  = plotArea.Width;
            double availableLegendHeight = plotArea.Height;

            if (this.LegendPlacement == LegendPlacement.Inside)
            {
                availableLegendWidth  -= this.LegendMargin * 2;
                availableLegendHeight -= this.LegendMargin * 2;
            }

            if (availableLegendWidth < 0)
            {
                availableLegendWidth = 0;
            }

            if (availableLegendHeight < 0)
            {
                availableLegendHeight = 0;
            }

            // Calculate the size of the legend box
            var legendSize = this.MeasureLegends(rc, new OxySize(availableLegendWidth, availableLegendHeight));

            // Adjust the plot area after the size of the legend box has been calculated
            if (this.IsLegendVisible && this.LegendPlacement == LegendPlacement.Outside)
            {
                switch (this.LegendPosition)
                {
                case LegendPosition.LeftTop:
                case LegendPosition.LeftMiddle:
                case LegendPosition.LeftBottom:
                    plotArea.Left  += legendSize.Width + this.LegendMargin;
                    plotArea.Width -= legendSize.Width + this.LegendMargin;
                    break;

                case LegendPosition.RightTop:
                case LegendPosition.RightMiddle:
                case LegendPosition.RightBottom:
                    plotArea.Width -= legendSize.Width + this.LegendMargin;
                    break;

                case LegendPosition.TopLeft:
                case LegendPosition.TopCenter:
                case LegendPosition.TopRight:
                    plotArea.Top    += legendSize.Height + this.LegendMargin;
                    plotArea.Height -= legendSize.Height + this.LegendMargin;
                    break;

                case LegendPosition.BottomLeft:
                case LegendPosition.BottomCenter:
                case LegendPosition.BottomRight:
                    plotArea.Height -= legendSize.Height + this.LegendMargin;
                    break;
                }
            }

            // Ensure the plot area is valid
            if (plotArea.Height < 0)
            {
                plotArea.Bottom = plotArea.Top + 1;
            }

            if (plotArea.Width < 0)
            {
                plotArea.Right = plotArea.Left + 1;
            }

            this.PlotArea        = plotArea;
            this.PlotAndAxisArea = new OxyRect(
                plotArea.Left - this.ActualPlotMargins.Left,
                plotArea.Top - this.ActualPlotMargins.Top,
                plotArea.Width + this.ActualPlotMargins.Left + this.ActualPlotMargins.Right,
                plotArea.Height + this.ActualPlotMargins.Top + this.ActualPlotMargins.Bottom);
            this.TitleArea  = new OxyRect(this.PlotArea.Left, this.Padding.Top, this.PlotArea.Width, titleSize.Height + (this.TitlePadding * 2));
            this.LegendArea = this.GetLegendRectangle(legendSize);
        }
Exemple #23
0
 /// <summary>
 /// Renders or measures the legends.
 /// </summary>
 /// <param name="rc">The render context.</param>
 /// <param name="rect">The rectangle.</param>
 private void RenderLegends(IRenderContext rc, OxyRect rect)
 {
     this.RenderOrMeasureLegends(rc, rect);
 }
Exemple #24
0
        /// <summary>
        /// Renders the legend for the specified series.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="s">The series.</param>
        /// <param name="rect">The position and size of the legend.</param>
        private void RenderLegend(IRenderContext rc, Series.Series s, OxyRect rect)
        {
            var actualItemAlignment = this.LegendItemAlignment;

            if (this.LegendOrientation == LegendOrientation.Horizontal)
            {
                // center/right alignment is not supported for horizontal orientation
                actualItemAlignment = HorizontalAlignment.Left;
            }

            double x = rect.Left;

            switch (actualItemAlignment)
            {
            case HorizontalAlignment.Center:
                x = (rect.Left + rect.Right) / 2;
                if (this.LegendSymbolPlacement == LegendSymbolPlacement.Left)
                {
                    x -= (this.LegendSymbolLength + this.LegendSymbolMargin) / 2;
                }
                else
                {
                    x -= (this.LegendSymbolLength + this.LegendSymbolMargin) / 2;
                }

                break;

            case HorizontalAlignment.Right:
                x = rect.Right;

                // if (LegendSymbolPlacement == LegendSymbolPlacement.Right)
                x -= this.LegendSymbolLength + this.LegendSymbolMargin;
                break;
            }

            if (this.LegendSymbolPlacement == LegendSymbolPlacement.Left)
            {
                x += this.LegendSymbolLength + this.LegendSymbolMargin;
            }

            double y       = rect.Top;
            var    maxsize = new OxySize(Math.Max(rect.Width - this.LegendSymbolLength - this.LegendSymbolMargin, 0), rect.Height);

            rc.SetToolTip(s.ToolTip);
            var textSize = rc.DrawMathText(
                new ScreenPoint(x, y),
                s.Title,
                this.LegendTextColor.GetActualColor(this.TextColor),
                this.LegendFont ?? this.DefaultFont,
                this.LegendFontSize,
                this.LegendFontWeight,
                0,
                actualItemAlignment,
                VerticalAlignment.Top,
                maxsize,
                true);
            double x0 = x;

            switch (actualItemAlignment)
            {
            case HorizontalAlignment.Center:
                x0 = x - (textSize.Width * 0.5);
                break;

            case HorizontalAlignment.Right:
                x0 = x - textSize.Width;
                break;
            }

            var symbolRect =
                new OxyRect(
                    this.LegendSymbolPlacement == LegendSymbolPlacement.Right
                        ? x0 + textSize.Width + this.LegendSymbolMargin
                        : x0 - this.LegendSymbolMargin - this.LegendSymbolLength,
                    rect.Top,
                    this.LegendSymbolLength,
                    textSize.Height);

            s.RenderLegend(rc, symbolRect);
            rc.SetToolTip(null);
        }
        /// <summary>
        /// Renders a legend on the line.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="clippingRect">The clipping rectangle.</param>
        protected void RenderLegendOnLine(IRenderContext rc, OxyRect clippingRect)
        {
            // Find the position
            IDataPoint point;
            var ha = HorizontalTextAlign.Left;
            double dx;
            switch (this.LineLegendPosition)
            {
                case LineLegendPosition.Start:
                    // start position
                    point = this.Points[0];
                    ha = HorizontalTextAlign.Right;
                    dx = -4;
                    break;
                default:
                    // end position
                    point = this.Points[this.Points.Count - 1];
                    dx = 4;
                    break;
            }

            var pt = this.XAxis.Transform(point.X, point.Y, this.YAxis);
            pt.X += dx;

            // Render the legend
            rc.DrawClippedText(
                clippingRect,
                pt,
                this.Title,
                this.ActualTextColor,
                this.ActualFont,
                this.ActualFontSize,
                this.ActualFontWeight,
                0,
                ha,
                VerticalTextAlign.Middle);
        }
Exemple #26
0
        /// <summary>
        /// Draws an ellipse.
        /// </summary>
        /// <param name="rect">The rectangle.</param>
        /// <param name="fill">The fill color.</param>
        /// <param name="stroke">The stroke color.</param>
        /// <param name="thickness">The thickness.</param>
        public virtual void DrawEllipse(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness)
        {
            var polygon = CreateEllipse(rect);

            this.DrawPolygon(polygon, fill, stroke, thickness, null, LineJoin.Miter, false);
        }
 /// <summary>
 /// Sets the clip rectangle.
 /// </summary>
 /// <param name="rect">The clip rectangle.</param>
 /// <returns>
 /// True if the clip rectangle was set.
 /// </returns>
 public bool SetClip(OxyRect rect)
 {
     return true;
 }
 /// <summary>
 /// Draws a list of markers.
 /// </summary>
 /// <param name="rc">
 /// The render context.
 /// </param>
 /// <param name="markerPoints">
 /// The marker points.
 /// </param>
 /// <param name="clippingRect">
 /// The clipping rectangle.
 /// </param>
 /// <param name="markerType">
 /// Type of the marker.
 /// </param>
 /// <param name="markerOutline">
 /// The marker outline.
 /// </param>
 /// <param name="markerSize">
 /// Size of the marker.
 /// </param>
 /// <param name="markerFill">
 /// The marker fill.
 /// </param>
 /// <param name="markerStroke">
 /// The marker stroke.
 /// </param>
 /// <param name="markerStrokeThickness">
 /// The marker stroke thickness.
 /// </param>
 /// <param name="resolution">
 /// The resolution.
 /// </param>
 /// <param name="binOffset">
 /// The bin Offset.
 /// </param>
 public static void DrawMarkers(
     this IRenderContext rc,
     IList<ScreenPoint> markerPoints,
     OxyRect clippingRect,
     MarkerType markerType,
     IList<ScreenPoint> markerOutline,
     double markerSize,
     OxyColor markerFill,
     OxyColor markerStroke,
     double markerStrokeThickness,
     int resolution = 0,
     ScreenPoint binOffset = new ScreenPoint())
 {
     DrawMarkers(
         rc,
         markerPoints,
         clippingRect,
         markerType,
         markerOutline,
         new[] { markerSize },
         markerFill,
         markerStroke,
         markerStrokeThickness,
         resolution,
         binOffset);
 }
Exemple #29
0
 /// <summary>
 /// Draws the rectangle.
 /// </summary>
 /// <param name="rect">The rectangle.</param>
 /// <param name="fill">The fill color.</param>
 /// <param name="stroke">The stroke color.</param>
 /// <param name="thickness">The stroke thickness.</param>
 public override void DrawRectangle(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness)
 {
     this.w.WriteRectangle(rect.Left, rect.Top, rect.Width, rect.Height, this.w.CreateStyle(fill, stroke, thickness));
 }
        /// <summary>
        /// Renders the bar/column item.
        /// </summary>
        /// <param name="rc">
        /// The render context.
        /// </param>
        /// <param name="clippingRect">
        /// The clipping rectangle.
        /// </param>
        /// <param name="topValue">
        /// The end value of the bar.
        /// </param>
        /// <param name="categoryValue">
        /// The category value.
        /// </param>
        /// <param name="actualBarWidth">
        /// The actual width of the bar.
        /// </param>
        /// <param name="item">
        /// The item.
        /// </param>
        /// <param name="rect">
        /// The rectangle of the bar.
        /// </param>
        protected override void RenderItem(
            IRenderContext rc,
            OxyRect clippingRect,
            double topValue,
            double categoryValue,
            double actualBarWidth,
            BarItemBase item,
            OxyRect rect)
        {
            base.RenderItem(rc, clippingRect, topValue, categoryValue, actualBarWidth, item, rect);

            var errorItem = item as ErrorColumnItem;

            if (errorItem == null)
            {
                return;
            }

            // Render the error
            var lowerValue  = topValue - errorItem.Error;
            var upperValue  = topValue + errorItem.Error;
            var left        = 0.5 - this.ErrorWidth / 2;
            var right       = 0.5 + this.ErrorWidth / 2;
            var leftValue   = categoryValue + (left * actualBarWidth);
            var middleValue = categoryValue + (0.5 * actualBarWidth);
            var rightValue  = categoryValue + (right * actualBarWidth);

            var lowerErrorPoint = this.Transform(middleValue, lowerValue);
            var upperErrorPoint = this.Transform(middleValue, upperValue);

            rc.DrawClippedLine(
                new List <ScreenPoint> {
                lowerErrorPoint, upperErrorPoint
            },
                clippingRect,
                0,
                this.StrokeColor,
                this.ErrorStrokeThickness,
                LineStyle.Solid,
                OxyPenLineJoin.Miter,
                true);

            if (this.ErrorWidth > 0)
            {
                var lowerLeftErrorPoint  = this.Transform(leftValue, lowerValue);
                var lowerRightErrorPoint = this.Transform(rightValue, lowerValue);
                rc.DrawClippedLine(
                    new List <ScreenPoint> {
                    lowerLeftErrorPoint, lowerRightErrorPoint
                },
                    clippingRect,
                    0,
                    this.StrokeColor,
                    this.ErrorStrokeThickness,
                    LineStyle.Solid,
                    OxyPenLineJoin.Miter,
                    true);

                var upperLeftErrorPoint  = this.Transform(leftValue, upperValue);
                var upperRightErrorPoint = this.Transform(rightValue, upperValue);
                rc.DrawClippedLine(
                    new List <ScreenPoint> {
                    upperLeftErrorPoint, upperRightErrorPoint
                },
                    clippingRect,
                    0,
                    this.StrokeColor,
                    this.ErrorStrokeThickness,
                    LineStyle.Solid,
                    OxyPenLineJoin.Miter,
                    true);
            }
        }
 public override bool SetClip(OxyRect rect)
 {
     _g.PushClipBox((float)rect.Left, (float)rect.Top, (float)rect.Right, (float)rect.Bottom);
     return(true);
 }
Exemple #32
0
 public AutoResetClipToken(IRenderContext renderContext, OxyRect clippingRectangle)
 {
     this.renderContext = renderContext;
     renderContext.SetClip(clippingRectangle);
 }
        /// <summary>
        /// Draws a list of markers.
        /// </summary>
        /// <param name="rc">
        /// The render context.
        /// </param>
        /// <param name="markerPoints">
        /// The marker points.
        /// </param>
        /// <param name="clippingRect">
        /// The clipping rectangle.
        /// </param>
        /// <param name="markerType">
        /// Type of the marker.
        /// </param>
        /// <param name="markerOutline">
        /// The marker outline.
        /// </param>
        /// <param name="markerSize">
        /// Size of the markers.
        /// </param>
        /// <param name="markerFill">
        /// The marker fill.
        /// </param>
        /// <param name="markerStroke">
        /// The marker stroke.
        /// </param>
        /// <param name="markerStrokeThickness">
        /// The marker stroke thickness.
        /// </param>
        /// <param name="resolution">
        /// The resolution.
        /// </param>
        /// <param name="binOffset">
        /// The bin Offset.
        /// </param>
        public static void DrawMarkers(
            this IRenderContext rc,
            IList<ScreenPoint> markerPoints,
            OxyRect clippingRect,
            MarkerType markerType,
            IList<ScreenPoint> markerOutline,
            IList<double> markerSize,
            OxyColor markerFill,
            OxyColor markerStroke,
            double markerStrokeThickness,
            int resolution = 0,
            ScreenPoint binOffset = new ScreenPoint())
        {
            if (markerType == MarkerType.None)
            {
                return;
            }

            int n = markerPoints.Count;
            var ellipses = new List<OxyRect>(n);
            var rects = new List<OxyRect>(n);
            var polygons = new List<IList<ScreenPoint>>(n);
            var lines = new List<ScreenPoint>(n);

            var hashset = new HashSet<uint>();

            int i = 0;

            double minx = clippingRect.Left;
            double maxx = clippingRect.Right;
            double miny = clippingRect.Top;
            double maxy = clippingRect.Bottom;

            foreach (var p in markerPoints)
            {
                if (resolution > 1)
                {
                    var x = (int)((p.X - binOffset.X) / resolution);
                    var y = (int)((p.Y - binOffset.Y) / resolution);
                    uint hash = (uint)(x << 16) + (uint)y;
                    if (hashset.Contains(hash))
                    {
                        i++;
                        continue;
                    }

                    hashset.Add(hash);
                }

                bool outside = p.x < minx || p.x > maxx || p.y < miny || p.y > maxy;
                if (!outside)
                {
                    int j = i < markerSize.Count ? i : 0;
                    AddMarkerGeometry(p, markerType, markerOutline, markerSize[j], ellipses, rects, polygons, lines);
                }

                i++;
            }

            if (ellipses.Count > 0)
            {
                rc.DrawEllipses(ellipses, markerFill, markerStroke, markerStrokeThickness);
            }

            if (rects.Count > 0)
            {
                rc.DrawRectangles(rects, markerFill, markerStroke, markerStrokeThickness);
            }

            if (polygons.Count > 0)
            {
                rc.DrawPolygons(polygons, markerFill, markerStroke, markerStrokeThickness);
            }

            if (lines.Count > 0)
            {
                rc.DrawLineSegments(lines, markerStroke, markerStrokeThickness);
            }
        }
Exemple #34
0
        /// <summary>
        /// Draws a list of markers.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="clippingRectangle">The clipping rectangle.</param>
        /// <param name="markerPoints">The marker points.</param>
        /// <param name="markerType">Type of the marker.</param>
        /// <param name="markerOutline">The marker outline.</param>
        /// <param name="markerSize">Size of the markers.</param>
        /// <param name="markerFill">The marker fill.</param>
        /// <param name="markerStroke">The marker stroke.</param>
        /// <param name="markerStrokeThickness">The marker stroke thickness.</param>
        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
        /// <param name="resolution">The resolution.</param>
        /// <param name="binOffset">The bin Offset.</param>
        public static void DrawMarkers(
            this IRenderContext rc,
            OxyRect clippingRectangle,
            IList <ScreenPoint> markerPoints,
            MarkerType markerType,
            IList <ScreenPoint> markerOutline,
            IList <double> markerSize,
            OxyColor markerFill,
            OxyColor markerStroke,
            double markerStrokeThickness,
            EdgeRenderingMode edgeRenderingMode,
            int resolution        = 0,
            ScreenPoint binOffset = new ScreenPoint())
        {
            if (markerType == MarkerType.None)
            {
                return;
            }

            int n        = markerPoints.Count;
            var ellipses = new List <OxyRect>(n);
            var rects    = new List <OxyRect>(n);
            var polygons = new List <IList <ScreenPoint> >(n);
            var lines    = new List <ScreenPoint>(n);

            var hashset = new Dictionary <uint, bool>();

            int i = 0;

            double minx = clippingRectangle.Left;
            double maxx = clippingRectangle.Right;
            double miny = clippingRectangle.Top;
            double maxy = clippingRectangle.Bottom;

            foreach (var p in markerPoints)
            {
                if (resolution > 1)
                {
                    var  x    = (int)((p.X - binOffset.X) / resolution);
                    var  y    = (int)((p.Y - binOffset.Y) / resolution);
                    uint hash = (uint)(x << 16) + (uint)y;
                    if (hashset.ContainsKey(hash))
                    {
                        i++;
                        continue;
                    }

                    hashset.Add(hash, true);
                }

                bool outside = p.x <minx || p.x> maxx || p.y <miny || p.y> maxy;
                if (!outside)
                {
                    int j = i < markerSize.Count ? i : 0;
                    AddMarkerGeometry(p, markerType, markerOutline, markerSize[j], ellipses, rects, polygons, lines);
                }

                i++;
            }

            if (edgeRenderingMode == EdgeRenderingMode.Automatic)
            {
                edgeRenderingMode = EdgeRenderingMode.PreferGeometricAccuracy;
            }

            if (ellipses.Count > 0)
            {
                rc.DrawEllipses(ellipses, markerFill, markerStroke, markerStrokeThickness, edgeRenderingMode);
            }

            if (rects.Count > 0)
            {
                rc.DrawRectangles(rects, markerFill, markerStroke, markerStrokeThickness, edgeRenderingMode);
            }

            if (polygons.Count > 0)
            {
                rc.DrawPolygons(polygons, markerFill, markerStroke, markerStrokeThickness, edgeRenderingMode);
            }

            if (lines.Count > 0)
            {
                rc.DrawLineSegments(lines, markerStroke, markerStrokeThickness, edgeRenderingMode);
            }
        }
        /// <summary>
        /// Draws the rectangle as an aliased polygon.
        /// (makes sure pixel alignment is the same as for lines)
        /// </summary>
        /// <param name="rc">
        /// The render context.
        /// </param>
        /// <param name="rect">
        /// The rectangle.
        /// </param>
        /// <param name="fill">
        /// The fill.
        /// </param>
        /// <param name="stroke">
        /// The stroke.
        /// </param>
        /// <param name="thickness">
        /// The thickness.
        /// </param>
        public static void DrawRectangleAsPolygon(
            this IRenderContext rc, OxyRect rect, OxyColor fill, OxyColor stroke, OxyThickness thickness)
        {
            if (thickness.Left == thickness.Right && thickness.Left == thickness.Top
                && thickness.Left == thickness.Bottom)
            {
                DrawRectangleAsPolygon(rc, rect, fill, stroke, thickness.Left);
                return;
            }

            var sp0 = new ScreenPoint(rect.Left, rect.Top);
            var sp1 = new ScreenPoint(rect.Right, rect.Top);
            var sp2 = new ScreenPoint(rect.Right, rect.Bottom);
            var sp3 = new ScreenPoint(rect.Left, rect.Bottom);
            rc.DrawPolygon(new[] { sp0, sp1, sp2, sp3 }, fill, null, 0, null, OxyPenLineJoin.Miter, true);
            rc.DrawPolygon(new[] { sp0, sp1 }, null, stroke, thickness.Top, null, OxyPenLineJoin.Miter, true);
            rc.DrawPolygon(new[] { sp1, sp2 }, null, stroke, thickness.Right, null, OxyPenLineJoin.Miter, true);
            rc.DrawPolygon(new[] { sp2, sp3 }, null, stroke, thickness.Bottom, null, OxyPenLineJoin.Miter, true);
            rc.DrawPolygon(new[] { sp3, sp0 }, null, stroke, thickness.Left, null, OxyPenLineJoin.Miter, true);
        }
Exemple #36
0
 /// <summary>
 /// Fills a rectangle at the specified position.
 /// </summary>
 /// <param name="rc">The render context.</param>
 /// <param name="rectangle">The rectangle.</param>
 /// <param name="fill">The fill color.</param>
 /// <param name="edgeRenderingMode">The edge rendering mode.</param>
 public static void FillRectangle(this IRenderContext rc, OxyRect rectangle, OxyColor fill, EdgeRenderingMode edgeRenderingMode)
 {
     rc.DrawRectangle(rectangle, fill, OxyColors.Undefined, 0d, edgeRenderingMode);
 }
        /// <summary>
        /// Draws the clipped line.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="points">The points.</param>
        /// <param name="clippingRectangle">The clipping rectangle.</param>
        /// <param name="minDistSquared">The min dist squared.</param>
        /// <param name="stroke">The stroke.</param>
        /// <param name="strokeThickness">The stroke thickness.</param>
        /// <param name="lineStyle">The line style.</param>
        /// <param name="lineJoin">The line join.</param>
        /// <param name="aliased">if set to <c>true</c> [aliased].</param>
        /// <param name="pointsRendered">The points rendered callback.</param>
        public static void DrawClippedLine(
            this IRenderContext rc,
            IList<ScreenPoint> points,
            OxyRect clippingRectangle,
            double minDistSquared,
            OxyColor stroke,
            double strokeThickness,
            LineStyle lineStyle,
            OxyPenLineJoin lineJoin,
            bool aliased,
            Action<IList<ScreenPoint>> pointsRendered = null)
        {
            var clipping = new CohenSutherlandClipping(
                clippingRectangle.Left, clippingRectangle.Right, clippingRectangle.Top, clippingRectangle.Bottom);

            var pts = new List<ScreenPoint>();
            int n = points.Count;
            if (n > 0)
            {

                if (n == 1)
                {
                    pts.Add(points[0]);
                }

                var last = points[0];
                for (int i = 1; i < n; i++)
                {
                    var s0 = points[i - 1];
                    var s1 = points[i];

                    // Clipped version of this and next point.
                    var s0c = s0;
                    var s1c = s1;
                    bool isInside = clipping.ClipLine(ref s0c, ref s1c);
                    s0 = s1;

                    if (!isInside)
                    {
                        // keep the previous coordinate
                        continue;
                    }

                    // render from s0c-s1c
                    double dx = s1c.x - last.x;
                    double dy = s1c.y - last.y;

                    if (dx * dx + dy * dy > minDistSquared || i == 1 || i == n - 1)
                    {
                        if (!s0c.Equals(last) || i == 1)
                        {
                            pts.Add(s0c);
                        }

                        pts.Add(s1c);
                        last = s1c;
                    }

                    // render the line if we are leaving the clipping region););
                    if (!clipping.IsInside(s1))
                    {
                        if (pts.Count > 0)
                        {
                            rc.DrawLine(
                                pts, stroke, strokeThickness, LineStyleHelper.GetDashArray(lineStyle), lineJoin, aliased);
                            if (pointsRendered != null)
                            {
                                pointsRendered(pts);
                            }
                            pts = new List<ScreenPoint>();
                        }
                    }
                }

                // Check if the line contains two points and they are at the same point
                if (pts.Count == 2)
                {
                    if (pts[0].DistanceTo(pts[1]) < 1)
                    {
                        // Modify to a small horizontal line to make sure it is being rendered
                        pts[1] = new ScreenPoint(pts[0].X + 1, pts[0].Y);
                        pts[0] = new ScreenPoint(pts[0].X - 1, pts[0].Y);
                    }
                }

                // Check if the line contains a single point
                if (pts.Count == 1)
                {
                    // Add a second point to make sure the line is being rendered as a small dot
                    pts.Add(new ScreenPoint(pts[0].X + 1, pts[0].Y));
                    pts[0] = new ScreenPoint(pts[0].X - 1, pts[0].Y);
                }

                if (pts.Count > 0)
                {
                    rc.DrawLine(pts, stroke, strokeThickness, LineStyleHelper.GetDashArray(lineStyle), lineJoin, aliased);

                    // Execute the 'callback'.
                    if (pointsRendered != null)
                    {
                        pointsRendered(pts);
                    }
                }
            }
        }
Exemple #38
0
        /// <summary>
        /// Draws a clipped polyline through the specified points.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="clippingRectangle">The clipping rectangle.</param>
        /// <param name="points">The points.</param>
        /// <param name="minDistSquared">The minimum line segment length (squared).</param>
        /// <param name="stroke">The stroke color.</param>
        /// <param name="strokeThickness">The stroke thickness.</param>
        /// <param name="edgeRenderingMode">The edge rendering mode.</param>
        /// <param name="dashArray">The dash array (in device independent units, 1/96 inch).</param>
        /// <param name="lineJoin">The line join.</param>
        /// <param name="outputBuffer">The output buffer.</param>
        /// <param name="pointsRendered">The points rendered callback.</param>
        public static void DrawClippedLine(
            this IRenderContext rc,
            OxyRect clippingRectangle,
            IList <ScreenPoint> points,
            double minDistSquared,
            OxyColor stroke,
            double strokeThickness,
            EdgeRenderingMode edgeRenderingMode,
            double[] dashArray,
            LineJoin lineJoin,
            List <ScreenPoint> outputBuffer = null,
            Action <IList <ScreenPoint> > pointsRendered = null)
        {
            var n = points.Count;

            if (n == 0)
            {
                return;
            }

            if (outputBuffer != null)
            {
                outputBuffer.Clear();
                outputBuffer.Capacity = n;
            }
            else
            {
                outputBuffer = new List <ScreenPoint>(n);
            }

            if (rc.SetClip(clippingRectangle))
            {
                ReducePoints(points, minDistSquared, outputBuffer);
                rc.DrawLine(outputBuffer, stroke, strokeThickness, edgeRenderingMode, dashArray, lineJoin);
                rc.ResetClip();

                if (outputBuffer != null)
                {
                    outputBuffer.Clear();
                    outputBuffer.AddRange(points);
                }

                pointsRendered?.Invoke(outputBuffer);

                return;
            }

            // draws the points in the output buffer and calls the callback (if specified)
            Action drawLine = () =>
            {
                EnsureNonEmptyLineIsVisible(outputBuffer);
                rc.DrawLine(outputBuffer, stroke, strokeThickness, edgeRenderingMode, dashArray, lineJoin);

                // Execute the 'callback'
                if (pointsRendered != null)
                {
                    pointsRendered(outputBuffer);
                }
            };

            var clipping = new CohenSutherlandClipping(clippingRectangle);

            if (n == 1 && clipping.IsInside(points[0]))
            {
                outputBuffer.Add(points[0]);
            }

            int lastPointIndex = 0;

            for (int i = 1; i < n; i++)
            {
                // Calculate the clipped version of previous and this point.
                var  sc0      = points[i - 1];
                var  sc1      = points[i];
                bool isInside = clipping.ClipLine(ref sc0, ref sc1);

                if (!isInside)
                {
                    // the line segment is outside the clipping rectangle
                    // keep the previous coordinate for minimum distance comparison
                    continue;
                }

                // length calculation (inlined for performance)
                var dx = sc1.X - points[lastPointIndex].X;
                var dy = sc1.Y - points[lastPointIndex].Y;

                if ((dx * dx) + (dy * dy) > minDistSquared || outputBuffer.Count == 0 || i == n - 1)
                {
                    // point comparison inlined for performance
                    // ReSharper disable CompareOfFloatsByEqualityOperator
                    if (sc0.X != points[lastPointIndex].X || sc0.Y != points[lastPointIndex].Y || outputBuffer.Count == 0)
                    // ReSharper restore disable CompareOfFloatsByEqualityOperator
                    {
                        outputBuffer.Add(new ScreenPoint(sc0.X, sc0.Y));
                    }

                    outputBuffer.Add(new ScreenPoint(sc1.X, sc1.Y));
                    lastPointIndex = i;
                }

                if (clipping.IsInside(points[i]) || outputBuffer.Count == 0)
                {
                    continue;
                }

                // we are leaving the clipping region - render the line
                drawLine();
                outputBuffer.Clear();
            }

            if (outputBuffer.Count > 0)
            {
                drawLine();
            }
        }
        /// <summary>
        /// Renders the legend for the specified series.
        /// </summary>
        /// <param name="rc">
        /// The render context.
        /// </param>
        /// <param name="s">
        /// The series.
        /// </param>
        /// <param name="rect">
        /// The position and size of the legend.
        /// </param>
        private void RenderLegend(IRenderContext rc, Series.Series s, OxyRect rect)
        {
            double x = rect.Left;
            switch (this.LegendItemAlignment)
            {
                case HorizontalAlignment.Center:
                    x = (rect.Left + rect.Right) / 2;
                    if (this.LegendSymbolPlacement == LegendSymbolPlacement.Left)
                    {
                        x -= (this.LegendSymbolLength + this.LegendSymbolMargin) / 2;
                    }
                    else
                    {
                        x -= (this.LegendSymbolLength + this.LegendSymbolMargin) / 2;
                    }

                    break;
                case HorizontalAlignment.Right:
                    x = rect.Right;

                    // if (LegendSymbolPlacement == LegendSymbolPlacement.Right)
                    x -= this.LegendSymbolLength + this.LegendSymbolMargin;
                    break;
            }

            if (this.LegendSymbolPlacement == LegendSymbolPlacement.Left)
            {
                x += this.LegendSymbolLength + this.LegendSymbolMargin;
            }

            double y = rect.Top;
            var maxsize = new OxySize(Math.Max(rect.Right - x, 0), Math.Max(rect.Bottom - y, 0));

            var textSize = rc.DrawMathText(
                new ScreenPoint(x, y),
                s.Title,
                this.LegendTextColor ?? this.TextColor,
                this.LegendFont ?? this.DefaultFont,
                this.LegendFontSize,
                this.LegendFontWeight,
                0,
                this.LegendItemAlignment,
                VerticalAlignment.Top,
                maxsize,
                true);
            double x0 = x;
            switch (this.LegendItemAlignment)
            {
                case HorizontalAlignment.Center:
                    x0 = x - (textSize.Width * 0.5);
                    break;
                case HorizontalAlignment.Right:
                    x0 = x - textSize.Width;
                    break;
            }

            var symbolRect =
                new OxyRect(
                    this.LegendSymbolPlacement == LegendSymbolPlacement.Right
                        ? x0 + textSize.Width + this.LegendSymbolMargin
                        : x0 - this.LegendSymbolMargin - this.LegendSymbolLength,
                    rect.Top,
                    this.LegendSymbolLength,
                    textSize.Height);

            s.RenderLegend(rc, symbolRect);
        }
Exemple #40
0
 /// <summary>
 /// Applies the specified clipping rectangle the the render context and returns a reset token. The clipping is reset once this token is disposed.
 /// </summary>
 /// <param name="rc">The render context.</param>
 /// <param name="clippingRectangle">The clipping rectangle.</param>
 /// <returns>The reset token. Clipping is reset once this is disposed.</returns>
 public static IDisposable AutoResetClip(this IRenderContext rc, OxyRect clippingRectangle)
 {
     return(new AutoResetClipToken(rc, clippingRectangle));
 }
 /// <summary>
 /// Renders the legend symbol for the series on the specified rendering context.
 /// </summary>
 /// <param name="rc">
 /// The rendering context.
 /// </param>
 /// <param name="legendBox">
 /// The bounding rectangle of the legend box.
 /// </param>
 public override void RenderLegend(IRenderContext rc, OxyRect legendBox)
 {
     double xmid = (legendBox.Left + legendBox.Right) / 2;
     double yopen = legendBox.Top + ((legendBox.Bottom - legendBox.Top) * 0.7);
     double yclose = legendBox.Top + ((legendBox.Bottom - legendBox.Top) * 0.3);
     double[] dashArray = LineStyleHelper.GetDashArray(this.LineStyle);
     var color = this.GetSelectableColor(this.ActualColor);
     rc.DrawLine(
         new[] { new ScreenPoint(xmid, legendBox.Top), new ScreenPoint(xmid, legendBox.Bottom) },
         color,
         this.StrokeThickness,
         dashArray,
         OxyPenLineJoin.Miter,
         true);
     rc.DrawLine(
         new[] { new ScreenPoint(xmid - this.TickLength, yopen), new ScreenPoint(xmid, yopen) },
         color,
         this.StrokeThickness,
         dashArray,
         OxyPenLineJoin.Miter,
         true);
     rc.DrawLine(
         new[] { new ScreenPoint(xmid + this.TickLength, yclose), new ScreenPoint(xmid, yclose) },
         color,
         this.StrokeThickness,
         dashArray,
         OxyPenLineJoin.Miter,
         true);
 }
Exemple #42
0
        /// <summary>
        /// Renders the legend for the specified series.
        /// </summary>
        /// <param name="rc">
        /// The render context.
        /// </param>
        /// <param name="s">
        /// The series.
        /// </param>
        /// <param name="rect">
        /// The position and size of the legend.
        /// </param>
        private void RenderLegend(IRenderContext rc, Series s, OxyRect rect)
        {
            double x = rect.Left;

            switch (this.LegendItemAlignment)
            {
            case HorizontalTextAlign.Center:
                x = (rect.Left + rect.Right) / 2;
                if (this.LegendSymbolPlacement == LegendSymbolPlacement.Left)
                {
                    x -= (this.LegendSymbolLength + this.LegendSymbolMargin) / 2;
                }
                else
                {
                    x -= (this.LegendSymbolLength + this.LegendSymbolMargin) / 2;
                }

                break;

            case HorizontalTextAlign.Right:
                x = rect.Right;

                // if (LegendSymbolPlacement == LegendSymbolPlacement.Right)
                x -= this.LegendSymbolLength + this.LegendSymbolMargin;
                break;
            }

            if (this.LegendSymbolPlacement == LegendSymbolPlacement.Left)
            {
                x += this.LegendSymbolLength + this.LegendSymbolMargin;
            }

            double y       = rect.Top;
            var    maxsize = new OxySize(Math.Max(rect.Right - x, 0), Math.Max(rect.Bottom - y, 0));

            var textSize = rc.DrawMathText(
                new ScreenPoint(x, y),
                s.Title,
                this.LegendTextColor ?? this.TextColor,
                this.LegendFont ?? this.DefaultFont,
                this.LegendFontSize,
                this.LegendFontWeight,
                0,
                this.LegendItemAlignment,
                VerticalTextAlign.Top,
                maxsize,
                true);
            double x0 = x;

            switch (this.LegendItemAlignment)
            {
            case HorizontalTextAlign.Center:
                x0 = x - (textSize.Width * 0.5);
                break;

            case HorizontalTextAlign.Right:
                x0 = x - textSize.Width;
                break;
            }

            var symbolRect =
                new OxyRect(
                    this.LegendSymbolPlacement == LegendSymbolPlacement.Right
                        ? x0 + textSize.Width + this.LegendSymbolMargin
                        : x0 - this.LegendSymbolMargin - this.LegendSymbolLength,
                    rect.Top,
                    this.LegendSymbolLength,
                    textSize.Height);

            s.RenderLegend(rc, symbolRect);
        }
 /// <summary>
 ///     Renders the legend symbol on the specified render context.
 /// </summary>
 /// <param name="rc">The rendering context.</param>
 /// <param name="legendBox">The legend rectangle.</param>
 public override void RenderLegend(IRenderContext rc, OxyRect legendBox)
 {
     rc.DrawText(
         legendBox.Center,
         this.Symbol,
         this.Color,
         this.FontFamily,
         this.FontSize,
         FontWeights.Normal,
         0,
         HorizontalAlignment.Center,
         VerticalAlignment.Middle);
 }
Exemple #44
0
 /// <summary>
 /// Renders or measures the legends.
 /// </summary>
 /// <param name="rc">
 /// The render context.
 /// </param>
 /// <param name="rect">
 /// The rectangle.
 /// </param>
 private void RenderLegends(IRenderContext rc, OxyRect rect)
 {
     this.RenderOrMeasureLegends(rc, rect);
 }
Exemple #45
0
        /// <summary>
        /// Renders the legend for the specified series.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="s">The series.</param>
        /// <param name="rect">The position and size of the legend.</param>
        private void RenderLegend(IRenderContext rc, Series.Series s, OxyRect rect)
        {
            var actualItemAlignment = this.LegendItemAlignment;
            if (this.LegendOrientation == LegendOrientation.Horizontal)
            {
                // center/right alignment is not supported for horizontal orientation
                actualItemAlignment = HorizontalAlignment.Left;
            }

            double x = rect.Left;
            switch (actualItemAlignment)
            {
                case HorizontalAlignment.Center:
                    x = (rect.Left + rect.Right) / 2;
                    if (this.LegendSymbolPlacement == LegendSymbolPlacement.Left)
                    {
                        x -= (this.LegendSymbolLength + this.LegendSymbolMargin) / 2;
                    }
                    else
                    {
                        x -= (this.LegendSymbolLength + this.LegendSymbolMargin) / 2;
                    }

                    break;
                case HorizontalAlignment.Right:
                    x = rect.Right;

                    // if (LegendSymbolPlacement == LegendSymbolPlacement.Right)
                    x -= this.LegendSymbolLength + this.LegendSymbolMargin;
                    break;
            }

            if (this.LegendSymbolPlacement == LegendSymbolPlacement.Left)
            {
                x += this.LegendSymbolLength + this.LegendSymbolMargin;
            }

            double y = rect.Top;
            var maxsize = new OxySize(Math.Max(rect.Width - this.LegendSymbolLength - this.LegendSymbolMargin, 0), rect.Height);

            rc.SetToolTip(s.ToolTip);
            var textSize = rc.DrawMathText(
                new ScreenPoint(x, y),
                s.Title,
                this.LegendTextColor.GetActualColor(this.TextColor),
                this.LegendFont ?? this.DefaultFont,
                this.LegendFontSize,
                this.LegendFontWeight,
                0,
                actualItemAlignment,
                VerticalAlignment.Top,
                maxsize,
                true);
            double x0 = x;
            switch (actualItemAlignment)
            {
                case HorizontalAlignment.Center:
                    x0 = x - (textSize.Width * 0.5);
                    break;
                case HorizontalAlignment.Right:
                    x0 = x - textSize.Width;
                    break;
            }

            var symbolRect =
                new OxyRect(
                    this.LegendSymbolPlacement == LegendSymbolPlacement.Right
                        ? x0 + textSize.Width + this.LegendSymbolMargin
                        : x0 - this.LegendSymbolMargin - this.LegendSymbolLength,
                    rect.Top,
                    this.LegendSymbolLength,
                    textSize.Height);

            s.RenderLegend(rc, symbolRect);
            rc.SetToolTip(null);
        }
Exemple #46
0
        /// <summary>
        /// Renders or measures the legends.
        /// </summary>
        /// <param name="rc">
        /// The render context.
        /// </param>
        /// <param name="rect">
        /// Provides the available size if measuring, otherwise it provides the position and size of the legend.
        /// </param>
        /// <param name="measureOnly">
        /// Specify if the size of the legend box should be measured only (not rendered).
        /// </param>
        /// <returns>
        /// The size of the legend box.
        /// </returns>
        private OxySize RenderOrMeasureLegends(IRenderContext rc, OxyRect rect, bool measureOnly = false)
        {
            // Render background and border around legend
            if (!measureOnly && rect.Width > 0 && rect.Height > 0)
            {
                rc.DrawRectangleAsPolygon(rect, this.LegendBackground, this.LegendBorder, this.LegendBorderThickness);
            }

            double availableWidth  = rect.Width;
            double availableHeight = rect.Height;

            double x   = this.LegendPadding;
            double top = this.LegendPadding;

            var size = new OxySize();

            // Render/measure the legend title
            if (!string.IsNullOrEmpty(this.LegendTitle))
            {
                OxySize titleSize;
                if (measureOnly)
                {
                    titleSize = rc.MeasureMathText(
                        this.LegendTitle,
                        this.LegendTitleFont ?? DefaultFont,
                        this.LegendTitleFontSize,
                        this.LegendTitleFontWeight);
                }
                else
                {
                    titleSize = rc.DrawMathText(
                        new ScreenPoint(rect.Left + x, rect.Top + top),
                        this.LegendTitle,
                        this.LegendTitleColor ?? this.TextColor,
                        this.LegendTitleFont ?? this.DefaultFont,
                        this.LegendTitleFontSize,
                        this.LegendTitleFontWeight,
                        0,
                        HorizontalTextAlign.Left,
                        VerticalTextAlign.Top,
                        null,
                        true);
                }

                top        += titleSize.Height;
                size.Width  = x + titleSize.Width + this.LegendPadding;
                size.Height = top + titleSize.Height;
            }

            double y = top;

            double lineHeight = 0;

            // tolerance for floating-point number comparisons
            const double Epsilon = 1e-3;

            // the maximum item with in the column being rendered (only used for vertical orientation)
            double maxItemWidth = 0;

            var items = this.LegendItemOrder == LegendItemOrder.Reverse ? this.VisibleSeries.Reverse() : this.VisibleSeries;

            // When orientation is vertical and alignment is center or right, the items cannot be rendered before
            // the max item width has been calculated. Render the items for each column, and at the end.
            var    seriesToRender = new Dictionary <Series, OxyRect>();
            Action renderItems    = () =>
            {
                foreach (var sr in seriesToRender)
                {
                    var itemRect   = sr.Value;
                    var itemSeries = sr.Key;

                    double rwidth = itemRect.Width;
                    if (itemRect.Left + rwidth + this.LegendPadding > rect.Left + availableWidth)
                    {
                        rwidth = rect.Left + availableWidth - itemRect.Left - this.LegendPadding;
                    }

                    double rheight = itemRect.Height;
                    if (rect.Top + rheight + this.LegendPadding > rect.Top + availableHeight)
                    {
                        rheight = rect.Top + availableHeight - rect.Top - this.LegendPadding;
                    }

                    var r = new OxyRect(itemRect.Left, itemRect.Top, Math.Max(rwidth, 0), Math.Max(rheight, 0));
                    this.RenderLegend(rc, itemSeries, r);
                }

                seriesToRender.Clear();
            };

            foreach (var s in items)
            {
                // Skip series with empty title
                if (string.IsNullOrEmpty(s.Title))
                {
                    continue;
                }

                var    textSize   = rc.MeasureMathText(s.Title, this.LegendFont ?? DefaultFont, this.LegendFontSize, this.LegendFontWeight);
                double itemWidth  = this.LegendSymbolLength + this.LegendSymbolMargin + textSize.Width;
                double itemHeight = textSize.Height;

                if (this.LegendOrientation == LegendOrientation.Horizontal)
                {
                    // Add spacing between items
                    if (x > this.LegendPadding)
                    {
                        x += this.LegendItemSpacing;
                    }

                    // Check if the item is too large to fit within the available width
                    if (x + itemWidth > availableWidth - this.LegendPadding + Epsilon)
                    {
                        // new line
                        x          = this.LegendPadding;
                        y         += lineHeight;
                        lineHeight = 0;
                    }

                    // Update the max size of the current line
                    lineHeight = Math.Max(lineHeight, textSize.Height);

                    if (!measureOnly)
                    {
                        seriesToRender.Add(s, new OxyRect(rect.Left + x, rect.Top + y, itemWidth, itemHeight));
                    }

                    x += itemWidth;

                    // Update the max width of the legend box
                    size.Width = Math.Max(size.Width, x);

                    // Update the max height of the legend box
                    size.Height = Math.Max(size.Height, y + textSize.Height);
                }
                else
                {
                    if (y + itemHeight > availableHeight - this.LegendPadding + Epsilon)
                    {
                        renderItems();

                        y            = top;
                        x           += maxItemWidth + this.LegendColumnSpacing;
                        maxItemWidth = 0;
                    }

                    if (!measureOnly)
                    {
                        seriesToRender.Add(s, new OxyRect(rect.Left + x, rect.Top + y, itemWidth, itemHeight));
                    }

                    y += itemHeight;

                    // Update the max size of the items in the current column
                    maxItemWidth = Math.Max(maxItemWidth, itemWidth);

                    // Update the max width of the legend box
                    size.Width = Math.Max(size.Width, x + itemWidth);

                    // Update the max height of the legend box
                    size.Height = Math.Max(size.Height, y);
                }
            }

            renderItems();

            if (size.Width > 0)
            {
                size.Width += this.LegendPadding;
            }

            if (size.Height > 0)
            {
                size.Height += this.LegendPadding;
            }

            if (size.Width > availableWidth)
            {
                size.Width = availableWidth;
            }

            if (size.Height > availableHeight)
            {
                size.Height = availableHeight;
            }

            if (!double.IsNaN(LegendMaxWidth) && size.Width > this.LegendMaxWidth)
            {
                size.Width = this.LegendMaxWidth;
            }

            return(size);
        }
Exemple #47
0
        /// <summary>
        /// Renders or measures the legends.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="rect">Provides the available size if measuring, otherwise it provides the position and size of the legend.</param>
        /// <param name="measureOnly">Specify if the size of the legend box should be measured only (not rendered).</param>
        /// <returns>The size of the legend box.</returns>
        private OxySize RenderOrMeasureLegends(IRenderContext rc, OxyRect rect, bool measureOnly = false)
        {
            // Render background and border around legend
            if (!measureOnly && rect.Width > 0 && rect.Height > 0)
            {
                rc.DrawRectangleAsPolygon(rect, this.LegendBackground, this.LegendBorder, this.LegendBorderThickness);
            }

            double availableWidth = rect.Width;
            double availableHeight = rect.Height;

            double x = this.LegendPadding;
            double top = this.LegendPadding;

            var size = new OxySize();

            // Render/measure the legend title
            if (!string.IsNullOrEmpty(this.LegendTitle))
            {
                OxySize titleSize;
                if (measureOnly)
                {
                    titleSize = rc.MeasureMathText(
                        this.LegendTitle,
                        this.LegendTitleFont ?? this.DefaultFont,
                        this.LegendTitleFontSize,
                        this.LegendTitleFontWeight);
                }
                else
                {
                    titleSize = rc.DrawMathText(
                        new ScreenPoint(rect.Left + x, rect.Top + top),
                        this.LegendTitle,
                        this.LegendTitleColor.GetActualColor(this.TextColor),
                        this.LegendTitleFont ?? this.DefaultFont,
                        this.LegendTitleFontSize,
                        this.LegendTitleFontWeight,
                        0,
                        HorizontalAlignment.Left,
                        VerticalAlignment.Top,
                        null,
                        true);
                }

                top += titleSize.Height;
                size.Width = x + titleSize.Width + this.LegendPadding;
                size.Height = top + titleSize.Height;
            }

            double y = top;

            double lineHeight = 0;

            // tolerance for floating-point number comparisons
            const double Epsilon = 1e-3;

            // the maximum item with in the column being rendered (only used for vertical orientation)
            double maxItemWidth = 0;

            var items = this.LegendItemOrder == LegendItemOrder.Reverse
                ? this.Series.Reverse().Where(s => s.IsVisible)
                : this.Series.Where(s => s.IsVisible);

            // When orientation is vertical and alignment is center or right, the items cannot be rendered before
            // the max item width has been calculated. Render the items for each column, and at the end.
            var seriesToRender = new Dictionary<Series.Series, OxyRect>();
            Action renderItems = () =>
                {
                    foreach (var sr in seriesToRender)
                    {
                        var itemRect = sr.Value;
                        var itemSeries = sr.Key;

                        double rwidth = availableWidth;
                        if (itemRect.Left + rwidth + this.LegendPadding > rect.Left + availableWidth)
                        {
                            rwidth = rect.Left + availableWidth - itemRect.Left - this.LegendPadding;
                        }

                        double rheight = itemRect.Height;
                        if (rect.Top + rheight + this.LegendPadding > rect.Top + availableHeight)
                        {
                            rheight = rect.Top + availableHeight - rect.Top - this.LegendPadding;
                        }

                        var r = new OxyRect(itemRect.Left, itemRect.Top, Math.Max(rwidth, 0), Math.Max(rheight, 0));
                        this.RenderLegend(rc, itemSeries, r);
                    }

                    seriesToRender.Clear();
                };

            foreach (var s in items)
            {
                // Skip series with empty title
                if (string.IsNullOrEmpty(s.Title))
                {
                    continue;
                }

                var textSize = rc.MeasureMathText(s.Title, this.LegendFont ?? this.DefaultFont, this.LegendFontSize, this.LegendFontWeight);
                double itemWidth = this.LegendSymbolLength + this.LegendSymbolMargin + textSize.Width;
                double itemHeight = textSize.Height;

                if (this.LegendOrientation == LegendOrientation.Horizontal)
                {
                    // Add spacing between items
                    if (x > this.LegendPadding)
                    {
                        x += this.LegendItemSpacing;
                    }

                    // Check if the item is too large to fit within the available width
                    if (x + itemWidth > availableWidth - this.LegendPadding + Epsilon)
                    {
                        // new line
                        x = this.LegendPadding;
                        y += lineHeight;
                        lineHeight = 0;
                    }

                    // Update the max size of the current line
                    lineHeight = Math.Max(lineHeight, textSize.Height);

                    if (!measureOnly)
                    {
                        seriesToRender.Add(s, new OxyRect(rect.Left + x, rect.Top + y, itemWidth, itemHeight));
                    }

                    x += itemWidth;

                    // Update the max width of the legend box
                    size.Width = Math.Max(size.Width, x);

                    // Update the max height of the legend box
                    size.Height = Math.Max(size.Height, y + textSize.Height);
                }
                else
                {
                    if (y + itemHeight > availableHeight - this.LegendPadding + Epsilon)
                    {
                        renderItems();

                        y = top;
                        x += maxItemWidth + this.LegendColumnSpacing;
                        maxItemWidth = 0;
                    }

                    if (!measureOnly)
                    {
                        seriesToRender.Add(s, new OxyRect(rect.Left + x, rect.Top + y, itemWidth, itemHeight));
                    }

                    y += itemHeight;

                    // Update the max size of the items in the current column
                    maxItemWidth = Math.Max(maxItemWidth, itemWidth);

                    // Update the max width of the legend box
                    size.Width = Math.Max(size.Width, x + itemWidth);

                    // Update the max height of the legend box
                    size.Height = Math.Max(size.Height, y);
                }
            }

            renderItems();

            if (size.Width > 0)
            {
                size.Width += this.LegendPadding;
            }

            if (size.Height > 0)
            {
                size.Height += this.LegendPadding;
            }

            if (size.Width > availableWidth)
            {
                size.Width = availableWidth;
            }

            if (size.Height > availableHeight)
            {
                size.Height = availableHeight;
            }

            if (!double.IsNaN(this.LegendMaxWidth) && size.Width > this.LegendMaxWidth)
            {
                size.Width = this.LegendMaxWidth;
            }

            return size;
        }
Exemple #48
0
 /// <summary>
 /// Sets the clip rectangle.
 /// </summary>
 /// <param name="rect">The clip rectangle.</param>
 /// <returns>
 /// True if the clip rectangle was set.
 /// </returns>
 public virtual bool SetClip(OxyRect rect)
 {
     return(false);
 }
        /// <summary>
        /// Renders the point labels.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="clippingRect">The clipping rect.</param>
        protected void RenderPointLabels(IRenderContext rc, OxyRect clippingRect)
        {
            int index = -1;
            foreach (var point in this.Points)
            {
                index++;

                if (!this.IsValidPoint(point, this.XAxis, this.YAxis))
                {
                    continue;
                }

                var pt = this.XAxis.Transform(point.X, point.Y, this.YAxis);
                pt.Y -= this.LabelMargin;

                if (!clippingRect.Contains(pt))
                {
                    continue;
                }

                var s = StringHelper.Format(
                    this.ActualCulture, this.LabelFormatString, this.GetItem(index), point.X, point.Y);

#if SUPPORTLABELPLACEMENT
                    switch (this.LabelPlacement)
                    {
                        case LabelPlacement.Inside:
                            pt = new ScreenPoint(rect.Right - this.LabelMargin, (rect.Top + rect.Bottom) / 2);
                            ha = HorizontalTextAlign.Right;
                            break;
                        case LabelPlacement.Middle:
                            pt = new ScreenPoint((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2);
                            ha = HorizontalTextAlign.Center;
                            break;
                        case LabelPlacement.Base:
                            pt = new ScreenPoint(rect.Left + this.LabelMargin, (rect.Top + rect.Bottom) / 2);
                            ha = HorizontalTextAlign.Left;
                            break;
                        default: // Outside
                            pt = new ScreenPoint(rect.Right + this.LabelMargin, (rect.Top + rect.Bottom) / 2);
                            ha = HorizontalTextAlign.Left;
                            break;
                    }
#endif

                rc.DrawClippedText(
                    clippingRect,
                    pt,
                    s,
                    this.ActualTextColor,
                    this.ActualFont,
                    this.ActualFontSize,
                    this.ActualFontWeight,
                    0,
                    HorizontalTextAlign.Center,
                    VerticalTextAlign.Bottom);
            }
        }
Exemple #50
0
 /// <summary>
 /// Draws an ellipse.
 /// </summary>
 /// <param name="rect">
 /// The rectangle.
 /// </param>
 /// <param name="fill">
 /// The fill color.
 /// </param>
 /// <param name="stroke">
 /// The stroke color.
 /// </param>
 /// <param name="thickness">
 /// The thickness.
 /// </param>
 public abstract void DrawEllipse(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness);
        /// <summary>
        /// Renders the transformed points.
        /// </summary>
        /// <param name="rc">
        /// The render context.
        /// </param>
        /// <param name="clippingRect">
        /// The clipping rect.
        /// </param>
        /// <param name="pointsToRender">
        /// The points to render.
        /// </param>
        protected void RenderPoints(IRenderContext rc, OxyRect clippingRect, IList<ScreenPoint> pointsToRender)
        {
            var screenPoints = pointsToRender;
            if (this.Smooth)
            {
                // spline smoothing (should only be used on small datasets)
                var resampledPoints = ScreenPointHelper.ResamplePoints(pointsToRender, this.MinimumSegmentLength);
                screenPoints = CanonicalSplineHelper.CreateSpline(resampledPoints, 0.5, null, false, 0.25);
            }

            // clip the line segments with the clipping rectangle
            if (this.StrokeThickness > 0 && this.ActualLineStyle != LineStyle.None)
            {
                this.RenderSmoothedLine(rc, clippingRect, screenPoints);
            }

            if (this.MarkerType != MarkerType.None)
            {
                rc.DrawMarkers(
                    pointsToRender,
                    clippingRect,
                    this.MarkerType,
                    this.MarkerOutline,
                    new[] { this.MarkerSize },
                    this.MarkerFill,
                    this.MarkerStroke,
                    this.MarkerStrokeThickness);
            }
        }
Exemple #52
0
 /// <summary>
 /// Occurs when an input device begins a manipulation on the plot.
 /// </summary>
 /// <param name="e">The <see cref="OxyPlot.OxyMouseEventArgs" /> instance containing the event data.</param>
 public override void Started(OxyMouseEventArgs e)
 {
     base.Started(e);
     this.zoomRectangle = new OxyRect(this.StartPosition.X, this.StartPosition.Y, 0, 0);
     this.PlotView.ShowZoomRectangle(this.zoomRectangle);
 }
 /// <summary>
 /// Draws a rectangle.
 /// </summary>
 /// <param name="rect">The rectangle.</param>
 /// <param name="fill">The fill color. If set to <c>OxyColors.Undefined</c>, the rectangle will not be filled.</param>
 /// <param name="stroke">The stroke color. If set to <c>OxyColors.Undefined</c>, the rectangle will not be stroked.</param>
 /// <param name="thickness">The stroke thickness (in device independent units, 1/96 inch).</param>
 public void DrawRectangle(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness = 1)
 {
 }
Exemple #54
0
 /// <summary>
 /// Sets the clip rectangle.
 /// </summary>
 /// <param name="rect">The clip rectangle.</param>
 /// <returns>True if the clip rectangle was set.</returns>
 public override bool SetClip(OxyRect rect)
 {
     this.doc.SaveState();
     this.doc.SetClippingRectangle(rect.Left, rect.Bottom, rect.Width, rect.Height);
     return(true);
 }
 /// <summary>
 /// Draws an ellipse.
 /// </summary>
 /// <param name="rect">The rectangle.</param>
 /// <param name="fill">The fill color. If set to <c>OxyColors.Undefined</c>, the ellipse will not be filled.</param>
 /// <param name="stroke">The stroke color. If set to <c>OxyColors.Undefined</c>, the ellipse will not be stroked.</param>
 /// <param name="thickness">The thickness (in device independent units, 1/96 inch).</param>
 public void DrawEllipse(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness = 1)
 {
 }
Exemple #56
0
 /// <summary>
 /// Renders the legend symbol on the specified rendering context.
 /// </summary>
 /// <param name = "rc">The rendering context.</param>
 /// <param name = "legendBox">The legend rectangle.</param>
 public override void RenderLegend(IRenderContext rc, OxyRect legendBox)
 {
 }