/// <summary> /// Gets the coordinates of the (rotated) background rectangle. /// </summary> /// <param name="position"> /// The position. /// </param> /// <param name="size"> /// The size. /// </param> /// <param name="padding"> /// The padding. /// </param> /// <param name="rotation"> /// The rotation. /// </param> /// <param name="horizontalAlignment"> /// The horizontal alignment. /// </param> /// <param name="verticalAlignment"> /// The vertical alignment. /// </param> /// <returns> /// The background rectangle coordinates. /// </returns> private static IList <ScreenPoint> GetTextBounds( ScreenPoint position, OxySize size, OxyThickness padding, double rotation, HorizontalTextAlign horizontalAlignment, VerticalTextAlign verticalAlignment) { double left, right, top, bottom; switch (horizontalAlignment) { case HorizontalTextAlign.Center: left = -size.Width * 0.5; right = -left; break; case HorizontalTextAlign.Right: left = -size.Width; right = 0; break; default: left = 0; right = size.Width; break; } switch (verticalAlignment) { case VerticalTextAlign.Middle: top = -size.Height * 0.5; bottom = -top; break; case VerticalTextAlign.Bottom: top = -size.Height; bottom = 0; break; default: top = 0; bottom = size.Height; break; } double cost = Math.Cos(rotation / 180 * Math.PI); double sint = Math.Sin(rotation / 180 * Math.PI); var u = new ScreenVector(cost, sint); var v = new ScreenVector(-sint, cost); var polygon = new ScreenPoint[4]; polygon[0] = position + u * (left - padding.Left) + v * (top - padding.Top); polygon[1] = position + u * (right + padding.Right) + v * (top - padding.Top); polygon[2] = position + u * (right + padding.Right) + v * (bottom + padding.Bottom); polygon[3] = position + u * (left - padding.Left) + v * (bottom + padding.Bottom); return(polygon); }
/// <summary> /// Adjusts the plot margins. /// </summary> /// <param name="rc">The render context.</param> /// <returns><c>true</c> if the margins were adjusted.</returns> private bool AdjustPlotMargins(IRenderContext rc) { var visibleAxes = this.Axes.Where(axis => axis.IsAxisVisible).ToList(); foreach (var axis in visibleAxes) { axis.Measure(rc); } var desiredMargin = new OxyThickness(); void IncludeInMargin(double size, AxisPosition borderPosition) { desiredMargin = borderPosition switch { AxisPosition.Bottom => new OxyThickness(desiredMargin.Left, desiredMargin.Top, desiredMargin.Right, Math.Max(desiredMargin.Bottom, size)), AxisPosition.Left => new OxyThickness(Math.Max(desiredMargin.Left, size), desiredMargin.Top, desiredMargin.Right, desiredMargin.Bottom), AxisPosition.Right => new OxyThickness(desiredMargin.Left, desiredMargin.Top, Math.Max(desiredMargin.Right, size), desiredMargin.Bottom), AxisPosition.Top => new OxyThickness(desiredMargin.Left, Math.Max(desiredMargin.Top, size), desiredMargin.Right, desiredMargin.Bottom), _ => desiredMargin, }; } // include the value of the outermost position tier on each side ('normal' axes only) for (var position = AxisPosition.Left; position <= AxisPosition.Bottom; position++) { var axesOfPosition = visibleAxes.Where(a => a.Position == position); var requiredSize = this.AdjustAxesPositions(axesOfPosition); IncludeInMargin(requiredSize, position); } // include the desired margin of all visible axes (including polar axes) foreach (var axis in visibleAxes) { desiredMargin = desiredMargin.Include(axis.DesiredMargin); } var currentMargin = this.PlotMargins; currentMargin = new OxyThickness( double.IsNaN(currentMargin.Left) ? desiredMargin.Left : currentMargin.Left, double.IsNaN(currentMargin.Top) ? desiredMargin.Top : currentMargin.Top, double.IsNaN(currentMargin.Right) ? desiredMargin.Right : currentMargin.Right, double.IsNaN(currentMargin.Bottom) ? desiredMargin.Bottom : currentMargin.Bottom); if (currentMargin.Equals(this.ActualPlotMargins)) { return(false); } this.ActualPlotMargins = currentMargin; return(true); }
/// <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.Equals(thickness.Right) && thickness.Left.Equals(thickness.Top) && thickness.Left.Equals(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); }
public LoadTestChart(List<Heartbeat> heartbeats) { Background = OxyColors.Transparent; PlotAreaBorderThickness = new OxyThickness(1, 0, 0, 1); Padding = new OxyThickness(15, 30, 30, 20); LegendPosition = LegendPosition.LeftTop; LegendPlacement = LegendPlacement.Inside; Series.Add(new LineSeries { ItemsSource = heartbeats, DataFieldX = "TotalRuntime", DataFieldY = "TotalErrors", Color = OxyColors.Red, Title = "Errors", Smooth = false }); Series.Add(new LineSeries { ItemsSource = heartbeats, DataFieldX = "TotalRuntime", DataFieldY = "TotalThreads", Color = OxyColors.Green, Title = "Threads", Smooth = false }); Series.Add(new LineSeries { ItemsSource = heartbeats, DataFieldX = "TotalRuntime", DataFieldY = "Throughput", Color = OxyColors.DodgerBlue, Title = "Throughput", Smooth = false }); }
/// <summary> /// Increases margin size if needed, do it on the specified border. /// </summary> /// <param name="currentMargin">The current margin.</param> /// <param name="minBorderSize">Minimum size of the border.</param> /// <param name="borderPosition">The border position.</param> private static void EnsureMarginIsBigEnough(ref OxyThickness currentMargin, double minBorderSize, AxisPosition borderPosition) { switch (borderPosition) { case AxisPosition.Bottom: currentMargin = new OxyThickness(currentMargin.Left, currentMargin.Top, currentMargin.Right, Math.Max(currentMargin.Bottom, minBorderSize)); break; case AxisPosition.Left: currentMargin = new OxyThickness(Math.Max(currentMargin.Left, minBorderSize), currentMargin.Top, currentMargin.Right, currentMargin.Bottom); break; case AxisPosition.Right: currentMargin = new OxyThickness(currentMargin.Left, currentMargin.Top, Math.Max(currentMargin.Right, minBorderSize), currentMargin.Bottom); break; case AxisPosition.Top: currentMargin = new OxyThickness(currentMargin.Left, Math.Max(currentMargin.Top, minBorderSize), currentMargin.Right, currentMargin.Bottom); break; default: throw new NotImplementedException(); } }
/// <summary> /// Determines whether this instance and another specified <see cref="T:OxyThickness" /> object have the same value. /// </summary> /// <param name="other">The thickness to compare to this instance.</param> /// <returns><c>true</c> if the value of the <paramref name="other" /> parameter is the same as the value of this instance; otherwise, <c>false</c>.</returns> public bool Equals(OxyThickness other) { return(this.Left.Equals(other.Left) && this.Top.Equals(other.Top) && this.Width.Equals(other.Width) && this.Height.Equals(other.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, 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> /// Creates a new <see cref="OxyThickness"/> with the maximum dimensions of this instance and the specified other instance. /// </summary> /// <param name="other">The other instance.</param> /// <returns>A new <see cref="OxyThickness"/>.</returns> public OxyThickness Include(OxyThickness other) { return(new OxyThickness(Math.Max(other.Left, this.Left), Math.Max(other.Top, this.Top), Math.Max(other.Right, this.Right), Math.Max(other.Bottom, this.Bottom))); }
/// <summary> /// Determines whether this instance and another specified <see cref="T:OxyThickness" /> object have the same value. /// </summary> /// <param name="other">The thickness to compare to this instance.</param> /// <returns><c>true</c> if the value of the <paramref name="other" /> parameter is the same as the value of this instance; otherwise, <c>false</c>.</returns> public bool Equals(OxyThickness other) { return(this.Left.Equals(other.Left) && this.Top.Equals(other.Top) && this.Right.Equals(other.Right) && this.Bottom.Equals(other.Bottom)); }
/// <summary> /// Gets the coordinates of the (rotated) background rectangle. /// </summary> /// <param name="position"> /// The position. /// </param> /// <param name="size"> /// The size. /// </param> /// <param name="padding"> /// The padding. /// </param> /// <param name="rotation"> /// The rotation. /// </param> /// <param name="horizontalAlignment"> /// The horizontal alignment. /// </param> /// <param name="verticalAlignment"> /// The vertical alignment. /// </param> /// <returns> /// The background rectangle coordinates. /// </returns> private static IList<ScreenPoint> GetTextBounds( ScreenPoint position, OxySize size, OxyThickness padding, double rotation, HorizontalTextAlign horizontalAlignment, VerticalTextAlign verticalAlignment) { double left, right, top, bottom; switch (horizontalAlignment) { case HorizontalTextAlign.Center: left = -size.Width * 0.5; right = -left; break; case HorizontalTextAlign.Right: left = -size.Width; right = 0; break; default: left = 0; right = size.Width; break; } switch (verticalAlignment) { case VerticalTextAlign.Middle: top = -size.Height * 0.5; bottom = -top; break; case VerticalTextAlign.Bottom: top = -size.Height; bottom = 0; break; default: top = 0; bottom = size.Height; break; } double cost = Math.Cos(rotation / 180 * Math.PI); double sint = Math.Sin(rotation / 180 * Math.PI); var u = new ScreenVector(cost, sint); var v = new ScreenVector(-sint, cost); var polygon = new ScreenPoint[4]; polygon[0] = position + u * (left - padding.Left) + v * (top - padding.Top); polygon[1] = position + u * (right + padding.Right) + v * (top - padding.Top); polygon[2] = position + u * (right + padding.Right) + v * (bottom + padding.Bottom); polygon[3] = position + u * (left - padding.Left) + v * (bottom + padding.Bottom); return polygon; }
/// <summary> /// Increases margin size if needed, do it on the specified border. /// </summary> /// <param name="currentMargin">The current margin.</param> /// <param name="minBorderSize">Minimum size of the border.</param> /// <param name="borderPosition">The border position.</param> private static void EnsureMarginIsBigEnough(ref OxyThickness currentMargin, double minBorderSize, AxisPosition borderPosition) { switch (borderPosition) { case AxisPosition.Bottom: currentMargin.Bottom = Math.Max(currentMargin.Bottom, minBorderSize); break; case AxisPosition.Left: currentMargin.Left = Math.Max(currentMargin.Left, minBorderSize); break; case AxisPosition.Right: currentMargin.Right = Math.Max(currentMargin.Right, minBorderSize); break; case AxisPosition.Top: currentMargin.Top = Math.Max(currentMargin.Top, minBorderSize); break; default: throw new NotImplementedException(); } }
/// <summary> /// Returns a rectangle that is shrunk by the specified thickness, in all directions. /// </summary> /// <param name="t">The thickness to apply to the rectangle.</param> /// <returns>The deflated <see cref="OxyRect" />.</returns> public OxyRect Deflate(OxyThickness t) { return(new OxyRect(this.left + t.Left, this.top + t.Top, Math.Max(0, this.width - t.Left - t.Right), Math.Max(0, this.height - t.Top - t.Bottom))); }
/// <summary> /// Returns a rectangle that is expanded by the specified thickness, in all directions. /// </summary> /// <param name="t">The thickness to apply to the rectangle.</param> /// <returns>The inflated <see cref="OxyRect" />.</returns> public OxyRect Inflate(OxyThickness t) { return(new OxyRect(this.left - t.Left, this.top - t.Top, this.width + t.Left + t.Right, this.height + t.Top + t.Bottom)); }
/// <summary> /// Determines whether this instance and another specified <see cref="T:OxyThickness" /> object have the same value. /// </summary> /// <param name="other">The thickness to compare to this instance.</param> /// <returns><c>true</c> if the value of the <paramref name="other" /> parameter is the same as the value of this instance; otherwise, <c>false</c>.</returns> public bool Equals(OxyThickness other) { return this.Left.Equals(other.Left) && this.Top.Equals(other.Top) && this.Width.Equals(other.Width) && this.Height.Equals(other.Height); }
/// <summary> /// Draws the outline of a rectangle with individual stroke thickness for each side. /// </summary> /// <param name="rc">The render context.</param> /// <param name="rect">The rectangle.</param> /// <param name="stroke">The stroke color.</param> /// <param name="thickness">The thickness.</param> /// <param name="edgeRenderingMode">The edge rendering mode.</param> public static void DrawRectangle(this IRenderContext rc, OxyRect rect, OxyColor stroke, OxyThickness thickness, EdgeRenderingMode edgeRenderingMode) { if (thickness.Left.Equals(thickness.Right) && thickness.Left.Equals(thickness.Top) && thickness.Left.Equals(thickness.Bottom)) { rc.DrawRectangle(rect, OxyColors.Undefined, stroke, thickness.Left, edgeRenderingMode); return; } var adjustedLeft = rect.Left - thickness.Left / 2 + 0.5; var adjustedRight = rect.Right + thickness.Right / 2 - 0.5; var adjustedTop = rect.Top - thickness.Top / 2 + 0.5; var adjustedBottom = rect.Bottom + thickness.Bottom / 2 - 0.5; var pointsTop = new[] { new ScreenPoint(adjustedLeft, rect.Top), new ScreenPoint(adjustedRight, rect.Top) }; var pointsRight = new[] { new ScreenPoint(rect.Right, adjustedTop), new ScreenPoint(rect.Right, adjustedBottom) }; var pointsBottom = new[] { new ScreenPoint(adjustedLeft, rect.Bottom), new ScreenPoint(adjustedRight, rect.Bottom) }; var pointsLeft = new[] { new ScreenPoint(rect.Left, adjustedTop), new ScreenPoint(rect.Left, adjustedBottom) }; rc.DrawLine(pointsTop, stroke, thickness.Top, edgeRenderingMode, null, LineJoin.Miter); rc.DrawLine(pointsRight, stroke, thickness.Right, edgeRenderingMode, null, LineJoin.Miter); rc.DrawLine(pointsBottom, stroke, thickness.Bottom, edgeRenderingMode, null, LineJoin.Miter); rc.DrawLine(pointsLeft, stroke, thickness.Left, edgeRenderingMode, null, LineJoin.Miter); }