/// <summary> /// Renders the minor items. /// </summary> /// <param name="axis">The axis.</param> /// <param name="axisPosition">The axis position.</param> protected virtual void RenderMinorItems(Axis axis, double axisPosition) { double eps = axis.ActualMinorStep * 1e-3; double actualMinimum = axis.ActualMinimum; double actualMaximum = axis.ActualMaximum; double plotAreaLeft = this.Plot.PlotArea.Left; double plotAreaRight = this.Plot.PlotArea.Right; double plotAreaTop = this.Plot.PlotArea.Top; double plotAreaBottom = this.Plot.PlotArea.Bottom; bool isHorizontal = axis.IsHorizontal(); double a0; double a1; var minorSegments = new List<ScreenPoint>(); var minorTickSegments = new List<ScreenPoint>(); this.GetTickPositions(axis, axis.TickStyle, axis.MinorTickSize, axis.Position, out a0, out a1); foreach (double value in this.MinorTickValues) { if (value < actualMinimum - eps || value > actualMaximum + eps) { continue; } if (this.MajorTickValues.Contains(value)) { continue; } if (axis.PositionAtZeroCrossing && Math.Abs(value) < eps) { continue; } double transformedValue = axis.Transform(value); if (isHorizontal) { SnapTo(plotAreaLeft, ref transformedValue); SnapTo(plotAreaRight, ref transformedValue); } else { SnapTo(plotAreaTop, ref transformedValue); SnapTo(plotAreaBottom, ref transformedValue); } // Draw the minor grid line if (this.MinorPen != null) { if (isHorizontal) { minorSegments.Add(new ScreenPoint(transformedValue, plotAreaTop)); minorSegments.Add(new ScreenPoint(transformedValue, plotAreaBottom)); } else { if (transformedValue < plotAreaTop || transformedValue > plotAreaBottom) { } minorSegments.Add(new ScreenPoint(plotAreaLeft, transformedValue)); minorSegments.Add(new ScreenPoint(plotAreaRight, transformedValue)); } } // Draw the minor tick if (axis.TickStyle != TickStyle.None && axis.MinorTickSize > 0) { if (isHorizontal) { minorTickSegments.Add(new ScreenPoint(transformedValue, axisPosition + a0)); minorTickSegments.Add(new ScreenPoint(transformedValue, axisPosition + a1)); } else { minorTickSegments.Add(new ScreenPoint(axisPosition + a0, transformedValue)); minorTickSegments.Add(new ScreenPoint(axisPosition + a1, transformedValue)); } } } // Draw all the line segments); if (this.MinorPen != null) { this.RenderContext.DrawLineSegments(minorSegments, this.MinorPen); } if (this.MinorTickPen != null) { this.RenderContext.DrawLineSegments(minorTickSegments, this.MinorTickPen); } }
/// <summary> /// Gets the axis title position, rotation and alignment. /// </summary> /// <param name="axis">The axis.</param> /// <param name="titlePosition">The title position.</param> /// <param name="angle">The angle.</param> /// <param name="halign">The horizontal alignment.</param> /// <param name="valign">The vertical alignment.</param> /// <returns>The <see cref="ScreenPoint" />.</returns> protected virtual ScreenPoint GetAxisTitlePositionAndAlignment( Axis axis, double titlePosition, ref double angle, ref HorizontalAlignment halign, ref VerticalAlignment valign) { double middle = axis.IsHorizontal() ? Lerp(axis.ScreenMin.X, axis.ScreenMax.X, axis.TitlePosition) : Lerp(axis.ScreenMax.Y, axis.ScreenMin.Y, axis.TitlePosition); if (axis.PositionAtZeroCrossing) { middle = Lerp(axis.Transform(axis.ActualMaximum), axis.Transform(axis.ActualMinimum), axis.TitlePosition); } switch (axis.Position) { case AxisPosition.Left: return new ScreenPoint(titlePosition, middle); case AxisPosition.Right: valign = VerticalAlignment.Bottom; return new ScreenPoint(titlePosition, middle); case AxisPosition.Top: halign = HorizontalAlignment.Center; valign = VerticalAlignment.Top; angle = 0; return new ScreenPoint(middle, titlePosition); case AxisPosition.Bottom: halign = HorizontalAlignment.Center; valign = VerticalAlignment.Bottom; angle = 0; return new ScreenPoint(middle, titlePosition); default: throw new ArgumentOutOfRangeException("axis"); } }
/// <summary> /// Renders the major items. /// </summary> /// <param name="axis">The axis.</param> /// <param name="axisPosition">The axis position.</param> /// <param name="titlePosition">The title position.</param> /// <param name="drawAxisLine">Draw the axis line if set to <c>true</c>.</param> protected virtual void RenderMajorItems(Axis axis, double axisPosition, double titlePosition, bool drawAxisLine) { double eps = axis.ActualMinorStep * 1e-3; double actualMinimum = axis.ActualMinimum; double actualMaximum = axis.ActualMaximum; double plotAreaLeft = this.Plot.PlotArea.Left; double plotAreaRight = this.Plot.PlotArea.Right; double plotAreaTop = this.Plot.PlotArea.Top; double plotAreaBottom = this.Plot.PlotArea.Bottom; bool isHorizontal = axis.IsHorizontal(); double a0; double a1; var majorSegments = new List<ScreenPoint>(); var majorTickSegments = new List<ScreenPoint>(); this.GetTickPositions(axis, axis.TickStyle, axis.MajorTickSize, axis.Position, out a0, out a1); foreach (double value in this.MajorTickValues) { if (value < actualMinimum - eps || value > actualMaximum + eps) { continue; } if (axis.PositionAtZeroCrossing && Math.Abs(value) < eps) { continue; } double transformedValue = axis.Transform(value); if (isHorizontal) { SnapTo(plotAreaLeft, ref transformedValue); SnapTo(plotAreaRight, ref transformedValue); } else { SnapTo(plotAreaTop, ref transformedValue); SnapTo(plotAreaBottom, ref transformedValue); } if (this.MajorPen != null) { if (isHorizontal) { majorSegments.Add(new ScreenPoint(transformedValue, plotAreaTop)); majorSegments.Add(new ScreenPoint(transformedValue, plotAreaBottom)); } else { majorSegments.Add(new ScreenPoint(plotAreaLeft, transformedValue)); majorSegments.Add(new ScreenPoint(plotAreaRight, transformedValue)); } } if (axis.TickStyle != TickStyle.None && axis.MajorTickSize > 0) { if (isHorizontal) { majorTickSegments.Add(new ScreenPoint(transformedValue, axisPosition + a0)); majorTickSegments.Add(new ScreenPoint(transformedValue, axisPosition + a1)); } else { majorTickSegments.Add(new ScreenPoint(axisPosition + a0, transformedValue)); majorTickSegments.Add(new ScreenPoint(axisPosition + a1, transformedValue)); } } } // Render the axis labels (numbers or category names) foreach (double value in this.MajorLabelValues) { if (value < actualMinimum - eps || value > actualMaximum + eps) { continue; } if (axis.PositionAtZeroCrossing && Math.Abs(value) < eps) { continue; } double transformedValue = axis.Transform(value); if (isHorizontal) { SnapTo(plotAreaLeft, ref transformedValue); SnapTo(plotAreaRight, ref transformedValue); } else { SnapTo(plotAreaTop, ref transformedValue); SnapTo(plotAreaBottom, ref transformedValue); } var pt = new ScreenPoint(); var ha = HorizontalAlignment.Right; var va = VerticalAlignment.Middle; switch (axis.Position) { case AxisPosition.Left: pt = new ScreenPoint(axisPosition + a1 - axis.AxisTickToLabelDistance, transformedValue); this.GetRotatedAlignments( axis.Angle, HorizontalAlignment.Right, VerticalAlignment.Middle, out ha, out va); break; case AxisPosition.Right: pt = new ScreenPoint(axisPosition + a1 + axis.AxisTickToLabelDistance, transformedValue); this.GetRotatedAlignments( axis.Angle, HorizontalAlignment.Left, VerticalAlignment.Middle, out ha, out va); break; case AxisPosition.Top: pt = new ScreenPoint(transformedValue, axisPosition + a1 - axis.AxisTickToLabelDistance); this.GetRotatedAlignments( axis.Angle, HorizontalAlignment.Center, VerticalAlignment.Bottom, out ha, out va); break; case AxisPosition.Bottom: pt = new ScreenPoint(transformedValue, axisPosition + a1 + axis.AxisTickToLabelDistance); this.GetRotatedAlignments( axis.Angle, HorizontalAlignment.Center, VerticalAlignment.Top, out ha, out va); break; } string text = axis.FormatValue(value); this.RenderContext.DrawMathText( pt, text, axis.ActualTextColor, axis.ActualFont, axis.ActualFontSize, axis.ActualFontWeight, axis.Angle, ha, va); } // Draw the zero crossing line if (axis.PositionAtZeroCrossing && this.ZeroPen != null && this.IsWithin(0, actualMinimum, actualMaximum)) { double t0 = axis.Transform(0); if (isHorizontal) { this.RenderContext.DrawLine(t0, plotAreaTop, t0, plotAreaBottom, this.ZeroPen); } else { this.RenderContext.DrawLine(plotAreaLeft, t0, plotAreaRight, t0, this.ZeroPen); } } // Draw extra grid lines if (axis.ExtraGridlines != null && this.ExtraPen != null) { foreach (double value in axis.ExtraGridlines) { if (!this.IsWithin(value, actualMinimum, actualMaximum)) { continue; } double transformedValue = axis.Transform(value); if (isHorizontal) { this.RenderContext.DrawLine( transformedValue, plotAreaTop, transformedValue, plotAreaBottom, this.ExtraPen); } else { this.RenderContext.DrawLine( plotAreaLeft, transformedValue, plotAreaRight, transformedValue, this.ExtraPen); } } } if (drawAxisLine) { // Draw the axis line (across the tick marks) if (isHorizontal) { this.RenderContext.DrawLine( axis.Transform(actualMinimum), axisPosition, axis.Transform(actualMaximum), axisPosition, this.AxislinePen); } else { this.RenderContext.DrawLine( axisPosition, axis.Transform(actualMinimum), axisPosition, axis.Transform(actualMaximum), this.AxislinePen); } } if (this.MajorPen != null) { this.RenderContext.DrawLineSegments(majorSegments, this.MajorPen); } if (this.MajorTickPen != null) { this.RenderContext.DrawLineSegments(majorTickSegments, this.MajorTickPen); } }
/// <summary> /// Transforms the specified point to screen coordinates. /// </summary> /// <param name="x">The x value (for the current axis).</param> /// <param name="y">The y value.</param> /// <param name="yaxis">The y axis.</param> /// <returns>The transformed point.</returns> public virtual ScreenPoint Transform(double x, double y, Axis yaxis) { if (yaxis == null) { throw new NullReferenceException("Y axis should not be null when transforming."); } return new ScreenPoint(this.Transform(x), yaxis.Transform(y)); }
/// <summary> /// Zooms at the specified position. /// </summary> /// <param name="axis"> /// The axis. /// </param> /// <param name="factor"> /// The zoom factor. /// </param> /// <param name="x"> /// The position to zoom at. /// </param> public void ZoomAt(Axis axis, double factor, double x = double.NaN) { if (double.IsNaN(x)) { double sx = (axis.Transform(axis.ActualMaximum) + axis.Transform(axis.ActualMinimum)) * 0.5; x = axis.InverseTransform(sx); } axis.ZoomAt(factor, x); }
/// <summary> /// Returns the angle (in radian) of the axis line in screen coordinate /// </summary> /// <param name="axis">The axis.</param> /// <param name="angleAxis">The angle axis.</param> /// <returns>The angle (in radians).</returns> private static double GetActualAngle(Axis axis, Axis angleAxis) { var a = axis.Transform(0, angleAxis.Angle, angleAxis); var b = axis.Transform(1, angleAxis.Angle, angleAxis); return Math.Atan2(b.y - a.y, b.x - a.x); }
/// <summary> /// Renders major tick text /// </summary> /// <param name="axis">The axis.</param> /// <param name="x">The x-value.</param> /// <param name="angleAxis">The angle axis.</param> private void RenderTickText(Axis axis, double x, Axis angleAxis) { var actualAngle = GetActualAngle(axis, angleAxis); var dx = axis.AxisTickToLabelDistance * Math.Sin(actualAngle); var dy = -axis.AxisTickToLabelDistance * Math.Cos(actualAngle); HorizontalAlignment ha; VerticalAlignment va; GetTickTextAligment(actualAngle, out ha, out va); var pt = axis.Transform(x, angleAxis.Angle, angleAxis); pt = new ScreenPoint(pt.X + dx, pt.Y + dy); string text = axis.FormatValue(x); this.RenderContext.DrawMathText( pt, text, axis.ActualTextColor, axis.ActualFont, axis.ActualFontSize, axis.ActualFontWeight, axis.Angle, ha, va); }
/// <summary> /// Renders a tick by drawing an lot of segments /// </summary> /// <param name="axis">The axis.</param> /// <param name="angleAxis">The angle axis.</param> /// <param name="x">The x-value.</param> /// <param name="pen">The pen.</param> private void RenderTickArc(Axis axis, AngleAxis angleAxis, double x, OxyPen pen) { // caution: make sure angleAxis.UpdateActualMaxMin(); has been called var minAngle = angleAxis.ActualMinimum; var maxAngle = angleAxis.ActualMaximum; // number of segment to draw a full circle // - decrease if you want get more speed // - increase if you want more detail // (making a public property of it would be a great idea) const double MaxSegments = 90.0; // compute the actual number of segments var segmentCount = (int)(MaxSegments * Math.Abs(angleAxis.EndAngle - angleAxis.StartAngle) / 360.0); var angleStep = (maxAngle - minAngle) / (segmentCount - 1); var points = new List<ScreenPoint>(); for (var i = 0; i < segmentCount; i++) { var angle = minAngle + (i * angleStep); points.Add(axis.Transform(x, angle, angleAxis)); } this.RenderContext.DrawLine(points, pen.Color, pen.Thickness, pen.ActualDashArray); }
/// <summary> /// Renders a tick by drawing an ellipse /// </summary> /// <param name="axis">The axis.</param> /// <param name="angleAxis">The angle axis.</param> /// <param name="x">The x-value.</param> /// <param name="pen">The pen.</param> private void RenderTickCircle(Axis axis, Axis angleAxis, double x, OxyPen pen) { var zero = angleAxis.Offset; var center = axis.Transform(axis.ActualMinimum, zero, angleAxis); var right = axis.Transform(x, zero, angleAxis).X; var radius = right - center.X; var width = radius * 2; var left = right - width; var top = center.Y - radius; var height = width; this.RenderContext.DrawEllipse(new OxyRect(left, top, width, height), OxyColors.Undefined, pen.Color, pen.Thickness); }
/// <summary> /// Transforms the specified point to screen coordinates. /// </summary> /// <param name="p"> /// The point. /// </param> /// <param name="xaxis"> /// The x axis. /// </param> /// <param name="yaxis"> /// The y axis. /// </param> /// <returns> /// The transformed point. /// </returns> public static ScreenPoint Transform(IDataPoint p, Axis xaxis, Axis yaxis) { return xaxis.Transform(p.X, p.Y, yaxis); }