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