|
//-------------------------------------------------------------
// <copyright company=’Microsoft Corporation’>
// Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
// File: LabelStyle.cs
//
// Namespace: DataVisualization.Charting
//
// Classes: CustomLabelsCollection, CustomLabel, LabelStyle
//
// Purpose: LabelStyle and CustomLabel classes are used to determine
// chart axis labels. Labels can be automatically
// generated based on the series data or be “manually”
// set by the user.
//
// Reviewed: AG - Jul 31, 2002
// AG - Microsoft 14, 2007
//
//===================================================================
#region Used namespaces
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
#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.Globalization;
using System.ComponentModel.Design.Serialization;
using System.Reflection;
#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.Utilities;
using System.Web.UI.DataVisualization.Charting.ChartTypes;
#endif
#endregion
#if Microsoft_CONTROL
namespace System.Windows.Forms.DataVisualization.Charting
#else
namespace System.Web.UI.DataVisualization.Charting
#endif
{
#region Labels enumerations
/// <summary>
/// An enumeration that specifies a mark for custom labels.
/// </summary>
public enum LabelMarkStyle
{
/// <summary>
/// No label marks are used.
/// </summary>
None,
/// <summary>
/// Labels use side marks.
/// </summary>
SideMark,
/// <summary>
/// Labels use line and side marks.
/// </summary>
LineSideMark,
/// <summary>
/// Draws a box around the label. The box always starts at the axis position.
/// </summary>
Box
};
/// <summary>
/// An enumeration of custom grid lines and tick marks flags used in the custom labels.
/// </summary>
[Flags]
public enum GridTickTypes
{
/// <summary>
/// No tick mark or grid line are shown.
/// </summary>
None = 0,
/// <summary>
/// Tick mark is shown.
/// </summary>
TickMark = 1,
/// <summary>
/// Grid line is shown.
/// </summary>
Gridline = 2,
/// <summary>
/// Tick mark and grid line are shown.
/// </summary>
All = TickMark | Gridline
}
/// <summary>
/// An enumeration of label styles for circular chart area axis.
/// </summary>
internal enum CircularAxisLabelsStyle
{
/// <summary>
/// Style depends on number of labels.
/// </summary>
Auto,
/// <summary>
/// Label text positions around the circular area.
/// </summary>
Circular,
/// <summary>
/// Label text is always horizontal.
/// </summary>
Horizontal,
/// <summary>
/// Label text has the same angle as circular axis.
/// </summary>
Radial
}
#endregion
/// <summary>
/// The CustomLabelsCollection class is a strongly typed collection of
/// custom axis labels.
/// </summary>
[
SRDescription("DescriptionAttributeCustomLabelsCollection_CustomLabelsCollection"),
]
#if ASPPERM_35
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
public class CustomLabelsCollection : ChartElementCollection<CustomLabel>
{
#region Constructors
/// <summary>
/// Custom labels collection object constructor
/// </summary>
/// <param name="axis">Reference to the axis object.</param>
internal CustomLabelsCollection(Axis axis) : base(axis)
{
}
#endregion
#region Properties
internal Axis Axis
{
get { return Parent as Axis; }
}
#endregion
#region Labels adding methods
/// <summary>
/// Adds a custom label into the collection.
/// </summary>
/// <param name="fromPosition">Label left position.</param>
/// <param name="toPosition">Label right position.</param>
/// <param name="text">Label text.</param>
/// <returns>Newly added item.</returns>
public CustomLabel Add(double fromPosition, double toPosition, string text)
{
CustomLabel label = new CustomLabel(fromPosition, toPosition, text, 0, LabelMarkStyle.None);
Add(label);
return label;
}
/// <summary>
/// Adds one custom label into the collection. Custom label flag may be specified.
/// </summary>
/// <param name="fromPosition">Label left position.</param>
/// <param name="toPosition">Label right position.</param>
/// <param name="text">Label text.</param>
/// <param name="customLabel">Indicates if label is custom (created by user).</param>
/// <returns>Newly added item.</returns>
internal CustomLabel Add(double fromPosition, double toPosition, string text, bool customLabel)
{
CustomLabel label = new CustomLabel(fromPosition, toPosition, text, 0, LabelMarkStyle.None);
label.customLabel = customLabel;
Add(label);
return label;
}
/// <summary>
/// Adds a custom label into the collection.
/// </summary>
/// <param name="fromPosition">Label left position.</param>
/// <param name="toPosition">Label right position.</param>
/// <param name="text">Label text.</param>
/// <param name="rowIndex">Label row index.</param>
/// <param name="markStyle">Label marking style.</param>
/// <returns>Newly added item.</returns>
public CustomLabel Add(double fromPosition, double toPosition, string text, int rowIndex, LabelMarkStyle markStyle)
{
CustomLabel label = new CustomLabel(fromPosition, toPosition, text, rowIndex, markStyle);
Add(label);
return label;
}
/// <summary>
/// Adds a custom label into the collection.
/// </summary>
/// <param name="fromPosition">Label left position.</param>
/// <param name="toPosition">Label right position.</param>
/// <param name="text">Label text.</param>
/// <param name="rowIndex">Label row index.</param>
/// <param name="markStyle">Label marking style.</param>
/// <returns>Index of newly added item.</returns>
/// <param name="gridTick">Custom grid line and tick mark flag.</param>
public CustomLabel Add(double fromPosition, double toPosition, string text, int rowIndex, LabelMarkStyle markStyle, GridTickTypes gridTick)
{
CustomLabel label = new CustomLabel(fromPosition, toPosition, text, rowIndex, markStyle, gridTick);
Add(label);
return label;
}
/// <summary>
/// Adds multiple custom labels to the collection.
/// The labels will be DateTime labels with the specified interval type,
/// and will be generated for the axis range that is determined by the minimum and maximum arguments.
/// </summary>
/// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
/// <param name="intervalType">Unit of measurement of the label step.</param>
/// <param name="min">Minimum value..</param>
/// <param name="max">Maximum value..</param>
/// <param name="format">Label text format.</param>
/// <param name="rowIndex">Label row index.</param>
/// <param name="markStyle">Label marking style.</param>
public void Add(double labelsStep, DateTimeIntervalType intervalType, double min, double max, string format, int rowIndex, LabelMarkStyle markStyle)
{
// Find labels range min/max values
if(min == 0.0 &&
max == 0.0 &&
this.Axis != null &&
!double.IsNaN(this.Axis.Minimum) &&
!double.IsNaN(this.Axis.Maximum))
{
min = this.Axis.Minimum;
max = this.Axis.Maximum;
}
double fromX = Math.Min(min, max);
double toX = Math.Max(min, max);
this.SuspendUpdates();
try
{
// Loop through all label points
double labelStart = fromX;
double labelEnd = 0;
while (labelStart < toX)
{
// Determine label end location
if (intervalType == DateTimeIntervalType.Number)
{
labelEnd = labelStart + labelsStep;
}
else if (intervalType == DateTimeIntervalType.Milliseconds)
{
labelEnd = DateTime.FromOADate(labelStart).AddMilliseconds(labelsStep).ToOADate();
}
else if (intervalType == DateTimeIntervalType.Seconds)
{
labelEnd = DateTime.FromOADate(labelStart).AddSeconds(labelsStep).ToOADate();
}
else if (intervalType == DateTimeIntervalType.Minutes)
{
labelEnd = DateTime.FromOADate(labelStart).AddMinutes(labelsStep).ToOADate();
}
else if (intervalType == DateTimeIntervalType.Hours)
{
labelEnd = DateTime.FromOADate(labelStart).AddHours(labelsStep).ToOADate();
}
else if (intervalType == DateTimeIntervalType.Days)
{
labelEnd = DateTime.FromOADate(labelStart).AddDays(labelsStep).ToOADate();
}
else if (intervalType == DateTimeIntervalType.Weeks)
{
labelEnd = DateTime.FromOADate(labelStart).AddDays(7 * labelsStep).ToOADate();
}
else if (intervalType == DateTimeIntervalType.Months)
{
labelEnd = DateTime.FromOADate(labelStart).AddMonths((int)labelsStep).ToOADate();
}
else if (intervalType == DateTimeIntervalType.Years)
{
labelEnd = DateTime.FromOADate(labelStart).AddYears((int)labelsStep).ToOADate();
}
else
{
// Unsupported step type
throw (new ArgumentException(SR.ExceptionAxisLabelsIntervalTypeUnsupported(intervalType.ToString())));
}
if (labelEnd > toX)
{
labelEnd = toX;
}
// Generate label text
ChartValueType valueType = ChartValueType.Double;
if (intervalType != DateTimeIntervalType.Number)
{
if (this.Axis.GetAxisValuesType() == ChartValueType.DateTimeOffset)
valueType = ChartValueType.DateTimeOffset;
else
valueType = ChartValueType.DateTime;
}
string text = ValueConverter.FormatValue(
this.Common.Chart,
this.Axis,
null,
labelStart + (labelEnd - labelStart) / 2,
format,
valueType,
ChartElementType.AxisLabels);
// Add label
CustomLabel label = new CustomLabel(labelStart, labelEnd, text, rowIndex, markStyle);
this.Add(label);
labelStart = labelEnd;
}
}
finally
{
this.ResumeUpdates();
}
}
/// <summary>
/// Adds multiple custom labels to the collection.
/// The labels will be DateTime labels with the specified interval type,
/// and will be generated for the axis range that is determined by the minimum and maximum arguments.
/// </summary>
/// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
/// <param name="intervalType">Unit of measurement of the label step.</param>
public void Add(double labelsStep, DateTimeIntervalType intervalType)
{
Add(labelsStep, intervalType, 0, 0, "", 0, LabelMarkStyle.None);
}
/// <summary>
/// Adds multiple custom labels to the collection.
/// The labels will be DateTime labels with the specified interval type,
/// and will be generated for the axis range that is determined by the minimum and maximum arguments.
/// </summary>
/// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
/// <param name="intervalType">Unit of measurement of the label step.</param>
/// <param name="format">Label text format.</param>
public void Add(double labelsStep, DateTimeIntervalType intervalType, string format)
{
Add(labelsStep, intervalType, 0, 0, format, 0, LabelMarkStyle.None);
}
/// <summary>
/// Adds multiple custom labels to the collection.
/// The labels will be DateTime labels with the specified interval type,
/// and will be generated for the axis range that is determined by the minimum and maximum arguments.
/// </summary>
/// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
/// <param name="intervalType">Unit of measurement of the label step.</param>
/// <param name="format">Label text format.</param>
/// <param name="rowIndex">Label row index.</param>
/// <param name="markStyle">Label marking style.</param>
public void Add(double labelsStep, DateTimeIntervalType intervalType, string format, int rowIndex, LabelMarkStyle markStyle)
{
Add(labelsStep, intervalType, 0, 0, format, rowIndex, markStyle);
}
#endregion
}
/// <summary>
/// The CustomLabel class represents a single custom axis label. Text and
/// position along the axis is provided by the caller.
/// </summary>
[
SRDescription("DescriptionAttributeCustomLabel_CustomLabel"),
DefaultProperty("Text"),
]
#if Microsoft_CONTROL
public class CustomLabel : ChartNamedElement
#else
#if ASPPERM_35
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
public class CustomLabel : ChartNamedElement, IChartMapArea
#endif
{
#region Fields and Constructors
// Private data members, which store properties values
private double _fromPosition = 0;
private double _toPosition = 0;
private string _text = "";
private LabelMarkStyle _labelMark = LabelMarkStyle.None;
private Color _foreColor = Color.Empty;
private Color _markColor = Color.Empty;
private int _labelRowIndex = 0;
// Custom grid lines and tick marks flags
private GridTickTypes _gridTick = GridTickTypes.None;
// Indicates if label was automatically created or cpecified by user (custom)
internal bool customLabel = true;
// Image associated with the label
private string _image = string.Empty;
// Image transparent color
private Color _imageTransparentColor = Color.Empty;
// Label tooltip
private string _tooltip = string.Empty;
private Axis _axis = null;
#if !Microsoft_CONTROL
// URL target of the label image.
private string _imageUrl = string.Empty;
// Other attributes of the label image map area.
private string _imageMapAreaAttributes = string.Empty;
private string _imagePostbackValue = String.Empty;
// Label tooltip
private string _url = string.Empty;
// Other attributes of the label image map area.
private string _mapAreaAttributes = string.Empty;
private string _postbackValue = String.Empty;
#endif // !Microsoft_CONTROL
#endregion
#region Constructors
/// <summary>
/// Default constructor
/// </summary>
public CustomLabel()
{
}
/// <summary>
/// CustomLabel constructor
/// </summary>
/// <param name="fromPosition">From position.</param>
/// <param name="toPosition">To position.</param>
/// <param name="text">Label text.</param>
/// <param name="labelRow">Label row index.</param>
/// <param name="markStyle">Label mark style.</param>
public CustomLabel(double fromPosition, double toPosition, string text, int labelRow, LabelMarkStyle markStyle)
{
this._fromPosition = fromPosition;
this._toPosition = toPosition;
this._text = text;
this._labelRowIndex = labelRow;
this._labelMark = markStyle;
this._gridTick = GridTickTypes.None;
}
/// <summary>
/// CustomLabel constructor
/// </summary>
/// <param name="fromPosition">From position.</param>
/// <param name="toPosition">To position.</param>
/// <param name="text">Label text.</param>
/// <param name="labelRow">Label row index.</param>
/// <param name="markStyle">Label mark style.</param>
/// <param name="gridTick">Custom grid line and tick marks flag.</param>
public CustomLabel(double fromPosition, double toPosition, string text, int labelRow, LabelMarkStyle markStyle, GridTickTypes gridTick)
{
this._fromPosition = fromPosition;
this._toPosition = toPosition;
this._text = text;
this._labelRowIndex = labelRow;
this._labelMark = markStyle;
this._gridTick = gridTick;
}
#endregion
#region Helper methods
/// <summary>
/// Returns a cloned label object.
/// </summary>
/// <returns>Copy of current custom label.</returns>
public CustomLabel Clone()
{
CustomLabel newLabel = new CustomLabel();
newLabel.FromPosition = this.FromPosition;
newLabel.ToPosition = this.ToPosition;
newLabel.Text = this.Text;
newLabel.ForeColor = this.ForeColor;
newLabel.MarkColor = this.MarkColor;
newLabel.RowIndex = this.RowIndex;
newLabel.LabelMark = this.LabelMark;
newLabel.GridTicks = this.GridTicks;
newLabel.ToolTip = this.ToolTip;
newLabel.Tag = this.Tag;
newLabel.Image = this.Image;
newLabel.ImageTransparentColor = this.ImageTransparentColor;
#if !Microsoft_CONTROL
newLabel.Url = this.Url;
newLabel.MapAreaAttributes = this.MapAreaAttributes;
newLabel.ImageUrl = this.ImageUrl;
newLabel.ImageMapAreaAttributes = this.ImageMapAreaAttributes;
#endif // !Microsoft_CONTROL
return newLabel;
}
internal override IChartElement Parent
{
get
{
return base.Parent;
}
set
{
base.Parent = value;
if (value != null)
{
_axis = Parent.Parent as Axis;
}
}
}
/// <summary>
/// Gets the axis to which this object is attached to.
/// </summary>
/// <returns>Axis.</returns>
[
Browsable(false),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
]
public Axis Axis
{
get
{
return _axis;
}
}
#endregion
#region CustomLabel properties
/// <summary>
/// Gets or sets the tooltip of the custom label.
/// </summary>
[
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif //!Microsoft_CONTROL
SRCategory("CategoryAttributeMapArea"),
Bindable(true),
SRDescription("DescriptionAttributeToolTip"),
DefaultValue("")
]
public string ToolTip
{
set
{
this._tooltip = value;
}
get
{
return this._tooltip;
}
}
#if !Microsoft_CONTROL
/// <summary>
/// URL target of the custom label.
/// </summary>
[
SRCategory("CategoryAttributeMapArea"),
Bindable(true),
SRDescription("DescriptionAttributeUrl"),
DefaultValue(""),
PersistenceMode(PersistenceMode.Attribute),
Editor(Editors.UrlValueEditor.Editor, Editors.UrlValueEditor.Base)
]
public string Url
{
set
{
this._url = value;
}
get
{
return this._url;
}
}
/// <summary>
/// Gets or sets the other attributes of the custom label map area.
/// </summary>
[
SRCategory("CategoryAttributeMapArea"),
Bindable(true),
SRDescription("DescriptionAttributeMapAreaAttributes"),
DefaultValue(""),
PersistenceMode(PersistenceMode.Attribute)
]
public string MapAreaAttributes
{
set
{
this._mapAreaAttributes = value;
}
get
{
return this._mapAreaAttributes;
}
}
/// <summary>
/// Gets or sets the postback value which can be processed on a click event.
/// </summary>
/// <value>The value which is passed to a click event as an argument.</value>
[DefaultValue("")]
[SRCategory(SR.Keys.CategoryAttributeMapArea)]
[SRDescription(SR.Keys.DescriptionAttributePostBackValue)]
public string PostBackValue
{
get
{
return this._postbackValue;
}
set
{
this._postbackValue = value;
}
}
/// <summary>
/// Gets or sets the URL target of the custom label image.
/// </summary>
[
SRCategory("CategoryAttributeMapArea"),
Bindable(true),
SRDescription("DescriptionAttributeCustomLabel_ImageUrl"),
DefaultValue(""),
PersistenceMode(PersistenceMode.Attribute),
Editor(Editors.UrlValueEditor.Editor, Editors.UrlValueEditor.Base),
System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")
]
public string ImageUrl
{
set
{
this._imageUrl = value;
}
get
{
return this._imageUrl;
}
}
/// <summary>
/// Gets or sets the other attributes of the map area of the custom label image.
/// </summary>
[
SRCategory("CategoryAttributeMapArea"),
Bindable(true),
SRDescription("DescriptionAttributeMapAreaAttributes"),
DefaultValue(""),
PersistenceMode(PersistenceMode.Attribute)
]
public string ImageMapAreaAttributes
{
set
{
this._imageMapAreaAttributes = value;
}
get
{
return this._imageMapAreaAttributes;
}
}
/// <summary>
/// Gets or sets the postback value which can be processed on a click event.
/// </summary>
/// <value>The value which is passed to a click event as an argument.</value>
[DefaultValue("")]
[SRCategory(SR.Keys.CategoryAttributeMapArea)]
[SRDescription(SR.Keys.DescriptionAttributePostBackValue)]
public string ImagePostBackValue
{
get
{
return this._imagePostbackValue;
}
set
{
this._imagePostbackValue = value;
}
}
#endif // !Microsoft_CONTROL
/// <summary>
/// Gets or sets the label image.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(""),
SRDescription("DescriptionAttributeCustomLabel_Image"),
Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif
NotifyParentPropertyAttribute(true)
]
public string Image
{
get
{
return _image;
}
set
{
_image = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets a color which will be replaced with a transparent color while drawing the image.
/// </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 ImageTransparentColor
{
get
{
return _imageTransparentColor;
}
set
{
_imageTransparentColor = value;
this.Invalidate();
}
}
/// <summary>
/// Custom label name. This property is for internal use only.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
SRDescription("DescriptionAttributeCustomLabel_Name"),
DefaultValue("Custom LabelStyle"),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
DesignOnlyAttribute(true),
SerializationVisibilityAttribute(SerializationVisibility.Hidden)
]
public override string Name
{
get
{
return base.Name;
}
set
{
base.Name = value;
}
}
/// <summary>
/// Gets or sets a property which specifies whether
/// custom tick marks and grid lines will be drawn in the center of the label.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(GridTickTypes.None),
SRDescription("DescriptionAttributeCustomLabel_GridTicks"),
Editor(Editors.FlagsEnumUITypeEditor.Editor, Editors.FlagsEnumUITypeEditor.Base)
]
public GridTickTypes GridTicks
{
get
{
return _gridTick;
}
set
{
_gridTick = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets the end position of the custom label in axis coordinates.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(0.0),
SRDescription("DescriptionAttributeCustomLabel_From"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif
TypeConverter(typeof(AxisLabelDateValueConverter))
]
public double FromPosition
{
get
{
return _fromPosition;
}
set
{
_fromPosition = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets the starting position of the custom label in axis coordinates.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(0.0),
SRDescription("DescriptionAttributeCustomLabel_To"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif
TypeConverter(typeof(AxisLabelDateValueConverter))
]
public double ToPosition
{
get
{
return _toPosition;
}
set
{
_toPosition = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets the text of the custom label.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(""),
SRDescription("DescriptionAttributeCustomLabel_Text"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public string Text
{
get
{
return _text;
}
set
{
_text = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets the text color of the custom label.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(typeof(Color), ""),
SRDescription("DescriptionAttributeForeColor"),
NotifyParentPropertyAttribute(true),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public Color ForeColor
{
get
{
return _foreColor;
}
set
{
_foreColor = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets the color of the label mark line of the custom label.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(typeof(Color), ""),
SRDescription("DescriptionAttributeCustomLabel_MarkColor"),
NotifyParentPropertyAttribute(true),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public Color MarkColor
{
get
{
return _markColor;
}
set
{
_markColor = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets the row index of the custom label.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(0),
SRDescription("DescriptionAttributeCustomLabel_RowIndex"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public int RowIndex
{
get
{
return this._labelRowIndex;
}
set
{
if(value < 0)
{
throw (new InvalidOperationException(SR.ExceptionAxisLabelRowIndexIsNegative));
}
this._labelRowIndex = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets a property which define the marks for the labels in the second row.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(LabelMarkStyle.None),
SRDescription("DescriptionAttributeCustomLabel_LabelMark"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public LabelMarkStyle LabelMark
{
get
{
return _labelMark;
}
set
{
_labelMark = value;
this.Invalidate();
}
}
#endregion
}
/// <summary>
/// The LabelStyle class contains properties which define the visual appearance of
/// the axis labels, their interval and position. This class is also
/// responsible for calculating the position of all the labels and
/// drawing them.
/// </summary>
[
SRDescription("DescriptionAttributeLabel_Label"),
DefaultProperty("Enabled"),
]
#if ASPPERM_35
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
public class LabelStyle : ChartElement
{
#region Fields
// Reference to the Axis
private Axis _axis = null;
// Private data members, which store properties values
private bool _enabled = true;
internal double intervalOffset = double.NaN;
internal double interval = double.NaN;
internal DateTimeIntervalType intervalType = DateTimeIntervalType.NotSet;
internal DateTimeIntervalType intervalOffsetType = DateTimeIntervalType.NotSet;
private FontCache _fontCache = new FontCache();
private Font _font;
private Color _foreColor = Color.Black;
internal int angle = 0;
internal bool isStaggered = false;
private bool _isEndLabelVisible = true;
private bool _truncatedLabels = false;
private string _format = "";
#endregion
#region Constructors
/// <summary>
/// Public default constructor.
/// </summary>
public LabelStyle()
{
_font = _fontCache.DefaultFont;
}
/// <summary>
/// Public constructor.
/// </summary>
/// <param name="axis">Axis which owns the grid.</param>
internal LabelStyle(Axis axis)
: this()
{
_axis = axis;
}
#endregion
#region Axis labels drawing methods
/// <summary>
/// Draws axis labels on the circular chart area.
/// </summary>
/// <param name="graph">Reference to the Chart Graphics object.</param>
internal void PaintCircular( ChartGraphics graph )
{
// Label string drawing format
using (StringFormat format = new StringFormat())
{
format.FormatFlags |= StringFormatFlags.LineLimit;
format.Trimming = StringTrimming.EllipsisCharacter;
// Labels are disabled for this axis
if (!_axis.LabelStyle.Enabled)
return;
// Draw text with anti-aliasing
/*
if( (graph.AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
{
graph.TextRenderingHint = TextRenderingHint.AntiAlias;
}
else
{
graph.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
}
*/
// Gets axis labels style
CircularAxisLabelsStyle labelsStyle = this._axis.ChartArea.GetCircularAxisLabelsStyle();
// Get list of circular axes with labels
ArrayList circularAxes = this._axis.ChartArea.GetCircularAxisList();
// Draw each axis label
int index = 0;
foreach (CircularChartAreaAxis circAxis in circularAxes)
{
if (circAxis.Title.Length > 0)
{
//******************************************************************
//** Calculate label position corner position
//******************************************************************
PointF labelRelativePosition = new PointF(
this._axis.ChartArea.circularCenter.X,
this._axis.ChartArea.PlotAreaPosition.Y);
// Adjust labels Y position
labelRelativePosition.Y -= _axis.markSize + Axis.elementSpacing;
// Convert to absolute
PointF[] labelPosition = new PointF[] { graph.GetAbsolutePoint(labelRelativePosition) };
// Get label rotation angle
float labelAngle = circAxis.AxisPosition;
ICircularChartType chartType = this._axis.ChartArea.GetCircularChartType();
if (chartType != null && chartType.XAxisCrossingSupported())
{
if (!double.IsNaN(this._axis.ChartArea.AxisX.Crossing))
{
labelAngle += (float)this._axis.ChartArea.AxisX.Crossing;
}
}
// Make sure angle is presented as a positive number
while (labelAngle < 0)
{
labelAngle = 360f + labelAngle;
}
// Set graphics rotation matrix
Matrix newMatrix = new Matrix();
newMatrix.RotateAt(labelAngle, graph.GetAbsolutePoint(this._axis.ChartArea.circularCenter));
newMatrix.TransformPoints(labelPosition);
// Set text alignment
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Near;
if (labelsStyle != CircularAxisLabelsStyle.Radial)
{
if (labelAngle < 5f || labelAngle > 355f)
{
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Far;
}
if (labelAngle < 185f && labelAngle > 175f)
{
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Near;
}
if (labelAngle > 185f && labelAngle < 355f)
{
format.Alignment = StringAlignment.Far;
}
}
else
{
if (labelAngle > 180f)
{
format.Alignment = StringAlignment.Far;
}
}
// Set text rotation angle
float textAngle = labelAngle;
if (labelsStyle == CircularAxisLabelsStyle.Radial)
{
if (labelAngle > 180)
{
textAngle += 90f;
}
else
{
textAngle -= 90f;
}
}
else if (labelsStyle == CircularAxisLabelsStyle.Circular)
{
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Far;
}
// Set text rotation matrix
Matrix oldMatrix = graph.Transform;
if (labelsStyle == CircularAxisLabelsStyle.Radial || labelsStyle == CircularAxisLabelsStyle.Circular)
{
Matrix textRotationMatrix = oldMatrix.Clone();
textRotationMatrix.RotateAt(textAngle, labelPosition[0]);
graph.Transform = textRotationMatrix;
}
// Get axis titl (label) color
Color labelColor = _foreColor;
if (!circAxis.TitleForeColor.IsEmpty)
{
labelColor = circAxis.TitleForeColor;
}
// Draw label
using (Brush brush = new SolidBrush(labelColor))
{
graph.DrawString(
circAxis.Title.Replace("\\n", "\n"),
(_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont,
brush,
labelPosition[0],
format);
}
// Process selection region
if (this._axis.Common.ProcessModeRegions)
{
SizeF size = graph.MeasureString(circAxis.Title.Replace("\\n", "\n"), (_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont);
RectangleF labelRect = GetLabelPosition(
labelPosition[0],
size,
format);
PointF[] points = new PointF[]
{
labelRect.Location,
new PointF(labelRect.Right, labelRect.Y),
new PointF(labelRect.Right, labelRect.Bottom),
new PointF(labelRect.X, labelRect.Bottom)
};
using (GraphicsPath path = new GraphicsPath())
{
path.AddPolygon(points);
path.CloseAllFigures();
path.Transform(graph.Transform);
this._axis.Common.HotRegionsList.AddHotRegion(
path,
false,
ChartElementType.AxisLabels,
circAxis.Title);
}
}
// Restore graphics
if(labelsStyle == CircularAxisLabelsStyle.Radial || labelsStyle == CircularAxisLabelsStyle.Circular)
{
graph.Transform = oldMatrix;
}
}
++index;
}
}
}
/// <summary>
/// Gets rectangle position of the label.
/// </summary>
/// <param name="position">Original label position.</param>
/// <param name="size">Label text size.</param>
/// <param name="format">Label string format.</param>
/// <returns>Label rectangle position.</returns>
internal static RectangleF GetLabelPosition(
PointF position,
SizeF size,
StringFormat format)
{
// Calculate label position rectangle
RectangleF labelPosition = RectangleF.Empty;
labelPosition.Width = size.Width;
labelPosition.Height = size.Height;
if(format.Alignment == StringAlignment.Far)
{
labelPosition.X = position.X - size.Width;
}
else if(format.Alignment == StringAlignment.Near)
{
labelPosition.X = position.X;
}
else if(format.Alignment == StringAlignment.Center)
{
labelPosition.X = position.X - size.Width/2F;
}
if(format.LineAlignment == StringAlignment.Far)
{
labelPosition.Y = position.Y - size.Height;
}
else if(format.LineAlignment == StringAlignment.Near)
{
labelPosition.Y = position.Y;
}
else if(format.LineAlignment == StringAlignment.Center)
{
labelPosition.Y = position.Y - size.Height/2F;
}
return labelPosition;
}
/// <summary>
/// Draws axis labels.
/// </summary>
/// <param name="graph">Reference to the Chart Graphics object.</param>
/// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
internal void Paint( ChartGraphics graph, bool backElements )
{
// Label string drawing format
using (StringFormat format = new StringFormat())
{
format.FormatFlags |= StringFormatFlags.LineLimit;
format.Trimming = StringTrimming.EllipsisCharacter;
// Labels are disabled for this axis
if (!_axis.LabelStyle.Enabled)
return;
// deliant fix-> VSTS #157848, #143286 - drawing custom label in empty axis
if (Double.IsNaN(_axis.ViewMinimum) || Double.IsNaN(_axis.ViewMaximum))
return;
// Draw labels in 3D space
if (this._axis.ChartArea.Area3DStyle.Enable3D && !this._axis.ChartArea.chartAreaIsCurcular)
{
this.Paint3D(graph, backElements);
return;
}
// Initialize all labels position rectangle
RectangleF rectLabels = _axis.ChartArea.Position.ToRectangleF();
float labelSize = _axis.labelSize;
if (_axis.AxisPosition == AxisPosition.Left)
{
rectLabels.Width = labelSize;
if (_axis.GetIsMarksNextToAxis())
rectLabels.X = (float)_axis.GetAxisPosition();
else
rectLabels.X = _axis.PlotAreaPosition.X;
rectLabels.X -= labelSize + _axis.markSize;
// Set label text alignment
format.Alignment = StringAlignment.Far;
format.LineAlignment = StringAlignment.Center;
}
else if (_axis.AxisPosition == AxisPosition.Right)
{
rectLabels.Width = labelSize;
if (_axis.GetIsMarksNextToAxis())
rectLabels.X = (float)_axis.GetAxisPosition();
else
rectLabels.X = _axis.PlotAreaPosition.Right;
rectLabels.X += _axis.markSize;
// Set label text alignment
format.Alignment = StringAlignment.Near;
format.LineAlignment = StringAlignment.Center;
}
else if (_axis.AxisPosition == AxisPosition.Top)
{
rectLabels.Height = labelSize;
if (_axis.GetIsMarksNextToAxis())
rectLabels.Y = (float)_axis.GetAxisPosition();
else
rectLabels.Y = _axis.PlotAreaPosition.Y;
rectLabels.Y -= labelSize + _axis.markSize;
// Set label text alignment
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Far;
}
else if (_axis.AxisPosition == AxisPosition.Bottom)
{
rectLabels.Height = labelSize;
if (_axis.GetIsMarksNextToAxis())
rectLabels.Y = (float)_axis.GetAxisPosition();
else
rectLabels.Y = _axis.PlotAreaPosition.Bottom;
rectLabels.Y += _axis.markSize;
// Set label text alignment
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Near;
}
// Calculate bounding rectangle
RectangleF boundaryRect = rectLabels;
if (boundaryRect != RectangleF.Empty && _axis.totlaGroupingLabelsSize > 0)
{
if (_axis.AxisPosition == AxisPosition.Left)
{
boundaryRect.X += _axis.totlaGroupingLabelsSize;
boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
}
else if (_axis.AxisPosition == AxisPosition.Right)
{
boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
}
else if (_axis.AxisPosition == AxisPosition.Top)
{
boundaryRect.Y += _axis.totlaGroupingLabelsSize;
boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
}
else if (_axis.AxisPosition == AxisPosition.Bottom)
{
boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
}
}
// Check if the AJAX zooming and scrolling mode is enabled.
// Labels are drawn slightly different in this case.
bool ajaxScrollingEnabled = false;
bool firstFrame = true;
bool lastFrame = true;
// Draw all labels from the collection
int labelIndex = 0;
foreach (CustomLabel label in this._axis.CustomLabels)
{
bool truncatedLeft = false;
bool truncatedRight = false;
double labelFrom = label.FromPosition;
double labelTo = label.ToPosition;
bool useRelativeCoordiantes = false;
double labelFromRelative = double.NaN;
double labelToRelative = double.NaN;
// Skip if label middle point is outside current scaleView
if (label.RowIndex == 0)
{
double middlePoint = (label.FromPosition + label.ToPosition) / 2.0;
decimal viewMin = (decimal)_axis.ViewMinimum;
decimal viewMax = (decimal)_axis.ViewMaximum;
if (ajaxScrollingEnabled)
{
// Skip very first and last labels if they are partialy outside the scaleView
if (firstFrame)
{
if ((decimal)label.FromPosition < (decimal)_axis.Minimum)
{
continue;
}
}
if (lastFrame)
{
if ((decimal)label.ToPosition > (decimal)_axis.Maximum)
{
continue;
}
}
// Skip label only if it is compleltly out of the scaleView
if ((decimal)label.ToPosition < viewMin ||
(decimal)label.FromPosition > viewMax)
{
continue;
}
// RecalculateAxesScale label index starting from the first frame.
// Index is used to determine position of the offset labels
if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
{
// Reset index
labelIndex = 0;
// Get first series attached to this axis
Series axisSeries = null;
if (_axis.axisType == AxisName.X || _axis.axisType == AxisName.X2)
{
List<string> seriesArray = _axis.ChartArea.GetXAxesSeries((_axis.axisType == AxisName.X) ? AxisType.Primary : AxisType.Secondary, _axis.SubAxisName);
if (seriesArray.Count > 0)
{
axisSeries = _axis.Common.DataManager.Series[seriesArray[0]];
if (axisSeries != null && !axisSeries.IsXValueIndexed)
{
axisSeries = null;
}
}
}
// Set start position and iterate through label positions
// NOTE: Labels offset should not be taken in the account
double currentPosition = _axis.Minimum;
while (currentPosition < _axis.Maximum)
{
if (currentPosition >= middlePoint)
{
break;
}
currentPosition += ChartHelper.GetIntervalSize(currentPosition, _axis.LabelStyle.GetInterval(), _axis.LabelStyle.GetIntervalType(),
axisSeries, 0.0, DateTimeIntervalType.Number, true);
++labelIndex;
}
}
}
else
{
// Skip label if label middle point is not in the scaleView
if ((decimal)middlePoint < viewMin ||
(decimal)middlePoint > viewMax)
{
continue;
}
}
// Make sure label To and From coordinates are processed by one scale segment based
// on the label middle point position.
if (_axis.ScaleSegments.Count > 0)
{
AxisScaleSegment scaleSegment = _axis.ScaleSegments.FindScaleSegmentForAxisValue(middlePoint);
_axis.ScaleSegments.AllowOutOfScaleValues = true;
_axis.ScaleSegments.EnforceSegment(scaleSegment);
}
// Use center point instead of the To/From if label takes all scaleView
// This is done to avoid issues with labels drawing with high
// zooming levels.
if ((decimal)label.FromPosition < viewMin &&
(decimal)label.ToPosition > viewMax)
{
// Indicates that chart relative coordinates should be used instead of axis values
useRelativeCoordiantes = true;
// Calculate label From/To in relative coordinates using
// label middle point and 100% width.
labelFromRelative = _axis.GetLinearPosition(middlePoint) - 50.0;
labelToRelative = labelFromRelative + 100.0;
}
}
else
{
// Skip labels completly outside the scaleView
if (label.ToPosition <= _axis.ViewMinimum || label.FromPosition >= _axis.ViewMaximum)
{
continue;
}
// Check if label is partially visible.
if (!ajaxScrollingEnabled &&
_axis.ScaleView.IsZoomed)
{
if (label.FromPosition < _axis.ViewMinimum)
{
truncatedLeft = true;
labelFrom = _axis.ViewMinimum;
}
if (label.ToPosition > _axis.ViewMaximum)
{
truncatedRight = true;
labelTo = _axis.ViewMaximum;
}
}
}
// Calculate single label position
RectangleF rect = rectLabels;
// Label is in the first row
if (label.RowIndex == 0)
{
if (_axis.AxisPosition == AxisPosition.Left)
{
rect.X = rectLabels.Right - _axis.unRotatedLabelSize;
rect.Width = _axis.unRotatedLabelSize;
// Adjust label rectangle if offset labels are used
if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
{
rect.Width /= 2F;
if (labelIndex % 2 != 0F)
{
rect.X += rect.Width;
}
}
}
else if (_axis.AxisPosition == AxisPosition.Right)
{
rect.Width = _axis.unRotatedLabelSize;
// Adjust label rectangle if offset labels are used
if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
{
rect.Width /= 2F;
if (labelIndex % 2 != 0F)
{
rect.X += rect.Width;
}
}
}
else if (_axis.AxisPosition == AxisPosition.Top)
{
rect.Y = rectLabels.Bottom - _axis.unRotatedLabelSize;
rect.Height = _axis.unRotatedLabelSize;
// Adjust label rectangle if offset labels are used
if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
{
rect.Height /= 2F;
if (labelIndex % 2 != 0F)
{
rect.Y += rect.Height;
}
}
}
else if (_axis.AxisPosition == AxisPosition.Bottom)
{
rect.Height = _axis.unRotatedLabelSize;
// Adjust label rectangle if offset labels are used
if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
{
rect.Height /= 2F;
if (labelIndex % 2 != 0F)
{
rect.Y += rect.Height;
}
}
}
// Increase label index
++labelIndex;
}
// Label is in the second row
else if (label.RowIndex > 0)
{
if (_axis.AxisPosition == AxisPosition.Left)
{
rect.X += _axis.totlaGroupingLabelsSizeAdjustment;
for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
{
rect.X += _axis.groupingLabelSizes[index - 1];
}
rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
}
else if (_axis.AxisPosition == AxisPosition.Right)
{
rect.X = rect.Right - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;// + Axis.elementSpacing * 0.25f;
for (int index = 1; index < label.RowIndex; index++)
{
rect.X += _axis.groupingLabelSizes[index - 1];
}
rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
}
else if (_axis.AxisPosition == AxisPosition.Top)
{
rect.Y += _axis.totlaGroupingLabelsSizeAdjustment;
for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
{
rect.Y += _axis.groupingLabelSizes[index - 1];
}
rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
}
if (_axis.AxisPosition == AxisPosition.Bottom)
{
rect.Y = rect.Bottom - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;
for (int index = 1; index < label.RowIndex; index++)
{
rect.Y += _axis.groupingLabelSizes[index - 1];
}
rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
}
}
// Unknown label row value
else
{
throw (new InvalidOperationException(SR.ExceptionAxisLabelIndexIsNegative));
}
// Set label From and To coordinates
double fromPosition = _axis.GetLinearPosition(labelFrom);
double toPosition = _axis.GetLinearPosition(labelTo);
if (useRelativeCoordiantes)
{
useRelativeCoordiantes = false;
fromPosition = labelFromRelative;
toPosition = labelToRelative;
}
if (_axis.AxisPosition == AxisPosition.Top || _axis.AxisPosition == AxisPosition.Bottom)
{
rect.X = (float)Math.Min(fromPosition, toPosition);
rect.Width = (float)Math.Max(fromPosition, toPosition) - rect.X;
// Adjust label To/From position if offset labels are used
if (label.RowIndex == 0 &&
((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
{
rect.X -= rect.Width / 2F;
rect.Width *= 2F;
}
}
else
{
rect.Y = (float)Math.Min(fromPosition, toPosition);
rect.Height = (float)Math.Max(fromPosition, toPosition) - rect.Y;
// Adjust label To/From position if offset labels are used
if (label.RowIndex == 0 &&
((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
{
rect.Y -= rect.Height / 2F;
rect.Height *= 2F;
}
}
// Draw label
using (Brush brush = new SolidBrush((label.ForeColor.IsEmpty) ? _foreColor : label.ForeColor))
{
graph.DrawLabelStringRel(_axis,
label.RowIndex,
label.LabelMark,
label.MarkColor,
label.Text,
label.Image,
label.ImageTransparentColor,
(_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont,
brush,
rect,
format,
(_axis.autoLabelAngle < -90) ? angle : _axis.autoLabelAngle,
(!this.TruncatedLabels || label.RowIndex > 0) ? RectangleF.Empty : boundaryRect,
label,
truncatedLeft,
truncatedRight);
}
// Clear scale segment enforcement
_axis.ScaleSegments.EnforceSegment(null);
_axis.ScaleSegments.AllowOutOfScaleValues = false;
}
}
}
#endregion
#region 3D Axis labels drawing methods
/// <summary>
/// Get a rectangle between chart area position and plotting area on specified side.
/// Also sets axis labels string formatting for the specified labels position.
/// </summary>
/// <param name="area">Chart area object.</param>
/// <param name="position">Position in chart area.</param>
/// <param name="stringFormat">Axis labels string format.</param>
/// <returns>Axis labels rectangle.</returns>
private RectangleF GetAllLabelsRect(ChartArea area, AxisPosition position, StringFormat stringFormat)
{
// Find axis with same position
Axis labelsAxis = null;
foreach(Axis curAxis in area.Axes)
{
if(curAxis.AxisPosition == position)
{
labelsAxis = curAxis;
break;
}
}
if(labelsAxis == null)
{
return RectangleF.Empty;
}
// Calculate rect for different positions
RectangleF rectLabels = area.Position.ToRectangleF();
if( position == AxisPosition.Left )
{
rectLabels.Width = labelsAxis.labelSize;
if( labelsAxis.GetIsMarksNextToAxis() )
{
rectLabels.X = (float)labelsAxis.GetAxisPosition();
rectLabels.Width = (float)Math.Max(rectLabels.Width, rectLabels.X - labelsAxis.PlotAreaPosition.X);
}
else
{
rectLabels.X = labelsAxis.PlotAreaPosition.X;
}
rectLabels.X -= rectLabels.Width;
if(area.IsSideSceneWallOnLeft() || area.Area3DStyle.WallWidth == 0)
{
rectLabels.X -= labelsAxis.markSize;
}
// Set label text alignment
stringFormat.Alignment = StringAlignment.Far;
stringFormat.LineAlignment = StringAlignment.Center;
}
else if( position == AxisPosition.Right )
{
rectLabels.Width = labelsAxis.labelSize;
if( labelsAxis.GetIsMarksNextToAxis() )
{
rectLabels.X = (float)labelsAxis.GetAxisPosition();
rectLabels.Width = (float)Math.Max(rectLabels.Width, labelsAxis.PlotAreaPosition.Right - rectLabels.X);
}
else
{
rectLabels.X = labelsAxis.PlotAreaPosition.Right;
}
if(!area.IsSideSceneWallOnLeft() || area.Area3DStyle.WallWidth == 0)
{
rectLabels.X += labelsAxis.markSize;
}
// Set label text alignment
stringFormat.Alignment = StringAlignment.Near;
stringFormat.LineAlignment = StringAlignment.Center;
}
else if( position == AxisPosition.Top )
{
rectLabels.Height = labelsAxis.labelSize;
if( labelsAxis.GetIsMarksNextToAxis() )
{
rectLabels.Y = (float)labelsAxis.GetAxisPosition();
rectLabels.Height = (float)Math.Max(rectLabels.Height, rectLabels.Y - labelsAxis.PlotAreaPosition.Y);
}
else
{
rectLabels.Y = labelsAxis.PlotAreaPosition.Y;
}
rectLabels.Y -= rectLabels.Height;
if(area.Area3DStyle.WallWidth == 0)
{
rectLabels.Y -= labelsAxis.markSize;
}
// Set label text alignment
stringFormat.Alignment = StringAlignment.Center;
stringFormat.LineAlignment = StringAlignment.Far;
}
else if( position == AxisPosition.Bottom )
{
rectLabels.Height = labelsAxis.labelSize;
if( labelsAxis.GetIsMarksNextToAxis() )
{
rectLabels.Y = (float)labelsAxis.GetAxisPosition();
rectLabels.Height = (float)Math.Max(rectLabels.Height, labelsAxis.PlotAreaPosition.Bottom - rectLabels.Y);
}
else
{
rectLabels.Y = labelsAxis.PlotAreaPosition.Bottom;
}
rectLabels.Y += labelsAxis.markSize;
// Set label text alignment
stringFormat.Alignment = StringAlignment.Center;
stringFormat.LineAlignment = StringAlignment.Near;
}
return rectLabels;
}
/// <summary>
/// Gets position of axis labels.
/// Top and Bottom axis labels can be drawn on the sides (left or right)
/// of the plotting area. If angle between axis and it's projection is
/// between -25 and 25 degrees the axis are drawn at the bottom/top,
/// otherwise labels are moved on the left or right side.
/// </summary>
/// <param name="axis">Axis object.</param>
/// <returns>Position where axis labels should be drawn.</returns>
private AxisPosition GetLabelsPosition(Axis axis)
{
// Get angle between 2D axis and it's 3D projection.
double axisAngle = axis.GetAxisProjectionAngle();
// Pick the side to draw the labels on
if(axis.AxisPosition == AxisPosition.Bottom)
{
if(axisAngle <= -25 )
return AxisPosition.Right;
else if(axisAngle >= 25 )
return AxisPosition.Left;
}
else if(axis.AxisPosition == AxisPosition.Top)
{
if(axisAngle <= -25 )
return AxisPosition.Left;
else if(axisAngle >= 25 )
return AxisPosition.Right;
}
// Labels are on the same side as the axis
return axis.AxisPosition;
}
/// <summary>
/// Draws axis labels in 3D space.
/// </summary>
/// <param name="graph">Reference to the Chart Graphics object.</param>
/// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
internal void Paint3D( ChartGraphics graph, bool backElements )
{
// Label string drawing format
using (StringFormat format = new StringFormat())
{
format.Trimming = StringTrimming.EllipsisCharacter;
// Calculate single pixel size in relative coordinates
SizeF pixelSize = graph.GetRelativeSize(new SizeF(1f, 1f));
//********************************************************************
//** Determine the side of the plotting area to draw the labels on.
//********************************************************************
AxisPosition labelsPosition = GetLabelsPosition(_axis);
//*****************************************************************
//** Set the labels Z position
//*****************************************************************
bool axisOnEdge;
float labelsZPosition = _axis.GetMarksZPosition(out axisOnEdge);
// Adjust Z position for the "bent" tick marks
bool adjustForWallWidth = false;
if (this._axis.AxisPosition == AxisPosition.Top &&
!this._axis.ChartArea.ShouldDrawOnSurface(SurfaceNames.Top, backElements, false))
{
adjustForWallWidth = true;
}
if (this._axis.AxisPosition == AxisPosition.Left &&
!this._axis.ChartArea.ShouldDrawOnSurface(SurfaceNames.Left, backElements, false))
{
adjustForWallWidth = true;
}
if (this._axis.AxisPosition == AxisPosition.Right &&
!this._axis.ChartArea.ShouldDrawOnSurface(SurfaceNames.Right, backElements, false))
{
adjustForWallWidth = true;
}
if (adjustForWallWidth && this._axis.ChartArea.Area3DStyle.WallWidth > 0)
{
if (this._axis.MajorTickMark.TickMarkStyle == TickMarkStyle.InsideArea)
{
labelsZPosition -= this._axis.ChartArea.areaSceneWallWidth.Width;
}
else if (this._axis.MajorTickMark.TickMarkStyle == TickMarkStyle.OutsideArea)
{
labelsZPosition -= this._axis.MajorTickMark.Size + this._axis.ChartArea.areaSceneWallWidth.Width;
}
else if (this._axis.MajorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis)
{
labelsZPosition -= this._axis.MajorTickMark.Size / 2f + this._axis.ChartArea.areaSceneWallWidth.Width;
}
}
//*****************************************************************
//** Check if labels should be drawn as back or front element.
//*****************************************************************
bool labelsInsidePlotArea = (this._axis.GetIsMarksNextToAxis() && !axisOnEdge);
if (backElements == labelsInsidePlotArea)
{
// Skip drawing
return;
}
//********************************************************************
//** Initialize all labels position rectangle
//********************************************************************
RectangleF rectLabels = this.GetAllLabelsRect(this._axis.ChartArea, this._axis.AxisPosition, format);
//********************************************************************
//** Calculate bounding rectangle used to truncate labels on the
//** chart area boundary if TruncatedLabels property is set to true.
//********************************************************************
RectangleF boundaryRect = rectLabels;
if (boundaryRect != RectangleF.Empty && _axis.totlaGroupingLabelsSize > 0)
{
if (this._axis.AxisPosition == AxisPosition.Left)
{
boundaryRect.X += _axis.totlaGroupingLabelsSize;
boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
}
else if (this._axis.AxisPosition == AxisPosition.Right)
{
boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
}
else if (this._axis.AxisPosition == AxisPosition.Top)
{
boundaryRect.Y += _axis.totlaGroupingLabelsSize;
boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
}
else if (this._axis.AxisPosition == AxisPosition.Bottom)
{
boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
}
}
// Pre-calculated height of the first labels row
float firstLabelsRowHeight = -1f;
// For 3D axis labels the first row of labels
// has to be drawn after all other rows because
// of hot regions.
for (int selectionRow = 0; selectionRow <= this._axis.GetGroupLabelLevelCount(); selectionRow++)
{
//********************************************************************
//** Draw all labels from the collection
//********************************************************************
int labelIndex = 0;
foreach (CustomLabel label in this._axis.CustomLabels)
{
bool truncatedLeft = false;
bool truncatedRight = false;
double labelFrom = label.FromPosition;
double labelTo = label.ToPosition;
if (label.RowIndex != selectionRow)
{
continue;
}
// Skip if label middle point is outside current scaleView
if (label.RowIndex == 0)
{
double middlePoint = (label.FromPosition + label.ToPosition) / 2.0;
if ((decimal)middlePoint < (decimal)_axis.ViewMinimum ||
(decimal)middlePoint > (decimal)_axis.ViewMaximum)
{
continue;
}
}
else
{
// Skip labels completly outside the scaleView
if (label.ToPosition <= _axis.ViewMinimum || label.FromPosition >= _axis.ViewMaximum)
{
continue;
}
// Check if label is partially visible
if (_axis.ScaleView.IsZoomed)
{
if (label.FromPosition < _axis.ViewMinimum)
{
truncatedLeft = true;
labelFrom = _axis.ViewMinimum;
}
if (label.ToPosition > _axis.ViewMaximum)
{
truncatedRight = true;
labelTo = _axis.ViewMaximum;
}
}
}
// Calculate single label position
RectangleF rect = rectLabels;
// Label is in the first row
if (label.RowIndex == 0)
{
if (this._axis.AxisPosition == AxisPosition.Left)
{
if (!this._axis.GetIsMarksNextToAxis())
{
rect.X = rectLabels.Right - _axis.unRotatedLabelSize;
rect.Width = _axis.unRotatedLabelSize;
}
// Adjust label rectangle if offset labels are used
if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
{
rect.Width /= 2F;
if (labelIndex % 2 != 0F)
{
rect.X += rect.Width;
}
}
}
else if (this._axis.AxisPosition == AxisPosition.Right)
{
if (!this._axis.GetIsMarksNextToAxis())
{
rect.Width = _axis.unRotatedLabelSize;
}
// Adjust label rectangle if offset labels are used
if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
{
rect.Width /= 2F;
if (labelIndex % 2 != 0F)
{
rect.X += rect.Width;
}
}
}
else if (this._axis.AxisPosition == AxisPosition.Top)
{
if (!this._axis.GetIsMarksNextToAxis())
{
rect.Y = rectLabels.Bottom - _axis.unRotatedLabelSize;
rect.Height = _axis.unRotatedLabelSize;
}
// Adjust label rectangle if offset labels are used
if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
{
rect.Height /= 2F;
if (labelIndex % 2 != 0F)
{
rect.Y += rect.Height;
}
}
}
else if (this._axis.AxisPosition == AxisPosition.Bottom)
{
if (!this._axis.GetIsMarksNextToAxis())
{
rect.Height = _axis.unRotatedLabelSize;
}
// Adjust label rectangle if offset labels are used
if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
{
rect.Height /= 2F;
if (labelIndex % 2 != 0F)
{
rect.Y += rect.Height;
}
}
}
// Increase label index
++labelIndex;
}
// Label is in the second row
else if (label.RowIndex > 0)
{
// Hide grouping labels (where index of row > 0) when they are displayed
// not on the same side as their axis. Fixes MS issue #64.
if (labelsPosition != this._axis.AxisPosition)
{
continue;
}
if (_axis.AxisPosition == AxisPosition.Left)
{
rect.X += _axis.totlaGroupingLabelsSizeAdjustment;
for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
{
rect.X += _axis.groupingLabelSizes[index - 1];
}
rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
}
else if (_axis.AxisPosition == AxisPosition.Right)
{
rect.X = rect.Right - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;// + Axis.elementSpacing * 0.25f;
for (int index = 1; index < label.RowIndex; index++)
{
rect.X += _axis.groupingLabelSizes[index - 1];
}
rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
}
else if (_axis.AxisPosition == AxisPosition.Top)
{
rect.Y += _axis.totlaGroupingLabelsSizeAdjustment;
for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
{
rect.Y += _axis.groupingLabelSizes[index - 1];
}
rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
}
if (_axis.AxisPosition == AxisPosition.Bottom)
{
rect.Y = rect.Bottom - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;
for (int index = 1; index < label.RowIndex; index++)
{
rect.Y += _axis.groupingLabelSizes[index - 1];
}
rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
}
}
// Unknown label row value
else
{
throw (new InvalidOperationException(SR.ExceptionAxisLabelRowIndexMustBe1Or2));
}
//********************************************************************
//** Set label From and To coordinates.
//********************************************************************
double fromPosition = _axis.GetLinearPosition(labelFrom);
double toPosition = _axis.GetLinearPosition(labelTo);
if (this._axis.AxisPosition == AxisPosition.Top || this._axis.AxisPosition == AxisPosition.Bottom)
{
rect.X = (float)Math.Min(fromPosition, toPosition);
rect.Width = (float)Math.Max(fromPosition, toPosition) - rect.X;
if (rect.Width < pixelSize.Width)
{
rect.Width = pixelSize.Width;
}
// Adjust label To/From position if offset labels are used
if (label.RowIndex == 0 &&
((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
{
rect.X -= rect.Width / 2F;
rect.Width *= 2F;
}
}
else
{
rect.Y = (float)Math.Min(fromPosition, toPosition);
rect.Height = (float)Math.Max(fromPosition, toPosition) - rect.Y;
if (rect.Height < pixelSize.Height)
{
rect.Height = pixelSize.Height;
}
// Adjust label To/From position if offset labels are used
if (label.RowIndex == 0 &&
((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
{
rect.Y -= rect.Height / 2F;
rect.Height *= 2F;
}
}
// Save original rect
RectangleF initialRect = new RectangleF(rect.Location, rect.Size);
//********************************************************************
//** Transform and adjust label rectangle coordinates in 3D space.
//********************************************************************
Point3D[] rectPoints = new Point3D[3];
if (this._axis.AxisPosition == AxisPosition.Left)
{
rectPoints[0] = new Point3D(rect.Right, rect.Y, labelsZPosition);
rectPoints[1] = new Point3D(rect.Right, rect.Y + rect.Height / 2f, labelsZPosition);
rectPoints[2] = new Point3D(rect.Right, rect.Bottom, labelsZPosition);
this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
rect.Y = rectPoints[0].Y;
rect.Height = rectPoints[2].Y - rect.Y;
rect.Width = rectPoints[1].X - rect.X;
}
else if (this._axis.AxisPosition == AxisPosition.Right)
{
rectPoints[0] = new Point3D(rect.X, rect.Y, labelsZPosition);
rectPoints[1] = new Point3D(rect.X, rect.Y + rect.Height / 2f, labelsZPosition);
rectPoints[2] = new Point3D(rect.X, rect.Bottom, labelsZPosition);
this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
rect.Y = rectPoints[0].Y;
rect.Height = rectPoints[2].Y - rect.Y;
rect.Width = rect.Right - rectPoints[1].X;
rect.X = rectPoints[1].X;
}
else if (this._axis.AxisPosition == AxisPosition.Top)
{
// Transform 3 points of the rectangle
rectPoints[0] = new Point3D(rect.X, rect.Bottom, labelsZPosition);
rectPoints[1] = new Point3D(rect.X + rect.Width / 2f, rect.Bottom, labelsZPosition);
rectPoints[2] = new Point3D(rect.Right, rect.Bottom, labelsZPosition);
this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
if (labelsPosition == AxisPosition.Top)
{
rect.X = rectPoints[0].X;
rect.Width = rectPoints[2].X - rect.X;
rect.Height = rectPoints[1].Y - rect.Y;
}
else if (labelsPosition == AxisPosition.Right)
{
RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
rect.Y = rectPoints[0].Y;
rect.Height = rectPoints[2].Y - rect.Y;
rect.X = rectPoints[1].X;
rect.Width = rightLabelsRect.Right - rect.X;
}
else if (labelsPosition == AxisPosition.Left)
{
RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
rect.Y = rectPoints[2].Y;
rect.Height = rectPoints[0].Y - rect.Y;
rect.X = rightLabelsRect.X;
rect.Width = rectPoints[1].X - rightLabelsRect.X;
}
}
else if (this._axis.AxisPosition == AxisPosition.Bottom)
{
// Transform 3 points of the rectangle
rectPoints[0] = new Point3D(rect.X, rect.Y, labelsZPosition);
rectPoints[1] = new Point3D(rect.X + rect.Width / 2f, rect.Y, labelsZPosition);
rectPoints[2] = new Point3D(rect.Right, rect.Y, labelsZPosition);
this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
if (labelsPosition == AxisPosition.Bottom)
{
rect.X = rectPoints[0].X;
rect.Width = rectPoints[2].X - rect.X;
rect.Height = rect.Bottom - rectPoints[1].Y;
rect.Y = rectPoints[1].Y;
}
else if (labelsPosition == AxisPosition.Right)
{
RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
rect.Y = rectPoints[2].Y;
rect.Height = rectPoints[0].Y - rect.Y;
rect.X = rectPoints[1].X;
rect.Width = rightLabelsRect.Right - rect.X;
// Adjust label rect by shifting it down by quarter of the tick size
if (this._axis.autoLabelAngle == 0)
{
rect.Y += this._axis.markSize / 4f;
}
}
else if (labelsPosition == AxisPosition.Left)
{
RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
rect.Y = rectPoints[0].Y;
rect.Height = rectPoints[2].Y - rect.Y;
rect.X = rightLabelsRect.X;
rect.Width = rectPoints[1].X - rightLabelsRect.X;
// Adjust label rect by shifting it down by quarter of the tick size
if (this._axis.autoLabelAngle == 0)
{
rect.Y += this._axis.markSize / 4f;
}
}
}
// Find axis with same position
Axis labelsAxis = null;
foreach (Axis curAxis in this._axis.ChartArea.Axes)
{
if (curAxis.AxisPosition == labelsPosition)
{
labelsAxis = curAxis;
break;
}
}
//********************************************************************
//** Adjust font angles for Top and Bottom axis
//********************************************************************
int labelsFontAngle = (_axis.autoLabelAngle < -90) ? angle : _axis.autoLabelAngle;
if (labelsPosition != this._axis.AxisPosition)
{
if ((this._axis.AxisPosition == AxisPosition.Top || this._axis.AxisPosition == AxisPosition.Bottom) &&
(labelsFontAngle == 90 || labelsFontAngle == -90))
{
labelsFontAngle = 0;
}
else if (this._axis.AxisPosition == AxisPosition.Bottom)
{
if (labelsPosition == AxisPosition.Left && labelsFontAngle > 0)
{
labelsFontAngle = -labelsFontAngle;
}
else if (labelsPosition == AxisPosition.Right && labelsFontAngle < 0)
{
labelsFontAngle = -labelsFontAngle;
}
}
else if (this._axis.AxisPosition == AxisPosition.Top)
{
if (labelsPosition == AxisPosition.Left && labelsFontAngle < 0)
{
labelsFontAngle = -labelsFontAngle;
}
else if (labelsPosition == AxisPosition.Right && labelsFontAngle > 0)
{
labelsFontAngle = -labelsFontAngle;
}
}
}
//********************************************************************
//** NOTE: Code below improves chart labels readability in scenarios
//** described in MS issue #65.
//**
//** Prevent labels in the first row from overlapping the grouping
//** labels in the rows below. The solution only apply to the limited
//** use cases defined by the condition below.
//********************************************************************
StringFormatFlags oldFormatFlags = format.FormatFlags;
if (label.RowIndex == 0 &&
labelsFontAngle == 0 &&
_axis.groupingLabelSizes != null &&
_axis.groupingLabelSizes.Length > 0 &&
this._axis.AxisPosition == AxisPosition.Bottom &&
labelsPosition == AxisPosition.Bottom &&
!((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
{
if (firstLabelsRowHeight == -1f)
{
// Calculate first labels row max height
Point3D[] labelPositionPoints = new Point3D[1];
labelPositionPoints[0] = new Point3D(initialRect.X, initialRect.Bottom - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment, labelsZPosition);
this._axis.ChartArea.matrix3D.TransformPoints(labelPositionPoints);
float height = labelPositionPoints[0].Y - rect.Y;
firstLabelsRowHeight = (height > 0f) ? height : rect.Height;
}
// Resuse pre-calculated first labels row height
rect.Height = firstLabelsRowHeight;
// Change current string format to prevent strings to go out of the
// specified bounding rectangle
if ((format.FormatFlags & StringFormatFlags.LineLimit) == 0)
{
format.FormatFlags |= StringFormatFlags.LineLimit;
}
}
//********************************************************************
//** Draw label text.
//********************************************************************
using (Brush brush = new SolidBrush((label.ForeColor.IsEmpty) ? _foreColor : label.ForeColor))
{
graph.DrawLabelStringRel(
labelsAxis,
label.RowIndex,
label.LabelMark,
label.MarkColor,
label.Text,
label.Image,
label.ImageTransparentColor,
(_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont,
brush,
rect,
format,
labelsFontAngle,
(!this.TruncatedLabels || label.RowIndex > 0) ? RectangleF.Empty : boundaryRect,
label,
truncatedLeft,
truncatedRight);
}
// Restore old string format that was temporary modified
if (format.FormatFlags != oldFormatFlags)
{
format.FormatFlags = oldFormatFlags;
}
}
}
}
}
#endregion
#region Helper methods
/// <summary>
/// Sets the axis to which this object attached to.
/// </summary>
/// <returns>Axis object.</returns>
internal Axis Axis
{
set { _axis = value; }
}
/// <summary>
/// Invalidate chart picture
/// </summary>
internal override void Invalidate()
{
#if Microsoft_CONTROL
if(this._axis != null)
{
this._axis.Invalidate();
}
#endif
base.Invalidate();
}
#endregion
#region Label properties
/// <summary>
/// Gets or sets the interval offset of the label.
/// </summary>
[
SRCategory("CategoryAttributeData"),
Bindable(true),
SRDescription("DescriptionAttributeLabel_IntervalOffset"),
DefaultValue(Double.NaN),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif
RefreshPropertiesAttribute(RefreshProperties.All),
TypeConverter(typeof(AxisElementIntervalValueConverter))
]
public double IntervalOffset
{
get
{
return intervalOffset;
}
set
{
intervalOffset = value;
this.Invalidate();
}
}
/// <summary>
/// Gets the interval offset.
/// </summary>
/// <returns></returns>
internal double GetIntervalOffset()
{
if(double.IsNaN(intervalOffset) && this._axis != null)
{
return this._axis.IntervalOffset;
}
return intervalOffset;
}
/// <summary>
/// Gets or sets the unit of measurement of the label offset.
/// </summary>
[
SRCategory("CategoryAttributeData"),
Bindable(true),
DefaultValue(DateTimeIntervalType.NotSet),
SRDescription("DescriptionAttributeLabel_IntervalOffsetType"),
RefreshPropertiesAttribute(RefreshProperties.All),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public DateTimeIntervalType IntervalOffsetType
{
get
{
return intervalOffsetType;
}
set
{
intervalOffsetType = value;
this.Invalidate();
}
}
/// <summary>
/// Gets the type of the interval offset.
/// </summary>
/// <returns></returns>
internal DateTimeIntervalType GetIntervalOffsetType()
{
if(intervalOffsetType == DateTimeIntervalType.NotSet && this._axis != null)
{
return this._axis.IntervalOffsetType;
}
return intervalOffsetType;
}
/// <summary>
/// Gets or sets the interval size of the label.
/// </summary>
[
SRCategory("CategoryAttributeData"),
Bindable(true),
DefaultValue(Double.NaN),
SRDescription("DescriptionAttributeLabel_Interval"),
TypeConverter(typeof(AxisElementIntervalValueConverter)),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif
]
public double Interval
{
get
{
return interval;
}
set
{
interval = value;
// Reset original property value fields
if (this._axis != null)
{
this._axis.tempLabelInterval = interval;
}
this.Invalidate();
}
}
/// <summary>
/// Gets the interval.
/// </summary>
/// <returns></returns>
internal double GetInterval()
{
if(double.IsNaN(interval) && this._axis != null)
{
return this._axis.Interval;
}
return interval;
}
/// <summary>
/// Gets or sets the unit of measurement of the interval size of the label.
/// </summary>
[
SRCategory("CategoryAttributeData"),
Bindable(true),
DefaultValue(DateTimeIntervalType.NotSet),
SRDescription("DescriptionAttributeLabel_IntervalType"),
RefreshPropertiesAttribute(RefreshProperties.All),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public DateTimeIntervalType IntervalType
{
get
{
return intervalType;
}
set
{
intervalType = value;
// Reset original property value fields
if (this._axis != null)
{
this._axis.tempLabelIntervalType = intervalType;
}
this.Invalidate();
}
}
/// <summary>
/// Gets the type of the interval.
/// </summary>
/// <returns></returns>
internal DateTimeIntervalType GetIntervalType()
{
if(intervalType == DateTimeIntervalType.NotSet && this._axis != null)
{
return this._axis.IntervalType;
}
return intervalType;
}
/// <summary>
/// Gets or sets the font of the label.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
SRDescription("DescriptionAttributeLabel_Font"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public Font Font
{
get
{
return _font;
}
set
{
// Turn off labels autofitting
if (this._axis != null && this._axis.Common!=null && this._axis.Common.Chart != null)
{
if(!this._axis.Common.Chart.serializing)
{
this._axis.IsLabelAutoFit = false;
}
}
_font = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets the fore color of the label.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(typeof(Color), "Black"),
SRDescription("DescriptionAttributeFontColor"),
NotifyParentPropertyAttribute(true),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public Color ForeColor
{
get
{
return _foreColor;
}
set
{
_foreColor = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets a value that represents the angle at which font is drawn.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(0),
SRDescription("DescriptionAttributeLabel_FontAngle"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif
RefreshPropertiesAttribute(RefreshProperties.All)
]
public int Angle
{
get
{
return angle;
}
set
{
if(value < -90 || value > 90)
{
throw (new ArgumentOutOfRangeException("value", SR.ExceptionAxisLabelFontAngleInvalid));
}
// Turn of label offset if angle is not 0, 90 or -90
if(IsStaggered && value != 0 && value != -90 && value != 90)
{
IsStaggered = false;
}
// Turn off labels autofitting
if(this._axis != null && this._axis.Common!=null && this._axis.Common.Chart != null)
{
if (!this._axis.Common.Chart.serializing)
{
this._axis.IsLabelAutoFit = false;
}
}
angle = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets a property which specifies whether the labels are shown with offset.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(false),
SRDescription("DescriptionAttributeLabel_OffsetLabels"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif
RefreshPropertiesAttribute(RefreshProperties.All)
]
public bool IsStaggered
{
get
{
return isStaggered;
}
set
{
// Make sure that angle is 0, 90 or -90
if(value && (this.Angle != 0 || this.Angle != -90 || this.Angle != 90))
{
this.Angle = 0;
}
// Turn off labels autofitting
if (this._axis != null && this._axis.Common != null && this._axis.Common.Chart != null)
{
if (!this._axis.Common.Chart.serializing)
{
this._axis.IsLabelAutoFit = false;
}
}
isStaggered = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets a property which specifies whether the labels are shown at axis ends.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(true),
SRDescription("DescriptionAttributeLabel_ShowEndLabels"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public bool IsEndLabelVisible
{
get
{
return _isEndLabelVisible;
}
set
{
_isEndLabelVisible = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets a property which specifies whether the label can be truncated.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(false),
SRDescription("DescriptionAttributeLabel_TruncatedLabels"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public bool TruncatedLabels
{
get
{
return _truncatedLabels;
}
set
{
_truncatedLabels = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets the formatting string for the label text.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(""),
SRDescription("DescriptionAttributeLabel_Format"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute),
#endif
]
public string Format
{
get
{
return _format;
}
set
{
_format = value;
this.Invalidate();
}
}
/// <summary>
/// Gets or sets a property which indicates whether the label is enabled.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
DefaultValue(true),
SRDescription("DescriptionAttributeLabel_Enabled"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
public bool Enabled
{
get
{
return _enabled;
}
set
{
_enabled = value;
this.Invalidate();
}
}
#endregion
#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>
protected override void Dispose(bool disposing)
{
if (disposing)
{
//Free managed resources
if (_fontCache!=null)
{
_fontCache.Dispose();
_fontCache = null;
}
}
}
#endregion
}
}
|