You've already forked linux-packaging-mono
3158 lines
102 KiB
C#
3158 lines
102 KiB
C#
|
|
//-------------------------------------------------------------
|
|||
|
|
// <copyright company=<3D>Microsoft Corporation<6F>>
|
|||
|
|
// Copyright <20> Microsoft Corporation. All Rights Reserved.
|
|||
|
|
// </copyright>
|
|||
|
|
//-------------------------------------------------------------
|
|||
|
|
// @owner=alexgor, deliant
|
|||
|
|
//=================================================================
|
|||
|
|
// File: ChartArea.cs
|
|||
|
|
//
|
|||
|
|
// Namespace: System.Web.UI.WebControls[Windows.Forms].Charting
|
|||
|
|
//
|
|||
|
|
// Classes: ChartArea
|
|||
|
|
//
|
|||
|
|
// Purpose: The ChartArea class represents one chart area within
|
|||
|
|
// a chart image, and is used to plot one or more chart
|
|||
|
|
// series. The number of chart series that can be plotted
|
|||
|
|
// in a chart area is unlimited.
|
|||
|
|
//
|
|||
|
|
// Reviewed: GS - August 6, 2002
|
|||
|
|
// AG - August 7, 2002
|
|||
|
|
// AG - Microsoft 16, 2007
|
|||
|
|
//
|
|||
|
|
//===================================================================
|
|||
|
|
|
|||
|
|
#region Used namespaces
|
|||
|
|
using System;
|
|||
|
|
using System.Collections;
|
|||
|
|
using System.Collections.Specialized;
|
|||
|
|
using System.ComponentModel;
|
|||
|
|
using System.ComponentModel.Design;
|
|||
|
|
using System.Data;
|
|||
|
|
using System.Drawing;
|
|||
|
|
using System.Drawing.Design;
|
|||
|
|
using System.Drawing.Drawing2D;
|
|||
|
|
using System.Globalization;
|
|||
|
|
using System.Diagnostics.CodeAnalysis;
|
|||
|
|
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
|
|||
|
|
using System.Windows.Forms.DataVisualization.Charting.Data;
|
|||
|
|
using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
|
|||
|
|
using System.Windows.Forms.DataVisualization.Charting.Utilities;
|
|||
|
|
using System.Windows.Forms.DataVisualization.Charting.Borders3D;
|
|||
|
|
using System.Windows.Forms.DataVisualization.Charting;
|
|||
|
|
using System.ComponentModel.Design.Serialization;
|
|||
|
|
using System.Reflection;
|
|||
|
|
using System.Windows.Forms.Design;
|
|||
|
|
#else
|
|||
|
|
using System.Web;
|
|||
|
|
using System.Web.UI;
|
|||
|
|
using System.Web.UI.DataVisualization.Charting;
|
|||
|
|
using System.Web.UI.DataVisualization.Charting.Data;
|
|||
|
|
using System.Web.UI.DataVisualization.Charting.ChartTypes;
|
|||
|
|
using System.Web.UI.DataVisualization.Charting.Utilities;
|
|||
|
|
using System.Web.UI.DataVisualization.Charting.Borders3D;
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
namespace System.Windows.Forms.DataVisualization.Charting
|
|||
|
|
#else
|
|||
|
|
namespace System.Web.UI.DataVisualization.Charting
|
|||
|
|
#endif
|
|||
|
|
{
|
|||
|
|
#region Chart area aligment enumerations
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// An enumeration of the alignment orientations of a ChartArea
|
|||
|
|
/// </summary>
|
|||
|
|
[Flags]
|
|||
|
|
public enum AreaAlignmentOrientations
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// Chart areas are not automatically aligned.
|
|||
|
|
/// </summary>
|
|||
|
|
None = 0,
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Chart areas are aligned vertically.
|
|||
|
|
/// </summary>
|
|||
|
|
Vertical = 1,
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Chart areas are aligned horizontally.
|
|||
|
|
/// </summary>
|
|||
|
|
Horizontal = 2,
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Chart areas are aligned using all values (horizontally and vertically).
|
|||
|
|
/// </summary>
|
|||
|
|
All = Vertical | Horizontal
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// An enumeration of the alignment styles of a ChartArea
|
|||
|
|
/// </summary>
|
|||
|
|
[Flags]
|
|||
|
|
public enum AreaAlignmentStyles
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// Chart areas are not automatically aligned.
|
|||
|
|
/// </summary>
|
|||
|
|
None = 0,
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Chart areas are aligned by positions.
|
|||
|
|
/// </summary>
|
|||
|
|
Position = 1,
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Chart areas are aligned by inner plot positions.
|
|||
|
|
/// </summary>
|
|||
|
|
PlotPosition = 2,
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Chart areas are aligned by axes views.
|
|||
|
|
/// </summary>
|
|||
|
|
AxesView = 4,
|
|||
|
|
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Cursor and Selection alignment.
|
|||
|
|
/// </summary>
|
|||
|
|
Cursor = 8,
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Complete alignment.
|
|||
|
|
/// </summary>
|
|||
|
|
All = Position | PlotPosition | Cursor | AxesView
|
|||
|
|
#else // Microsoft_CONTROL
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Complete alignment.
|
|||
|
|
/// </summary>
|
|||
|
|
All = Position | PlotPosition | AxesView
|
|||
|
|
|
|||
|
|
#endif // Microsoft_CONTROL
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// The ChartArea class is used to create and display a chart
|
|||
|
|
/// area within a chart image. The chart area is a rectangular
|
|||
|
|
/// area on a chart image. It has 4 axes, horizontal and vertical grids.
|
|||
|
|
/// A chart area can contain more than one different chart type.
|
|||
|
|
/// The number of chart series that can be plotted in a chart area
|
|||
|
|
/// is unlimited.
|
|||
|
|
///
|
|||
|
|
/// ChartArea class exposes all the properties and methods
|
|||
|
|
/// of its base ChartArea3D class.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
DefaultProperty("Axes"),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_ChartArea"),
|
|||
|
|
]
|
|||
|
|
#if ASPPERM_35
|
|||
|
|
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
|||
|
|
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
|||
|
|
#endif
|
|||
|
|
public partial class ChartArea : ChartNamedElement
|
|||
|
|
{
|
|||
|
|
#region Chart Area Fields
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Plot area position
|
|||
|
|
/// </summary>
|
|||
|
|
internal ElementPosition PlotAreaPosition;
|
|||
|
|
|
|||
|
|
// Private data members, which store properties values
|
|||
|
|
private Axis[] _axisArray = new Axis[4];
|
|||
|
|
private Color _backColor = Color.Empty;
|
|||
|
|
private ChartHatchStyle _backHatchStyle = ChartHatchStyle.None;
|
|||
|
|
private string _backImage = "";
|
|||
|
|
private ChartImageWrapMode _backImageWrapMode = ChartImageWrapMode.Tile;
|
|||
|
|
private Color _backImageTransparentColor = Color.Empty;
|
|||
|
|
private ChartImageAlignmentStyle _backImageAlignment = ChartImageAlignmentStyle.TopLeft;
|
|||
|
|
private GradientStyle _backGradientStyle = GradientStyle.None;
|
|||
|
|
private Color _backSecondaryColor = Color.Empty;
|
|||
|
|
private Color _borderColor = Color.Black;
|
|||
|
|
private int _borderWidth = 1;
|
|||
|
|
private ChartDashStyle _borderDashStyle = ChartDashStyle.NotSet;
|
|||
|
|
private int _shadowOffset = 0;
|
|||
|
|
private Color _shadowColor = Color.FromArgb(128, 0, 0, 0);
|
|||
|
|
private ElementPosition _areaPosition = null;
|
|||
|
|
private ElementPosition _innerPlotPosition = null;
|
|||
|
|
internal int IterationCounter = 0;
|
|||
|
|
|
|||
|
|
private bool _isSameFontSizeForAllAxes = false;
|
|||
|
|
internal float axesAutoFontSize = 8f;
|
|||
|
|
|
|||
|
|
private string _alignWithChartArea = Constants.NotSetValue;
|
|||
|
|
private AreaAlignmentOrientations _alignmentOrientation = AreaAlignmentOrientations.Vertical;
|
|||
|
|
private AreaAlignmentStyles _alignmentStyle = AreaAlignmentStyles.All;
|
|||
|
|
private int _circularSectorNumber = int.MinValue;
|
|||
|
|
private int _circularUsePolygons = int.MinValue;
|
|||
|
|
|
|||
|
|
// Flag indicates that chart area is acurrently aligned
|
|||
|
|
internal bool alignmentInProcess = false;
|
|||
|
|
|
|||
|
|
// Chart area position before adjustments
|
|||
|
|
internal RectangleF originalAreaPosition = RectangleF.Empty;
|
|||
|
|
|
|||
|
|
// Chart area inner plot position before adjustments
|
|||
|
|
internal RectangleF originalInnerPlotPosition = RectangleF.Empty;
|
|||
|
|
|
|||
|
|
// Chart area position before adjustments
|
|||
|
|
internal RectangleF lastAreaPosition = RectangleF.Empty;
|
|||
|
|
|
|||
|
|
|
|||
|
|
// Center of the circulat chart area
|
|||
|
|
internal PointF circularCenter = PointF.Empty;
|
|||
|
|
|
|||
|
|
private ArrayList _circularAxisList = null;
|
|||
|
|
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
// Buffered plotting area image
|
|||
|
|
internal Bitmap areaBufferBitmap = null;
|
|||
|
|
|
|||
|
|
private Cursor _cursorX = new Cursor();
|
|||
|
|
private Cursor _cursorY = new Cursor();
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
// Area SmartLabel class
|
|||
|
|
internal SmartLabel smartLabels = new SmartLabel();
|
|||
|
|
|
|||
|
|
// Gets or sets a flag that specifies whether the chart area is visible.
|
|||
|
|
private bool _visible = true;
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Chart Area Cursor properties
|
|||
|
|
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets a Cursor object that is used for cursors and selected ranges along the X-axis.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeCursor"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(null),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_CursorX"),
|
|||
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
|
|||
|
|
TypeConverter(typeof(NoNameExpandableObjectConverter)),
|
|||
|
|
]
|
|||
|
|
public Cursor CursorX
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _cursorX;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_cursorX = value;
|
|||
|
|
|
|||
|
|
// Initialize chart object
|
|||
|
|
_cursorX.Initialize(this, AxisName.X);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets a Cursor object that is used for cursors and selected ranges along the Y-axis.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeCursor"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(null),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_CursorY"),
|
|||
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
|
|||
|
|
TypeConverter(typeof(NoNameExpandableObjectConverter)),
|
|||
|
|
]
|
|||
|
|
public Cursor CursorY
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _cursorY;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_cursorY = value;
|
|||
|
|
|
|||
|
|
// Initialize chart object
|
|||
|
|
_cursorY.Initialize(this, AxisName.Y);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endif // Microsoft_CONTROL
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Chart Area properties
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets a flag that specifies whether the chart area is visible.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <remarks>
|
|||
|
|
/// When this flag is set to false, all series, legends, titles and annotation objects
|
|||
|
|
/// associated with the chart area will also be hidden.
|
|||
|
|
/// </remarks>
|
|||
|
|
/// <value>
|
|||
|
|
/// <b>True</b> if the chart area is visible; <b>false</b> otherwise.
|
|||
|
|
/// </value>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
DefaultValue(true),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_Visible"),
|
|||
|
|
ParenthesizePropertyNameAttribute(true),
|
|||
|
|
]
|
|||
|
|
virtual public bool Visible
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _visible;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_visible = value;
|
|||
|
|
this.Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the name of the ChartArea object to which this chart area should be aligned.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAlignment"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(Constants.NotSetValue),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_AlignWithChartArea"),
|
|||
|
|
TypeConverter(typeof(LegendAreaNameConverter)),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public string AlignWithChartArea
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _alignWithChartArea;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
if (value != _alignWithChartArea)
|
|||
|
|
{
|
|||
|
|
if (String.IsNullOrEmpty(value))
|
|||
|
|
{
|
|||
|
|
_alignWithChartArea = Constants.NotSetValue;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
if (Chart != null && Chart.ChartAreas != null)
|
|||
|
|
{
|
|||
|
|
Chart.ChartAreas.VerifyNameReference(value);
|
|||
|
|
}
|
|||
|
|
_alignWithChartArea = value;
|
|||
|
|
}
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the alignment orientation of a chart area.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAlignment"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(AreaAlignmentOrientations.Vertical),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_AlignOrientation"),
|
|||
|
|
Editor(Editors.FlagsEnumUITypeEditor.Editor, Editors.FlagsEnumUITypeEditor.Base),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public AreaAlignmentOrientations AlignmentOrientation
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _alignmentOrientation;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_alignmentOrientation = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the alignment style of the ChartArea.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAlignment"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(AreaAlignmentStyles.All),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_AlignType"),
|
|||
|
|
Editor(Editors.FlagsEnumUITypeEditor.Editor, Editors.FlagsEnumUITypeEditor.Base),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public AreaAlignmentStyles AlignmentStyle
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _alignmentStyle;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_alignmentStyle = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets an array that represents all axes for a chart area.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAxes"),
|
|||
|
|
Bindable(true),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_Axes"),
|
|||
|
|
TypeConverter(typeof(AxesArrayConverter)),
|
|||
|
|
Editor(Editors.AxesArrayEditor.Editor, Editors.AxesArrayEditor.Base),
|
|||
|
|
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
|
|||
|
|
SerializationVisibilityAttribute(SerializationVisibility.Hidden)
|
|||
|
|
]
|
|||
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
|||
|
|
public Axis[] Axes
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _axisArray;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
AxisX = value[0];
|
|||
|
|
AxisY = value[1];
|
|||
|
|
AxisX2 = value[2];
|
|||
|
|
AxisY2 = value[3];
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Avoid serialization of the axes array
|
|||
|
|
/// </summary>
|
|||
|
|
[EditorBrowsableAttribute(EditorBrowsableState.Never)]
|
|||
|
|
internal bool ShouldSerializeAxes()
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets an Axis object that represents the primary Y-axis.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAxis"),
|
|||
|
|
Bindable(true),
|
|||
|
|
Browsable(false),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_AxisY"),
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
|
|||
|
|
#else
|
|||
|
|
PersistenceMode(PersistenceMode.InnerProperty),
|
|||
|
|
#endif
|
|||
|
|
TypeConverter(typeof(NoNameExpandableObjectConverter))
|
|||
|
|
]
|
|||
|
|
public Axis AxisY
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return axisY;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
axisY = value;
|
|||
|
|
axisY.Initialize(this, AxisName.Y);
|
|||
|
|
_axisArray[1] = axisY;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets an Axis object that represents the primary X-axis.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAxis"),
|
|||
|
|
Bindable(true),
|
|||
|
|
Browsable(false),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_AxisX"),
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
|
|||
|
|
#else
|
|||
|
|
PersistenceMode(PersistenceMode.InnerProperty),
|
|||
|
|
#endif
|
|||
|
|
TypeConverter(typeof(NoNameExpandableObjectConverter))
|
|||
|
|
]
|
|||
|
|
public Axis AxisX
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return axisX;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
axisX = value;
|
|||
|
|
axisX.Initialize(this, AxisName.X);
|
|||
|
|
_axisArray[0] = axisX;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets an Axis object that represents the secondary X-axis.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAxis"),
|
|||
|
|
Bindable(true),
|
|||
|
|
Browsable(false),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_AxisX2"),
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
|
|||
|
|
#else
|
|||
|
|
PersistenceMode(PersistenceMode.InnerProperty),
|
|||
|
|
#endif
|
|||
|
|
TypeConverter(typeof(NoNameExpandableObjectConverter))
|
|||
|
|
]
|
|||
|
|
public Axis AxisX2
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return axisX2;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
axisX2 = value;
|
|||
|
|
axisX2.Initialize(this, AxisName.X2);
|
|||
|
|
_axisArray[2] = axisX2;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets an Axis object that represents the secondary Y-axis.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAxis"),
|
|||
|
|
Bindable(true),
|
|||
|
|
Browsable(false),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_AxisY2"),
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
|
|||
|
|
#else
|
|||
|
|
PersistenceMode(PersistenceMode.InnerProperty),
|
|||
|
|
#endif
|
|||
|
|
TypeConverter(typeof(NoNameExpandableObjectConverter))
|
|||
|
|
]
|
|||
|
|
public Axis AxisY2
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return axisY2;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
axisY2 = value;
|
|||
|
|
axisY2.Initialize(this, AxisName.Y2);
|
|||
|
|
_axisArray[3] = axisY2;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets an ElementPosition object, which defines the position of a chart area object within the chart image.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_Position"),
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
|
|||
|
|
#else
|
|||
|
|
PersistenceMode(PersistenceMode.InnerProperty),
|
|||
|
|
#endif
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
TypeConverter(typeof(ElementPositionConverter)),
|
|||
|
|
SerializationVisibilityAttribute(SerializationVisibility.Element)
|
|||
|
|
]
|
|||
|
|
public ElementPosition Position
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
// Serialize only position values if Auto set to false
|
|||
|
|
if(this.Chart != null && this.Chart.serializationStatus == SerializationStatus.Saving )
|
|||
|
|
{
|
|||
|
|
if(_areaPosition.Auto)
|
|||
|
|
{
|
|||
|
|
return new ElementPosition();
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
ElementPosition newPosition = new ElementPosition();
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
newPosition.Auto = false;
|
|||
|
|
#else
|
|||
|
|
newPosition.Auto = true;
|
|||
|
|
#endif
|
|||
|
|
newPosition.SetPositionNoAuto(_areaPosition.X, _areaPosition.Y, _areaPosition.Width, _areaPosition.Height);
|
|||
|
|
return newPosition;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return _areaPosition;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_areaPosition = value;
|
|||
|
|
_areaPosition.Parent = this;
|
|||
|
|
_areaPosition.resetAreaAutoPosition = true;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Determoines if this position should be serialized.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
internal bool ShouldSerializePosition()
|
|||
|
|
{
|
|||
|
|
return !this.Position.Auto;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets an ElementPosition object, which defines the inner plot position of a chart area object.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_InnerPlotPosition"),
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
|
|||
|
|
#else
|
|||
|
|
PersistenceMode(PersistenceMode.InnerProperty),
|
|||
|
|
#endif
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
TypeConverter(typeof(ElementPositionConverter)),
|
|||
|
|
SerializationVisibilityAttribute(SerializationVisibility.Element)
|
|||
|
|
]
|
|||
|
|
public ElementPosition InnerPlotPosition
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
// Serialize only position values if Auto set to false
|
|||
|
|
if (this.Common != null && this.Common.Chart != null && this.Common.Chart.serializationStatus == SerializationStatus.Saving)
|
|||
|
|
{
|
|||
|
|
if(_innerPlotPosition.Auto)
|
|||
|
|
{
|
|||
|
|
return new ElementPosition();
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
ElementPosition newPosition = new ElementPosition();
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
newPosition.Auto = false;
|
|||
|
|
#else
|
|||
|
|
newPosition.Auto = true;
|
|||
|
|
#endif
|
|||
|
|
newPosition.SetPositionNoAuto(_innerPlotPosition.X, _innerPlotPosition.Y, _innerPlotPosition.Width, _innerPlotPosition.Height);
|
|||
|
|
return newPosition;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return _innerPlotPosition;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_innerPlotPosition = value;
|
|||
|
|
_innerPlotPosition.Parent = this;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Determoines if this position should be serialized.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
internal bool ShouldSerializeInnerPlotPosition()
|
|||
|
|
{
|
|||
|
|
return !this.InnerPlotPosition.Auto;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the background color of a ChartArea object.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(typeof(Color), ""),
|
|||
|
|
SRDescription("DescriptionAttributeBackColor"),
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
TypeConverter(typeof(ColorConverter)),
|
|||
|
|
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public Color BackColor
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _backColor;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_backColor = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the hatching style of a ChartArea object.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
|
|||
|
|
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(ChartHatchStyle.None),
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
SRDescription("DescriptionAttributeBackHatchStyle"),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute),
|
|||
|
|
#endif
|
|||
|
|
Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base)
|
|||
|
|
|
|||
|
|
]
|
|||
|
|
public ChartHatchStyle BackHatchStyle
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _backHatchStyle;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_backHatchStyle = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the background image of a ChartArea object.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(""),
|
|||
|
|
SRDescription("DescriptionAttributeBackImage"),
|
|||
|
|
Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute),
|
|||
|
|
#endif
|
|||
|
|
NotifyParentPropertyAttribute(true)
|
|||
|
|
]
|
|||
|
|
public string BackImage
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _backImage;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_backImage = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the drawing mode of the background image of a ChartArea object.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(ChartImageWrapMode.Tile),
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
SRDescription("DescriptionAttributeImageWrapMode"),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public ChartImageWrapMode BackImageWrapMode
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _backImageWrapMode;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_backImageWrapMode = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the color of a ChartArea object's background image that will be drawn as transparent.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(typeof(Color), ""),
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
SRDescription("DescriptionAttributeImageTransparentColor"),
|
|||
|
|
TypeConverter(typeof(ColorConverter)),
|
|||
|
|
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public Color BackImageTransparentColor
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _backImageTransparentColor;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_backImageTransparentColor = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the alignment of a ChartArea object.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(ChartImageAlignmentStyle.TopLeft),
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
SRDescription("DescriptionAttributeBackImageAlign"),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public ChartImageAlignmentStyle BackImageAlignment
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _backImageAlignment;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_backImageAlignment = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the orientation of a chart element's gradient,
|
|||
|
|
/// and also determines whether or not a gradient is used.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(GradientStyle.None),
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
SRDescription("DescriptionAttributeBackGradientStyle"),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute),
|
|||
|
|
#endif
|
|||
|
|
Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base)
|
|||
|
|
]
|
|||
|
|
public GradientStyle BackGradientStyle
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _backGradientStyle;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_backGradientStyle = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the secondary color of a ChartArea object.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(typeof(Color), ""),
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
SRDescription("DescriptionAttributeBackSecondaryColor"),
|
|||
|
|
TypeConverter(typeof(ColorConverter)),
|
|||
|
|
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public Color BackSecondaryColor
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _backSecondaryColor;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_backSecondaryColor = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the shadow color of a ChartArea object.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(typeof(Color), "128,0,0,0"),
|
|||
|
|
SRDescription("DescriptionAttributeShadowColor"),
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
TypeConverter(typeof(ColorConverter)),
|
|||
|
|
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public Color ShadowColor
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _shadowColor;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_shadowColor = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the shadow offset (in pixels) of a ChartArea object.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(0),
|
|||
|
|
SRDescription("DescriptionAttributeShadowOffset"),
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public int ShadowOffset
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _shadowOffset;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_shadowOffset = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the border color of a ChartArea object.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(typeof(Color), "Black"),
|
|||
|
|
SRDescription("DescriptionAttributeBorderColor"),
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
TypeConverter(typeof(ColorConverter)),
|
|||
|
|
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public Color BorderColor
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _borderColor;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_borderColor = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the border width of a ChartArea object.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(1),
|
|||
|
|
SRDescription("DescriptionAttributeBorderWidth"),
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public int BorderWidth
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _borderWidth;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
if(value < 0)
|
|||
|
|
{
|
|||
|
|
throw (new ArgumentOutOfRangeException("value", SR.ExceptionBorderWidthIsNegative));
|
|||
|
|
}
|
|||
|
|
_borderWidth = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the style of the border line of a ChartArea object.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(ChartDashStyle.NotSet),
|
|||
|
|
SRDescription("DescriptionAttributeBorderDashStyle"),
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public ChartDashStyle BorderDashStyle
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _borderDashStyle;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_borderDashStyle = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets the unique name of a ChartArea object.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
|
|||
|
|
SRCategory("CategoryAttributeMisc"),
|
|||
|
|
Bindable(true),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_Name"),
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public override string Name
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return base.Name;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
base.Name = value;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets or sets a Boolean that determines if the labels of the axes for all chart area
|
|||
|
|
/// , which have LabelsAutoFit property set to true, are of equal size.
|
|||
|
|
/// </summary>
|
|||
|
|
[
|
|||
|
|
SRCategory("CategoryAttributeAppearance"),
|
|||
|
|
Bindable(true),
|
|||
|
|
DefaultValue(false),
|
|||
|
|
SRDescription("DescriptionAttributeChartArea_EquallySizedAxesFont"),
|
|||
|
|
NotifyParentPropertyAttribute(true),
|
|||
|
|
#if !Microsoft_CONTROL
|
|||
|
|
PersistenceMode(PersistenceMode.Attribute)
|
|||
|
|
#endif
|
|||
|
|
]
|
|||
|
|
public bool IsSameFontSizeForAllAxes
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return _isSameFontSizeForAllAxes;
|
|||
|
|
}
|
|||
|
|
set
|
|||
|
|
{
|
|||
|
|
_isSameFontSizeForAllAxes = value;
|
|||
|
|
Invalidate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Constructors
|
|||
|
|
/// <summary>
|
|||
|
|
/// ChartArea constructor.
|
|||
|
|
/// </summary>
|
|||
|
|
public ChartArea()
|
|||
|
|
{
|
|||
|
|
Initialize();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// ChartArea constructor.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="name">The name.</param>
|
|||
|
|
public ChartArea(string name) : base(name)
|
|||
|
|
{
|
|||
|
|
Initialize();
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Chart Area Methods
|
|||
|
|
/// <summary>
|
|||
|
|
/// Restores series order and X axis reversed mode for the 3D charts.
|
|||
|
|
/// </summary>
|
|||
|
|
internal void Restore3DAnglesAndReverseMode()
|
|||
|
|
{
|
|||
|
|
if(this.Area3DStyle.Enable3D && !this.chartAreaIsCurcular)
|
|||
|
|
{
|
|||
|
|
// Restore axis "IsReversed" property and old Y angle
|
|||
|
|
this.AxisX.IsReversed = oldReverseX;
|
|||
|
|
this.AxisX2.IsReversed = oldReverseX;
|
|||
|
|
this.AxisY.IsReversed = oldReverseY;
|
|||
|
|
this.AxisY2.IsReversed = oldReverseY;
|
|||
|
|
this.Area3DStyle.Rotation = oldYAngle;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Sets series order and X axis reversed mode for the 3D charts.
|
|||
|
|
/// </summary>
|
|||
|
|
internal void Set3DAnglesAndReverseMode()
|
|||
|
|
{
|
|||
|
|
// Clear series reversed flag
|
|||
|
|
_reverseSeriesOrder = false;
|
|||
|
|
|
|||
|
|
// If 3D charting is enabled
|
|||
|
|
if(this.Area3DStyle.Enable3D)
|
|||
|
|
{
|
|||
|
|
// Make sure primary & secondary axis has the same IsReversed settings
|
|||
|
|
// This is a limitation for the 3D chart required for labels drawing.
|
|||
|
|
this.AxisX2.IsReversed = this.AxisX.IsReversed;
|
|||
|
|
this.AxisY2.IsReversed = this.AxisY.IsReversed;
|
|||
|
|
|
|||
|
|
// Remember reversed order of X & Y axis and Angles
|
|||
|
|
oldReverseX = this.AxisX.IsReversed;
|
|||
|
|
oldReverseY = this.AxisY.IsReversed;
|
|||
|
|
oldYAngle = this.Area3DStyle.Rotation;
|
|||
|
|
|
|||
|
|
// Check if Y angle
|
|||
|
|
if(this.Area3DStyle.Rotation > 90 || this.Area3DStyle.Rotation < -90)
|
|||
|
|
{
|
|||
|
|
// This method depends on the 'switchValueAxes' field which is calculated based on the chart types
|
|||
|
|
// of the series associated with the chart area. We need to call SetData method to make sure this field
|
|||
|
|
// is correctly initialized. Because we only need to collect information about the series, we pass 'false'
|
|||
|
|
// as parameters to limit the amount of work this function does.
|
|||
|
|
this.SetData(false, false);
|
|||
|
|
|
|||
|
|
// Reversed series order
|
|||
|
|
_reverseSeriesOrder = true;
|
|||
|
|
|
|||
|
|
// Reversed primary and secondary X axis
|
|||
|
|
if(!this.switchValueAxes)
|
|||
|
|
{
|
|||
|
|
this.AxisX.IsReversed = !this.AxisX.IsReversed;
|
|||
|
|
this.AxisX2.IsReversed = !this.AxisX2.IsReversed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Reversed primary and secondary Y axis for chart types like Bar
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
this.AxisY.IsReversed = !this.AxisY.IsReversed;
|
|||
|
|
this.AxisY2.IsReversed = !this.AxisY2.IsReversed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Adjust Y angle
|
|||
|
|
if(this.Area3DStyle.Rotation > 90)
|
|||
|
|
{
|
|||
|
|
this.Area3DStyle.Rotation = (this.Area3DStyle.Rotation - 90) - 90;
|
|||
|
|
}
|
|||
|
|
else if(this.Area3DStyle.Rotation < -90)
|
|||
|
|
{
|
|||
|
|
this.Area3DStyle.Rotation = (this.Area3DStyle.Rotation + 90) + 90;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Save all automatic values like Minimum and Maximum.
|
|||
|
|
/// </summary>
|
|||
|
|
internal void SetTempValues()
|
|||
|
|
{
|
|||
|
|
// Save non automatic area position
|
|||
|
|
if(!this.Position.Auto)
|
|||
|
|
{
|
|||
|
|
this.originalAreaPosition = this.Position.ToRectangleF();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Save non automatic area inner plot position
|
|||
|
|
if(!this.InnerPlotPosition.Auto)
|
|||
|
|
{
|
|||
|
|
this.originalInnerPlotPosition = this.InnerPlotPosition.ToRectangleF();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this._circularSectorNumber = int.MinValue;
|
|||
|
|
this._circularUsePolygons = int.MinValue;
|
|||
|
|
this._circularAxisList = null;
|
|||
|
|
|
|||
|
|
// Save Minimum and maximum values for all axes
|
|||
|
|
axisX.StoreAxisValues();
|
|||
|
|
axisX2.StoreAxisValues();
|
|||
|
|
axisY.StoreAxisValues();
|
|||
|
|
axisY2.StoreAxisValues();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Load all automatic values like Minimum and Maximum with original values.
|
|||
|
|
/// </summary>
|
|||
|
|
internal void GetTempValues()
|
|||
|
|
{
|
|||
|
|
// Take Minimum and maximum values for all axes
|
|||
|
|
axisX.ResetAxisValues();
|
|||
|
|
axisX2.ResetAxisValues();
|
|||
|
|
axisY.ResetAxisValues();
|
|||
|
|
axisY2.ResetAxisValues();
|
|||
|
|
|
|||
|
|
// Restore non automatic area position
|
|||
|
|
if(!this.originalAreaPosition.IsEmpty)
|
|||
|
|
{
|
|||
|
|
this.lastAreaPosition = this.Position.ToRectangleF();
|
|||
|
|
this.Position.SetPositionNoAuto(this.originalAreaPosition.X, this.originalAreaPosition.Y, this.originalAreaPosition.Width, this.originalAreaPosition.Height);
|
|||
|
|
this.originalAreaPosition = RectangleF.Empty;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Save non automatic area inner plot position
|
|||
|
|
if(!this.originalInnerPlotPosition.IsEmpty)
|
|||
|
|
{
|
|||
|
|
this.InnerPlotPosition.SetPositionNoAuto(this.originalInnerPlotPosition.X, this.originalInnerPlotPosition.Y, this.originalInnerPlotPosition.Width, this.originalInnerPlotPosition.Height);
|
|||
|
|
this.originalInnerPlotPosition = RectangleF.Empty;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Initialize Chart area and axes
|
|||
|
|
/// </summary>
|
|||
|
|
internal void Initialize()
|
|||
|
|
{
|
|||
|
|
// Initialize 3D style class
|
|||
|
|
_area3DStyle = new ChartArea3DStyle(this);
|
|||
|
|
|
|||
|
|
// Create axes for this chart area.
|
|||
|
|
axisY = new Axis( );
|
|||
|
|
axisX = new Axis( );
|
|||
|
|
axisX2 = new Axis( );
|
|||
|
|
axisY2 = new Axis( );
|
|||
|
|
|
|||
|
|
// Initialize axes;
|
|||
|
|
axisX.Initialize(this, AxisName.X);
|
|||
|
|
axisY.Initialize(this, AxisName.Y);
|
|||
|
|
axisX2.Initialize(this, AxisName.X2);
|
|||
|
|
axisY2.Initialize(this, AxisName.Y2);
|
|||
|
|
|
|||
|
|
// Initialize axes array
|
|||
|
|
_axisArray[0] = axisX;
|
|||
|
|
_axisArray[1] = axisY;
|
|||
|
|
_axisArray[2] = axisX2;
|
|||
|
|
_axisArray[3] = axisY2;
|
|||
|
|
|
|||
|
|
// Set flag to reset auto values for all areas
|
|||
|
|
_areaPosition = new ElementPosition(this);
|
|||
|
|
_areaPosition.resetAreaAutoPosition = true;
|
|||
|
|
|
|||
|
|
_innerPlotPosition = new ElementPosition(this);
|
|||
|
|
|
|||
|
|
// Set the position of the new chart area
|
|||
|
|
if( PlotAreaPosition == null )
|
|||
|
|
{
|
|||
|
|
PlotAreaPosition = new ElementPosition(this);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
|
|||
|
|
// Initialize cursor class
|
|||
|
|
this._cursorX.Initialize(this, AxisName.X);
|
|||
|
|
this._cursorY.Initialize(this, AxisName.Y);
|
|||
|
|
|
|||
|
|
#endif // Microsoft_CONTROL
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Minimum and maximum do not have to be calculated
|
|||
|
|
/// from data series every time. It is very time
|
|||
|
|
/// consuming. Minimum and maximum are buffered
|
|||
|
|
/// and only when this flags are set Minimum and
|
|||
|
|
/// Maximum are refreshed from data.
|
|||
|
|
/// </summary>
|
|||
|
|
internal void ResetMinMaxFromData()
|
|||
|
|
{
|
|||
|
|
_axisArray[0].refreshMinMaxFromData = true;
|
|||
|
|
_axisArray[1].refreshMinMaxFromData = true;
|
|||
|
|
_axisArray[2].refreshMinMaxFromData = true;
|
|||
|
|
_axisArray[3].refreshMinMaxFromData = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Recalculates the axes scale of a chart area.
|
|||
|
|
/// </summary>
|
|||
|
|
public void RecalculateAxesScale()
|
|||
|
|
{
|
|||
|
|
// Read axis Max/Min from data
|
|||
|
|
ResetMinMaxFromData();
|
|||
|
|
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
Set3DAnglesAndReverseMode();
|
|||
|
|
SetTempValues();
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
// Initialize area position
|
|||
|
|
_axisArray[0].ReCalc( PlotAreaPosition );
|
|||
|
|
_axisArray[1].ReCalc( PlotAreaPosition );
|
|||
|
|
_axisArray[2].ReCalc( PlotAreaPosition );
|
|||
|
|
_axisArray[3].ReCalc( PlotAreaPosition );
|
|||
|
|
|
|||
|
|
// Find all Data and chart types which belong
|
|||
|
|
// to this chart area an set default values
|
|||
|
|
SetData();
|
|||
|
|
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
Restore3DAnglesAndReverseMode();
|
|||
|
|
GetTempValues();
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// RecalculateAxesScale the chart area
|
|||
|
|
/// </summary>
|
|||
|
|
internal void ReCalcInternal()
|
|||
|
|
{
|
|||
|
|
// Initialize area position
|
|||
|
|
_axisArray[0].ReCalc( PlotAreaPosition );
|
|||
|
|
_axisArray[1].ReCalc( PlotAreaPosition );
|
|||
|
|
_axisArray[2].ReCalc( PlotAreaPosition );
|
|||
|
|
_axisArray[3].ReCalc( PlotAreaPosition );
|
|||
|
|
|
|||
|
|
// Find all Data and chart types which belong
|
|||
|
|
// to this chart area an set default values
|
|||
|
|
SetData();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Reset auto calculated chart area values.
|
|||
|
|
/// </summary>
|
|||
|
|
internal void ResetAutoValues()
|
|||
|
|
{
|
|||
|
|
_axisArray[0].ResetAutoValues();
|
|||
|
|
_axisArray[1].ResetAutoValues();
|
|||
|
|
_axisArray[2].ResetAutoValues();
|
|||
|
|
_axisArray[3].ResetAutoValues();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Calculates Position for the background.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="withScrollBars">Calculate with scroll bars</param>
|
|||
|
|
/// <returns>Background rectangle</returns>
|
|||
|
|
internal RectangleF GetBackgroundPosition( bool withScrollBars )
|
|||
|
|
{
|
|||
|
|
// For pie and doughnut, which do not have axes, the position
|
|||
|
|
// for the background is Chart area position not plotting
|
|||
|
|
// area position.
|
|||
|
|
RectangleF backgroundPosition = PlotAreaPosition.ToRectangleF();
|
|||
|
|
if( !requireAxes )
|
|||
|
|
{
|
|||
|
|
backgroundPosition = Position.ToRectangleF();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Without scroll bars
|
|||
|
|
if( !withScrollBars )
|
|||
|
|
{
|
|||
|
|
return backgroundPosition;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Add scroll bar rectangles to the area background
|
|||
|
|
RectangleF backgroundPositionWithScrollBars = new RectangleF(backgroundPosition.Location, backgroundPosition.Size);
|
|||
|
|
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
|
|||
|
|
if( requireAxes )
|
|||
|
|
{
|
|||
|
|
// Loop through all axis
|
|||
|
|
foreach(Axis axis in this.Axes)
|
|||
|
|
{
|
|||
|
|
// Find axis with visible scroll bars
|
|||
|
|
if(axis.ScrollBar.IsVisible && axis.ScrollBar.IsPositionedInside)
|
|||
|
|
{
|
|||
|
|
// Change size of the background rectangle depending on the axis position
|
|||
|
|
if(axis.AxisPosition == AxisPosition.Bottom)
|
|||
|
|
{
|
|||
|
|
backgroundPositionWithScrollBars.Height += (float)axis.ScrollBar.GetScrollBarRelativeSize();
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Top)
|
|||
|
|
{
|
|||
|
|
backgroundPositionWithScrollBars.Y -= (float)axis.ScrollBar.GetScrollBarRelativeSize();
|
|||
|
|
backgroundPositionWithScrollBars.Height += (float)axis.ScrollBar.GetScrollBarRelativeSize();
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Left)
|
|||
|
|
{
|
|||
|
|
backgroundPositionWithScrollBars.X -= (float)axis.ScrollBar.GetScrollBarRelativeSize();
|
|||
|
|
backgroundPositionWithScrollBars.Width += (float)axis.ScrollBar.GetScrollBarRelativeSize();
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Left)
|
|||
|
|
{
|
|||
|
|
backgroundPositionWithScrollBars.Width += (float)axis.ScrollBar.GetScrollBarRelativeSize();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endif // Microsoft_CONTROL
|
|||
|
|
return backgroundPositionWithScrollBars;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Call when the chart area is resized.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="chartGraph">Chart graphics object.</param>
|
|||
|
|
internal void Resize(ChartGraphics chartGraph)
|
|||
|
|
{
|
|||
|
|
// Initialize plotting area position
|
|||
|
|
RectangleF plottingRect = Position.ToRectangleF();
|
|||
|
|
if(!InnerPlotPosition.Auto)
|
|||
|
|
{
|
|||
|
|
plottingRect.X += (Position.Width / 100F) * InnerPlotPosition.X;
|
|||
|
|
plottingRect.Y += (Position.Height / 100F) * InnerPlotPosition.Y;
|
|||
|
|
plottingRect.Width = (Position.Width / 100F) * InnerPlotPosition.Width;
|
|||
|
|
plottingRect.Height = (Position.Height / 100F) * InnerPlotPosition.Height;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//******************************************************
|
|||
|
|
//** Calculate number of vertical and horizontal axis
|
|||
|
|
//******************************************************
|
|||
|
|
int verticalAxes = 0;
|
|||
|
|
int horizontalAxes = 0;
|
|||
|
|
foreach(Axis axis in this.Axes)
|
|||
|
|
{
|
|||
|
|
if(axis.enabled)
|
|||
|
|
{
|
|||
|
|
if(axis.AxisPosition == AxisPosition.Bottom)
|
|||
|
|
{
|
|||
|
|
++horizontalAxes;
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Top)
|
|||
|
|
{
|
|||
|
|
++horizontalAxes;
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Left)
|
|||
|
|
{
|
|||
|
|
++verticalAxes;
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Right)
|
|||
|
|
{
|
|||
|
|
++verticalAxes;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if(horizontalAxes <= 0 )
|
|||
|
|
{
|
|||
|
|
horizontalAxes = 1;
|
|||
|
|
}
|
|||
|
|
if(verticalAxes <= 0 )
|
|||
|
|
{
|
|||
|
|
verticalAxes = 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//******************************************************
|
|||
|
|
//** Find same auto-fit font size
|
|||
|
|
//******************************************************
|
|||
|
|
Axis[] axisArray = (this.switchValueAxes) ?
|
|||
|
|
new Axis[] {this.AxisX, this.AxisX2, this.AxisY, this.AxisY2} :
|
|||
|
|
new Axis[] {this.AxisY, this.AxisY2, this.AxisX, this.AxisX2};
|
|||
|
|
if(this.IsSameFontSizeForAllAxes)
|
|||
|
|
{
|
|||
|
|
axesAutoFontSize = 20;
|
|||
|
|
foreach(Axis axis in axisArray)
|
|||
|
|
{
|
|||
|
|
// Process only enabled axis
|
|||
|
|
if(axis.enabled)
|
|||
|
|
{
|
|||
|
|
// Resize axis
|
|||
|
|
if(axis.AxisPosition == AxisPosition.Bottom || axis.AxisPosition == AxisPosition.Top)
|
|||
|
|
{
|
|||
|
|
axis.Resize(chartGraph, this.PlotAreaPosition, plottingRect, horizontalAxes, InnerPlotPosition.Auto);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
axis.Resize(chartGraph, this.PlotAreaPosition, plottingRect, verticalAxes, InnerPlotPosition.Auto);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Calculate smallest font size
|
|||
|
|
if(axis.IsLabelAutoFit && axis.autoLabelFont != null)
|
|||
|
|
{
|
|||
|
|
axesAutoFontSize = Math.Min(axesAutoFontSize, axis.autoLabelFont.Size);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//******************************************************
|
|||
|
|
//** Adjust plotting area position according to the axes
|
|||
|
|
//** elements (title, labels, tick marks) size.
|
|||
|
|
//******************************************************
|
|||
|
|
RectangleF rectLabelSideSpacing = RectangleF.Empty;
|
|||
|
|
foreach(Axis axis in axisArray)
|
|||
|
|
{
|
|||
|
|
// Process only enabled axis
|
|||
|
|
if( ! axis.enabled )
|
|||
|
|
{
|
|||
|
|
//******************************************************
|
|||
|
|
//** Adjust for the 3D Wall Width for disabled axis
|
|||
|
|
//******************************************************
|
|||
|
|
if(InnerPlotPosition.Auto && this.Area3DStyle.Enable3D && !this.chartAreaIsCurcular)
|
|||
|
|
{
|
|||
|
|
SizeF areaWallSize = chartGraph.GetRelativeSize(new SizeF(this.Area3DStyle.WallWidth, this.Area3DStyle.WallWidth));
|
|||
|
|
if(axis.AxisPosition == AxisPosition.Bottom)
|
|||
|
|
{
|
|||
|
|
plottingRect.Height -= areaWallSize.Height;
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Top)
|
|||
|
|
{
|
|||
|
|
plottingRect.Y += areaWallSize.Height;
|
|||
|
|
plottingRect.Height -= areaWallSize.Height;
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Right)
|
|||
|
|
{
|
|||
|
|
plottingRect.Width -= areaWallSize.Width;
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Left)
|
|||
|
|
{
|
|||
|
|
plottingRect.X += areaWallSize.Width;
|
|||
|
|
plottingRect.Width -= areaWallSize.Width;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//******************************************************
|
|||
|
|
//** Calculate axes elements position
|
|||
|
|
//******************************************************
|
|||
|
|
if(axis.AxisPosition == AxisPosition.Bottom || axis.AxisPosition == AxisPosition.Top)
|
|||
|
|
{
|
|||
|
|
axis.Resize(chartGraph, this.PlotAreaPosition, plottingRect, horizontalAxes, InnerPlotPosition.Auto);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
axis.Resize(chartGraph, this.PlotAreaPosition, plottingRect, verticalAxes, InnerPlotPosition.Auto);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Shift top/bottom labels so they will not overlap with left/right labels
|
|||
|
|
PreventTopBottomAxesLabelsOverlapping(axis);
|
|||
|
|
|
|||
|
|
//******************************************************
|
|||
|
|
//** Check axis position
|
|||
|
|
//******************************************************
|
|||
|
|
float axisPosition = (float)axis.GetAxisPosition();
|
|||
|
|
if(axis.AxisPosition == AxisPosition.Bottom)
|
|||
|
|
{
|
|||
|
|
if(!axis.GetIsMarksNextToAxis())
|
|||
|
|
{
|
|||
|
|
axisPosition = plottingRect.Bottom;
|
|||
|
|
}
|
|||
|
|
axisPosition = plottingRect.Bottom - axisPosition;
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Top)
|
|||
|
|
{
|
|||
|
|
if(!axis.GetIsMarksNextToAxis())
|
|||
|
|
{
|
|||
|
|
axisPosition = plottingRect.Y;
|
|||
|
|
}
|
|||
|
|
axisPosition = axisPosition - plottingRect.Top;
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Right)
|
|||
|
|
{
|
|||
|
|
if(!axis.GetIsMarksNextToAxis())
|
|||
|
|
{
|
|||
|
|
axisPosition = plottingRect.Right;
|
|||
|
|
}
|
|||
|
|
axisPosition = plottingRect.Right - axisPosition;
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Left)
|
|||
|
|
{
|
|||
|
|
if(!axis.GetIsMarksNextToAxis())
|
|||
|
|
{
|
|||
|
|
axisPosition = plottingRect.X;
|
|||
|
|
}
|
|||
|
|
axisPosition = axisPosition - plottingRect.Left;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//******************************************************
|
|||
|
|
//** Adjust axis elements size with axis position
|
|||
|
|
//******************************************************
|
|||
|
|
// Calculate total size of axis elements
|
|||
|
|
float axisSize = axis.markSize + axis.labelSize;
|
|||
|
|
|
|||
|
|
#if SUBAXES
|
|||
|
|
// Add sub-axis size
|
|||
|
|
if(!this.chartAreaIsCurcular && !this.Area3DStyle.Enable3D)
|
|||
|
|
{
|
|||
|
|
foreach(SubAxis subAxis in axis.SubAxes)
|
|||
|
|
{
|
|||
|
|
axisSize += subAxis.markSize + subAxis.labelSize + subAxis.titleSize;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endif // SUBAXES
|
|||
|
|
|
|||
|
|
// Adjust depending on the axis position
|
|||
|
|
axisSize -= axisPosition;
|
|||
|
|
if(axisSize < 0)
|
|||
|
|
{
|
|||
|
|
axisSize = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// Add axis title and scroll bar size (always outside of plotting area)
|
|||
|
|
axisSize += axis.titleSize + axis.scrollBarSize;
|
|||
|
|
|
|||
|
|
|
|||
|
|
// Calculate horizontal axes size for circualar area
|
|||
|
|
if(this.chartAreaIsCurcular &&
|
|||
|
|
(axis.AxisPosition == AxisPosition.Top || axis.AxisPosition == AxisPosition.Bottom) )
|
|||
|
|
{
|
|||
|
|
axisSize = axis.titleSize + axis.markSize + axis.scrollBarSize;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//******************************************************
|
|||
|
|
//** Adjust plotting area
|
|||
|
|
//******************************************************
|
|||
|
|
if(InnerPlotPosition.Auto)
|
|||
|
|
{
|
|||
|
|
if(axis.AxisPosition == AxisPosition.Bottom)
|
|||
|
|
{
|
|||
|
|
plottingRect.Height -= axisSize;
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Top)
|
|||
|
|
{
|
|||
|
|
plottingRect.Y += axisSize;
|
|||
|
|
plottingRect.Height -= axisSize;
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Left)
|
|||
|
|
{
|
|||
|
|
plottingRect.X += axisSize;
|
|||
|
|
plottingRect.Width -= axisSize;
|
|||
|
|
}
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Right)
|
|||
|
|
{
|
|||
|
|
plottingRect.Width -= axisSize;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Check if labels side offset should be processed
|
|||
|
|
bool addLabelsSideOffsets = true;
|
|||
|
|
|
|||
|
|
// Update the plotting area depending on the size required for labels on the sides
|
|||
|
|
if (addLabelsSideOffsets)
|
|||
|
|
{
|
|||
|
|
if (axis.AxisPosition == AxisPosition.Bottom || axis.AxisPosition == AxisPosition.Top)
|
|||
|
|
{
|
|||
|
|
if (axis.labelNearOffset != 0 && axis.labelNearOffset < Position.X)
|
|||
|
|
{
|
|||
|
|
float offset = Position.X - axis.labelNearOffset;
|
|||
|
|
if (Math.Abs(offset) > plottingRect.Width * 0.3f)
|
|||
|
|
{
|
|||
|
|
offset = plottingRect.Width * 0.3f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NOTE: Code was removed to solve an issue with extra space when labels angle = 45
|
|||
|
|
//rectLabelSideSpacing.Width = (float)Math.Max(offset, rectLabelSideSpacing.Width);
|
|||
|
|
rectLabelSideSpacing.X = (float)Math.Max(offset, rectLabelSideSpacing.X);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (axis.labelFarOffset > Position.Right)
|
|||
|
|
{
|
|||
|
|
if ((axis.labelFarOffset - Position.Right) < plottingRect.Width * 0.3f)
|
|||
|
|
{
|
|||
|
|
rectLabelSideSpacing.Width = (float)Math.Max(axis.labelFarOffset - Position.Right, rectLabelSideSpacing.Width);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
rectLabelSideSpacing.Width = (float)Math.Max(plottingRect.Width * 0.3f, rectLabelSideSpacing.Width);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
if (axis.labelNearOffset != 0 && axis.labelNearOffset < Position.Y)
|
|||
|
|
{
|
|||
|
|
float offset = Position.Y - axis.labelNearOffset;
|
|||
|
|
if (Math.Abs(offset) > plottingRect.Height * 0.3f)
|
|||
|
|
{
|
|||
|
|
offset = plottingRect.Height * 0.3f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NOTE: Code was removed to solve an issue with extra space when labels angle = 45
|
|||
|
|
//rectLabelSideSpacing.Height = (float)Math.Max(offset, rectLabelSideSpacing.Height);
|
|||
|
|
rectLabelSideSpacing.Y = (float)Math.Max(offset, rectLabelSideSpacing.Y);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (axis.labelFarOffset > Position.Bottom)
|
|||
|
|
{
|
|||
|
|
if ((axis.labelFarOffset - Position.Bottom) < plottingRect.Height * 0.3f)
|
|||
|
|
{
|
|||
|
|
rectLabelSideSpacing.Height = (float)Math.Max(axis.labelFarOffset - Position.Bottom, rectLabelSideSpacing.Height);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
rectLabelSideSpacing.Height = (float)Math.Max(plottingRect.Height * 0.3f, rectLabelSideSpacing.Height);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//******************************************************
|
|||
|
|
//** Make sure there is enough space
|
|||
|
|
//** for labels on the chart sides
|
|||
|
|
//******************************************************
|
|||
|
|
if (!this.chartAreaIsCurcular)
|
|||
|
|
{
|
|||
|
|
if (rectLabelSideSpacing.Y > 0 && rectLabelSideSpacing.Y > plottingRect.Y - Position.Y)
|
|||
|
|
{
|
|||
|
|
float delta = (plottingRect.Y - Position.Y) - rectLabelSideSpacing.Y;
|
|||
|
|
plottingRect.Y -= delta;
|
|||
|
|
plottingRect.Height += delta;
|
|||
|
|
}
|
|||
|
|
if (rectLabelSideSpacing.X > 0 && rectLabelSideSpacing.X > plottingRect.X - Position.X)
|
|||
|
|
{
|
|||
|
|
float delta = (plottingRect.X - Position.X) - rectLabelSideSpacing.X;
|
|||
|
|
plottingRect.X -= delta;
|
|||
|
|
plottingRect.Width += delta;
|
|||
|
|
}
|
|||
|
|
if (rectLabelSideSpacing.Height > 0 && rectLabelSideSpacing.Height > Position.Bottom - plottingRect.Bottom)
|
|||
|
|
{
|
|||
|
|
plottingRect.Height += (Position.Bottom - plottingRect.Bottom) - rectLabelSideSpacing.Height;
|
|||
|
|
}
|
|||
|
|
if (rectLabelSideSpacing.Width > 0 && rectLabelSideSpacing.Width > Position.Right - plottingRect.Right)
|
|||
|
|
{
|
|||
|
|
plottingRect.Width += (Position.Right - plottingRect.Right) - rectLabelSideSpacing.Width;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//******************************************************
|
|||
|
|
//** Plotting area must be square for the circular
|
|||
|
|
//** chart area (in pixels).
|
|||
|
|
//******************************************************
|
|||
|
|
if(this.chartAreaIsCurcular)
|
|||
|
|
{
|
|||
|
|
// Adjust area to fit the axis title
|
|||
|
|
float xTitleSize = (float)Math.Max(this.AxisY.titleSize, this.AxisY2.titleSize);
|
|||
|
|
if(xTitleSize > 0)
|
|||
|
|
{
|
|||
|
|
plottingRect.X += xTitleSize;
|
|||
|
|
plottingRect.Width -= 2f * xTitleSize;
|
|||
|
|
}
|
|||
|
|
float yTitleSize = (float)Math.Max(this.AxisX.titleSize, this.AxisX2.titleSize);
|
|||
|
|
if(yTitleSize > 0)
|
|||
|
|
{
|
|||
|
|
plottingRect.Y += yTitleSize;
|
|||
|
|
plottingRect.Height -= 2f * yTitleSize;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Make a square plotting rect
|
|||
|
|
RectangleF rect = chartGraph.GetAbsoluteRectangle( plottingRect );
|
|||
|
|
if(rect.Width > rect.Height)
|
|||
|
|
{
|
|||
|
|
rect.X += (rect.Width - rect.Height) / 2f;
|
|||
|
|
rect.Width = rect.Height;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
rect.Y += (rect.Height - rect.Width) / 2f;
|
|||
|
|
rect.Height = rect.Width;
|
|||
|
|
}
|
|||
|
|
plottingRect = chartGraph.GetRelativeRectangle( rect );
|
|||
|
|
|
|||
|
|
// Remember circular chart area center
|
|||
|
|
this.circularCenter = new PointF(plottingRect.X + plottingRect.Width/2f, plottingRect.Y + plottingRect.Height/2f);
|
|||
|
|
|
|||
|
|
// Calculate auto-fit font of the circular axis labels and update area position
|
|||
|
|
FitCircularLabels(chartGraph, this.PlotAreaPosition, ref plottingRect, xTitleSize, yTitleSize);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//******************************************************
|
|||
|
|
//** Set plotting area position
|
|||
|
|
//******************************************************
|
|||
|
|
if(plottingRect.Width < 0f)
|
|||
|
|
{
|
|||
|
|
plottingRect.Width = 0f;
|
|||
|
|
}
|
|||
|
|
if(plottingRect.Height < 0f)
|
|||
|
|
{
|
|||
|
|
plottingRect.Height = 0f;
|
|||
|
|
}
|
|||
|
|
PlotAreaPosition.FromRectangleF(plottingRect);
|
|||
|
|
InnerPlotPosition.SetPositionNoAuto(
|
|||
|
|
(float)Math.Round((plottingRect.X - Position.X) / (Position.Width / 100F), 5),
|
|||
|
|
(float)Math.Round((plottingRect.Y - Position.Y) / (Position.Height / 100F), 5),
|
|||
|
|
(float)Math.Round(plottingRect.Width / (Position.Width / 100F), 5),
|
|||
|
|
(float)Math.Round(plottingRect.Height / (Position.Height / 100F), 5));
|
|||
|
|
|
|||
|
|
|
|||
|
|
//******************************************************
|
|||
|
|
//** Adjust label font size for axis, which were
|
|||
|
|
//** automatically calculated after the opposite axis
|
|||
|
|
//** change the size of plotting area.
|
|||
|
|
//******************************************************
|
|||
|
|
this.AxisY2.AdjustLabelFontAtSecondPass(chartGraph, InnerPlotPosition.Auto);
|
|||
|
|
this.AxisY.AdjustLabelFontAtSecondPass(chartGraph, InnerPlotPosition.Auto);
|
|||
|
|
if(InnerPlotPosition.Auto)
|
|||
|
|
{
|
|||
|
|
this.AxisX2.AdjustLabelFontAtSecondPass(chartGraph, InnerPlotPosition.Auto);
|
|||
|
|
this.AxisX.AdjustLabelFontAtSecondPass(chartGraph, InnerPlotPosition.Auto);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Finds axis by it's position. Can be Null.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="axisPosition">Axis position to find</param>
|
|||
|
|
/// <returns>Found axis.</returns>
|
|||
|
|
private Axis FindAxis(AxisPosition axisPosition)
|
|||
|
|
{
|
|||
|
|
foreach(Axis axis in this.Axes)
|
|||
|
|
{
|
|||
|
|
if(axis.AxisPosition == axisPosition)
|
|||
|
|
{
|
|||
|
|
return axis;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Shift top/bottom labels so they will not overlap with left/right labels.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="axis">Axis to shift up/down.</param>
|
|||
|
|
private void PreventTopBottomAxesLabelsOverlapping(Axis axis)
|
|||
|
|
{
|
|||
|
|
// If axis is not on the edge of the chart area do not
|
|||
|
|
// try to adjust it's position when axis labels overlap
|
|||
|
|
// labels of the oppositie axis.
|
|||
|
|
if( !axis.IsAxisOnAreaEdge )
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Shift bottom axis labels down
|
|||
|
|
if(axis.AxisPosition == AxisPosition.Bottom)
|
|||
|
|
{
|
|||
|
|
// Get labels position
|
|||
|
|
float labelsPosition = (float)axis.GetAxisPosition();
|
|||
|
|
if( !axis.GetIsMarksNextToAxis() )
|
|||
|
|
{
|
|||
|
|
labelsPosition = axis.PlotAreaPosition.Bottom;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Only adjust labels outside plotting area
|
|||
|
|
if(Math.Round(labelsPosition, 2) < Math.Round(axis.PlotAreaPosition.Bottom, 2))
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Check if labels may overlap with Left axis
|
|||
|
|
Axis leftAxis = FindAxis(AxisPosition.Left);
|
|||
|
|
if(leftAxis != null &&
|
|||
|
|
leftAxis.enabled &&
|
|||
|
|
leftAxis.labelFarOffset != 0 &&
|
|||
|
|
leftAxis.labelFarOffset > labelsPosition &&
|
|||
|
|
axis.labelNearOffset != 0 &&
|
|||
|
|
axis.labelNearOffset < PlotAreaPosition.X)
|
|||
|
|
{
|
|||
|
|
float overlap = (float)(leftAxis.labelFarOffset - labelsPosition) * 0.75f;
|
|||
|
|
if(overlap > axis.markSize)
|
|||
|
|
{
|
|||
|
|
axis.markSize += overlap - axis.markSize;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Check if labels may overlap with Right axis
|
|||
|
|
Axis rightAxis = FindAxis(AxisPosition.Right);
|
|||
|
|
if(rightAxis != null &&
|
|||
|
|
rightAxis.enabled &&
|
|||
|
|
rightAxis.labelFarOffset != 0 &&
|
|||
|
|
rightAxis.labelFarOffset > labelsPosition &&
|
|||
|
|
axis.labelFarOffset != 0 &&
|
|||
|
|
axis.labelFarOffset > PlotAreaPosition.Right)
|
|||
|
|
{
|
|||
|
|
float overlap = (float)(rightAxis.labelFarOffset - labelsPosition) * 0.75f;
|
|||
|
|
if(overlap > axis.markSize)
|
|||
|
|
{
|
|||
|
|
axis.markSize += overlap - axis.markSize;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Shift top axis labels up
|
|||
|
|
else if(axis.AxisPosition == AxisPosition.Top)
|
|||
|
|
{
|
|||
|
|
// Get labels position
|
|||
|
|
float labelsPosition = (float)axis.GetAxisPosition();
|
|||
|
|
if( !axis.GetIsMarksNextToAxis() )
|
|||
|
|
{
|
|||
|
|
labelsPosition = axis.PlotAreaPosition.Y;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Only adjust labels outside plotting area
|
|||
|
|
if(Math.Round(labelsPosition, 2) < Math.Round(axis.PlotAreaPosition.Y, 2))
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Check if labels may overlap with Left axis
|
|||
|
|
Axis leftAxis = FindAxis(AxisPosition.Left);
|
|||
|
|
if(leftAxis != null &&
|
|||
|
|
leftAxis.enabled &&
|
|||
|
|
leftAxis.labelNearOffset != 0 &&
|
|||
|
|
leftAxis.labelNearOffset < labelsPosition &&
|
|||
|
|
axis.labelNearOffset != 0 &&
|
|||
|
|
axis.labelNearOffset < PlotAreaPosition.X)
|
|||
|
|
{
|
|||
|
|
float overlap = (float)(labelsPosition - leftAxis.labelNearOffset) * 0.75f;
|
|||
|
|
if(overlap > axis.markSize)
|
|||
|
|
{
|
|||
|
|
axis.markSize += overlap - axis.markSize;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Check if labels may overlap with Right axis
|
|||
|
|
Axis rightAxis = FindAxis(AxisPosition.Right);
|
|||
|
|
if(rightAxis != null &&
|
|||
|
|
rightAxis.enabled &&
|
|||
|
|
rightAxis.labelNearOffset != 0 &&
|
|||
|
|
rightAxis.labelNearOffset < labelsPosition &&
|
|||
|
|
axis.labelFarOffset != 0 &&
|
|||
|
|
axis.labelFarOffset > PlotAreaPosition.Right)
|
|||
|
|
{
|
|||
|
|
float overlap = (float)(labelsPosition - rightAxis.labelNearOffset) * 0.75f;
|
|||
|
|
if(overlap > axis.markSize)
|
|||
|
|
{
|
|||
|
|
axis.markSize += overlap - axis.markSize;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Painting and Selection Methods
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Draws chart area background and/or border.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="graph">Chart graphics.</param>
|
|||
|
|
/// <param name="position">Background position.</param>
|
|||
|
|
/// <param name="borderOnly">Draws chart area border only.</param>
|
|||
|
|
private void PaintAreaBack(ChartGraphics graph, RectangleF position, bool borderOnly)
|
|||
|
|
{
|
|||
|
|
if(!borderOnly)
|
|||
|
|
{
|
|||
|
|
// Draw background
|
|||
|
|
if(!this.Area3DStyle.Enable3D || !requireAxes || chartAreaIsCurcular)
|
|||
|
|
{
|
|||
|
|
// 3D Pie Chart doesn't need scene
|
|||
|
|
// Draw 2D background
|
|||
|
|
graph.FillRectangleRel(
|
|||
|
|
position,
|
|||
|
|
BackColor,
|
|||
|
|
BackHatchStyle,
|
|||
|
|
BackImage,
|
|||
|
|
BackImageWrapMode,
|
|||
|
|
BackImageTransparentColor,
|
|||
|
|
BackImageAlignment,
|
|||
|
|
BackGradientStyle,
|
|||
|
|
BackSecondaryColor,
|
|||
|
|
(requireAxes) ? Color.Empty : BorderColor,
|
|||
|
|
(requireAxes) ? 0 : BorderWidth,
|
|||
|
|
BorderDashStyle,
|
|||
|
|
ShadowColor,
|
|||
|
|
ShadowOffset,
|
|||
|
|
PenAlignment.Outset,
|
|||
|
|
chartAreaIsCurcular,
|
|||
|
|
(chartAreaIsCurcular && this.CircularUsePolygons) ? this.CircularSectorsNumber : 0,
|
|||
|
|
this.Area3DStyle.Enable3D);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// Draw chart area 3D scene
|
|||
|
|
this.DrawArea3DScene(graph, position);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
if(!this.Area3DStyle.Enable3D || !requireAxes || chartAreaIsCurcular)
|
|||
|
|
{
|
|||
|
|
// Draw chart area border
|
|||
|
|
if(BorderColor != Color.Empty && BorderWidth > 0)
|
|||
|
|
{
|
|||
|
|
graph.FillRectangleRel( position,
|
|||
|
|
Color.Transparent,
|
|||
|
|
ChartHatchStyle.None,
|
|||
|
|
"",
|
|||
|
|
ChartImageWrapMode.Tile,
|
|||
|
|
Color.Empty,
|
|||
|
|
ChartImageAlignmentStyle.Center,
|
|||
|
|
GradientStyle.None,
|
|||
|
|
Color.Empty,
|
|||
|
|
BorderColor,
|
|||
|
|
BorderWidth,
|
|||
|
|
BorderDashStyle,
|
|||
|
|
Color.Empty,
|
|||
|
|
0,
|
|||
|
|
PenAlignment.Outset,
|
|||
|
|
chartAreaIsCurcular,
|
|||
|
|
(chartAreaIsCurcular && this.CircularUsePolygons) ? this.CircularSectorsNumber : 0,
|
|||
|
|
this.Area3DStyle.Enable3D);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Paint the chart area.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="graph">Chart graphics.</param>
|
|||
|
|
internal void Paint( ChartGraphics graph )
|
|||
|
|
{
|
|||
|
|
// Check if plot area position was recalculated.
|
|||
|
|
// If not and non-auto InnerPlotPosition & Position were
|
|||
|
|
// specified - do all needed calculations
|
|||
|
|
if (PlotAreaPosition.Width == 0 &&
|
|||
|
|
PlotAreaPosition.Height == 0 &&
|
|||
|
|
!InnerPlotPosition.Auto
|
|||
|
|
&& !Position.Auto)
|
|||
|
|
{
|
|||
|
|
// Initialize plotting area position
|
|||
|
|
RectangleF plottingRect = Position.ToRectangleF();
|
|||
|
|
if (!InnerPlotPosition.Auto)
|
|||
|
|
{
|
|||
|
|
plottingRect.X += (Position.Width / 100F) * InnerPlotPosition.X;
|
|||
|
|
plottingRect.Y += (Position.Height / 100F) * InnerPlotPosition.Y;
|
|||
|
|
plottingRect.Width = (Position.Width / 100F) * InnerPlotPosition.Width;
|
|||
|
|
plottingRect.Height = (Position.Height / 100F) * InnerPlotPosition.Height;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
PlotAreaPosition.FromRectangleF(plottingRect);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Get background position rectangle.
|
|||
|
|
RectangleF backgroundPositionWithScrollBars = GetBackgroundPosition(true);
|
|||
|
|
RectangleF backgroundPosition = GetBackgroundPosition(false);
|
|||
|
|
|
|||
|
|
// Add hot region for plotting area.
|
|||
|
|
if (Common.ProcessModeRegions)
|
|||
|
|
{
|
|||
|
|
Common.HotRegionsList.AddHotRegion(backgroundPosition, this, ChartElementType.PlottingArea, true);
|
|||
|
|
}
|
|||
|
|
// Draw background
|
|||
|
|
PaintAreaBack(graph, backgroundPositionWithScrollBars, false);
|
|||
|
|
|
|||
|
|
// Call BackPaint event
|
|||
|
|
Common.Chart.CallOnPrePaint(new ChartPaintEventArgs(this, graph, Common, PlotAreaPosition));
|
|||
|
|
|
|||
|
|
// Draw chart types without axes - Pie.
|
|||
|
|
if (!requireAxes && ChartTypes.Count != 0)
|
|||
|
|
{
|
|||
|
|
// Find first chart type that do not require axis (like Pie) and draw it.
|
|||
|
|
// Chart types that do not require axes (circular charts) cannot be combined with
|
|||
|
|
// any other chart types.
|
|||
|
|
// NOTE: Fixes issues #4672 and #4692
|
|||
|
|
for (int chartTypeIndex = 0; chartTypeIndex < ChartTypes.Count; chartTypeIndex++)
|
|||
|
|
{
|
|||
|
|
IChartType chartType = Common.ChartTypeRegistry.GetChartType((string)ChartTypes[chartTypeIndex]);
|
|||
|
|
if (!chartType.RequireAxes)
|
|||
|
|
{
|
|||
|
|
chartType.Paint(graph, Common, this, null);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Call Paint event
|
|||
|
|
Common.Chart.CallOnPostPaint(new ChartPaintEventArgs(this, graph, Common, PlotAreaPosition));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
// Reset Smart Labels
|
|||
|
|
this.smartLabels.Reset();
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
// Set values for optimized drawing
|
|||
|
|
foreach (Axis currentAxis in this._axisArray)
|
|||
|
|
{
|
|||
|
|
currentAxis.optimizedGetPosition = true;
|
|||
|
|
currentAxis.paintViewMax = currentAxis.ViewMaximum;
|
|||
|
|
currentAxis.paintViewMin = currentAxis.ViewMinimum;
|
|||
|
|
currentAxis.paintRange = currentAxis.paintViewMax - currentAxis.paintViewMin;
|
|||
|
|
currentAxis.paintAreaPosition = PlotAreaPosition.ToRectangleF();
|
|||
|
|
if (currentAxis.ChartArea != null && currentAxis.ChartArea.chartAreaIsCurcular)
|
|||
|
|
{
|
|||
|
|
// Update position for circular chart area
|
|||
|
|
currentAxis.paintAreaPosition.Width /= 2.0f;
|
|||
|
|
currentAxis.paintAreaPosition.Height /= 2.0f;
|
|||
|
|
}
|
|||
|
|
currentAxis.paintAreaPositionBottom = currentAxis.paintAreaPosition.Y + currentAxis.paintAreaPosition.Height;
|
|||
|
|
currentAxis.paintAreaPositionRight = currentAxis.paintAreaPosition.X + currentAxis.paintAreaPosition.Width;
|
|||
|
|
if (currentAxis.AxisPosition == AxisPosition.Top || currentAxis.AxisPosition == AxisPosition.Bottom)
|
|||
|
|
currentAxis.paintChartAreaSize = currentAxis.paintAreaPosition.Width;
|
|||
|
|
else
|
|||
|
|
currentAxis.paintChartAreaSize = currentAxis.paintAreaPosition.Height;
|
|||
|
|
|
|||
|
|
currentAxis.valueMultiplier = 0.0;
|
|||
|
|
if (currentAxis.paintRange != 0)
|
|||
|
|
{
|
|||
|
|
currentAxis.valueMultiplier = currentAxis.paintChartAreaSize / currentAxis.paintRange;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Draw Axis Striplines (only when StripWidth > 0)
|
|||
|
|
bool useScaleSegments = false;
|
|||
|
|
Axis[] axesArray = new Axis[] { axisY, axisY2, axisX, axisX2 };
|
|||
|
|
foreach (Axis currentAxis in axesArray)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
useScaleSegments = (currentAxis.ScaleSegments.Count > 0);
|
|||
|
|
|
|||
|
|
if (!useScaleSegments)
|
|||
|
|
{
|
|||
|
|
currentAxis.PaintStrips(graph, false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
foreach (AxisScaleSegment scaleSegment in currentAxis.ScaleSegments)
|
|||
|
|
{
|
|||
|
|
scaleSegment.SetTempAxisScaleAndInterval();
|
|||
|
|
|
|||
|
|
currentAxis.PaintStrips(graph, false);
|
|||
|
|
|
|||
|
|
scaleSegment.RestoreAxisScaleAndInterval();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Draw Axis Grids
|
|||
|
|
axesArray = new Axis[] { axisY, axisX2, axisY2, axisX };
|
|||
|
|
foreach (Axis currentAxis in axesArray)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
useScaleSegments = (currentAxis.ScaleSegments.Count > 0);
|
|||
|
|
|
|||
|
|
if (!useScaleSegments)
|
|||
|
|
{
|
|||
|
|
currentAxis.PaintGrids(graph);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
foreach (AxisScaleSegment scaleSegment in currentAxis.ScaleSegments)
|
|||
|
|
{
|
|||
|
|
scaleSegment.SetTempAxisScaleAndInterval();
|
|||
|
|
|
|||
|
|
currentAxis.PaintGrids(graph);
|
|||
|
|
|
|||
|
|
scaleSegment.RestoreAxisScaleAndInterval();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Draw Axis Striplines (only when StripWidth == 0)
|
|||
|
|
foreach (Axis currentAxis in axesArray)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
useScaleSegments = (currentAxis.ScaleSegments.Count > 0);
|
|||
|
|
|
|||
|
|
if (!useScaleSegments)
|
|||
|
|
{
|
|||
|
|
currentAxis.PaintStrips(graph, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
foreach (AxisScaleSegment scaleSegment in currentAxis.ScaleSegments)
|
|||
|
|
{
|
|||
|
|
scaleSegment.SetTempAxisScaleAndInterval();
|
|||
|
|
|
|||
|
|
currentAxis.PaintStrips(graph, true);
|
|||
|
|
|
|||
|
|
scaleSegment.RestoreAxisScaleAndInterval();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Draw Axis elements on the back of the 3D scene
|
|||
|
|
if (this.Area3DStyle.Enable3D && !this.chartAreaIsCurcular)
|
|||
|
|
{
|
|||
|
|
foreach (Axis currentAxis in axesArray)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
useScaleSegments = (currentAxis.ScaleSegments.Count > 0);
|
|||
|
|
|
|||
|
|
if (!useScaleSegments)
|
|||
|
|
{
|
|||
|
|
currentAxis.PrePaint(graph);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
foreach (AxisScaleSegment scaleSegment in currentAxis.ScaleSegments)
|
|||
|
|
{
|
|||
|
|
scaleSegment.SetTempAxisScaleAndInterval();
|
|||
|
|
|
|||
|
|
currentAxis.PrePaint(graph);
|
|||
|
|
|
|||
|
|
scaleSegment.RestoreAxisScaleAndInterval();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Draws chart area border
|
|||
|
|
bool borderDrawn = false;
|
|||
|
|
if (this.Area3DStyle.Enable3D || !IsBorderOnTopSeries())
|
|||
|
|
{
|
|||
|
|
borderDrawn = true;
|
|||
|
|
PaintAreaBack(graph, backgroundPosition, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Draw chart types
|
|||
|
|
if (!this.Area3DStyle.Enable3D || this.chartAreaIsCurcular)
|
|||
|
|
{
|
|||
|
|
// Drawing in 2D space
|
|||
|
|
|
|||
|
|
// NOTE: Fixes issue #6443 and #5385
|
|||
|
|
// If two chart series of the same type (for example Line) are separated
|
|||
|
|
// by other series (for example Area) the order is not correct.
|
|||
|
|
// Old implementation draws ALL series that belongs to the chart type.
|
|||
|
|
ArrayList typeAndSeries = this.GetChartTypesAndSeriesToDraw();
|
|||
|
|
|
|||
|
|
// Draw series by chart type or by series
|
|||
|
|
foreach (ChartTypeAndSeriesInfo chartTypeInfo in typeAndSeries)
|
|||
|
|
{
|
|||
|
|
this.IterationCounter = 0;
|
|||
|
|
IChartType type = Common.ChartTypeRegistry.GetChartType(chartTypeInfo.ChartType);
|
|||
|
|
|
|||
|
|
// If 'chartTypeInfo.Series' set to NULL all series of that chart type are drawn at once
|
|||
|
|
type.Paint(graph, Common, this, chartTypeInfo.Series);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// Drawing in 3D space
|
|||
|
|
PaintChartSeries3D(graph);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Draw area border if it wasn't drawn prior to the series
|
|||
|
|
if (!borderDrawn)
|
|||
|
|
{
|
|||
|
|
PaintAreaBack(graph, backgroundPosition, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Draw Axis
|
|||
|
|
foreach (Axis currentAxis in axesArray)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
useScaleSegments = (currentAxis.ScaleSegments.Count > 0);
|
|||
|
|
|
|||
|
|
if (!useScaleSegments)
|
|||
|
|
{
|
|||
|
|
// Paint axis and Reset temp axis offset for side-by-side charts like column
|
|||
|
|
currentAxis.Paint(graph);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// Some of the axis elements like grid lines and tickmarks
|
|||
|
|
// are drawn for each segment
|
|||
|
|
foreach (AxisScaleSegment scaleSegment in currentAxis.ScaleSegments)
|
|||
|
|
{
|
|||
|
|
scaleSegment.SetTempAxisScaleAndInterval();
|
|||
|
|
|
|||
|
|
currentAxis.PaintOnSegmentedScalePassOne(graph);
|
|||
|
|
|
|||
|
|
scaleSegment.RestoreAxisScaleAndInterval();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Other elements like labels, title, axis line are drawn once
|
|||
|
|
currentAxis.PaintOnSegmentedScalePassTwo(graph);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Call Paint event
|
|||
|
|
Common.Chart.CallOnPostPaint(new ChartPaintEventArgs(this, graph, Common, PlotAreaPosition));
|
|||
|
|
|
|||
|
|
// Draw axis scale break lines
|
|||
|
|
axesArray = new Axis[] { axisY, axisY2 };
|
|||
|
|
foreach (Axis currentAxis in axesArray)
|
|||
|
|
{
|
|||
|
|
for (int segmentIndex = 0; segmentIndex < (currentAxis.ScaleSegments.Count - 1); segmentIndex++)
|
|||
|
|
{
|
|||
|
|
currentAxis.ScaleSegments[segmentIndex].PaintBreakLine(graph, currentAxis.ScaleSegments[segmentIndex + 1]);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Reset values for optimized drawing
|
|||
|
|
foreach (Axis curentAxis in this._axisArray)
|
|||
|
|
{
|
|||
|
|
curentAxis.optimizedGetPosition = false;
|
|||
|
|
|
|||
|
|
|
|||
|
|
// Reset preffered number of intervals on the axis
|
|||
|
|
curentAxis.prefferedNumberofIntervals = 5;
|
|||
|
|
|
|||
|
|
// Reset flag that scale segments are used
|
|||
|
|
curentAxis.scaleSegmentsUsed = false;
|
|||
|
|
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Checks if chart area border should be drawn on top of series.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns>True if border should be darwn on top.</returns>
|
|||
|
|
private bool IsBorderOnTopSeries()
|
|||
|
|
{
|
|||
|
|
// For most of the chart types chart area border is drawn on top.
|
|||
|
|
bool result = true;
|
|||
|
|
foreach( Series series in this.Common.Chart.Series )
|
|||
|
|
{
|
|||
|
|
if(series.ChartArea == this.Name)
|
|||
|
|
{
|
|||
|
|
// It is common for the Bubble and Point chart types to draw markers
|
|||
|
|
// partially outside of the chart area. By drawing the border before
|
|||
|
|
// series we avoiding the possibility of drawing the border line on
|
|||
|
|
// top of the marker.
|
|||
|
|
if(series.ChartType == SeriesChartType.Bubble ||
|
|||
|
|
series.ChartType == SeriesChartType.Point)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Paint the chart area cursors.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="graph">Chart graphics.</param>
|
|||
|
|
/// <param name="cursorOnly">Indicates that only cursors are redrawn.</param>
|
|||
|
|
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "These parameters are used when compiling for the Microsoft version of Chart")]
|
|||
|
|
internal void PaintCursors( ChartGraphics graph, bool cursorOnly )
|
|||
|
|
{
|
|||
|
|
// Cursors and selection are supoorted only in 2D charts
|
|||
|
|
if(this.Area3DStyle.Enable3D == true)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Do not draw cursor/selection for chart types that do not require axis (like Pie)
|
|||
|
|
if(!this.requireAxes)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Cursors and selection are not supoorted in circular areas
|
|||
|
|
if(this.chartAreaIsCurcular)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Do not draw cursor/selection while printing
|
|||
|
|
if(this.Common != null &&
|
|||
|
|
this.Common.ChartPicture != null &&
|
|||
|
|
this.Common.ChartPicture.isPrinting)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Do not draw cursor/selection when chart area is not visible
|
|||
|
|
// because either width or height is set to zero
|
|||
|
|
if(this.Position.Width == 0f ||
|
|||
|
|
this.Position.Height == 0f)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
|
|||
|
|
Chart chart = this.Common.Chart;
|
|||
|
|
ChartPicture chartPicture = Common.ChartPicture;
|
|||
|
|
|
|||
|
|
// Check if cursor should be drawn
|
|||
|
|
if(!double.IsNaN(_cursorX.SelectionStart) ||
|
|||
|
|
!double.IsNaN(_cursorX.SelectionEnd) ||
|
|||
|
|
!double.IsNaN(_cursorX.Position) ||
|
|||
|
|
!double.IsNaN(_cursorY.SelectionStart) ||
|
|||
|
|
!double.IsNaN(_cursorY.SelectionEnd) ||
|
|||
|
|
!double.IsNaN(_cursorY.Position))
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
if(!chartPicture.backgroundRestored &&
|
|||
|
|
!chartPicture.isSelectionMode )
|
|||
|
|
{
|
|||
|
|
chartPicture.backgroundRestored = true;
|
|||
|
|
|
|||
|
|
Rectangle chartPosition = new Rectangle(0, 0, chartPicture.Width, chartPicture.Height);
|
|||
|
|
|
|||
|
|
// Get chart area position
|
|||
|
|
Rectangle absAreaPlotPosition = Rectangle.Round(graph.GetAbsoluteRectangle(PlotAreaPosition.ToRectangleF()));
|
|||
|
|
int maxCursorWidth = (CursorY.LineWidth > CursorX.LineWidth) ? CursorY.LineWidth + 1 : CursorX.LineWidth + 1;
|
|||
|
|
absAreaPlotPosition.Inflate(maxCursorWidth, maxCursorWidth);
|
|||
|
|
absAreaPlotPosition.Intersect(new Rectangle(0, 0, chart.Width, chart.Height));
|
|||
|
|
|
|||
|
|
// Create area buffer bitmap
|
|||
|
|
if(areaBufferBitmap == null ||
|
|||
|
|
chartPicture.nonTopLevelChartBuffer == null ||
|
|||
|
|
!cursorOnly)
|
|||
|
|
{
|
|||
|
|
// Dispose previous bitmap
|
|||
|
|
if(areaBufferBitmap != null)
|
|||
|
|
{
|
|||
|
|
areaBufferBitmap.Dispose();
|
|||
|
|
areaBufferBitmap = null;
|
|||
|
|
}
|
|||
|
|
if(chartPicture.nonTopLevelChartBuffer != null)
|
|||
|
|
{
|
|||
|
|
chartPicture.nonTopLevelChartBuffer.Dispose();
|
|||
|
|
chartPicture.nonTopLevelChartBuffer = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// Copy chart area plotting rectangle from the chart's dubble buffer image into area dubble buffer image
|
|||
|
|
if(chart.paintBufferBitmap != null)
|
|||
|
|
{
|
|||
|
|
areaBufferBitmap = chart.paintBufferBitmap.Clone(absAreaPlotPosition, chart.paintBufferBitmap.PixelFormat);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Copy whole chart from the chart's dubble buffer image into area dubble buffer image
|
|||
|
|
if(chart.paintBufferBitmap != null &&
|
|||
|
|
chart.paintBufferBitmap.Size.Width >= chartPosition.Size.Width &&
|
|||
|
|
chart.paintBufferBitmap.Size.Height >= chartPosition.Size.Height)
|
|||
|
|
{
|
|||
|
|
chartPicture.nonTopLevelChartBuffer = chart.paintBufferBitmap.Clone(
|
|||
|
|
chartPosition, chart.paintBufferBitmap.PixelFormat);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
else if(cursorOnly && chartPicture.nonTopLevelChartBuffer != null)
|
|||
|
|
{
|
|||
|
|
// Restore previous background
|
|||
|
|
chart.paintBufferBitmapGraphics.DrawImageUnscaled(
|
|||
|
|
chartPicture.nonTopLevelChartBuffer,
|
|||
|
|
chartPosition);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Draw chart area cursors and range selection
|
|||
|
|
|
|||
|
|
_cursorY.Paint(graph);
|
|||
|
|
_cursorX.Paint(graph);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
#endif // Microsoft_CONTROL
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Circular chart area methods
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets a circular chart type interface that belongs to this chart area.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns>ICircularChartType interface or null.</returns>
|
|||
|
|
internal ICircularChartType GetCircularChartType()
|
|||
|
|
{
|
|||
|
|
// Get number of sectors in circular chart area
|
|||
|
|
foreach(Series series in this.Common.DataManager.Series)
|
|||
|
|
{
|
|||
|
|
if(series.IsVisible() && series.ChartArea == this.Name)
|
|||
|
|
{
|
|||
|
|
ICircularChartType type = Common.ChartTypeRegistry.GetChartType(series.ChartTypeName) as ICircularChartType;;
|
|||
|
|
if(type != null)
|
|||
|
|
{
|
|||
|
|
return type;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Calculate size of the circular axis labels and sets auto-fit font.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="chartGraph">Chart graphics object.</param>
|
|||
|
|
/// <param name="chartAreaPosition">The Chart area position.</param>
|
|||
|
|
/// <param name="plotArea">Plotting area size.</param>
|
|||
|
|
/// <param name="xTitleSize">Size of title on the axis.</param>
|
|||
|
|
/// <param name="yTitleSize">Size of title on the axis.</param>
|
|||
|
|
internal void FitCircularLabels(
|
|||
|
|
ChartGraphics chartGraph,
|
|||
|
|
ElementPosition chartAreaPosition,
|
|||
|
|
ref RectangleF plotArea,
|
|||
|
|
float xTitleSize,
|
|||
|
|
float yTitleSize)
|
|||
|
|
{
|
|||
|
|
// Check if axis labels are enabled
|
|||
|
|
if(!this.AxisX.LabelStyle.Enabled)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Get absolute titles size
|
|||
|
|
SizeF titleSize = chartGraph.GetAbsoluteSize(new SizeF(xTitleSize, yTitleSize));
|
|||
|
|
|
|||
|
|
// Get absolute position of area
|
|||
|
|
RectangleF plotAreaRectAbs = chartGraph.GetAbsoluteRectangle( plotArea );
|
|||
|
|
RectangleF areaRectAbs = chartGraph.GetAbsoluteRectangle( chartAreaPosition.ToRectangleF());
|
|||
|
|
|
|||
|
|
// Get absolute markers size and spacing
|
|||
|
|
float spacing = chartGraph.GetAbsolutePoint(new PointF(0, this.AxisX.markSize + Axis.elementSpacing)).Y;
|
|||
|
|
|
|||
|
|
// Get circular axis list
|
|||
|
|
ArrayList axisList = GetCircularAxisList();
|
|||
|
|
|
|||
|
|
// Get circular axis labels style
|
|||
|
|
CircularAxisLabelsStyle labelsStyle = GetCircularAxisLabelsStyle();
|
|||
|
|
|
|||
|
|
//*****************************************************************
|
|||
|
|
//** Calculate the auto-fit font if required
|
|||
|
|
//*****************************************************************
|
|||
|
|
if(this.AxisX.LabelStyle.Enabled && this.AxisX.IsLabelAutoFit)
|
|||
|
|
{
|
|||
|
|
// Set max auto fit font
|
|||
|
|
this.AxisX.autoLabelFont = Common.ChartPicture.FontCache.GetFont(
|
|||
|
|
this.AxisX.LabelStyle.Font.FontFamily,
|
|||
|
|
14,
|
|||
|
|
this.AxisX.LabelStyle.Font.Style,
|
|||
|
|
GraphicsUnit.Point);
|
|||
|
|
|
|||
|
|
// Get estimated labels size
|
|||
|
|
float labelsSizeEstimate = GetCircularLabelsSize(chartGraph, areaRectAbs, plotAreaRectAbs, titleSize);
|
|||
|
|
labelsSizeEstimate = (float)Math.Min(labelsSizeEstimate * 1.1f, plotAreaRectAbs.Width / 5f);
|
|||
|
|
labelsSizeEstimate += spacing;
|
|||
|
|
|
|||
|
|
// Calculate auto-fit font
|
|||
|
|
this.AxisX.GetCircularAxisLabelsAutoFitFont(chartGraph, axisList, labelsStyle, plotAreaRectAbs, areaRectAbs, labelsSizeEstimate);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//*****************************************************************
|
|||
|
|
//** Shrink plot area size proportionally
|
|||
|
|
//*****************************************************************
|
|||
|
|
|
|||
|
|
// Get labels size
|
|||
|
|
float labelsSize = GetCircularLabelsSize(chartGraph, areaRectAbs, plotAreaRectAbs, titleSize);
|
|||
|
|
|
|||
|
|
// Check if change size is smaller than radius
|
|||
|
|
labelsSize = (float)Math.Min(labelsSize, plotAreaRectAbs.Width / 2.5f);
|
|||
|
|
labelsSize += spacing;
|
|||
|
|
|
|||
|
|
plotAreaRectAbs.X += labelsSize;
|
|||
|
|
plotAreaRectAbs.Width -= 2f * labelsSize;
|
|||
|
|
plotAreaRectAbs.Y += labelsSize;
|
|||
|
|
plotAreaRectAbs.Height -= 2f * labelsSize;
|
|||
|
|
|
|||
|
|
// Restrict minimum plot area size
|
|||
|
|
if(plotAreaRectAbs.Width < 1.0f)
|
|||
|
|
{
|
|||
|
|
plotAreaRectAbs.Width = 1.0f;
|
|||
|
|
}
|
|||
|
|
if(plotAreaRectAbs.Height < 1.0f)
|
|||
|
|
{
|
|||
|
|
plotAreaRectAbs.Height = 1.0f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
plotArea = chartGraph.GetRelativeRectangle( plotAreaRectAbs );
|
|||
|
|
|
|||
|
|
|
|||
|
|
//*****************************************************************
|
|||
|
|
//** Set axes labels size
|
|||
|
|
//*****************************************************************
|
|||
|
|
SizeF relativeLabelSize = chartGraph.GetRelativeSize(new SizeF(labelsSize, labelsSize));
|
|||
|
|
this.AxisX.labelSize = relativeLabelSize.Height;
|
|||
|
|
this.AxisX2.labelSize = relativeLabelSize.Height;
|
|||
|
|
this.AxisY.labelSize = relativeLabelSize.Width;
|
|||
|
|
this.AxisY2.labelSize = relativeLabelSize.Width;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Calculate size of the circular axis labels.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="chartGraph">Chart graphics object.</param>
|
|||
|
|
/// <param name="areaRectAbs">The Chart area position.</param>
|
|||
|
|
/// <param name="plotAreaRectAbs">Plotting area size.</param>
|
|||
|
|
/// <param name="titleSize">Size of title on the axes.</param>
|
|||
|
|
/// <returns>Circulat labels style.</returns>
|
|||
|
|
internal float GetCircularLabelsSize(
|
|||
|
|
ChartGraphics chartGraph,
|
|||
|
|
RectangleF areaRectAbs,
|
|||
|
|
RectangleF plotAreaRectAbs,
|
|||
|
|
SizeF titleSize)
|
|||
|
|
{
|
|||
|
|
// Find current horiz. and vert. spacing between plotting and chart areas
|
|||
|
|
SizeF areaDiff = new SizeF(plotAreaRectAbs.X - areaRectAbs.X, plotAreaRectAbs.Y - areaRectAbs.Y);
|
|||
|
|
areaDiff.Width -= titleSize.Width;
|
|||
|
|
areaDiff.Height -= titleSize.Height;
|
|||
|
|
|
|||
|
|
// Get absolute center of the area
|
|||
|
|
PointF areaCenterAbs = chartGraph.GetAbsolutePoint(this.circularCenter);
|
|||
|
|
|
|||
|
|
// Get circular axis list
|
|||
|
|
ArrayList axisList = GetCircularAxisList();
|
|||
|
|
|
|||
|
|
// Get circular axis labels style
|
|||
|
|
CircularAxisLabelsStyle labelsStyle = GetCircularAxisLabelsStyle();
|
|||
|
|
|
|||
|
|
// Defines on how much (pixels) the circular chart area radius should be reduced
|
|||
|
|
float labelsSize = 0f;
|
|||
|
|
|
|||
|
|
//*****************************************************************
|
|||
|
|
//** Loop through all axis labels
|
|||
|
|
//*****************************************************************
|
|||
|
|
foreach(CircularChartAreaAxis axis in axisList)
|
|||
|
|
{
|
|||
|
|
//*****************************************************************
|
|||
|
|
//** Measure label text
|
|||
|
|
//*****************************************************************
|
|||
|
|
SizeF textSize = chartGraph.MeasureString(
|
|||
|
|
axis.Title.Replace("\\n", "\n"),
|
|||
|
|
(this.AxisX.autoLabelFont == null) ? this.AxisX.LabelStyle.Font : this.AxisX.autoLabelFont);
|
|||
|
|
textSize.Width = (float)Math.Ceiling(textSize.Width * 1.1f);
|
|||
|
|
textSize.Height = (float)Math.Ceiling(textSize.Height * 1.1f);
|
|||
|
|
|
|||
|
|
|
|||
|
|
//*****************************************************************
|
|||
|
|
//** Calculate area size change depending on labels style
|
|||
|
|
//*****************************************************************
|
|||
|
|
if(labelsStyle == CircularAxisLabelsStyle.Circular)
|
|||
|
|
{
|
|||
|
|
labelsSize = (float)Math.Max(
|
|||
|
|
labelsSize,
|
|||
|
|
textSize.Height);
|
|||
|
|
}
|
|||
|
|
else if(labelsStyle == CircularAxisLabelsStyle.Radial)
|
|||
|
|
{
|
|||
|
|
float textAngle = axis.AxisPosition + 90;
|
|||
|
|
|
|||
|
|
// For angled text find it's X and Y components
|
|||
|
|
float width = (float)Math.Cos(textAngle/180F*Math.PI) * textSize.Width;
|
|||
|
|
float height = (float)Math.Sin(textAngle/180F*Math.PI) * textSize.Width;
|
|||
|
|
width = (float)Math.Abs(Math.Ceiling(width));
|
|||
|
|
height = (float)Math.Abs(Math.Ceiling(height));
|
|||
|
|
|
|||
|
|
// Reduce text size by current spacing between plotting area and chart area
|
|||
|
|
width -= areaDiff.Width;
|
|||
|
|
height -= areaDiff.Height;
|
|||
|
|
if(width < 0)
|
|||
|
|
width = 0;
|
|||
|
|
if(height < 0)
|
|||
|
|
height = 0;
|
|||
|
|
|
|||
|
|
|
|||
|
|
labelsSize = (float)Math.Max(
|
|||
|
|
labelsSize,
|
|||
|
|
Math.Max(width, height));
|
|||
|
|
}
|
|||
|
|
else if(labelsStyle == CircularAxisLabelsStyle.Horizontal)
|
|||
|
|
{
|
|||
|
|
// Get text angle
|
|||
|
|
float textAngle = axis.AxisPosition;
|
|||
|
|
if(textAngle > 180f)
|
|||
|
|
{
|
|||
|
|
textAngle -= 180f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Get label rotated position
|
|||
|
|
PointF[] labelPosition = new PointF[] { new PointF(areaCenterAbs.X, plotAreaRectAbs.Y) };
|
|||
|
|
Matrix newMatrix = new Matrix();
|
|||
|
|
newMatrix.RotateAt(textAngle, areaCenterAbs);
|
|||
|
|
newMatrix.TransformPoints(labelPosition);
|
|||
|
|
|
|||
|
|
// Calculate width
|
|||
|
|
float width = textSize.Width;
|
|||
|
|
width -= areaRectAbs.Right - labelPosition[0].X;
|
|||
|
|
if(width < 0f)
|
|||
|
|
{
|
|||
|
|
width = 0f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
labelsSize = (float)Math.Max(
|
|||
|
|
labelsSize,
|
|||
|
|
Math.Max(width, textSize.Height));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return labelsSize;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// True if polygons should be used instead of the circles for the chart area.
|
|||
|
|
/// </summary>
|
|||
|
|
internal bool CircularUsePolygons
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
// Check if value was precalculated
|
|||
|
|
if(this._circularUsePolygons == int.MinValue)
|
|||
|
|
{
|
|||
|
|
_circularUsePolygons = 0;
|
|||
|
|
|
|||
|
|
// Look for custom properties in series
|
|||
|
|
foreach(Series series in this.Common.DataManager.Series)
|
|||
|
|
{
|
|||
|
|
if(series.ChartArea == this.Name && series.IsVisible())
|
|||
|
|
{
|
|||
|
|
// Get custom attribute
|
|||
|
|
if (series.IsCustomPropertySet(CustomPropertyName.AreaDrawingStyle))
|
|||
|
|
{
|
|||
|
|
if(String.Compare(series[CustomPropertyName.AreaDrawingStyle], "Polygon", StringComparison.OrdinalIgnoreCase) == 0)
|
|||
|
|
{
|
|||
|
|
_circularUsePolygons = 1;
|
|||
|
|
}
|
|||
|
|
else if (String.Compare(series[CustomPropertyName.AreaDrawingStyle], "Circle", StringComparison.OrdinalIgnoreCase) == 0)
|
|||
|
|
{
|
|||
|
|
_circularUsePolygons = 0;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
throw(new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid( series[CustomPropertyName.AreaDrawingStyle], "AreaDrawingStyle")));
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return (this._circularUsePolygons == 1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets circular area axis labels style.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns>Axis labels style.</returns>
|
|||
|
|
internal CircularAxisLabelsStyle GetCircularAxisLabelsStyle()
|
|||
|
|
{
|
|||
|
|
CircularAxisLabelsStyle style = CircularAxisLabelsStyle.Auto;
|
|||
|
|
|
|||
|
|
// Get maximum number of points in all series
|
|||
|
|
foreach(Series series in this.Common.DataManager.Series)
|
|||
|
|
{
|
|||
|
|
if(series.IsVisible() && series.ChartArea == this.Name && series.IsCustomPropertySet(CustomPropertyName.CircularLabelsStyle))
|
|||
|
|
{
|
|||
|
|
string styleName = series[CustomPropertyName.CircularLabelsStyle];
|
|||
|
|
if(String.Compare( styleName, "Auto", StringComparison.OrdinalIgnoreCase) == 0 )
|
|||
|
|
{
|
|||
|
|
style = CircularAxisLabelsStyle.Auto;
|
|||
|
|
}
|
|||
|
|
else if(String.Compare( styleName,"Circular", StringComparison.OrdinalIgnoreCase) == 0)
|
|||
|
|
{
|
|||
|
|
style = CircularAxisLabelsStyle.Circular;
|
|||
|
|
}
|
|||
|
|
else if(String.Compare( styleName,"Radial", StringComparison.OrdinalIgnoreCase) == 0)
|
|||
|
|
{
|
|||
|
|
style = CircularAxisLabelsStyle.Radial;
|
|||
|
|
}
|
|||
|
|
else if (String.Compare(styleName, "Horizontal", StringComparison.OrdinalIgnoreCase) == 0)
|
|||
|
|
{
|
|||
|
|
style = CircularAxisLabelsStyle.Horizontal;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
throw(new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid( styleName, "CircularLabelsStyle")));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Get auto style
|
|||
|
|
if(style == CircularAxisLabelsStyle.Auto)
|
|||
|
|
{
|
|||
|
|
int sectorNumber = CircularSectorsNumber;
|
|||
|
|
style = CircularAxisLabelsStyle.Horizontal;
|
|||
|
|
if(sectorNumber > 30)
|
|||
|
|
{
|
|||
|
|
style = CircularAxisLabelsStyle.Radial;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return style;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Number of sectors in the circular area.
|
|||
|
|
/// </summary>
|
|||
|
|
internal int CircularSectorsNumber
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
// Check if value was precalculated
|
|||
|
|
if(this._circularSectorNumber == int.MinValue)
|
|||
|
|
{
|
|||
|
|
this._circularSectorNumber = GetCircularSectorNumber();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return this._circularSectorNumber;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Gets number of sectors in the circular chart area.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns>Number of sectors.</returns>
|
|||
|
|
private int GetCircularSectorNumber()
|
|||
|
|
{
|
|||
|
|
ICircularChartType type = this.GetCircularChartType();
|
|||
|
|
if(type != null)
|
|||
|
|
{
|
|||
|
|
return type.GetNumerOfSectors(this, this.Common.DataManager.Series);
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Fills a list of circular axis.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns>Axes list.</returns>
|
|||
|
|
internal ArrayList GetCircularAxisList()
|
|||
|
|
{
|
|||
|
|
// Check if list was already created
|
|||
|
|
if(_circularAxisList == null)
|
|||
|
|
{
|
|||
|
|
_circularAxisList = new ArrayList();
|
|||
|
|
|
|||
|
|
// Loop through all sectors
|
|||
|
|
int sectorNumber = GetCircularSectorNumber();
|
|||
|
|
for(int sectorIndex = 0; sectorIndex < sectorNumber; sectorIndex++)
|
|||
|
|
{
|
|||
|
|
// Create new axis object
|
|||
|
|
CircularChartAreaAxis axis = new CircularChartAreaAxis(sectorIndex * 360f/sectorNumber);
|
|||
|
|
|
|||
|
|
// Check if custom X axis labels will be used
|
|||
|
|
if(this.AxisX.CustomLabels.Count > 0)
|
|||
|
|
{
|
|||
|
|
if(sectorIndex < this.AxisX.CustomLabels.Count)
|
|||
|
|
{
|
|||
|
|
axis.Title = this.AxisX.CustomLabels[sectorIndex].Text;
|
|||
|
|
axis.TitleForeColor = this.AxisX.CustomLabels[sectorIndex].ForeColor;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// Get axis title from all series
|
|||
|
|
foreach(Series series in this.Common.DataManager.Series)
|
|||
|
|
{
|
|||
|
|
if(series.IsVisible() && series.ChartArea == this.Name && sectorIndex < series.Points.Count)
|
|||
|
|
{
|
|||
|
|
if(series.Points[sectorIndex].AxisLabel.Length > 0)
|
|||
|
|
{
|
|||
|
|
axis.Title = series.Points[sectorIndex].AxisLabel;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Add axis into the list
|
|||
|
|
_circularAxisList.Add(axis);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
return _circularAxisList;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Converts circular position of the X axis to angle in degrees.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="position">X axis position.</param>
|
|||
|
|
/// <returns>Angle in degrees.</returns>
|
|||
|
|
internal float CircularPositionToAngle(double position)
|
|||
|
|
{
|
|||
|
|
// Get X axis scale size
|
|||
|
|
double scaleRatio = 360.0 / Math.Abs(this.AxisX.Maximum - this.AxisX.Minimum);
|
|||
|
|
|
|||
|
|
return (float)(position * scaleRatio + this.AxisX.Crossing);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 2D Series drawing order methods
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Helper method that returns a list of 'ChartTypeAndSeriesInfo' objects.
|
|||
|
|
/// This list is used for chart area series drawing in 2D mode. Each
|
|||
|
|
/// object may represent an individual series or all series that belong
|
|||
|
|
/// to one chart type.
|
|||
|
|
///
|
|||
|
|
/// This method is intended to fix issues #6443 and #5385 when area chart
|
|||
|
|
/// type incorrectly overlaps point or line chart type.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns>List of 'ChartTypeAndSeriesInfo' objects.</returns>
|
|||
|
|
private ArrayList GetChartTypesAndSeriesToDraw()
|
|||
|
|
{
|
|||
|
|
ArrayList resultList = new ArrayList();
|
|||
|
|
|
|||
|
|
// Build chart type or series position based lists
|
|||
|
|
if (this.ChartTypes.Count > 1 &&
|
|||
|
|
(this.ChartTypes.Contains(ChartTypeNames.Area)
|
|||
|
|
|| this.ChartTypes.Contains(ChartTypeNames.SplineArea)
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
{
|
|||
|
|
// Array of chart type names that do not require furher processing
|
|||
|
|
ArrayList processedChartType = new ArrayList();
|
|||
|
|
ArrayList splitChartType = new ArrayList();
|
|||
|
|
|
|||
|
|
// Draw using the exact order in the series collection
|
|||
|
|
int seriesIndex = 0;
|
|||
|
|
foreach (Series series in this.Common.DataManager.Series)
|
|||
|
|
{
|
|||
|
|
// Check if series is visible and belongs to the chart area
|
|||
|
|
if (series.ChartArea==this.Name && series.IsVisible() && series.Points.Count > 0)
|
|||
|
|
{
|
|||
|
|
// Check if this chart type was already processed
|
|||
|
|
if (!processedChartType.Contains(series.ChartTypeName))
|
|||
|
|
{
|
|||
|
|
// Check if curent chart type can be individually processed
|
|||
|
|
bool canBeIndividuallyProcessed = false;
|
|||
|
|
if (series.ChartType == SeriesChartType.Point ||
|
|||
|
|
series.ChartType == SeriesChartType.Line ||
|
|||
|
|
series.ChartType == SeriesChartType.Spline ||
|
|||
|
|
series.ChartType == SeriesChartType.StepLine)
|
|||
|
|
{
|
|||
|
|
canBeIndividuallyProcessed = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!canBeIndividuallyProcessed)
|
|||
|
|
{
|
|||
|
|
// Add a record to process all series of that chart type at once
|
|||
|
|
resultList.Add(new ChartTypeAndSeriesInfo(series.ChartTypeName));
|
|||
|
|
processedChartType.Add(series.ChartTypeName);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// Check if curent chart type has more that 1 series and they are split
|
|||
|
|
// by other series
|
|||
|
|
bool chartTypeIsSplit = false;
|
|||
|
|
|
|||
|
|
if (splitChartType.Contains(series.ChartTypeName))
|
|||
|
|
{
|
|||
|
|
chartTypeIsSplit = true;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
bool otherChartTypeFound = false;
|
|||
|
|
for (int curentSeriesIndex = seriesIndex + 1; curentSeriesIndex < this.Common.DataManager.Series.Count; curentSeriesIndex++)
|
|||
|
|
{
|
|||
|
|
if (series.ChartTypeName == this.Common.DataManager.Series[curentSeriesIndex].ChartTypeName)
|
|||
|
|
{
|
|||
|
|
if (otherChartTypeFound)
|
|||
|
|
{
|
|||
|
|
chartTypeIsSplit = true;
|
|||
|
|
splitChartType.Add(series.ChartTypeName);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
if (this.Common.DataManager.Series[curentSeriesIndex].ChartType == SeriesChartType.Area ||
|
|||
|
|
this.Common.DataManager.Series[curentSeriesIndex].ChartType == SeriesChartType.SplineArea)
|
|||
|
|
{
|
|||
|
|
otherChartTypeFound = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (chartTypeIsSplit)
|
|||
|
|
{
|
|||
|
|
// Add a record to process this series individually
|
|||
|
|
resultList.Add(new ChartTypeAndSeriesInfo(series));
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// Add a record to process all series of that chart type at once
|
|||
|
|
resultList.Add(new ChartTypeAndSeriesInfo(series.ChartTypeName));
|
|||
|
|
processedChartType.Add(series.ChartTypeName);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
++seriesIndex;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
foreach (string chartType in this.ChartTypes)
|
|||
|
|
{
|
|||
|
|
resultList.Add(new ChartTypeAndSeriesInfo(chartType));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return resultList;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Internal data structure that stores chart type name and optionally series object.
|
|||
|
|
/// </summary>
|
|||
|
|
internal class ChartTypeAndSeriesInfo
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// Object constructor.
|
|||
|
|
/// </summary>
|
|||
|
|
public ChartTypeAndSeriesInfo()
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Object constructor.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="chartType">Chart type name to initialize with.</param>
|
|||
|
|
public ChartTypeAndSeriesInfo(string chartType)
|
|||
|
|
{
|
|||
|
|
this.ChartType = chartType;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Object constructor.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="series">Series to initialize with.</param>
|
|||
|
|
public ChartTypeAndSeriesInfo(Series series)
|
|||
|
|
{
|
|||
|
|
this.ChartType = series.ChartTypeName;
|
|||
|
|
this.Series = series;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Chart type name
|
|||
|
|
internal string ChartType = string.Empty;
|
|||
|
|
|
|||
|
|
// Series object. Can be set to NULL!
|
|||
|
|
internal Series Series = null;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion // 2D Series drawing order methods
|
|||
|
|
|
|||
|
|
#region IDisposable Members
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Releases unmanaged and - optionally - managed resources
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
|||
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "axisX")]
|
|||
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "axisX2")]
|
|||
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "axisY")]
|
|||
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "axisY2")]
|
|||
|
|
protected override void Dispose(bool disposing)
|
|||
|
|
{
|
|||
|
|
if (disposing)
|
|||
|
|
{
|
|||
|
|
// Dispose managed resources
|
|||
|
|
if (this._axisArray != null)
|
|||
|
|
{
|
|||
|
|
foreach (Axis axis in this._axisArray)
|
|||
|
|
{
|
|||
|
|
axis.Dispose();
|
|||
|
|
}
|
|||
|
|
this._axisArray = null;
|
|||
|
|
}
|
|||
|
|
if ( this._areaPosition != null)
|
|||
|
|
{
|
|||
|
|
this._areaPosition.Dispose();
|
|||
|
|
this._areaPosition = null;
|
|||
|
|
}
|
|||
|
|
if (this._innerPlotPosition != null)
|
|||
|
|
{
|
|||
|
|
this._innerPlotPosition.Dispose();
|
|||
|
|
this._innerPlotPosition = null;
|
|||
|
|
}
|
|||
|
|
if (this.PlotAreaPosition != null)
|
|||
|
|
{
|
|||
|
|
this.PlotAreaPosition.Dispose();
|
|||
|
|
this.PlotAreaPosition = null;
|
|||
|
|
}
|
|||
|
|
#if Microsoft_CONTROL
|
|||
|
|
if (this.areaBufferBitmap != null)
|
|||
|
|
{
|
|||
|
|
this.areaBufferBitmap.Dispose();
|
|||
|
|
this.areaBufferBitmap = null;
|
|||
|
|
}
|
|||
|
|
if (this._cursorX != null)
|
|||
|
|
{
|
|||
|
|
this._cursorX.Dispose();
|
|||
|
|
this._cursorX = null;
|
|||
|
|
}
|
|||
|
|
if (this._cursorY != null)
|
|||
|
|
{
|
|||
|
|
this._cursorY.Dispose();
|
|||
|
|
this._cursorY = null;
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
base.Dispose(disposing);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|