1 //-------------------------------------------------------------
2 // <copyright company=
\92Microsoft Corporation
\92>
3 // Copyright © Microsoft Corporation. All Rights Reserved.
5 //-------------------------------------------------------------
6 // @owner=alexgor, deliant
7 //=================================================================
10 // Namespace: System.Web.UI.WebControls[Windows.Forms].Charting
14 // Purpose: The ChartArea class represents one chart area within
15 // a chart image, and is used to plot one or more chart
16 // series. The number of chart series that can be plotted
17 // in a chart area is unlimited.
19 // Reviewed: GS - August 6, 2002
20 // AG - August 7, 2002
21 // AG - Microsoft 16, 2007
23 //===================================================================
25 #region Used namespaces
27 using System.Collections;
28 using System.Collections.Specialized;
29 using System.ComponentModel;
30 using System.ComponentModel.Design;
33 using System.Drawing.Design;
34 using System.Drawing.Drawing2D;
35 using System.Globalization;
36 using System.Diagnostics.CodeAnalysis;
40 using System.Windows.Forms.DataVisualization.Charting.Data;
41 using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
42 using System.Windows.Forms.DataVisualization.Charting.Utilities;
43 using System.Windows.Forms.DataVisualization.Charting.Borders3D;
44 using System.Windows.Forms.DataVisualization.Charting;
45 using System.ComponentModel.Design.Serialization;
46 using System.Reflection;
47 using System.Windows.Forms.Design;
51 using System.Web.UI.DataVisualization.Charting;
52 using System.Web.UI.DataVisualization.Charting.Data;
53 using System.Web.UI.DataVisualization.Charting.ChartTypes;
54 using System.Web.UI.DataVisualization.Charting.Utilities;
55 using System.Web.UI.DataVisualization.Charting.Borders3D;
62 namespace System.Windows.Forms.DataVisualization.Charting
64 namespace System.Web.UI.DataVisualization.Charting
67 #region Chart area aligment enumerations
70 /// An enumeration of the alignment orientations of a ChartArea
73 public enum AreaAlignmentOrientations
76 /// Chart areas are not automatically aligned.
81 /// Chart areas are aligned vertically.
86 /// Chart areas are aligned horizontally.
91 /// Chart areas are aligned using all values (horizontally and vertically).
93 All = Vertical | Horizontal
97 /// An enumeration of the alignment styles of a ChartArea
100 public enum AreaAlignmentStyles
103 /// Chart areas are not automatically aligned.
108 /// Chart areas are aligned by positions.
113 /// Chart areas are aligned by inner plot positions.
118 /// Chart areas are aligned by axes views.
122 #if Microsoft_CONTROL
125 /// Cursor and Selection alignment.
130 /// Complete alignment.
132 All = Position | PlotPosition | Cursor | AxesView
133 #else // Microsoft_CONTROL
136 /// Complete alignment.
138 All = Position | PlotPosition | AxesView
140 #endif // Microsoft_CONTROL
146 /// The ChartArea class is used to create and display a chart
147 /// area within a chart image. The chart area is a rectangular
148 /// area on a chart image. It has 4 axes, horizontal and vertical grids.
149 /// A chart area can contain more than one different chart type.
150 /// The number of chart series that can be plotted in a chart area
153 /// ChartArea class exposes all the properties and methods
154 /// of its base ChartArea3D class.
157 DefaultProperty("Axes"),
158 SRDescription("DescriptionAttributeChartArea_ChartArea"),
161 [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
162 [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
164 public partial class ChartArea : ChartNamedElement
166 #region Chart Area Fields
169 /// Plot area position
171 internal ElementPosition PlotAreaPosition;
173 // Private data members, which store properties values
174 private Axis[] _axisArray = new Axis[4];
175 private Color _backColor = Color.Empty;
176 private ChartHatchStyle _backHatchStyle = ChartHatchStyle.None;
177 private string _backImage = "";
178 private ChartImageWrapMode _backImageWrapMode = ChartImageWrapMode.Tile;
179 private Color _backImageTransparentColor = Color.Empty;
180 private ChartImageAlignmentStyle _backImageAlignment = ChartImageAlignmentStyle.TopLeft;
181 private GradientStyle _backGradientStyle = GradientStyle.None;
182 private Color _backSecondaryColor = Color.Empty;
183 private Color _borderColor = Color.Black;
184 private int _borderWidth = 1;
185 private ChartDashStyle _borderDashStyle = ChartDashStyle.NotSet;
186 private int _shadowOffset = 0;
187 private Color _shadowColor = Color.FromArgb(128, 0, 0, 0);
188 private ElementPosition _areaPosition = null;
189 private ElementPosition _innerPlotPosition = null;
190 internal int IterationCounter = 0;
192 private bool _isSameFontSizeForAllAxes = false;
193 internal float axesAutoFontSize = 8f;
195 private string _alignWithChartArea = Constants.NotSetValue;
196 private AreaAlignmentOrientations _alignmentOrientation = AreaAlignmentOrientations.Vertical;
197 private AreaAlignmentStyles _alignmentStyle = AreaAlignmentStyles.All;
198 private int _circularSectorNumber = int.MinValue;
199 private int _circularUsePolygons = int.MinValue;
201 // Flag indicates that chart area is acurrently aligned
202 internal bool alignmentInProcess = false;
204 // Chart area position before adjustments
205 internal RectangleF originalAreaPosition = RectangleF.Empty;
207 // Chart area inner plot position before adjustments
208 internal RectangleF originalInnerPlotPosition = RectangleF.Empty;
210 // Chart area position before adjustments
211 internal RectangleF lastAreaPosition = RectangleF.Empty;
214 // Center of the circulat chart area
215 internal PointF circularCenter = PointF.Empty;
217 private ArrayList _circularAxisList = null;
219 #if Microsoft_CONTROL
220 // Buffered plotting area image
221 internal Bitmap areaBufferBitmap = null;
223 private Cursor _cursorX = new Cursor();
224 private Cursor _cursorY = new Cursor();
227 // Area SmartLabel class
228 internal SmartLabel smartLabels = new SmartLabel();
230 // Gets or sets a flag that specifies whether the chart area is visible.
231 private bool _visible = true;
235 #region Chart Area Cursor properties
237 #if Microsoft_CONTROL
240 /// Gets or sets a Cursor object that is used for cursors and selected ranges along the X-axis.
243 SRCategory("CategoryAttributeCursor"),
246 SRDescription("DescriptionAttributeChartArea_CursorX"),
247 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
248 TypeConverter(typeof(NoNameExpandableObjectConverter)),
250 public Cursor CursorX
260 // Initialize chart object
261 _cursorX.Initialize(this, AxisName.X);
266 /// Gets or sets a Cursor object that is used for cursors and selected ranges along the Y-axis.
269 SRCategory("CategoryAttributeCursor"),
272 SRDescription("DescriptionAttributeChartArea_CursorY"),
273 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
274 TypeConverter(typeof(NoNameExpandableObjectConverter)),
276 public Cursor CursorY
286 // Initialize chart object
287 _cursorY.Initialize(this, AxisName.Y);
291 #endif // Microsoft_CONTROL
295 #region Chart Area properties
298 /// Gets or sets a flag that specifies whether the chart area is visible.
301 /// When this flag is set to false, all series, legends, titles and annotation objects
302 /// associated with the chart area will also be hidden.
305 /// <b>True</b> if the chart area is visible; <b>false</b> otherwise.
308 SRCategory("CategoryAttributeAppearance"),
310 SRDescription("DescriptionAttributeChartArea_Visible"),
311 ParenthesizePropertyNameAttribute(true),
313 virtual public bool Visible
327 /// Gets or sets the name of the ChartArea object to which this chart area should be aligned.
330 SRCategory("CategoryAttributeAlignment"),
332 DefaultValue(Constants.NotSetValue),
333 SRDescription("DescriptionAttributeChartArea_AlignWithChartArea"),
334 TypeConverter(typeof(LegendAreaNameConverter)),
335 #if !Microsoft_CONTROL
336 PersistenceMode(PersistenceMode.Attribute)
339 public string AlignWithChartArea
343 return _alignWithChartArea;
347 if (value != _alignWithChartArea)
349 if (String.IsNullOrEmpty(value))
351 _alignWithChartArea = Constants.NotSetValue;
355 if (Chart != null && Chart.ChartAreas != null)
357 Chart.ChartAreas.VerifyNameReference(value);
359 _alignWithChartArea = value;
367 /// Gets or sets the alignment orientation of a chart area.
370 SRCategory("CategoryAttributeAlignment"),
372 DefaultValue(AreaAlignmentOrientations.Vertical),
373 SRDescription("DescriptionAttributeChartArea_AlignOrientation"),
374 Editor(Editors.FlagsEnumUITypeEditor.Editor, Editors.FlagsEnumUITypeEditor.Base),
375 #if !Microsoft_CONTROL
376 PersistenceMode(PersistenceMode.Attribute)
379 public AreaAlignmentOrientations AlignmentOrientation
383 return _alignmentOrientation;
387 _alignmentOrientation = value;
394 /// Gets or sets the alignment style of the ChartArea.
397 SRCategory("CategoryAttributeAlignment"),
399 DefaultValue(AreaAlignmentStyles.All),
400 SRDescription("DescriptionAttributeChartArea_AlignType"),
401 Editor(Editors.FlagsEnumUITypeEditor.Editor, Editors.FlagsEnumUITypeEditor.Base),
402 #if !Microsoft_CONTROL
403 PersistenceMode(PersistenceMode.Attribute)
406 public AreaAlignmentStyles AlignmentStyle
410 return _alignmentStyle;
414 _alignmentStyle = value;
420 /// Gets or sets an array that represents all axes for a chart area.
423 SRCategory("CategoryAttributeAxes"),
425 SRDescription("DescriptionAttributeChartArea_Axes"),
426 TypeConverter(typeof(AxesArrayConverter)),
427 Editor(Editors.AxesArrayEditor.Editor, Editors.AxesArrayEditor.Base),
428 DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
429 SerializationVisibilityAttribute(SerializationVisibility.Hidden)
431 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
449 /// Avoid serialization of the axes array
451 [EditorBrowsableAttribute(EditorBrowsableState.Never)]
452 internal bool ShouldSerializeAxes()
458 /// Gets or sets an Axis object that represents the primary Y-axis.
461 SRCategory("CategoryAttributeAxis"),
464 SRDescription("DescriptionAttributeChartArea_AxisY"),
465 #if Microsoft_CONTROL
466 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
468 PersistenceMode(PersistenceMode.InnerProperty),
470 TypeConverter(typeof(NoNameExpandableObjectConverter))
481 axisY.Initialize(this, AxisName.Y);
482 _axisArray[1] = axisY;
488 /// Gets or sets an Axis object that represents the primary X-axis.
491 SRCategory("CategoryAttributeAxis"),
494 SRDescription("DescriptionAttributeChartArea_AxisX"),
495 #if Microsoft_CONTROL
496 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
498 PersistenceMode(PersistenceMode.InnerProperty),
500 TypeConverter(typeof(NoNameExpandableObjectConverter))
511 axisX.Initialize(this, AxisName.X);
512 _axisArray[0] = axisX;
518 /// Gets or sets an Axis object that represents the secondary X-axis.
521 SRCategory("CategoryAttributeAxis"),
524 SRDescription("DescriptionAttributeChartArea_AxisX2"),
525 #if Microsoft_CONTROL
526 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
528 PersistenceMode(PersistenceMode.InnerProperty),
530 TypeConverter(typeof(NoNameExpandableObjectConverter))
541 axisX2.Initialize(this, AxisName.X2);
542 _axisArray[2] = axisX2;
548 /// Gets or sets an Axis object that represents the secondary Y-axis.
551 SRCategory("CategoryAttributeAxis"),
554 SRDescription("DescriptionAttributeChartArea_AxisY2"),
555 #if Microsoft_CONTROL
556 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
558 PersistenceMode(PersistenceMode.InnerProperty),
560 TypeConverter(typeof(NoNameExpandableObjectConverter))
571 axisY2.Initialize(this, AxisName.Y2);
572 _axisArray[3] = axisY2;
578 /// Gets or sets an ElementPosition object, which defines the position of a chart area object within the chart image.
581 SRCategory("CategoryAttributeAppearance"),
583 SRDescription("DescriptionAttributeChartArea_Position"),
584 #if Microsoft_CONTROL
585 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
587 PersistenceMode(PersistenceMode.InnerProperty),
589 NotifyParentPropertyAttribute(true),
590 TypeConverter(typeof(ElementPositionConverter)),
591 SerializationVisibilityAttribute(SerializationVisibility.Element)
593 public ElementPosition Position
597 // Serialize only position values if Auto set to false
598 if(this.Chart != null && this.Chart.serializationStatus == SerializationStatus.Saving )
600 if(_areaPosition.Auto)
602 return new ElementPosition();
606 ElementPosition newPosition = new ElementPosition();
607 #if Microsoft_CONTROL
608 newPosition.Auto = false;
610 newPosition.Auto = true;
612 newPosition.SetPositionNoAuto(_areaPosition.X, _areaPosition.Y, _areaPosition.Width, _areaPosition.Height);
616 return _areaPosition;
620 _areaPosition = value;
621 _areaPosition.Parent = this;
622 _areaPosition.resetAreaAutoPosition = true;
628 /// Determoines if this position should be serialized.
630 /// <returns></returns>
631 internal bool ShouldSerializePosition()
633 return !this.Position.Auto;
637 /// Gets or sets an ElementPosition object, which defines the inner plot position of a chart area object.
640 SRCategory("CategoryAttributeAppearance"),
642 SRDescription("DescriptionAttributeChartArea_InnerPlotPosition"),
643 #if Microsoft_CONTROL
644 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
646 PersistenceMode(PersistenceMode.InnerProperty),
648 NotifyParentPropertyAttribute(true),
649 TypeConverter(typeof(ElementPositionConverter)),
650 SerializationVisibilityAttribute(SerializationVisibility.Element)
652 public ElementPosition InnerPlotPosition
656 // Serialize only position values if Auto set to false
657 if (this.Common != null && this.Common.Chart != null && this.Common.Chart.serializationStatus == SerializationStatus.Saving)
659 if(_innerPlotPosition.Auto)
661 return new ElementPosition();
665 ElementPosition newPosition = new ElementPosition();
666 #if Microsoft_CONTROL
667 newPosition.Auto = false;
669 newPosition.Auto = true;
671 newPosition.SetPositionNoAuto(_innerPlotPosition.X, _innerPlotPosition.Y, _innerPlotPosition.Width, _innerPlotPosition.Height);
675 return _innerPlotPosition;
679 _innerPlotPosition = value;
680 _innerPlotPosition.Parent = this;
686 /// Determoines if this position should be serialized.
688 /// <returns></returns>
689 internal bool ShouldSerializeInnerPlotPosition()
691 return !this.InnerPlotPosition.Auto;
695 /// Gets or sets the background color of a ChartArea object.
699 SRCategory("CategoryAttributeAppearance"),
701 DefaultValue(typeof(Color), ""),
702 SRDescription("DescriptionAttributeBackColor"),
703 NotifyParentPropertyAttribute(true),
704 TypeConverter(typeof(ColorConverter)),
705 Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
706 #if !Microsoft_CONTROL
707 PersistenceMode(PersistenceMode.Attribute)
710 public Color BackColor
724 /// Gets or sets the hatching style of a ChartArea object.
729 SRCategory("CategoryAttributeAppearance"),
731 DefaultValue(ChartHatchStyle.None),
732 NotifyParentPropertyAttribute(true),
733 SRDescription("DescriptionAttributeBackHatchStyle"),
734 #if !Microsoft_CONTROL
735 PersistenceMode(PersistenceMode.Attribute),
737 Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base)
740 public ChartHatchStyle BackHatchStyle
744 return _backHatchStyle;
748 _backHatchStyle = value;
754 /// Gets or sets the background image of a ChartArea object.
757 SRCategory("CategoryAttributeAppearance"),
760 SRDescription("DescriptionAttributeBackImage"),
761 Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base),
762 #if !Microsoft_CONTROL
763 PersistenceMode(PersistenceMode.Attribute),
765 NotifyParentPropertyAttribute(true)
767 public string BackImage
781 /// Gets or sets the drawing mode of the background image of a ChartArea object.
784 SRCategory("CategoryAttributeAppearance"),
786 DefaultValue(ChartImageWrapMode.Tile),
787 NotifyParentPropertyAttribute(true),
788 SRDescription("DescriptionAttributeImageWrapMode"),
789 #if !Microsoft_CONTROL
790 PersistenceMode(PersistenceMode.Attribute)
793 public ChartImageWrapMode BackImageWrapMode
797 return _backImageWrapMode;
801 _backImageWrapMode = value;
807 /// Gets or sets the color of a ChartArea object's background image that will be drawn as transparent.
810 SRCategory("CategoryAttributeAppearance"),
812 DefaultValue(typeof(Color), ""),
813 NotifyParentPropertyAttribute(true),
814 SRDescription("DescriptionAttributeImageTransparentColor"),
815 TypeConverter(typeof(ColorConverter)),
816 Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
817 #if !Microsoft_CONTROL
818 PersistenceMode(PersistenceMode.Attribute)
821 public Color BackImageTransparentColor
825 return _backImageTransparentColor;
829 _backImageTransparentColor = value;
835 /// Gets or sets the alignment of a ChartArea object.
838 SRCategory("CategoryAttributeAppearance"),
840 DefaultValue(ChartImageAlignmentStyle.TopLeft),
841 NotifyParentPropertyAttribute(true),
842 SRDescription("DescriptionAttributeBackImageAlign"),
843 #if !Microsoft_CONTROL
844 PersistenceMode(PersistenceMode.Attribute)
847 public ChartImageAlignmentStyle BackImageAlignment
851 return _backImageAlignment;
855 _backImageAlignment = value;
861 /// Gets or sets the orientation of a chart element's gradient,
862 /// and also determines whether or not a gradient is used.
866 SRCategory("CategoryAttributeAppearance"),
868 DefaultValue(GradientStyle.None),
869 NotifyParentPropertyAttribute(true),
870 SRDescription("DescriptionAttributeBackGradientStyle"),
871 #if !Microsoft_CONTROL
872 PersistenceMode(PersistenceMode.Attribute),
874 Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base)
876 public GradientStyle BackGradientStyle
880 return _backGradientStyle;
884 _backGradientStyle = value;
890 /// Gets or sets the secondary color of a ChartArea object.
894 SRCategory("CategoryAttributeAppearance"),
896 DefaultValue(typeof(Color), ""),
897 NotifyParentPropertyAttribute(true),
898 SRDescription("DescriptionAttributeBackSecondaryColor"),
899 TypeConverter(typeof(ColorConverter)),
900 Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
901 #if !Microsoft_CONTROL
902 PersistenceMode(PersistenceMode.Attribute)
905 public Color BackSecondaryColor
909 return _backSecondaryColor;
913 _backSecondaryColor = value;
919 /// Gets or sets the shadow color of a ChartArea object.
922 SRCategory("CategoryAttributeAppearance"),
924 DefaultValue(typeof(Color), "128,0,0,0"),
925 SRDescription("DescriptionAttributeShadowColor"),
926 NotifyParentPropertyAttribute(true),
927 TypeConverter(typeof(ColorConverter)),
928 Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
929 #if !Microsoft_CONTROL
930 PersistenceMode(PersistenceMode.Attribute)
933 public Color ShadowColor
941 _shadowColor = value;
947 /// Gets or sets the shadow offset (in pixels) of a ChartArea object.
950 SRCategory("CategoryAttributeAppearance"),
953 SRDescription("DescriptionAttributeShadowOffset"),
954 NotifyParentPropertyAttribute(true),
955 #if !Microsoft_CONTROL
956 PersistenceMode(PersistenceMode.Attribute)
959 public int ShadowOffset
963 return _shadowOffset;
967 _shadowOffset = value;
973 /// Gets or sets the border color of a ChartArea object.
977 SRCategory("CategoryAttributeAppearance"),
979 DefaultValue(typeof(Color), "Black"),
980 SRDescription("DescriptionAttributeBorderColor"),
981 NotifyParentPropertyAttribute(true),
982 TypeConverter(typeof(ColorConverter)),
983 Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
984 #if !Microsoft_CONTROL
985 PersistenceMode(PersistenceMode.Attribute)
988 public Color BorderColor
996 _borderColor = value;
1002 /// Gets or sets the border width of a ChartArea object.
1006 SRCategory("CategoryAttributeAppearance"),
1009 SRDescription("DescriptionAttributeBorderWidth"),
1010 NotifyParentPropertyAttribute(true),
1011 #if !Microsoft_CONTROL
1012 PersistenceMode(PersistenceMode.Attribute)
1015 public int BorderWidth
1019 return _borderWidth;
1025 throw (new ArgumentOutOfRangeException("value", SR.ExceptionBorderWidthIsNegative));
1027 _borderWidth = value;
1033 /// Gets or sets the style of the border line of a ChartArea object.
1037 SRCategory("CategoryAttributeAppearance"),
1039 DefaultValue(ChartDashStyle.NotSet),
1040 SRDescription("DescriptionAttributeBorderDashStyle"),
1041 NotifyParentPropertyAttribute(true),
1042 #if !Microsoft_CONTROL
1043 PersistenceMode(PersistenceMode.Attribute)
1046 public ChartDashStyle BorderDashStyle
1050 return _borderDashStyle;
1054 _borderDashStyle = value;
1060 /// Gets or sets the unique name of a ChartArea object.
1064 SRCategory("CategoryAttributeMisc"),
1066 SRDescription("DescriptionAttributeChartArea_Name"),
1067 NotifyParentPropertyAttribute(true),
1068 #if !Microsoft_CONTROL
1069 PersistenceMode(PersistenceMode.Attribute)
1072 public override string Name
1085 /// Gets or sets a Boolean that determines if the labels of the axes for all chart area
1086 /// , which have LabelsAutoFit property set to true, are of equal size.
1089 SRCategory("CategoryAttributeAppearance"),
1091 DefaultValue(false),
1092 SRDescription("DescriptionAttributeChartArea_EquallySizedAxesFont"),
1093 NotifyParentPropertyAttribute(true),
1094 #if !Microsoft_CONTROL
1095 PersistenceMode(PersistenceMode.Attribute)
1098 public bool IsSameFontSizeForAllAxes
1102 return _isSameFontSizeForAllAxes;
1106 _isSameFontSizeForAllAxes = value;
1114 #region Constructors
1116 /// ChartArea constructor.
1124 /// ChartArea constructor.
1126 /// <param name="name">The name.</param>
1127 public ChartArea(string name) : base(name)
1133 #region Chart Area Methods
1135 /// Restores series order and X axis reversed mode for the 3D charts.
1137 internal void Restore3DAnglesAndReverseMode()
1139 if(this.Area3DStyle.Enable3D && !this.chartAreaIsCurcular)
1141 // Restore axis "IsReversed" property and old Y angle
1142 this.AxisX.IsReversed = oldReverseX;
1143 this.AxisX2.IsReversed = oldReverseX;
1144 this.AxisY.IsReversed = oldReverseY;
1145 this.AxisY2.IsReversed = oldReverseY;
1146 this.Area3DStyle.Rotation = oldYAngle;
1151 /// Sets series order and X axis reversed mode for the 3D charts.
1153 internal void Set3DAnglesAndReverseMode()
1155 // Clear series reversed flag
1156 _reverseSeriesOrder = false;
1158 // If 3D charting is enabled
1159 if(this.Area3DStyle.Enable3D)
1161 // Make sure primary & secondary axis has the same IsReversed settings
1162 // This is a limitation for the 3D chart required for labels drawing.
1163 this.AxisX2.IsReversed = this.AxisX.IsReversed;
1164 this.AxisY2.IsReversed = this.AxisY.IsReversed;
1166 // Remember reversed order of X & Y axis and Angles
1167 oldReverseX = this.AxisX.IsReversed;
1168 oldReverseY = this.AxisY.IsReversed;
1169 oldYAngle = this.Area3DStyle.Rotation;
1172 if(this.Area3DStyle.Rotation > 90 || this.Area3DStyle.Rotation < -90)
1174 // This method depends on the 'switchValueAxes' field which is calculated based on the chart types
1175 // of the series associated with the chart area. We need to call SetData method to make sure this field
1176 // is correctly initialized. Because we only need to collect information about the series, we pass 'false'
1177 // as parameters to limit the amount of work this function does.
1178 this.SetData(false, false);
1180 // Reversed series order
1181 _reverseSeriesOrder = true;
1183 // Reversed primary and secondary X axis
1184 if(!this.switchValueAxes)
1186 this.AxisX.IsReversed = !this.AxisX.IsReversed;
1187 this.AxisX2.IsReversed = !this.AxisX2.IsReversed;
1190 // Reversed primary and secondary Y axis for chart types like Bar
1193 this.AxisY.IsReversed = !this.AxisY.IsReversed;
1194 this.AxisY2.IsReversed = !this.AxisY2.IsReversed;
1198 if(this.Area3DStyle.Rotation > 90)
1200 this.Area3DStyle.Rotation = (this.Area3DStyle.Rotation - 90) - 90;
1202 else if(this.Area3DStyle.Rotation < -90)
1204 this.Area3DStyle.Rotation = (this.Area3DStyle.Rotation + 90) + 90;
1211 /// Save all automatic values like Minimum and Maximum.
1213 internal void SetTempValues()
1215 // Save non automatic area position
1216 if(!this.Position.Auto)
1218 this.originalAreaPosition = this.Position.ToRectangleF();
1221 // Save non automatic area inner plot position
1222 if(!this.InnerPlotPosition.Auto)
1224 this.originalInnerPlotPosition = this.InnerPlotPosition.ToRectangleF();
1227 this._circularSectorNumber = int.MinValue;
1228 this._circularUsePolygons = int.MinValue;
1229 this._circularAxisList = null;
1231 // Save Minimum and maximum values for all axes
1232 axisX.StoreAxisValues();
1233 axisX2.StoreAxisValues();
1234 axisY.StoreAxisValues();
1235 axisY2.StoreAxisValues();
1239 /// Load all automatic values like Minimum and Maximum with original values.
1241 internal void GetTempValues()
1243 // Take Minimum and maximum values for all axes
1244 axisX.ResetAxisValues();
1245 axisX2.ResetAxisValues();
1246 axisY.ResetAxisValues();
1247 axisY2.ResetAxisValues();
1249 // Restore non automatic area position
1250 if(!this.originalAreaPosition.IsEmpty)
1252 this.lastAreaPosition = this.Position.ToRectangleF();
1253 this.Position.SetPositionNoAuto(this.originalAreaPosition.X, this.originalAreaPosition.Y, this.originalAreaPosition.Width, this.originalAreaPosition.Height);
1254 this.originalAreaPosition = RectangleF.Empty;
1257 // Save non automatic area inner plot position
1258 if(!this.originalInnerPlotPosition.IsEmpty)
1260 this.InnerPlotPosition.SetPositionNoAuto(this.originalInnerPlotPosition.X, this.originalInnerPlotPosition.Y, this.originalInnerPlotPosition.Width, this.originalInnerPlotPosition.Height);
1261 this.originalInnerPlotPosition = RectangleF.Empty;
1266 /// Initialize Chart area and axes
1268 internal void Initialize()
1270 // Initialize 3D style class
1271 _area3DStyle = new ChartArea3DStyle(this);
1273 // Create axes for this chart area.
1274 axisY = new Axis( );
1275 axisX = new Axis( );
1276 axisX2 = new Axis( );
1277 axisY2 = new Axis( );
1280 axisX.Initialize(this, AxisName.X);
1281 axisY.Initialize(this, AxisName.Y);
1282 axisX2.Initialize(this, AxisName.X2);
1283 axisY2.Initialize(this, AxisName.Y2);
1285 // Initialize axes array
1286 _axisArray[0] = axisX;
1287 _axisArray[1] = axisY;
1288 _axisArray[2] = axisX2;
1289 _axisArray[3] = axisY2;
1291 // Set flag to reset auto values for all areas
1292 _areaPosition = new ElementPosition(this);
1293 _areaPosition.resetAreaAutoPosition = true;
1295 _innerPlotPosition = new ElementPosition(this);
1297 // Set the position of the new chart area
1298 if( PlotAreaPosition == null )
1300 PlotAreaPosition = new ElementPosition(this);
1303 #if Microsoft_CONTROL
1305 // Initialize cursor class
1306 this._cursorX.Initialize(this, AxisName.X);
1307 this._cursorY.Initialize(this, AxisName.Y);
1309 #endif // Microsoft_CONTROL
1313 /// Minimum and maximum do not have to be calculated
1314 /// from data series every time. It is very time
1315 /// consuming. Minimum and maximum are buffered
1316 /// and only when this flags are set Minimum and
1317 /// Maximum are refreshed from data.
1319 internal void ResetMinMaxFromData()
1321 _axisArray[0].refreshMinMaxFromData = true;
1322 _axisArray[1].refreshMinMaxFromData = true;
1323 _axisArray[2].refreshMinMaxFromData = true;
1324 _axisArray[3].refreshMinMaxFromData = true;
1328 /// Recalculates the axes scale of a chart area.
1330 public void RecalculateAxesScale()
1332 // Read axis Max/Min from data
1333 ResetMinMaxFromData();
1335 #if Microsoft_CONTROL
1336 Set3DAnglesAndReverseMode();
1340 // Initialize area position
1341 _axisArray[0].ReCalc( PlotAreaPosition );
1342 _axisArray[1].ReCalc( PlotAreaPosition );
1343 _axisArray[2].ReCalc( PlotAreaPosition );
1344 _axisArray[3].ReCalc( PlotAreaPosition );
1346 // Find all Data and chart types which belong
1347 // to this chart area an set default values
1350 #if Microsoft_CONTROL
1351 Restore3DAnglesAndReverseMode();
1357 /// RecalculateAxesScale the chart area
1359 internal void ReCalcInternal()
1361 // Initialize area position
1362 _axisArray[0].ReCalc( PlotAreaPosition );
1363 _axisArray[1].ReCalc( PlotAreaPosition );
1364 _axisArray[2].ReCalc( PlotAreaPosition );
1365 _axisArray[3].ReCalc( PlotAreaPosition );
1367 // Find all Data and chart types which belong
1368 // to this chart area an set default values
1374 /// Reset auto calculated chart area values.
1376 internal void ResetAutoValues()
1378 _axisArray[0].ResetAutoValues();
1379 _axisArray[1].ResetAutoValues();
1380 _axisArray[2].ResetAutoValues();
1381 _axisArray[3].ResetAutoValues();
1385 /// Calculates Position for the background.
1387 /// <param name="withScrollBars">Calculate with scroll bars</param>
1388 /// <returns>Background rectangle</returns>
1389 internal RectangleF GetBackgroundPosition( bool withScrollBars )
1391 // For pie and doughnut, which do not have axes, the position
1392 // for the background is Chart area position not plotting
1394 RectangleF backgroundPosition = PlotAreaPosition.ToRectangleF();
1397 backgroundPosition = Position.ToRectangleF();
1400 // Without scroll bars
1401 if( !withScrollBars )
1403 return backgroundPosition;
1406 // Add scroll bar rectangles to the area background
1407 RectangleF backgroundPositionWithScrollBars = new RectangleF(backgroundPosition.Location, backgroundPosition.Size);
1409 #if Microsoft_CONTROL
1413 // Loop through all axis
1414 foreach(Axis axis in this.Axes)
1416 // Find axis with visible scroll bars
1417 if(axis.ScrollBar.IsVisible && axis.ScrollBar.IsPositionedInside)
1419 // Change size of the background rectangle depending on the axis position
1420 if(axis.AxisPosition == AxisPosition.Bottom)
1422 backgroundPositionWithScrollBars.Height += (float)axis.ScrollBar.GetScrollBarRelativeSize();
1424 else if(axis.AxisPosition == AxisPosition.Top)
1426 backgroundPositionWithScrollBars.Y -= (float)axis.ScrollBar.GetScrollBarRelativeSize();
1427 backgroundPositionWithScrollBars.Height += (float)axis.ScrollBar.GetScrollBarRelativeSize();
1429 else if(axis.AxisPosition == AxisPosition.Left)
1431 backgroundPositionWithScrollBars.X -= (float)axis.ScrollBar.GetScrollBarRelativeSize();
1432 backgroundPositionWithScrollBars.Width += (float)axis.ScrollBar.GetScrollBarRelativeSize();
1434 else if(axis.AxisPosition == AxisPosition.Left)
1436 backgroundPositionWithScrollBars.Width += (float)axis.ScrollBar.GetScrollBarRelativeSize();
1442 #endif // Microsoft_CONTROL
1443 return backgroundPositionWithScrollBars;
1447 /// Call when the chart area is resized.
1449 /// <param name="chartGraph">Chart graphics object.</param>
1450 internal void Resize(ChartGraphics chartGraph)
1452 // Initialize plotting area position
1453 RectangleF plottingRect = Position.ToRectangleF();
1454 if(!InnerPlotPosition.Auto)
1456 plottingRect.X += (Position.Width / 100F) * InnerPlotPosition.X;
1457 plottingRect.Y += (Position.Height / 100F) * InnerPlotPosition.Y;
1458 plottingRect.Width = (Position.Width / 100F) * InnerPlotPosition.Width;
1459 plottingRect.Height = (Position.Height / 100F) * InnerPlotPosition.Height;
1462 //******************************************************
1463 //** Calculate number of vertical and horizontal axis
1464 //******************************************************
1465 int verticalAxes = 0;
1466 int horizontalAxes = 0;
1467 foreach(Axis axis in this.Axes)
1471 if(axis.AxisPosition == AxisPosition.Bottom)
1475 else if(axis.AxisPosition == AxisPosition.Top)
1479 else if(axis.AxisPosition == AxisPosition.Left)
1483 else if(axis.AxisPosition == AxisPosition.Right)
1489 if(horizontalAxes <= 0 )
1493 if(verticalAxes <= 0 )
1499 //******************************************************
1500 //** Find same auto-fit font size
1501 //******************************************************
1502 Axis[] axisArray = (this.switchValueAxes) ?
1503 new Axis[] {this.AxisX, this.AxisX2, this.AxisY, this.AxisY2} :
1504 new Axis[] {this.AxisY, this.AxisY2, this.AxisX, this.AxisX2};
1505 if(this.IsSameFontSizeForAllAxes)
1507 axesAutoFontSize = 20;
1508 foreach(Axis axis in axisArray)
1510 // Process only enabled axis
1514 if(axis.AxisPosition == AxisPosition.Bottom || axis.AxisPosition == AxisPosition.Top)
1516 axis.Resize(chartGraph, this.PlotAreaPosition, plottingRect, horizontalAxes, InnerPlotPosition.Auto);
1520 axis.Resize(chartGraph, this.PlotAreaPosition, plottingRect, verticalAxes, InnerPlotPosition.Auto);
1523 // Calculate smallest font size
1524 if(axis.IsLabelAutoFit && axis.autoLabelFont != null)
1526 axesAutoFontSize = Math.Min(axesAutoFontSize, axis.autoLabelFont.Size);
1532 //******************************************************
1533 //** Adjust plotting area position according to the axes
1534 //** elements (title, labels, tick marks) size.
1535 //******************************************************
1536 RectangleF rectLabelSideSpacing = RectangleF.Empty;
1537 foreach(Axis axis in axisArray)
1539 // Process only enabled axis
1540 if( ! axis.enabled )
1542 //******************************************************
1543 //** Adjust for the 3D Wall Width for disabled axis
1544 //******************************************************
1545 if(InnerPlotPosition.Auto && this.Area3DStyle.Enable3D && !this.chartAreaIsCurcular)
1547 SizeF areaWallSize = chartGraph.GetRelativeSize(new SizeF(this.Area3DStyle.WallWidth, this.Area3DStyle.WallWidth));
1548 if(axis.AxisPosition == AxisPosition.Bottom)
1550 plottingRect.Height -= areaWallSize.Height;
1552 else if(axis.AxisPosition == AxisPosition.Top)
1554 plottingRect.Y += areaWallSize.Height;
1555 plottingRect.Height -= areaWallSize.Height;
1557 else if(axis.AxisPosition == AxisPosition.Right)
1559 plottingRect.Width -= areaWallSize.Width;
1561 else if(axis.AxisPosition == AxisPosition.Left)
1563 plottingRect.X += areaWallSize.Width;
1564 plottingRect.Width -= areaWallSize.Width;
1571 //******************************************************
1572 //** Calculate axes elements position
1573 //******************************************************
1574 if(axis.AxisPosition == AxisPosition.Bottom || axis.AxisPosition == AxisPosition.Top)
1576 axis.Resize(chartGraph, this.PlotAreaPosition, plottingRect, horizontalAxes, InnerPlotPosition.Auto);
1580 axis.Resize(chartGraph, this.PlotAreaPosition, plottingRect, verticalAxes, InnerPlotPosition.Auto);
1583 // Shift top/bottom labels so they will not overlap with left/right labels
1584 PreventTopBottomAxesLabelsOverlapping(axis);
1586 //******************************************************
1587 //** Check axis position
1588 //******************************************************
1589 float axisPosition = (float)axis.GetAxisPosition();
1590 if(axis.AxisPosition == AxisPosition.Bottom)
1592 if(!axis.GetIsMarksNextToAxis())
1594 axisPosition = plottingRect.Bottom;
1596 axisPosition = plottingRect.Bottom - axisPosition;
1598 else if(axis.AxisPosition == AxisPosition.Top)
1600 if(!axis.GetIsMarksNextToAxis())
1602 axisPosition = plottingRect.Y;
1604 axisPosition = axisPosition - plottingRect.Top;
1606 else if(axis.AxisPosition == AxisPosition.Right)
1608 if(!axis.GetIsMarksNextToAxis())
1610 axisPosition = plottingRect.Right;
1612 axisPosition = plottingRect.Right - axisPosition;
1614 else if(axis.AxisPosition == AxisPosition.Left)
1616 if(!axis.GetIsMarksNextToAxis())
1618 axisPosition = plottingRect.X;
1620 axisPosition = axisPosition - plottingRect.Left;
1623 //******************************************************
1624 //** Adjust axis elements size with axis position
1625 //******************************************************
1626 // Calculate total size of axis elements
1627 float axisSize = axis.markSize + axis.labelSize;
1630 // Add sub-axis size
1631 if(!this.chartAreaIsCurcular && !this.Area3DStyle.Enable3D)
1633 foreach(SubAxis subAxis in axis.SubAxes)
1635 axisSize += subAxis.markSize + subAxis.labelSize + subAxis.titleSize;
1640 // Adjust depending on the axis position
1641 axisSize -= axisPosition;
1648 // Add axis title and scroll bar size (always outside of plotting area)
1649 axisSize += axis.titleSize + axis.scrollBarSize;
1652 // Calculate horizontal axes size for circualar area
1653 if(this.chartAreaIsCurcular &&
1654 (axis.AxisPosition == AxisPosition.Top || axis.AxisPosition == AxisPosition.Bottom) )
1656 axisSize = axis.titleSize + axis.markSize + axis.scrollBarSize;
1659 //******************************************************
1660 //** Adjust plotting area
1661 //******************************************************
1662 if(InnerPlotPosition.Auto)
1664 if(axis.AxisPosition == AxisPosition.Bottom)
1666 plottingRect.Height -= axisSize;
1668 else if(axis.AxisPosition == AxisPosition.Top)
1670 plottingRect.Y += axisSize;
1671 plottingRect.Height -= axisSize;
1673 else if(axis.AxisPosition == AxisPosition.Left)
1675 plottingRect.X += axisSize;
1676 plottingRect.Width -= axisSize;
1678 else if(axis.AxisPosition == AxisPosition.Right)
1680 plottingRect.Width -= axisSize;
1683 // Check if labels side offset should be processed
1684 bool addLabelsSideOffsets = true;
1686 // Update the plotting area depending on the size required for labels on the sides
1687 if (addLabelsSideOffsets)
1689 if (axis.AxisPosition == AxisPosition.Bottom || axis.AxisPosition == AxisPosition.Top)
1691 if (axis.labelNearOffset != 0 && axis.labelNearOffset < Position.X)
1693 float offset = Position.X - axis.labelNearOffset;
1694 if (Math.Abs(offset) > plottingRect.Width * 0.3f)
1696 offset = plottingRect.Width * 0.3f;
1699 // NOTE: Code was removed to solve an issue with extra space when labels angle = 45
1700 //rectLabelSideSpacing.Width = (float)Math.Max(offset, rectLabelSideSpacing.Width);
1701 rectLabelSideSpacing.X = (float)Math.Max(offset, rectLabelSideSpacing.X);
1704 if (axis.labelFarOffset > Position.Right)
1706 if ((axis.labelFarOffset - Position.Right) < plottingRect.Width * 0.3f)
1708 rectLabelSideSpacing.Width = (float)Math.Max(axis.labelFarOffset - Position.Right, rectLabelSideSpacing.Width);
1712 rectLabelSideSpacing.Width = (float)Math.Max(plottingRect.Width * 0.3f, rectLabelSideSpacing.Width);
1719 if (axis.labelNearOffset != 0 && axis.labelNearOffset < Position.Y)
1721 float offset = Position.Y - axis.labelNearOffset;
1722 if (Math.Abs(offset) > plottingRect.Height * 0.3f)
1724 offset = plottingRect.Height * 0.3f;
1727 // NOTE: Code was removed to solve an issue with extra space when labels angle = 45
1728 //rectLabelSideSpacing.Height = (float)Math.Max(offset, rectLabelSideSpacing.Height);
1729 rectLabelSideSpacing.Y = (float)Math.Max(offset, rectLabelSideSpacing.Y);
1732 if (axis.labelFarOffset > Position.Bottom)
1734 if ((axis.labelFarOffset - Position.Bottom) < plottingRect.Height * 0.3f)
1736 rectLabelSideSpacing.Height = (float)Math.Max(axis.labelFarOffset - Position.Bottom, rectLabelSideSpacing.Height);
1740 rectLabelSideSpacing.Height = (float)Math.Max(plottingRect.Height * 0.3f, rectLabelSideSpacing.Height);
1748 //******************************************************
1749 //** Make sure there is enough space
1750 //** for labels on the chart sides
1751 //******************************************************
1752 if (!this.chartAreaIsCurcular)
1754 if (rectLabelSideSpacing.Y > 0 && rectLabelSideSpacing.Y > plottingRect.Y - Position.Y)
1756 float delta = (plottingRect.Y - Position.Y) - rectLabelSideSpacing.Y;
1757 plottingRect.Y -= delta;
1758 plottingRect.Height += delta;
1760 if (rectLabelSideSpacing.X > 0 && rectLabelSideSpacing.X > plottingRect.X - Position.X)
1762 float delta = (plottingRect.X - Position.X) - rectLabelSideSpacing.X;
1763 plottingRect.X -= delta;
1764 plottingRect.Width += delta;
1766 if (rectLabelSideSpacing.Height > 0 && rectLabelSideSpacing.Height > Position.Bottom - plottingRect.Bottom)
1768 plottingRect.Height += (Position.Bottom - plottingRect.Bottom) - rectLabelSideSpacing.Height;
1770 if (rectLabelSideSpacing.Width > 0 && rectLabelSideSpacing.Width > Position.Right - plottingRect.Right)
1772 plottingRect.Width += (Position.Right - plottingRect.Right) - rectLabelSideSpacing.Width;
1776 //******************************************************
1777 //** Plotting area must be square for the circular
1778 //** chart area (in pixels).
1779 //******************************************************
1780 if(this.chartAreaIsCurcular)
1782 // Adjust area to fit the axis title
1783 float xTitleSize = (float)Math.Max(this.AxisY.titleSize, this.AxisY2.titleSize);
1786 plottingRect.X += xTitleSize;
1787 plottingRect.Width -= 2f * xTitleSize;
1789 float yTitleSize = (float)Math.Max(this.AxisX.titleSize, this.AxisX2.titleSize);
1792 plottingRect.Y += yTitleSize;
1793 plottingRect.Height -= 2f * yTitleSize;
1796 // Make a square plotting rect
1797 RectangleF rect = chartGraph.GetAbsoluteRectangle( plottingRect );
1798 if(rect.Width > rect.Height)
1800 rect.X += (rect.Width - rect.Height) / 2f;
1801 rect.Width = rect.Height;
1805 rect.Y += (rect.Height - rect.Width) / 2f;
1806 rect.Height = rect.Width;
1808 plottingRect = chartGraph.GetRelativeRectangle( rect );
1810 // Remember circular chart area center
1811 this.circularCenter = new PointF(plottingRect.X + plottingRect.Width/2f, plottingRect.Y + plottingRect.Height/2f);
1813 // Calculate auto-fit font of the circular axis labels and update area position
1814 FitCircularLabels(chartGraph, this.PlotAreaPosition, ref plottingRect, xTitleSize, yTitleSize);
1817 //******************************************************
1818 //** Set plotting area position
1819 //******************************************************
1820 if(plottingRect.Width < 0f)
1822 plottingRect.Width = 0f;
1824 if(plottingRect.Height < 0f)
1826 plottingRect.Height = 0f;
1828 PlotAreaPosition.FromRectangleF(plottingRect);
1829 InnerPlotPosition.SetPositionNoAuto(
1830 (float)Math.Round((plottingRect.X - Position.X) / (Position.Width / 100F), 5),
1831 (float)Math.Round((plottingRect.Y - Position.Y) / (Position.Height / 100F), 5),
1832 (float)Math.Round(plottingRect.Width / (Position.Width / 100F), 5),
1833 (float)Math.Round(plottingRect.Height / (Position.Height / 100F), 5));
1836 //******************************************************
1837 //** Adjust label font size for axis, which were
1838 //** automatically calculated after the opposite axis
1839 //** change the size of plotting area.
1840 //******************************************************
1841 this.AxisY2.AdjustLabelFontAtSecondPass(chartGraph, InnerPlotPosition.Auto);
1842 this.AxisY.AdjustLabelFontAtSecondPass(chartGraph, InnerPlotPosition.Auto);
1843 if(InnerPlotPosition.Auto)
1845 this.AxisX2.AdjustLabelFontAtSecondPass(chartGraph, InnerPlotPosition.Auto);
1846 this.AxisX.AdjustLabelFontAtSecondPass(chartGraph, InnerPlotPosition.Auto);
1852 /// Finds axis by it's position. Can be Null.
1854 /// <param name="axisPosition">Axis position to find</param>
1855 /// <returns>Found axis.</returns>
1856 private Axis FindAxis(AxisPosition axisPosition)
1858 foreach(Axis axis in this.Axes)
1860 if(axis.AxisPosition == axisPosition)
1869 /// Shift top/bottom labels so they will not overlap with left/right labels.
1871 /// <param name="axis">Axis to shift up/down.</param>
1872 private void PreventTopBottomAxesLabelsOverlapping(Axis axis)
1874 // If axis is not on the edge of the chart area do not
1875 // try to adjust it's position when axis labels overlap
1876 // labels of the oppositie axis.
1877 if( !axis.IsAxisOnAreaEdge )
1882 // Shift bottom axis labels down
1883 if(axis.AxisPosition == AxisPosition.Bottom)
1885 // Get labels position
1886 float labelsPosition = (float)axis.GetAxisPosition();
1887 if( !axis.GetIsMarksNextToAxis() )
1889 labelsPosition = axis.PlotAreaPosition.Bottom;
1892 // Only adjust labels outside plotting area
1893 if(Math.Round(labelsPosition, 2) < Math.Round(axis.PlotAreaPosition.Bottom, 2))
1898 // Check if labels may overlap with Left axis
1899 Axis leftAxis = FindAxis(AxisPosition.Left);
1900 if(leftAxis != null &&
1902 leftAxis.labelFarOffset != 0 &&
1903 leftAxis.labelFarOffset > labelsPosition &&
1904 axis.labelNearOffset != 0 &&
1905 axis.labelNearOffset < PlotAreaPosition.X)
1907 float overlap = (float)(leftAxis.labelFarOffset - labelsPosition) * 0.75f;
1908 if(overlap > axis.markSize)
1910 axis.markSize += overlap - axis.markSize;
1914 // Check if labels may overlap with Right axis
1915 Axis rightAxis = FindAxis(AxisPosition.Right);
1916 if(rightAxis != null &&
1917 rightAxis.enabled &&
1918 rightAxis.labelFarOffset != 0 &&
1919 rightAxis.labelFarOffset > labelsPosition &&
1920 axis.labelFarOffset != 0 &&
1921 axis.labelFarOffset > PlotAreaPosition.Right)
1923 float overlap = (float)(rightAxis.labelFarOffset - labelsPosition) * 0.75f;
1924 if(overlap > axis.markSize)
1926 axis.markSize += overlap - axis.markSize;
1931 // Shift top axis labels up
1932 else if(axis.AxisPosition == AxisPosition.Top)
1934 // Get labels position
1935 float labelsPosition = (float)axis.GetAxisPosition();
1936 if( !axis.GetIsMarksNextToAxis() )
1938 labelsPosition = axis.PlotAreaPosition.Y;
1941 // Only adjust labels outside plotting area
1942 if(Math.Round(labelsPosition, 2) < Math.Round(axis.PlotAreaPosition.Y, 2))
1947 // Check if labels may overlap with Left axis
1948 Axis leftAxis = FindAxis(AxisPosition.Left);
1949 if(leftAxis != null &&
1951 leftAxis.labelNearOffset != 0 &&
1952 leftAxis.labelNearOffset < labelsPosition &&
1953 axis.labelNearOffset != 0 &&
1954 axis.labelNearOffset < PlotAreaPosition.X)
1956 float overlap = (float)(labelsPosition - leftAxis.labelNearOffset) * 0.75f;
1957 if(overlap > axis.markSize)
1959 axis.markSize += overlap - axis.markSize;
1963 // Check if labels may overlap with Right axis
1964 Axis rightAxis = FindAxis(AxisPosition.Right);
1965 if(rightAxis != null &&
1966 rightAxis.enabled &&
1967 rightAxis.labelNearOffset != 0 &&
1968 rightAxis.labelNearOffset < labelsPosition &&
1969 axis.labelFarOffset != 0 &&
1970 axis.labelFarOffset > PlotAreaPosition.Right)
1972 float overlap = (float)(labelsPosition - rightAxis.labelNearOffset) * 0.75f;
1973 if(overlap > axis.markSize)
1975 axis.markSize += overlap - axis.markSize;
1984 #region Painting and Selection Methods
1987 /// Draws chart area background and/or border.
1989 /// <param name="graph">Chart graphics.</param>
1990 /// <param name="position">Background position.</param>
1991 /// <param name="borderOnly">Draws chart area border only.</param>
1992 private void PaintAreaBack(ChartGraphics graph, RectangleF position, bool borderOnly)
1997 if(!this.Area3DStyle.Enable3D || !requireAxes || chartAreaIsCurcular)
1999 // 3D Pie Chart doesn't need scene
2000 // Draw 2D background
2001 graph.FillRectangleRel(
2007 BackImageTransparentColor,
2011 (requireAxes) ? Color.Empty : BorderColor,
2012 (requireAxes) ? 0 : BorderWidth,
2016 PenAlignment.Outset,
2017 chartAreaIsCurcular,
2018 (chartAreaIsCurcular && this.CircularUsePolygons) ? this.CircularSectorsNumber : 0,
2019 this.Area3DStyle.Enable3D);
2023 // Draw chart area 3D scene
2024 this.DrawArea3DScene(graph, position);
2029 if(!this.Area3DStyle.Enable3D || !requireAxes || chartAreaIsCurcular)
2031 // Draw chart area border
2032 if(BorderColor != Color.Empty && BorderWidth > 0)
2034 graph.FillRectangleRel( position,
2036 ChartHatchStyle.None,
2038 ChartImageWrapMode.Tile,
2040 ChartImageAlignmentStyle.Center,
2048 PenAlignment.Outset,
2049 chartAreaIsCurcular,
2050 (chartAreaIsCurcular && this.CircularUsePolygons) ? this.CircularSectorsNumber : 0,
2051 this.Area3DStyle.Enable3D);
2059 /// Paint the chart area.
2061 /// <param name="graph">Chart graphics.</param>
2062 internal void Paint( ChartGraphics graph )
2064 // Check if plot area position was recalculated.
2065 // If not and non-auto InnerPlotPosition & Position were
2066 // specified - do all needed calculations
2067 if (PlotAreaPosition.Width == 0 &&
2068 PlotAreaPosition.Height == 0 &&
2069 !InnerPlotPosition.Auto
2072 // Initialize plotting area position
2073 RectangleF plottingRect = Position.ToRectangleF();
2074 if (!InnerPlotPosition.Auto)
2076 plottingRect.X += (Position.Width / 100F) * InnerPlotPosition.X;
2077 plottingRect.Y += (Position.Height / 100F) * InnerPlotPosition.Y;
2078 plottingRect.Width = (Position.Width / 100F) * InnerPlotPosition.Width;
2079 plottingRect.Height = (Position.Height / 100F) * InnerPlotPosition.Height;
2082 PlotAreaPosition.FromRectangleF(plottingRect);
2085 // Get background position rectangle.
2086 RectangleF backgroundPositionWithScrollBars = GetBackgroundPosition(true);
2087 RectangleF backgroundPosition = GetBackgroundPosition(false);
2089 // Add hot region for plotting area.
2090 if (Common.ProcessModeRegions)
2092 Common.HotRegionsList.AddHotRegion(backgroundPosition, this, ChartElementType.PlottingArea, true);
2095 PaintAreaBack(graph, backgroundPositionWithScrollBars, false);
2097 // Call BackPaint event
2098 Common.Chart.CallOnPrePaint(new ChartPaintEventArgs(this, graph, Common, PlotAreaPosition));
2100 // Draw chart types without axes - Pie.
2101 if (!requireAxes && ChartTypes.Count != 0)
2103 // Find first chart type that do not require axis (like Pie) and draw it.
2104 // Chart types that do not require axes (circular charts) cannot be combined with
2105 // any other chart types.
2106 // NOTE: Fixes issues #4672 and #4692
2107 for (int chartTypeIndex = 0; chartTypeIndex < ChartTypes.Count; chartTypeIndex++)
2109 IChartType chartType = Common.ChartTypeRegistry.GetChartType((string)ChartTypes[chartTypeIndex]);
2110 if (!chartType.RequireAxes)
2112 chartType.Paint(graph, Common, this, null);
2118 Common.Chart.CallOnPostPaint(new ChartPaintEventArgs(this, graph, Common, PlotAreaPosition));
2124 // Reset Smart Labels
2125 this.smartLabels.Reset();
2129 // Set values for optimized drawing
2130 foreach (Axis currentAxis in this._axisArray)
2132 currentAxis.optimizedGetPosition = true;
2133 currentAxis.paintViewMax = currentAxis.ViewMaximum;
2134 currentAxis.paintViewMin = currentAxis.ViewMinimum;
2135 currentAxis.paintRange = currentAxis.paintViewMax - currentAxis.paintViewMin;
2136 currentAxis.paintAreaPosition = PlotAreaPosition.ToRectangleF();
2137 if (currentAxis.ChartArea != null && currentAxis.ChartArea.chartAreaIsCurcular)
2139 // Update position for circular chart area
2140 currentAxis.paintAreaPosition.Width /= 2.0f;
2141 currentAxis.paintAreaPosition.Height /= 2.0f;
2143 currentAxis.paintAreaPositionBottom = currentAxis.paintAreaPosition.Y + currentAxis.paintAreaPosition.Height;
2144 currentAxis.paintAreaPositionRight = currentAxis.paintAreaPosition.X + currentAxis.paintAreaPosition.Width;
2145 if (currentAxis.AxisPosition == AxisPosition.Top || currentAxis.AxisPosition == AxisPosition.Bottom)
2146 currentAxis.paintChartAreaSize = currentAxis.paintAreaPosition.Width;
2148 currentAxis.paintChartAreaSize = currentAxis.paintAreaPosition.Height;
2150 currentAxis.valueMultiplier = 0.0;
2151 if (currentAxis.paintRange != 0)
2153 currentAxis.valueMultiplier = currentAxis.paintChartAreaSize / currentAxis.paintRange;
2157 // Draw Axis Striplines (only when StripWidth > 0)
2158 bool useScaleSegments = false;
2159 Axis[] axesArray = new Axis[] { axisY, axisY2, axisX, axisX2 };
2160 foreach (Axis currentAxis in axesArray)
2163 useScaleSegments = (currentAxis.ScaleSegments.Count > 0);
2165 if (!useScaleSegments)
2167 currentAxis.PaintStrips(graph, false);
2172 foreach (AxisScaleSegment scaleSegment in currentAxis.ScaleSegments)
2174 scaleSegment.SetTempAxisScaleAndInterval();
2176 currentAxis.PaintStrips(graph, false);
2178 scaleSegment.RestoreAxisScaleAndInterval();
2184 axesArray = new Axis[] { axisY, axisX2, axisY2, axisX };
2185 foreach (Axis currentAxis in axesArray)
2188 useScaleSegments = (currentAxis.ScaleSegments.Count > 0);
2190 if (!useScaleSegments)
2192 currentAxis.PaintGrids(graph);
2197 foreach (AxisScaleSegment scaleSegment in currentAxis.ScaleSegments)
2199 scaleSegment.SetTempAxisScaleAndInterval();
2201 currentAxis.PaintGrids(graph);
2203 scaleSegment.RestoreAxisScaleAndInterval();
2209 // Draw Axis Striplines (only when StripWidth == 0)
2210 foreach (Axis currentAxis in axesArray)
2213 useScaleSegments = (currentAxis.ScaleSegments.Count > 0);
2215 if (!useScaleSegments)
2217 currentAxis.PaintStrips(graph, true);
2222 foreach (AxisScaleSegment scaleSegment in currentAxis.ScaleSegments)
2224 scaleSegment.SetTempAxisScaleAndInterval();
2226 currentAxis.PaintStrips(graph, true);
2228 scaleSegment.RestoreAxisScaleAndInterval();
2234 // Draw Axis elements on the back of the 3D scene
2235 if (this.Area3DStyle.Enable3D && !this.chartAreaIsCurcular)
2237 foreach (Axis currentAxis in axesArray)
2240 useScaleSegments = (currentAxis.ScaleSegments.Count > 0);
2242 if (!useScaleSegments)
2244 currentAxis.PrePaint(graph);
2249 foreach (AxisScaleSegment scaleSegment in currentAxis.ScaleSegments)
2251 scaleSegment.SetTempAxisScaleAndInterval();
2253 currentAxis.PrePaint(graph);
2255 scaleSegment.RestoreAxisScaleAndInterval();
2263 // Draws chart area border
2264 bool borderDrawn = false;
2265 if (this.Area3DStyle.Enable3D || !IsBorderOnTopSeries())
2268 PaintAreaBack(graph, backgroundPosition, true);
2272 if (!this.Area3DStyle.Enable3D || this.chartAreaIsCurcular)
2274 // Drawing in 2D space
2276 // NOTE: Fixes issue #6443 and #5385
2277 // If two chart series of the same type (for example Line) are separated
2278 // by other series (for example Area) the order is not correct.
2279 // Old implementation draws ALL series that belongs to the chart type.
2280 ArrayList typeAndSeries = this.GetChartTypesAndSeriesToDraw();
2282 // Draw series by chart type or by series
2283 foreach (ChartTypeAndSeriesInfo chartTypeInfo in typeAndSeries)
2285 this.IterationCounter = 0;
2286 IChartType type = Common.ChartTypeRegistry.GetChartType(chartTypeInfo.ChartType);
2288 // If 'chartTypeInfo.Series' set to NULL all series of that chart type are drawn at once
2289 type.Paint(graph, Common, this, chartTypeInfo.Series);
2294 // Drawing in 3D space
2295 PaintChartSeries3D(graph);
2298 // Draw area border if it wasn't drawn prior to the series
2301 PaintAreaBack(graph, backgroundPosition, true);
2305 foreach (Axis currentAxis in axesArray)
2308 useScaleSegments = (currentAxis.ScaleSegments.Count > 0);
2310 if (!useScaleSegments)
2312 // Paint axis and Reset temp axis offset for side-by-side charts like column
2313 currentAxis.Paint(graph);
2318 // Some of the axis elements like grid lines and tickmarks
2319 // are drawn for each segment
2320 foreach (AxisScaleSegment scaleSegment in currentAxis.ScaleSegments)
2322 scaleSegment.SetTempAxisScaleAndInterval();
2324 currentAxis.PaintOnSegmentedScalePassOne(graph);
2326 scaleSegment.RestoreAxisScaleAndInterval();
2329 // Other elements like labels, title, axis line are drawn once
2330 currentAxis.PaintOnSegmentedScalePassTwo(graph);
2336 Common.Chart.CallOnPostPaint(new ChartPaintEventArgs(this, graph, Common, PlotAreaPosition));
2338 // Draw axis scale break lines
2339 axesArray = new Axis[] { axisY, axisY2 };
2340 foreach (Axis currentAxis in axesArray)
2342 for (int segmentIndex = 0; segmentIndex < (currentAxis.ScaleSegments.Count - 1); segmentIndex++)
2344 currentAxis.ScaleSegments[segmentIndex].PaintBreakLine(graph, currentAxis.ScaleSegments[segmentIndex + 1]);
2349 // Reset values for optimized drawing
2350 foreach (Axis curentAxis in this._axisArray)
2352 curentAxis.optimizedGetPosition = false;
2355 // Reset preffered number of intervals on the axis
2356 curentAxis.prefferedNumberofIntervals = 5;
2358 // Reset flag that scale segments are used
2359 curentAxis.scaleSegmentsUsed = false;
2366 /// Checks if chart area border should be drawn on top of series.
2368 /// <returns>True if border should be darwn on top.</returns>
2369 private bool IsBorderOnTopSeries()
2371 // For most of the chart types chart area border is drawn on top.
2373 foreach( Series series in this.Common.Chart.Series )
2375 if(series.ChartArea == this.Name)
2377 // It is common for the Bubble and Point chart types to draw markers
2378 // partially outside of the chart area. By drawing the border before
2379 // series we avoiding the possibility of drawing the border line on
2380 // top of the marker.
2381 if(series.ChartType == SeriesChartType.Bubble ||
2382 series.ChartType == SeriesChartType.Point)
2392 /// Paint the chart area cursors.
2394 /// <param name="graph">Chart graphics.</param>
2395 /// <param name="cursorOnly">Indicates that only cursors are redrawn.</param>
2396 [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "These parameters are used when compiling for the Microsoft version of Chart")]
2397 internal void PaintCursors( ChartGraphics graph, bool cursorOnly )
2399 // Cursors and selection are supoorted only in 2D charts
2400 if(this.Area3DStyle.Enable3D == true)
2405 // Do not draw cursor/selection for chart types that do not require axis (like Pie)
2406 if(!this.requireAxes)
2411 // Cursors and selection are not supoorted in circular areas
2412 if(this.chartAreaIsCurcular)
2417 // Do not draw cursor/selection while printing
2418 if(this.Common != null &&
2419 this.Common.ChartPicture != null &&
2420 this.Common.ChartPicture.isPrinting)
2425 // Do not draw cursor/selection when chart area is not visible
2426 // because either width or height is set to zero
2427 if(this.Position.Width == 0f ||
2428 this.Position.Height == 0f)
2433 #if Microsoft_CONTROL
2435 Chart chart = this.Common.Chart;
2436 ChartPicture chartPicture = Common.ChartPicture;
2438 // Check if cursor should be drawn
2439 if(!double.IsNaN(_cursorX.SelectionStart) ||
2440 !double.IsNaN(_cursorX.SelectionEnd) ||
2441 !double.IsNaN(_cursorX.Position) ||
2442 !double.IsNaN(_cursorY.SelectionStart) ||
2443 !double.IsNaN(_cursorY.SelectionEnd) ||
2444 !double.IsNaN(_cursorY.Position))
2447 if(!chartPicture.backgroundRestored &&
2448 !chartPicture.isSelectionMode )
2450 chartPicture.backgroundRestored = true;
2452 Rectangle chartPosition = new Rectangle(0, 0, chartPicture.Width, chartPicture.Height);
2454 // Get chart area position
2455 Rectangle absAreaPlotPosition = Rectangle.Round(graph.GetAbsoluteRectangle(PlotAreaPosition.ToRectangleF()));
2456 int maxCursorWidth = (CursorY.LineWidth > CursorX.LineWidth) ? CursorY.LineWidth + 1 : CursorX.LineWidth + 1;
2457 absAreaPlotPosition.Inflate(maxCursorWidth, maxCursorWidth);
2458 absAreaPlotPosition.Intersect(new Rectangle(0, 0, chart.Width, chart.Height));
2460 // Create area buffer bitmap
2461 if(areaBufferBitmap == null ||
2462 chartPicture.nonTopLevelChartBuffer == null ||
2465 // Dispose previous bitmap
2466 if(areaBufferBitmap != null)
2468 areaBufferBitmap.Dispose();
2469 areaBufferBitmap = null;
2471 if(chartPicture.nonTopLevelChartBuffer != null)
2473 chartPicture.nonTopLevelChartBuffer.Dispose();
2474 chartPicture.nonTopLevelChartBuffer = null;
2478 // Copy chart area plotting rectangle from the chart's dubble buffer image into area dubble buffer image
2479 if(chart.paintBufferBitmap != null)
2481 areaBufferBitmap = chart.paintBufferBitmap.Clone(absAreaPlotPosition, chart.paintBufferBitmap.PixelFormat);
2484 // Copy whole chart from the chart's dubble buffer image into area dubble buffer image
2485 if(chart.paintBufferBitmap != null &&
2486 chart.paintBufferBitmap.Size.Width >= chartPosition.Size.Width &&
2487 chart.paintBufferBitmap.Size.Height >= chartPosition.Size.Height)
2489 chartPicture.nonTopLevelChartBuffer = chart.paintBufferBitmap.Clone(
2490 chartPosition, chart.paintBufferBitmap.PixelFormat);
2494 else if(cursorOnly && chartPicture.nonTopLevelChartBuffer != null)
2496 // Restore previous background
2497 chart.paintBufferBitmapGraphics.DrawImageUnscaled(
2498 chartPicture.nonTopLevelChartBuffer,
2503 // Draw chart area cursors and range selection
2505 _cursorY.Paint(graph);
2506 _cursorX.Paint(graph);
2509 #endif // Microsoft_CONTROL
2515 #region Circular chart area methods
2518 /// Gets a circular chart type interface that belongs to this chart area.
2520 /// <returns>ICircularChartType interface or null.</returns>
2521 internal ICircularChartType GetCircularChartType()
2523 // Get number of sectors in circular chart area
2524 foreach(Series series in this.Common.DataManager.Series)
2526 if(series.IsVisible() && series.ChartArea == this.Name)
2528 ICircularChartType type = Common.ChartTypeRegistry.GetChartType(series.ChartTypeName) as ICircularChartType;;
2539 /// Calculate size of the circular axis labels and sets auto-fit font.
2541 /// <param name="chartGraph">Chart graphics object.</param>
2542 /// <param name="chartAreaPosition">The Chart area position.</param>
2543 /// <param name="plotArea">Plotting area size.</param>
2544 /// <param name="xTitleSize">Size of title on the axis.</param>
2545 /// <param name="yTitleSize">Size of title on the axis.</param>
2546 internal void FitCircularLabels(
2547 ChartGraphics chartGraph,
2548 ElementPosition chartAreaPosition,
2549 ref RectangleF plotArea,
2553 // Check if axis labels are enabled
2554 if(!this.AxisX.LabelStyle.Enabled)
2559 // Get absolute titles size
2560 SizeF titleSize = chartGraph.GetAbsoluteSize(new SizeF(xTitleSize, yTitleSize));
2562 // Get absolute position of area
2563 RectangleF plotAreaRectAbs = chartGraph.GetAbsoluteRectangle( plotArea );
2564 RectangleF areaRectAbs = chartGraph.GetAbsoluteRectangle( chartAreaPosition.ToRectangleF());
2566 // Get absolute markers size and spacing
2567 float spacing = chartGraph.GetAbsolutePoint(new PointF(0, this.AxisX.markSize + Axis.elementSpacing)).Y;
2569 // Get circular axis list
2570 ArrayList axisList = GetCircularAxisList();
2572 // Get circular axis labels style
2573 CircularAxisLabelsStyle labelsStyle = GetCircularAxisLabelsStyle();
2575 //*****************************************************************
2576 //** Calculate the auto-fit font if required
2577 //*****************************************************************
2578 if(this.AxisX.LabelStyle.Enabled && this.AxisX.IsLabelAutoFit)
2580 // Set max auto fit font
2581 this.AxisX.autoLabelFont = Common.ChartPicture.FontCache.GetFont(
2582 this.AxisX.LabelStyle.Font.FontFamily,
2584 this.AxisX.LabelStyle.Font.Style,
2585 GraphicsUnit.Point);
2587 // Get estimated labels size
2588 float labelsSizeEstimate = GetCircularLabelsSize(chartGraph, areaRectAbs, plotAreaRectAbs, titleSize);
2589 labelsSizeEstimate = (float)Math.Min(labelsSizeEstimate * 1.1f, plotAreaRectAbs.Width / 5f);
2590 labelsSizeEstimate += spacing;
2592 // Calculate auto-fit font
2593 this.AxisX.GetCircularAxisLabelsAutoFitFont(chartGraph, axisList, labelsStyle, plotAreaRectAbs, areaRectAbs, labelsSizeEstimate);
2596 //*****************************************************************
2597 //** Shrink plot area size proportionally
2598 //*****************************************************************
2601 float labelsSize = GetCircularLabelsSize(chartGraph, areaRectAbs, plotAreaRectAbs, titleSize);
2603 // Check if change size is smaller than radius
2604 labelsSize = (float)Math.Min(labelsSize, plotAreaRectAbs.Width / 2.5f);
2605 labelsSize += spacing;
2607 plotAreaRectAbs.X += labelsSize;
2608 plotAreaRectAbs.Width -= 2f * labelsSize;
2609 plotAreaRectAbs.Y += labelsSize;
2610 plotAreaRectAbs.Height -= 2f * labelsSize;
2612 // Restrict minimum plot area size
2613 if(plotAreaRectAbs.Width < 1.0f)
2615 plotAreaRectAbs.Width = 1.0f;
2617 if(plotAreaRectAbs.Height < 1.0f)
2619 plotAreaRectAbs.Height = 1.0f;
2622 plotArea = chartGraph.GetRelativeRectangle( plotAreaRectAbs );
2625 //*****************************************************************
2626 //** Set axes labels size
2627 //*****************************************************************
2628 SizeF relativeLabelSize = chartGraph.GetRelativeSize(new SizeF(labelsSize, labelsSize));
2629 this.AxisX.labelSize = relativeLabelSize.Height;
2630 this.AxisX2.labelSize = relativeLabelSize.Height;
2631 this.AxisY.labelSize = relativeLabelSize.Width;
2632 this.AxisY2.labelSize = relativeLabelSize.Width;
2637 /// Calculate size of the circular axis labels.
2639 /// <param name="chartGraph">Chart graphics object.</param>
2640 /// <param name="areaRectAbs">The Chart area position.</param>
2641 /// <param name="plotAreaRectAbs">Plotting area size.</param>
2642 /// <param name="titleSize">Size of title on the axes.</param>
2643 /// <returns>Circulat labels style.</returns>
2644 internal float GetCircularLabelsSize(
2645 ChartGraphics chartGraph,
2646 RectangleF areaRectAbs,
2647 RectangleF plotAreaRectAbs,
2650 // Find current horiz. and vert. spacing between plotting and chart areas
2651 SizeF areaDiff = new SizeF(plotAreaRectAbs.X - areaRectAbs.X, plotAreaRectAbs.Y - areaRectAbs.Y);
2652 areaDiff.Width -= titleSize.Width;
2653 areaDiff.Height -= titleSize.Height;
2655 // Get absolute center of the area
2656 PointF areaCenterAbs = chartGraph.GetAbsolutePoint(this.circularCenter);
2658 // Get circular axis list
2659 ArrayList axisList = GetCircularAxisList();
2661 // Get circular axis labels style
2662 CircularAxisLabelsStyle labelsStyle = GetCircularAxisLabelsStyle();
2664 // Defines on how much (pixels) the circular chart area radius should be reduced
2665 float labelsSize = 0f;
2667 //*****************************************************************
2668 //** Loop through all axis labels
2669 //*****************************************************************
2670 foreach(CircularChartAreaAxis axis in axisList)
2672 //*****************************************************************
2673 //** Measure label text
2674 //*****************************************************************
2675 SizeF textSize = chartGraph.MeasureString(
2676 axis.Title.Replace("\\n", "\n"),
2677 (this.AxisX.autoLabelFont == null) ? this.AxisX.LabelStyle.Font : this.AxisX.autoLabelFont);
2678 textSize.Width = (float)Math.Ceiling(textSize.Width * 1.1f);
2679 textSize.Height = (float)Math.Ceiling(textSize.Height * 1.1f);
2682 //*****************************************************************
2683 //** Calculate area size change depending on labels style
2684 //*****************************************************************
2685 if(labelsStyle == CircularAxisLabelsStyle.Circular)
2687 labelsSize = (float)Math.Max(
2691 else if(labelsStyle == CircularAxisLabelsStyle.Radial)
2693 float textAngle = axis.AxisPosition + 90;
2695 // For angled text find it's X and Y components
2696 float width = (float)Math.Cos(textAngle/180F*Math.PI) * textSize.Width;
2697 float height = (float)Math.Sin(textAngle/180F*Math.PI) * textSize.Width;
2698 width = (float)Math.Abs(Math.Ceiling(width));
2699 height = (float)Math.Abs(Math.Ceiling(height));
2701 // Reduce text size by current spacing between plotting area and chart area
2702 width -= areaDiff.Width;
2703 height -= areaDiff.Height;
2710 labelsSize = (float)Math.Max(
2712 Math.Max(width, height));
2714 else if(labelsStyle == CircularAxisLabelsStyle.Horizontal)
2717 float textAngle = axis.AxisPosition;
2718 if(textAngle > 180f)
2723 // Get label rotated position
2724 PointF[] labelPosition = new PointF[] { new PointF(areaCenterAbs.X, plotAreaRectAbs.Y) };
2725 Matrix newMatrix = new Matrix();
2726 newMatrix.RotateAt(textAngle, areaCenterAbs);
2727 newMatrix.TransformPoints(labelPosition);
2730 float width = textSize.Width;
2731 width -= areaRectAbs.Right - labelPosition[0].X;
2737 labelsSize = (float)Math.Max(
2739 Math.Max(width, textSize.Height));
2747 /// True if polygons should be used instead of the circles for the chart area.
2749 internal bool CircularUsePolygons
2753 // Check if value was precalculated
2754 if(this._circularUsePolygons == int.MinValue)
2756 _circularUsePolygons = 0;
2758 // Look for custom properties in series
2759 foreach(Series series in this.Common.DataManager.Series)
2761 if(series.ChartArea == this.Name && series.IsVisible())
2763 // Get custom attribute
2764 if (series.IsCustomPropertySet(CustomPropertyName.AreaDrawingStyle))
2766 if(String.Compare(series[CustomPropertyName.AreaDrawingStyle], "Polygon", StringComparison.OrdinalIgnoreCase) == 0)
2768 _circularUsePolygons = 1;
2770 else if (String.Compare(series[CustomPropertyName.AreaDrawingStyle], "Circle", StringComparison.OrdinalIgnoreCase) == 0)
2772 _circularUsePolygons = 0;
2776 throw(new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid( series[CustomPropertyName.AreaDrawingStyle], "AreaDrawingStyle")));
2784 return (this._circularUsePolygons == 1);
2789 /// Gets circular area axis labels style.
2791 /// <returns>Axis labels style.</returns>
2792 internal CircularAxisLabelsStyle GetCircularAxisLabelsStyle()
2794 CircularAxisLabelsStyle style = CircularAxisLabelsStyle.Auto;
2796 // Get maximum number of points in all series
2797 foreach(Series series in this.Common.DataManager.Series)
2799 if(series.IsVisible() && series.ChartArea == this.Name && series.IsCustomPropertySet(CustomPropertyName.CircularLabelsStyle))
2801 string styleName = series[CustomPropertyName.CircularLabelsStyle];
2802 if(String.Compare( styleName, "Auto", StringComparison.OrdinalIgnoreCase) == 0 )
2804 style = CircularAxisLabelsStyle.Auto;
2806 else if(String.Compare( styleName,"Circular", StringComparison.OrdinalIgnoreCase) == 0)
2808 style = CircularAxisLabelsStyle.Circular;
2810 else if(String.Compare( styleName,"Radial", StringComparison.OrdinalIgnoreCase) == 0)
2812 style = CircularAxisLabelsStyle.Radial;
2814 else if (String.Compare(styleName, "Horizontal", StringComparison.OrdinalIgnoreCase) == 0)
2816 style = CircularAxisLabelsStyle.Horizontal;
2820 throw(new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid( styleName, "CircularLabelsStyle")));
2827 if(style == CircularAxisLabelsStyle.Auto)
2829 int sectorNumber = CircularSectorsNumber;
2830 style = CircularAxisLabelsStyle.Horizontal;
2831 if(sectorNumber > 30)
2833 style = CircularAxisLabelsStyle.Radial;
2841 /// Number of sectors in the circular area.
2843 internal int CircularSectorsNumber
2847 // Check if value was precalculated
2848 if(this._circularSectorNumber == int.MinValue)
2850 this._circularSectorNumber = GetCircularSectorNumber();
2853 return this._circularSectorNumber;
2858 /// Gets number of sectors in the circular chart area.
2860 /// <returns>Number of sectors.</returns>
2861 private int GetCircularSectorNumber()
2863 ICircularChartType type = this.GetCircularChartType();
2866 return type.GetNumerOfSectors(this, this.Common.DataManager.Series);
2872 /// Fills a list of circular axis.
2874 /// <returns>Axes list.</returns>
2875 internal ArrayList GetCircularAxisList()
2877 // Check if list was already created
2878 if(_circularAxisList == null)
2880 _circularAxisList = new ArrayList();
2882 // Loop through all sectors
2883 int sectorNumber = GetCircularSectorNumber();
2884 for(int sectorIndex = 0; sectorIndex < sectorNumber; sectorIndex++)
2886 // Create new axis object
2887 CircularChartAreaAxis axis = new CircularChartAreaAxis(sectorIndex * 360f/sectorNumber);
2889 // Check if custom X axis labels will be used
2890 if(this.AxisX.CustomLabels.Count > 0)
2892 if(sectorIndex < this.AxisX.CustomLabels.Count)
2894 axis.Title = this.AxisX.CustomLabels[sectorIndex].Text;
2895 axis.TitleForeColor = this.AxisX.CustomLabels[sectorIndex].ForeColor;
2900 // Get axis title from all series
2901 foreach(Series series in this.Common.DataManager.Series)
2903 if(series.IsVisible() && series.ChartArea == this.Name && sectorIndex < series.Points.Count)
2905 if(series.Points[sectorIndex].AxisLabel.Length > 0)
2907 axis.Title = series.Points[sectorIndex].AxisLabel;
2914 // Add axis into the list
2915 _circularAxisList.Add(axis);
2919 return _circularAxisList;
2923 /// Converts circular position of the X axis to angle in degrees.
2925 /// <param name="position">X axis position.</param>
2926 /// <returns>Angle in degrees.</returns>
2927 internal float CircularPositionToAngle(double position)
2929 // Get X axis scale size
2930 double scaleRatio = 360.0 / Math.Abs(this.AxisX.Maximum - this.AxisX.Minimum);
2932 return (float)(position * scaleRatio + this.AxisX.Crossing);
2937 #region 2D Series drawing order methods
2940 /// Helper method that returns a list of 'ChartTypeAndSeriesInfo' objects.
2941 /// This list is used for chart area series drawing in 2D mode. Each
2942 /// object may represent an individual series or all series that belong
2943 /// to one chart type.
2945 /// This method is intended to fix issues #6443 and #5385 when area chart
2946 /// type incorrectly overlaps point or line chart type.
2948 /// <returns>List of 'ChartTypeAndSeriesInfo' objects.</returns>
2949 private ArrayList GetChartTypesAndSeriesToDraw()
2951 ArrayList resultList = new ArrayList();
2953 // Build chart type or series position based lists
2954 if (this.ChartTypes.Count > 1 &&
2955 (this.ChartTypes.Contains(ChartTypeNames.Area)
2956 || this.ChartTypes.Contains(ChartTypeNames.SplineArea)
2960 // Array of chart type names that do not require furher processing
2961 ArrayList processedChartType = new ArrayList();
2962 ArrayList splitChartType = new ArrayList();
2964 // Draw using the exact order in the series collection
2965 int seriesIndex = 0;
2966 foreach (Series series in this.Common.DataManager.Series)
2968 // Check if series is visible and belongs to the chart area
2969 if (series.ChartArea==this.Name && series.IsVisible() && series.Points.Count > 0)
2971 // Check if this chart type was already processed
2972 if (!processedChartType.Contains(series.ChartTypeName))
2974 // Check if curent chart type can be individually processed
2975 bool canBeIndividuallyProcessed = false;
2976 if (series.ChartType == SeriesChartType.Point ||
2977 series.ChartType == SeriesChartType.Line ||
2978 series.ChartType == SeriesChartType.Spline ||
2979 series.ChartType == SeriesChartType.StepLine)
2981 canBeIndividuallyProcessed = true;
2984 if (!canBeIndividuallyProcessed)
2986 // Add a record to process all series of that chart type at once
2987 resultList.Add(new ChartTypeAndSeriesInfo(series.ChartTypeName));
2988 processedChartType.Add(series.ChartTypeName);
2992 // Check if curent chart type has more that 1 series and they are split
2994 bool chartTypeIsSplit = false;
2996 if (splitChartType.Contains(series.ChartTypeName))
2998 chartTypeIsSplit = true;
3002 bool otherChartTypeFound = false;
3003 for (int curentSeriesIndex = seriesIndex + 1; curentSeriesIndex < this.Common.DataManager.Series.Count; curentSeriesIndex++)
3005 if (series.ChartTypeName == this.Common.DataManager.Series[curentSeriesIndex].ChartTypeName)
3007 if (otherChartTypeFound)
3009 chartTypeIsSplit = true;
3010 splitChartType.Add(series.ChartTypeName);
3015 if (this.Common.DataManager.Series[curentSeriesIndex].ChartType == SeriesChartType.Area ||
3016 this.Common.DataManager.Series[curentSeriesIndex].ChartType == SeriesChartType.SplineArea)
3018 otherChartTypeFound = true;
3024 if (chartTypeIsSplit)
3026 // Add a record to process this series individually
3027 resultList.Add(new ChartTypeAndSeriesInfo(series));
3031 // Add a record to process all series of that chart type at once
3032 resultList.Add(new ChartTypeAndSeriesInfo(series.ChartTypeName));
3033 processedChartType.Add(series.ChartTypeName);
3044 foreach (string chartType in this.ChartTypes)
3046 resultList.Add(new ChartTypeAndSeriesInfo(chartType));
3054 /// Internal data structure that stores chart type name and optionally series object.
3056 internal class ChartTypeAndSeriesInfo
3059 /// Object constructor.
3061 public ChartTypeAndSeriesInfo()
3066 /// Object constructor.
3068 /// <param name="chartType">Chart type name to initialize with.</param>
3069 public ChartTypeAndSeriesInfo(string chartType)
3071 this.ChartType = chartType;
3075 /// Object constructor.
3077 /// <param name="series">Series to initialize with.</param>
3078 public ChartTypeAndSeriesInfo(Series series)
3080 this.ChartType = series.ChartTypeName;
3081 this.Series = series;
3085 internal string ChartType = string.Empty;
3087 // Series object. Can be set to NULL!
3088 internal Series Series = null;
3092 #endregion // 2D Series drawing order methods
3094 #region IDisposable Members
3097 /// Releases unmanaged and - optionally - managed resources
3099 /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
3100 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "axisX")]
3101 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "axisX2")]
3102 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "axisY")]
3103 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "axisY2")]
3104 protected override void Dispose(bool disposing)
3108 // Dispose managed resources
3109 if (this._axisArray != null)
3111 foreach (Axis axis in this._axisArray)
3115 this._axisArray = null;
3117 if ( this._areaPosition != null)
3119 this._areaPosition.Dispose();
3120 this._areaPosition = null;
3122 if (this._innerPlotPosition != null)
3124 this._innerPlotPosition.Dispose();
3125 this._innerPlotPosition = null;
3127 if (this.PlotAreaPosition != null)
3129 this.PlotAreaPosition.Dispose();
3130 this.PlotAreaPosition = null;
3132 #if Microsoft_CONTROL
3133 if (this.areaBufferBitmap != null)
3135 this.areaBufferBitmap.Dispose();
3136 this.areaBufferBitmap = null;
3138 if (this._cursorX != null)
3140 this._cursorX.Dispose();
3141 this._cursorX = null;
3143 if (this._cursorY != null)
3145 this._cursorY.Dispose();
3146 this._cursorY = null;
3150 base.Dispose(disposing);