369 lines
14 KiB
C#
369 lines
14 KiB
C#
|
#region MigraDoc - Creating Documents on the Fly
|
||
|
//
|
||
|
// Authors:
|
||
|
// Klaus Potzesny
|
||
|
//
|
||
|
// Copyright (c) 2001-2017 empira Software GmbH, Cologne Area (Germany)
|
||
|
//
|
||
|
// http://www.pdfsharp.com
|
||
|
// http://www.migradoc.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 MigraDoc.DocumentObjectModel.publics;
|
||
|
using MigraDoc.DocumentObjectModel.Tables;
|
||
|
using PdfSharp.Drawing;
|
||
|
using MigraDoc.DocumentObjectModel.Shapes;
|
||
|
using MigraDoc.DocumentObjectModel.Shapes.Charts;
|
||
|
|
||
|
namespace MigraDoc.Rendering
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Renders a chart to an XGraphics object.
|
||
|
/// </summary>
|
||
|
public class ChartRenderer : ShapeRenderer
|
||
|
{
|
||
|
public ChartRenderer(XGraphics gfx, Chart chart, FieldInfos fieldInfos)
|
||
|
: base(gfx, chart, fieldInfos)
|
||
|
{
|
||
|
_chart = chart;
|
||
|
ChartRenderInfo renderInfo = new ChartRenderInfo();
|
||
|
renderInfo.DocumentObject = _shape;
|
||
|
_renderInfo = renderInfo;
|
||
|
}
|
||
|
|
||
|
public ChartRenderer(XGraphics gfx, RenderInfo renderInfo, FieldInfos fieldInfos)
|
||
|
: base(gfx, renderInfo, fieldInfos)
|
||
|
{
|
||
|
_chart = (Chart)renderInfo.DocumentObject;
|
||
|
}
|
||
|
|
||
|
FormattedTextArea GetFormattedTextArea(TextArea area, XUnit width)
|
||
|
{
|
||
|
if (area == null)
|
||
|
return null;
|
||
|
|
||
|
FormattedTextArea formattedTextArea = new FormattedTextArea(_documentRenderer, area, _fieldInfos);
|
||
|
|
||
|
if (!double.IsNaN(width))
|
||
|
formattedTextArea.InnerWidth = width;
|
||
|
|
||
|
formattedTextArea.Format(_gfx);
|
||
|
return formattedTextArea;
|
||
|
}
|
||
|
|
||
|
FormattedTextArea GetFormattedTextArea(TextArea area)
|
||
|
{
|
||
|
return GetFormattedTextArea(area, double.NaN);
|
||
|
}
|
||
|
|
||
|
void GetLeftRightVerticalPosition(out XUnit top, out XUnit bottom)
|
||
|
{
|
||
|
//REM: Line width is still ignored while layouting charts.
|
||
|
Area contentArea = _renderInfo.LayoutInfo.ContentArea;
|
||
|
ChartFormatInfo formatInfo = (ChartFormatInfo)_renderInfo.FormatInfo;
|
||
|
top = contentArea.Y;
|
||
|
|
||
|
if (formatInfo.FormattedHeader != null)
|
||
|
top += formatInfo.FormattedHeader.InnerHeight;
|
||
|
|
||
|
bottom = contentArea.Y + contentArea.Height;
|
||
|
if (formatInfo.FormattedFooter != null)
|
||
|
bottom -= formatInfo.FormattedFooter.InnerHeight;
|
||
|
}
|
||
|
|
||
|
Rectangle GetLeftRect()
|
||
|
{
|
||
|
Area contentArea = _renderInfo.LayoutInfo.ContentArea;
|
||
|
ChartFormatInfo formatInfo = (ChartFormatInfo)_renderInfo.FormatInfo;
|
||
|
XUnit top;
|
||
|
XUnit bottom;
|
||
|
GetLeftRightVerticalPosition(out top, out bottom);
|
||
|
|
||
|
XUnit left = contentArea.X;
|
||
|
XUnit width = formatInfo.FormattedLeft.InnerWidth;
|
||
|
|
||
|
return new Rectangle(left, top, width, bottom - top);
|
||
|
}
|
||
|
|
||
|
Rectangle GetRightRect()
|
||
|
{
|
||
|
Area contentArea = _renderInfo.LayoutInfo.ContentArea;
|
||
|
ChartFormatInfo formatInfo = (ChartFormatInfo)_renderInfo.FormatInfo;
|
||
|
XUnit top;
|
||
|
XUnit bottom;
|
||
|
GetLeftRightVerticalPosition(out top, out bottom);
|
||
|
|
||
|
XUnit left = contentArea.X + contentArea.Width - formatInfo.FormattedRight.InnerWidth;
|
||
|
XUnit width = formatInfo.FormattedRight.InnerWidth;
|
||
|
|
||
|
return new Rectangle(left, top, width, bottom - top);
|
||
|
}
|
||
|
|
||
|
Rectangle GetHeaderRect()
|
||
|
{
|
||
|
Area contentArea = _renderInfo.LayoutInfo.ContentArea;
|
||
|
ChartFormatInfo formatInfo = (ChartFormatInfo)_renderInfo.FormatInfo;
|
||
|
|
||
|
XUnit left = contentArea.X;
|
||
|
XUnit top = contentArea.Y;
|
||
|
XUnit width = contentArea.Width;
|
||
|
XUnit height = formatInfo.FormattedHeader.InnerHeight;
|
||
|
|
||
|
return new Rectangle(left, top, width, height);
|
||
|
}
|
||
|
|
||
|
Rectangle GetFooterRect()
|
||
|
{
|
||
|
Area contentArea = _renderInfo.LayoutInfo.ContentArea;
|
||
|
ChartFormatInfo formatInfo = (ChartFormatInfo)_renderInfo.FormatInfo;
|
||
|
|
||
|
XUnit left = contentArea.X;
|
||
|
XUnit top = contentArea.Y + contentArea.Height - formatInfo.FormattedFooter.InnerHeight;
|
||
|
XUnit width = contentArea.Width;
|
||
|
XUnit height = formatInfo.FormattedFooter.InnerHeight;
|
||
|
|
||
|
return new Rectangle(left, top, width, height);
|
||
|
}
|
||
|
|
||
|
Rectangle GetTopRect()
|
||
|
{
|
||
|
Area contentArea = _renderInfo.LayoutInfo.ContentArea;
|
||
|
ChartFormatInfo formatInfo = (ChartFormatInfo)_renderInfo.FormatInfo;
|
||
|
|
||
|
XUnit left;
|
||
|
XUnit right;
|
||
|
GetTopBottomHorizontalPosition(out left, out right);
|
||
|
|
||
|
XUnit top = contentArea.Y;
|
||
|
if (formatInfo.FormattedHeader != null)
|
||
|
top += formatInfo.FormattedHeader.InnerHeight;
|
||
|
|
||
|
XUnit height = formatInfo.FormattedTop.InnerHeight;
|
||
|
|
||
|
return new Rectangle(left, top, right - left, height);
|
||
|
}
|
||
|
|
||
|
Rectangle GetBottomRect()
|
||
|
{
|
||
|
Area contentArea = _renderInfo.LayoutInfo.ContentArea;
|
||
|
ChartFormatInfo formatInfo = (ChartFormatInfo)_renderInfo.FormatInfo;
|
||
|
|
||
|
XUnit left;
|
||
|
XUnit right;
|
||
|
GetTopBottomHorizontalPosition(out left, out right);
|
||
|
|
||
|
XUnit top = contentArea.Y + contentArea.Height - formatInfo.FormattedBottom.InnerHeight;
|
||
|
if (formatInfo.FormattedFooter != null)
|
||
|
top -= formatInfo.FormattedFooter.InnerHeight;
|
||
|
|
||
|
XUnit height = formatInfo.FormattedBottom.InnerHeight;
|
||
|
return new Rectangle(left, top, right - left, height);
|
||
|
}
|
||
|
|
||
|
Rectangle GetPlotRect()
|
||
|
{
|
||
|
Area contentArea = _renderInfo.LayoutInfo.ContentArea;
|
||
|
ChartFormatInfo formatInfo = (ChartFormatInfo)_renderInfo.FormatInfo;
|
||
|
XUnit top = contentArea.Y;
|
||
|
if (formatInfo.FormattedHeader != null)
|
||
|
top += formatInfo.FormattedHeader.InnerHeight;
|
||
|
|
||
|
if (formatInfo.FormattedTop != null)
|
||
|
top += formatInfo.FormattedTop.InnerHeight;
|
||
|
|
||
|
XUnit bottom = contentArea.Y + contentArea.Height;
|
||
|
if (formatInfo.FormattedFooter != null)
|
||
|
bottom -= formatInfo.FormattedFooter.InnerHeight;
|
||
|
|
||
|
if (formatInfo.FormattedBottom != null)
|
||
|
bottom -= formatInfo.FormattedBottom.InnerHeight;
|
||
|
|
||
|
XUnit left = contentArea.X;
|
||
|
if (formatInfo.FormattedLeft != null)
|
||
|
left += formatInfo.FormattedLeft.InnerWidth;
|
||
|
|
||
|
XUnit right = contentArea.X + contentArea.Width;
|
||
|
if (formatInfo.FormattedRight != null)
|
||
|
right -= formatInfo.FormattedRight.InnerWidth;
|
||
|
|
||
|
return new Rectangle(left, top, right - left, bottom - top);
|
||
|
}
|
||
|
|
||
|
public override void Format(Area area, FormatInfo previousFormatInfo)
|
||
|
{
|
||
|
ChartFormatInfo formatInfo = (ChartFormatInfo)_renderInfo.FormatInfo;
|
||
|
|
||
|
TextArea textArea = (TextArea)_chart.GetValue("HeaderArea", GV.ReadOnly);
|
||
|
formatInfo.FormattedHeader = GetFormattedTextArea(textArea, _chart.Width.Point);
|
||
|
|
||
|
textArea = (TextArea)_chart.GetValue("FooterArea", GV.ReadOnly);
|
||
|
formatInfo.FormattedFooter = GetFormattedTextArea(textArea, _chart.Width.Point);
|
||
|
|
||
|
textArea = (TextArea)_chart.GetValue("LeftArea", GV.ReadOnly);
|
||
|
formatInfo.FormattedLeft = GetFormattedTextArea(textArea);
|
||
|
|
||
|
textArea = (TextArea)_chart.GetValue("RightArea", GV.ReadOnly);
|
||
|
formatInfo.FormattedRight = GetFormattedTextArea(textArea);
|
||
|
|
||
|
textArea = (TextArea)_chart.GetValue("TopArea", GV.ReadOnly);
|
||
|
formatInfo.FormattedTop = GetFormattedTextArea(textArea, GetTopBottomWidth());
|
||
|
|
||
|
textArea = (TextArea)_chart.GetValue("BottomArea", GV.ReadOnly);
|
||
|
formatInfo.FormattedBottom = GetFormattedTextArea(textArea, GetTopBottomWidth());
|
||
|
|
||
|
base.Format(area, previousFormatInfo);
|
||
|
formatInfo.ChartFrame = ChartMapper.ChartMapper.Map(_chart);
|
||
|
}
|
||
|
|
||
|
|
||
|
XUnit AlignVertically(VerticalAlignment vAlign, XUnit top, XUnit bottom, XUnit height)
|
||
|
{
|
||
|
switch (vAlign)
|
||
|
{
|
||
|
case VerticalAlignment.Bottom:
|
||
|
return bottom - height;
|
||
|
|
||
|
case VerticalAlignment.Center:
|
||
|
return (top + bottom - height) / 2;
|
||
|
|
||
|
default:
|
||
|
return top;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the width of the top and bottom area.
|
||
|
/// Used while formatting.
|
||
|
/// </summary>
|
||
|
/// <returns>The width of the top and bottom area</returns>
|
||
|
private XUnit GetTopBottomWidth()
|
||
|
{
|
||
|
ChartFormatInfo formatInfo = (ChartFormatInfo)_renderInfo.FormatInfo;
|
||
|
XUnit width = _chart.Width.Point;
|
||
|
if (formatInfo.FormattedRight != null)
|
||
|
width -= formatInfo.FormattedRight.InnerWidth;
|
||
|
if (formatInfo.FormattedLeft != null)
|
||
|
width -= formatInfo.FormattedLeft.InnerWidth;
|
||
|
return width;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the horizontal boundaries of the top and bottom area.
|
||
|
/// Used while rendering.
|
||
|
/// </summary>
|
||
|
/// <param name="left">The left boundary of the top and bottom area</param>
|
||
|
/// <param name="right">The right boundary of the top and bottom area</param>
|
||
|
private void GetTopBottomHorizontalPosition(out XUnit left, out XUnit right)
|
||
|
{
|
||
|
Area contentArea = _renderInfo.LayoutInfo.ContentArea;
|
||
|
ChartFormatInfo formatInfo = (ChartFormatInfo)_renderInfo.FormatInfo;
|
||
|
left = contentArea.X;
|
||
|
right = contentArea.X + contentArea.Width;
|
||
|
|
||
|
if (formatInfo.FormattedRight != null)
|
||
|
right -= formatInfo.FormattedRight.InnerWidth;
|
||
|
if (formatInfo.FormattedLeft != null)
|
||
|
left += formatInfo.FormattedLeft.InnerWidth;
|
||
|
}
|
||
|
|
||
|
void RenderArea(FormattedTextArea area, Rectangle rect)
|
||
|
{
|
||
|
if (area == null)
|
||
|
return;
|
||
|
|
||
|
TextArea textArea = area.TextArea;
|
||
|
|
||
|
FillFormatRenderer fillFormatRenderer = new FillFormatRenderer((FillFormat)textArea.GetValue("FillFormat", GV.ReadOnly), _gfx);
|
||
|
fillFormatRenderer.Render(rect.X, rect.Y, rect.Width, rect.Height);
|
||
|
|
||
|
XUnit top = rect.Y;
|
||
|
top += textArea.TopPadding;
|
||
|
XUnit bottom = rect.Y + rect.Height;
|
||
|
bottom -= textArea.BottomPadding;
|
||
|
top = AlignVertically(textArea.VerticalAlignment, top, bottom, area.ContentHeight);
|
||
|
|
||
|
XUnit left = rect.X;
|
||
|
left += textArea.LeftPadding;
|
||
|
|
||
|
RenderInfo[] renderInfos = area.GetRenderInfos();
|
||
|
RenderByInfos(left, top, renderInfos);
|
||
|
|
||
|
LineFormatRenderer lineFormatRenderer = new LineFormatRenderer((LineFormat)textArea.GetValue("LineFormat", GV.ReadOnly), _gfx);
|
||
|
lineFormatRenderer.Render(rect.X, rect.Y, rect.Width, rect.Height);
|
||
|
}
|
||
|
|
||
|
public override void Render()
|
||
|
{
|
||
|
RenderFilling();
|
||
|
Area contentArea = _renderInfo.LayoutInfo.ContentArea;
|
||
|
|
||
|
ChartFormatInfo formatInfo = (ChartFormatInfo)_renderInfo.FormatInfo;
|
||
|
if (formatInfo.FormattedHeader != null)
|
||
|
RenderArea(formatInfo.FormattedHeader, GetHeaderRect());
|
||
|
|
||
|
if (formatInfo.FormattedFooter != null)
|
||
|
RenderArea(formatInfo.FormattedFooter, GetFooterRect());
|
||
|
|
||
|
if (formatInfo.FormattedTop != null)
|
||
|
RenderArea(formatInfo.FormattedTop, GetTopRect());
|
||
|
|
||
|
if (formatInfo.FormattedBottom != null)
|
||
|
RenderArea(formatInfo.FormattedBottom, GetBottomRect());
|
||
|
|
||
|
if (formatInfo.FormattedLeft != null)
|
||
|
RenderArea(formatInfo.FormattedLeft, GetLeftRect());
|
||
|
|
||
|
if (formatInfo.FormattedRight != null)
|
||
|
RenderArea(formatInfo.FormattedRight, GetRightRect());
|
||
|
|
||
|
PlotArea plotArea = (PlotArea)_chart.GetValue("PlotArea", GV.ReadOnly);
|
||
|
if (plotArea != null)
|
||
|
RenderPlotArea(plotArea, GetPlotRect());
|
||
|
|
||
|
RenderLine();
|
||
|
}
|
||
|
|
||
|
void RenderPlotArea(PlotArea area, Rectangle rect)
|
||
|
{
|
||
|
PdfSharp.Charting.ChartFrame chartFrame = ((ChartFormatInfo)_renderInfo.FormatInfo).ChartFrame;
|
||
|
|
||
|
XUnit top = rect.Y;
|
||
|
top += area.TopPadding;
|
||
|
|
||
|
XUnit bottom = rect.Y + rect.Height;
|
||
|
bottom -= area.BottomPadding;
|
||
|
|
||
|
XUnit left = rect.X;
|
||
|
left += area.LeftPadding;
|
||
|
|
||
|
XUnit right = rect.X + rect.Width;
|
||
|
right -= area.RightPadding;
|
||
|
|
||
|
chartFrame.Location = new XPoint(left, top);
|
||
|
chartFrame.Size = new XSize(right - left, bottom - top);
|
||
|
chartFrame.DrawChart(_gfx);
|
||
|
}
|
||
|
|
||
|
readonly Chart _chart;
|
||
|
}
|
||
|
}
|