#region PDFsharp Charting - A .NET charting library based on PDFsharp
//
// Authors:
// Niklas Schneider
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
using System;
using PdfSharp.Drawing;
namespace PdfSharp.Charting.Renderers
{
///
/// Represents an axis renderer used for charts of type Bar2D.
///
internal class VerticalXAxisRenderer : XAxisRenderer
{
///
/// Initializes a new instance of the VerticalXAxisRenderer class with the specified renderer parameters.
///
internal VerticalXAxisRenderer(RendererParameters parms)
: base(parms)
{ }
///
/// Returns an initialized rendererInfo based on the X axis.
///
internal override RendererInfo Init()
{
Chart chart = (Chart)_rendererParms.DrawingItem;
AxisRendererInfo xari = new AxisRendererInfo();
xari._axis = chart._xAxis;
if (xari._axis != null)
{
ChartRendererInfo cri = (ChartRendererInfo)_rendererParms.RendererInfo;
CalculateXAxisValues(xari);
InitXValues(xari);
InitAxisTitle(xari, cri.DefaultFont);
InitTickLabels(xari, cri.DefaultFont);
InitAxisLineFormat(xari);
InitGridlines(xari);
}
return xari;
}
///
/// Calculates the space used for the X axis.
///
internal override void Format()
{
AxisRendererInfo xari = ((ChartRendererInfo)_rendererParms.RendererInfo).xAxisRendererInfo;
if (xari._axis != null)
{
AxisTitleRendererInfo atri = xari._axisTitleRendererInfo;
// Calculate space used for axis title.
XSize titleSize = new XSize(0, 0);
if (atri != null && atri.AxisTitleText != null && atri.AxisTitleText.Length > 0)
titleSize = _rendererParms.Graphics.MeasureString(atri.AxisTitleText, atri.AxisTitleFont);
// Calculate space used for tick labels.
XSize size = new XSize(0, 0);
foreach (XSeries xs in xari.XValues)
{
foreach (XValue xv in xs)
{
XSize valueSize = _rendererParms.Graphics.MeasureString(xv._value, xari.TickLabelsFont);
size.Height += valueSize.Height;
size.Width = Math.Max(valueSize.Width, size.Width);
}
}
// Remember space for later drawing.
if (atri != null)
atri.AxisTitleSize = titleSize;
xari.TickLabelsHeight = size.Height;
xari.Height = size.Height;
xari.Width = titleSize.Width + size.Width + xari.MajorTickMarkWidth;
}
}
///
/// Draws the horizontal X axis.
///
internal override void Draw()
{
XGraphics gfx = _rendererParms.Graphics;
ChartRendererInfo cri = (ChartRendererInfo)_rendererParms.RendererInfo;
AxisRendererInfo xari = cri.xAxisRendererInfo;
double xMin = xari.MinimumScale;
double xMax = xari.MaximumScale;
double xMajorTick = xari.MajorTick;
double xMinorTick = xari.MinorTick;
double xMaxExtension = xari.MajorTick;
// Draw tick labels. Each tick label will be aligned centered.
int countTickLabels = (int)xMax;
double tickLabelStep = xari.Height / countTickLabels;
XPoint startPos = new XPoint(xari.X + xari.Width - xari.MajorTickMarkWidth, xari.Y + tickLabelStep / 2);
foreach (XSeries xs in xari.XValues)
{
for (int idx = countTickLabels - 1; idx >= 0; --idx)
{
XValue xv = xs[idx];
string tickLabel = xv._value;
XSize size = gfx.MeasureString(tickLabel, xari.TickLabelsFont);
gfx.DrawString(tickLabel, xari.TickLabelsFont, xari.TickLabelsBrush, startPos.X - size.Width, startPos.Y + size.Height / 2);
startPos.Y += tickLabelStep;
}
}
// Draw axis.
// First draw tick marks, second draw axis.
double majorTickMarkStart = 0, majorTickMarkEnd = 0,
minorTickMarkStart = 0, minorTickMarkEnd = 0;
GetTickMarkPos(xari, ref majorTickMarkStart, ref majorTickMarkEnd, ref minorTickMarkStart, ref minorTickMarkEnd);
LineFormatRenderer lineFormatRenderer = new LineFormatRenderer(gfx, xari.LineFormat);
XPoint[] points = new XPoint[2];
// Minor ticks.
if (xari.MinorTickMark != TickMarkType.None)
{
int countMinorTickMarks = (int)(xMax / xMinorTick);
double minorTickMarkStep = xari.Height / countMinorTickMarks;
startPos.Y = xari.Y;
for (int x = 0; x <= countMinorTickMarks; x++)
{
points[0].X = minorTickMarkStart;
points[0].Y = startPos.Y + minorTickMarkStep * x;
points[1].X = minorTickMarkEnd;
points[1].Y = points[0].Y;
lineFormatRenderer.DrawLine(points[0], points[1]);
}
}
// Major ticks.
if (xari.MajorTickMark != TickMarkType.None)
{
int countMajorTickMarks = (int)(xMax / xMajorTick);
double majorTickMarkStep = xari.Height / countMajorTickMarks;
startPos.Y = xari.Y;
for (int x = 0; x <= countMajorTickMarks; x++)
{
points[0].X = majorTickMarkStart;
points[0].Y = startPos.Y + majorTickMarkStep * x;
points[1].X = majorTickMarkEnd;
points[1].Y = points[0].Y;
lineFormatRenderer.DrawLine(points[0], points[1]);
}
}
// Axis.
if (xari.LineFormat != null)
{
points[0].X = xari.X + xari.Width;
points[0].Y = xari.Y;
points[1].X = xari.X + xari.Width;
points[1].Y = xari.Y + xari.Height;
if (xari.MajorTickMark != TickMarkType.None)
{
points[0].Y -= xari.LineFormat.Width / 2;
points[1].Y += xari.LineFormat.Width / 2;
}
lineFormatRenderer.DrawLine(points[0], points[1]);
}
// Draw axis title.
AxisTitleRendererInfo atri = xari._axisTitleRendererInfo;
if (atri != null && atri.AxisTitleText != null && atri.AxisTitleText.Length > 0)
{
XRect rect = new XRect(xari.X, xari.Y + xari.Height / 2, atri.AxisTitleSize.Width, 0);
gfx.DrawString(atri.AxisTitleText, atri.AxisTitleFont, atri.AxisTitleBrush, rect);
}
}
///
/// Calculates the X axis describing values like minimum/maximum scale, major/minor tick and
/// major/minor tick mark width.
///
private void CalculateXAxisValues(AxisRendererInfo rendererInfo)
{
// Calculates the maximum number of data points over all series.
SeriesCollection seriesCollection = ((Chart)rendererInfo._axis._parent)._seriesCollection;
int count = 0;
foreach (Series series in seriesCollection)
count = Math.Max(count, series.Count);
rendererInfo.MinimumScale = 0;
rendererInfo.MaximumScale = count; // At least 0
rendererInfo.MajorTick = 1;
rendererInfo.MinorTick = 0.5;
rendererInfo.MajorTickMarkWidth = DefaultMajorTickMarkWidth;
rendererInfo.MinorTickMarkWidth = DefaultMinorTickMarkWidth;
}
///
/// Initializes the rendererInfo's xvalues. If not set by the user xvalues will be simply numbers
/// from minimum scale + 1 to maximum scale.
///
private void InitXValues(AxisRendererInfo rendererInfo)
{
rendererInfo.XValues = ((Chart)rendererInfo._axis._parent)._xValues;
if (rendererInfo.XValues == null)
{
rendererInfo.XValues = new XValues();
XSeries xs = rendererInfo.XValues.AddXSeries();
for (double i = rendererInfo.MinimumScale + 1; i <= rendererInfo.MaximumScale; ++i)
xs.Add(i.ToString());
}
}
///
/// Calculates the starting and ending y position for the minor and major tick marks.
///
private void GetTickMarkPos(AxisRendererInfo rendererInfo,
ref double majorTickMarkStart, ref double majorTickMarkEnd,
ref double minorTickMarkStart, ref double minorTickMarkEnd)
{
double majorTickMarkWidth = rendererInfo.MajorTickMarkWidth;
double minorTickMarkWidth = rendererInfo.MinorTickMarkWidth;
double x = rendererInfo.Rect.X + rendererInfo.Rect.Width;
switch (rendererInfo.MajorTickMark)
{
case TickMarkType.Inside:
majorTickMarkStart = x;
majorTickMarkEnd = x + majorTickMarkWidth;
break;
case TickMarkType.Outside:
majorTickMarkStart = x - majorTickMarkWidth;
majorTickMarkEnd = x;
break;
case TickMarkType.Cross:
majorTickMarkStart = x - majorTickMarkWidth;
majorTickMarkEnd = x + majorTickMarkWidth;
break;
case TickMarkType.None:
majorTickMarkStart = 0;
majorTickMarkEnd = 0;
break;
}
switch (rendererInfo.MinorTickMark)
{
case TickMarkType.Inside:
minorTickMarkStart = x;
minorTickMarkEnd = x + minorTickMarkWidth;
break;
case TickMarkType.Outside:
minorTickMarkStart = x - minorTickMarkWidth;
minorTickMarkEnd = x;
break;
case TickMarkType.Cross:
minorTickMarkStart = x - minorTickMarkWidth;
minorTickMarkEnd = x + minorTickMarkWidth;
break;
case TickMarkType.None:
minorTickMarkStart = 0;
minorTickMarkEnd = 0;
break;
}
}
}
}