//------------------------------------------------------------- // // Copyright © Microsoft Corporation. All Rights Reserved. // //------------------------------------------------------------- // @owner=alexgor, deliant //================================================================= // File: Title.cs // // Namespace: DataVisualization.Charting // // Classes: TitleCollection, Title, Docking // // Purpose: Titles can be added to the chart by simply including // those titles into the Titles collection, which is // found in the root Chart object. The Title object // incorporates several properties that can be used to // position, dock, and control the appearance of any // Title. Title positioning can be explicitly set, or // you can specify that your title be docked. The // charting control gives you full control over all of // the appearance properties of your Titles, so you have // the ability to set specific properties for such things // as fonts, or colors, and even text effects. // // NOTE: In early versions of the Chart control only 1 title was // exposed through the Title, TitleFont and TitleFontColor properties // in the root chart object. Due to the customer requests, support for // unlimited number of titles was added through the TitleCollection // exposed as a Titles property of the root chart object. Old // properties were deprecated and marked as non-browsable. // // Reviewed: AG - Microsoft 13, 2007 // //=================================================================== #region Used namespaces using System; using System.Collections; using System.Collections.Specialized; using System.ComponentModel; using System.ComponentModel.Design; using System.Data; using System.Drawing; using System.Drawing.Design; using System.Drawing.Drawing2D; using System.Diagnostics.CodeAnalysis; using System.Globalization; #if Microsoft_CONTROL using System.Windows.Forms.DataVisualization.Charting; 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.ComponentModel.Design.Serialization; using System.Reflection; using System.Windows.Forms.Design; #else using System.Web; using System.Web.UI; using System.Web.UI.DataVisualization.Charting; using System.Web.UI.DataVisualization.Charting.Data; using System.Web.UI.DataVisualization.Charting.Utilities; #endif #endregion #if Microsoft_CONTROL namespace System.Windows.Forms.DataVisualization.Charting #else namespace System.Web.UI.DataVisualization.Charting #endif { #region Title enumerations /// /// An enumeration of chart element docking styles. /// public enum Docking { /// /// Docked to the top. /// Top, /// /// Docked to the right. /// Right, /// /// Docked to the bottom. /// Bottom, /// /// Docked to the left. /// Left, }; /// /// Text drawing styles. /// public enum TextStyle { /// /// Default text drawing style. /// Default, /// /// Shadow text. /// Shadow, /// /// Emboss text. /// Emboss, /// /// Embed text. /// Embed, /// /// Frame text. /// Frame } /// /// An enumeration of chart text orientation. /// public enum TextOrientation { /// /// Orientation is automatically determined based on the type of the /// chart element it is used in. /// Auto, /// /// Horizontal text. /// Horizontal, /// /// Text rotated 90 degrees and oriented from top to bottom. /// Rotated90, /// /// Text rotated 270 degrees and oriented from bottom to top. /// Rotated270, /// /// Text characters are not rotated and position one below the other. /// Stacked } #endregion /// /// The Title class provides properties which define content, visual /// appearance and position of the single chart title. It also /// contains methods responsible for calculating title position, /// drawing and hit testing. /// [ SRDescription("DescriptionAttributeTitle5"), ] #if Microsoft_CONTROL public class Title : ChartNamedElement, IDisposable #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 Title : ChartNamedElement, IDisposable, IChartMapArea #endif { #region Fields // Spacing between title text and the border in pixels internal int titleBorderSpacing = 4; //*********************************************************** //** Private data members, which store properties values //*********************************************************** // Title text private string _text = String.Empty; // Title drawing style private TextStyle _style = TextStyle.Default; // Title position private ElementPosition _position = null; // Background properties private bool _visible = true; private Color _backColor = Color.Empty; private ChartHatchStyle _backHatchStyle = ChartHatchStyle.None; private string _backImage = ""; private ChartImageWrapMode _backImageWrapMode = ChartImageWrapMode.Tile; private Color _backImageTransparentColor = Color.Empty; private ChartImageAlignmentStyle _backImageAlignment = ChartImageAlignmentStyle.TopLeft; private GradientStyle _backGradientStyle = GradientStyle.None; private Color _backSecondaryColor = Color.Empty; private int _shadowOffset = 0; private Color _shadowColor = Color.FromArgb(128, 0, 0, 0); // Border properties private Color _borderColor = Color.Empty; private int _borderWidth = 1; private ChartDashStyle _borderDashStyle = ChartDashStyle.Solid; // Font properties private FontCache _fontCache = new FontCache(); private Font _font; private Color _foreColor = Color.Black; // Docking and Alignment properties private ContentAlignment _alignment = ContentAlignment.MiddleCenter; private Docking _docking = Docking.Top; private string _dockedToChartArea = Constants.NotSetValue; private bool _isDockedInsideChartArea = true; private int _dockingOffset = 0; // Interactive properties private string _toolTip = String.Empty; #if !Microsoft_CONTROL private string _url = String.Empty; private string _mapAreaAttributes = String.Empty; private string _postbackValue = String.Empty; #endif // Default text orientation private TextOrientation _textOrientation = TextOrientation.Auto; #endregion #region Constructors and Initialization /// /// Title constructor. /// public Title() { Initialize(string.Empty, Docking.Top, null, Color.Black); } /// /// Public constructor. /// /// Title text. public Title(string text) { Initialize(text, Docking.Top, null, Color.Black); } /// /// Title constructor. /// /// Title text. /// Title docking. public Title(string text, Docking docking) { Initialize(text, docking, null, Color.Black); } /// /// Title constructor. /// /// Title text. /// Title docking. /// Title font. /// Title color. public Title(string text, Docking docking, Font font, Color color) { Initialize(text, docking, font, color); } /// /// Initialize title object. /// /// Title text. /// Title docking. /// Title font. /// Title color. private void Initialize(string text, Docking docking, Font font, Color color) { // Initialize fields this._position = new ElementPosition(this); this._font = _fontCache.DefaultFont; this._text = text; this._docking = docking; this._foreColor = color; if(font != null) { this._font = font; } } #endregion #region Properties /// /// Gets or sets the unique name of a ChartArea object. /// [ SRCategory("CategoryAttributeMisc"), Bindable(true), SRDescription("DescriptionAttributeTitle_Name"), NotifyParentPropertyAttribute(true), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public override string Name { get { return base.Name; } set { base.Name = value; } } /// /// Gets or sets the text orientation. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(TextOrientation.Auto), SRDescription("DescriptionAttribute_TextOrientation"), NotifyParentPropertyAttribute(true), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public TextOrientation TextOrientation { get { return this._textOrientation; } set { this._textOrientation = value; this.Invalidate(true); } } /// /// Gets or sets a flag that specifies whether the title is visible. /// /// /// True if the title is visible; false otherwise. /// [ SRCategory("CategoryAttributeAppearance"), DefaultValue(true), SRDescription("DescriptionAttributeTitle_Visible"), ParenthesizePropertyNameAttribute(true), ] virtual public bool Visible { get { return _visible; } set { _visible = value; this.Invalidate(false); } } /// /// Gets or sets the chart area name which the title is docked to inside or outside. /// [ SRCategory("CategoryAttributeDocking"), Bindable(true), DefaultValue(Constants.NotSetValue), SRDescription("DescriptionAttributeTitle_DockToChartArea"), TypeConverter(typeof(LegendAreaNameConverter)), NotifyParentPropertyAttribute(true), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute), #endif ] public string DockedToChartArea { get { return _dockedToChartArea; } set { if(value != _dockedToChartArea) { if(value.Length == 0) { _dockedToChartArea = Constants.NotSetValue; } else { if (Chart != null && Chart.ChartAreas != null) { Chart.ChartAreas.VerifyNameReference(value); } _dockedToChartArea = value; } this.Invalidate(false); } } } /// /// Gets or sets a property which indicates whether the title is docked inside chart area. /// DockedToChartArea property must be set first. /// [ SRCategory("CategoryAttributeDocking"), Bindable(true), DefaultValue(true), SRDescription("DescriptionAttributeTitle_DockInsideChartArea"), NotifyParentPropertyAttribute(true), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute), #endif ] public bool IsDockedInsideChartArea { get { return _isDockedInsideChartArea; } set { if(value != _isDockedInsideChartArea) { _isDockedInsideChartArea = value; this.Invalidate(false); } } } /// /// Gets or sets the positive or negative offset of the docked title position. /// [ SRCategory("CategoryAttributeDocking"), Bindable(true), DefaultValue(0), SRDescription("DescriptionAttributeTitle_DockOffset"), NotifyParentPropertyAttribute(true), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute), #endif ] public int DockingOffset { get { return _dockingOffset; } set { if(value != _dockingOffset) { if (value < -100 || value > 100) { throw (new ArgumentOutOfRangeException("value", SR.ExceptionValueMustBeInRange("DockingOffset", (-100).ToString(CultureInfo.CurrentCulture), (100).ToString(CultureInfo.CurrentCulture)))); } _dockingOffset = value; this.Invalidate(false); } } } /// /// Gets or sets the position of the title. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), SRDescription("DescriptionAttributeTitle_Position"), #if Microsoft_CONTROL DesignerSerializationVisibility(DesignerSerializationVisibility.Content), #else PersistenceMode(PersistenceMode.InnerProperty), #endif NotifyParentPropertyAttribute(true), TypeConverter(typeof(ElementPositionConverter)), SerializationVisibilityAttribute(SerializationVisibility.Element) ] public ElementPosition Position { get { // Serialize only position values if Auto set to false if (Chart != null && Chart.serializationStatus == SerializationStatus.Saving) { if(_position.Auto) { return new ElementPosition(); } else { ElementPosition newPosition = new ElementPosition(); #if Microsoft_CONTROL newPosition.Auto = false; #else newPosition.Auto = true; #endif newPosition.SetPositionNoAuto(_position.X, _position.Y, _position.Width, _position.Height); return newPosition; } } return _position; } set { _position = value; _position.Parent = this; this.Invalidate(false); } } /// /// Determoines if this position should be serialized. /// /// internal bool ShouldSerializePosition() { return !this.Position.Auto; } /// /// Gets or sets the text of the title. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(""), SRDescription("DescriptionAttributeTitle_Text"), NotifyParentPropertyAttribute(true), ParenthesizePropertyNameAttribute(true), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public string Text { get { return _text; } set { _text = (value == null) ? string.Empty : value; this.Invalidate(false); } } /// /// Title drawing style. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(TextStyle.Default), SRDescription("DescriptionAttributeTextStyle"), NotifyParentPropertyAttribute(true), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public TextStyle TextStyle { get { return _style; } set { _style = value; this.Invalidate(true); } } /// /// Gets or sets the background color of the title. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(typeof(Color), ""), SRDescription("DescriptionAttributeBackColor"), NotifyParentPropertyAttribute(true), TypeConverter(typeof(ColorConverter)), Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public Color BackColor { get { return _backColor; } set { _backColor = value; this.Invalidate(true); } } /// /// Gets or sets the border color of the title. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(typeof(Color), ""), SRDescription("DescriptionAttributeBorderColor"), NotifyParentPropertyAttribute(true), TypeConverter(typeof(ColorConverter)), Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public Color BorderColor { get { return _borderColor; } set { _borderColor = value; this.Invalidate(true); } } /// /// Gets or sets the border style of the title. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(ChartDashStyle.Solid), SRDescription("DescriptionAttributeBorderDashStyle"), NotifyParentPropertyAttribute(true), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public ChartDashStyle BorderDashStyle { get { return _borderDashStyle; } set { _borderDashStyle = value; this.Invalidate(true); } } /// /// Gets or sets the border width of the title. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(1), SRDescription("DescriptionAttributeBorderWidth"), NotifyParentPropertyAttribute(true), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public int BorderWidth { get { return _borderWidth; } set { if(value < 0) { throw (new ArgumentOutOfRangeException("value", SR.ExceptionTitleBorderWidthIsNegative)); } _borderWidth = value; this.Invalidate(false); } } /// /// Gets or sets the background image. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(""), SRDescription("DescriptionAttributeBackImage"), Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute), #endif NotifyParentPropertyAttribute(true), ] public string BackImage { get { return _backImage; } set { _backImage = value; this.Invalidate(true); } } /// /// Gets or sets the background image drawing mode. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(ChartImageWrapMode.Tile), NotifyParentPropertyAttribute(true), SRDescription("DescriptionAttributeImageWrapMode"), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public ChartImageWrapMode BackImageWrapMode { get { return _backImageWrapMode; } set { _backImageWrapMode = value; this.Invalidate(true); } } /// /// Gets or sets a color which will be replaced with a transparent color while drawing the background image. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(typeof(Color), ""), NotifyParentPropertyAttribute(true), SRDescription("DescriptionAttributeImageTransparentColor"), TypeConverter(typeof(ColorConverter)), Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public Color BackImageTransparentColor { get { return _backImageTransparentColor; } set { _backImageTransparentColor = value; this.Invalidate(true); } } /// /// Gets or sets the background image alignment used by unscale drawing mode. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(ChartImageAlignmentStyle.TopLeft), NotifyParentPropertyAttribute(true), SRDescription("DescriptionAttributeBackImageAlign"), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public ChartImageAlignmentStyle BackImageAlignment { get { return _backImageAlignment; } set { _backImageAlignment = value; this.Invalidate(true); } } /// /// Gets or sets the background gradient style. /// /// /// /// /// /// A value used for the background. /// /// /// Two colors are used to draw the gradient, and . /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(GradientStyle.None), NotifyParentPropertyAttribute(true), SRDescription("DescriptionAttributeBackGradientStyle"), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute), #endif Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base) ] public GradientStyle BackGradientStyle { get { return _backGradientStyle; } set { _backGradientStyle = value; this.Invalidate(true); } } /// /// Gets or sets the secondary background color. /// /// /// /// /// /// A value used for the secondary color of a background with /// hatching or gradient fill. /// /// /// This color is used with when or /// are used. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(typeof(Color), ""), NotifyParentPropertyAttribute(true), SRDescription("DescriptionAttributeBackSecondaryColor"), TypeConverter(typeof(ColorConverter)), Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public Color BackSecondaryColor { get { return _backSecondaryColor; } set { _backSecondaryColor = value; this.Invalidate(true); } } /// /// Gets or sets the background hatch style. /// /// /// /// /// /// A value used for the background. /// /// /// Two colors are used to draw the hatching, and . /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(ChartHatchStyle.None), NotifyParentPropertyAttribute(true), SRDescription("DescriptionAttributeBackHatchStyle"), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute), #endif Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base) ] public ChartHatchStyle BackHatchStyle { get { return _backHatchStyle; } set { _backHatchStyle = value; this.Invalidate(true); } } /// /// Gets or sets the title font. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"), SRDescription("DescriptionAttributeTitle_Font"), NotifyParentPropertyAttribute(true), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public Font Font { get { return _font; } set { _font = value; this.Invalidate(false); } } /// /// Gets or sets the title fore color. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(typeof(Color), "Black"), SRDescription("DescriptionAttributeTitle_Color"), 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(true); } } /// /// Gets or sets title alignment. /// [ SRCategory("CategoryAttributeDocking"), Bindable(true), DefaultValue(ContentAlignment.MiddleCenter), SRDescription("DescriptionAttributeTitle_Alignment"), NotifyParentPropertyAttribute(true), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public ContentAlignment Alignment { get { return _alignment; } set { _alignment = value; this.Invalidate(false); } } /// /// Gets or sets the title docking style. /// [ SRCategory("CategoryAttributeDocking"), Bindable(true), DefaultValue(Docking.Top), SRDescription("DescriptionAttributeTitle_Docking"), NotifyParentPropertyAttribute(true), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public Docking Docking { get { return _docking; } set { _docking = value; this.Invalidate(false); } } /// /// Gets or sets the title shadow offset. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(0), SRDescription("DescriptionAttributeShadowOffset"), NotifyParentPropertyAttribute(true), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public int ShadowOffset { get { return _shadowOffset; } set { _shadowOffset = value; this.Invalidate(false); } } /// /// Gets or sets the title shadow color. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(typeof(Color), "128, 0, 0, 0"), SRDescription("DescriptionAttributeShadowColor"), NotifyParentPropertyAttribute(true), TypeConverter(typeof(ColorConverter)), Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public Color ShadowColor { get { return _shadowColor; } set { _shadowColor = value; this.Invalidate(false); } } /// /// Gets or sets the tooltip. /// [ #if !Microsoft_CONTROL SRCategory("CategoryAttributeMapArea"), #else SRCategory("CategoryAttributeToolTip"), #endif Bindable(true), SRDescription("DescriptionAttributeToolTip"), DefaultValue(""), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public string ToolTip { set { _toolTip = value; } get { return _toolTip; } } #if !Microsoft_CONTROL /// /// Gets or sets the URL target of the title. /// [ SRCategory("CategoryAttributeMapArea"), Bindable(true), SRDescription("DescriptionAttributeUrl"), DefaultValue(""), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute), Editor(Editors.UrlValueEditor.Editor, Editors.UrlValueEditor.Base) #endif ] public string Url { set { _url = value; } get { return _url; } } /// /// Gets or sets the other attributes of the title map area. /// [ SRCategory("CategoryAttributeMapArea"), Bindable(true), SRDescription("DescriptionAttributeMapAreaAttributes"), DefaultValue(""), PersistenceMode(PersistenceMode.Attribute) ] public string MapAreaAttributes { set { _mapAreaAttributes = value; } get { return _mapAreaAttributes; } } /// /// Gets or sets the postback value which can be processed on a click event. /// /// The value which is passed to a click event as an argument. [DefaultValue("")] [SRCategory(SR.Keys.CategoryAttributeMapArea)] [SRDescription(SR.Keys.DescriptionAttributePostBackValue)] public string PostBackValue { get { return this._postbackValue; } set { this._postbackValue = value; } } #endif /// /// True if title background or border is visible /// internal bool BackGroundIsVisible { get { if(!this.BackColor.IsEmpty || this.BackImage.Length > 0 || (!this.BorderColor.IsEmpty && this.BorderDashStyle != ChartDashStyle.NotSet) ) { return true; } return false; } } #endregion #region Helper Methods /// /// Checks if chart title is drawn vertically. /// Note: From the drawing perspective stacked text orientation is not vertical. /// /// True if text is vertical. private bool IsTextVertical { get { TextOrientation currentTextOrientation = this.GetTextOrientation(); return currentTextOrientation == TextOrientation.Rotated90 || currentTextOrientation == TextOrientation.Rotated270; } } /// /// Returns title text orientation. If set to Auto automatically determines the /// orientation based on title docking. /// /// Current text orientation. private TextOrientation GetTextOrientation() { if (this.TextOrientation == TextOrientation.Auto) { // When chart title is docked to the left or right we automatically // set vertical text with different rotation angles. if (this.Position.Auto) { if (this.Docking == Docking.Left) { return TextOrientation.Rotated270; } else if (this.Docking == Docking.Right) { return TextOrientation.Rotated90; } } return TextOrientation.Horizontal; } return this.TextOrientation; } /// /// Helper method that checks if title is visible. /// /// True if title is visible. internal bool IsVisible() { if(this.Visible) { // Check if title is docked to the chart area if(this.DockedToChartArea.Length > 0 && this.Chart != null) { if(this.Chart.ChartAreas.IndexOf(this.DockedToChartArea) >= 0) { // Do not show title when it is docked to invisible chart area ChartArea area = this.Chart.ChartAreas[this.DockedToChartArea]; if(!area.Visible) { return false; } } } return true; } return false; } /// /// Invalidate chart title when one of the properties is changed. /// /// Indicates that only title area should be invalidated. [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "This parameter is used when compiling for the Microsoft version of Chart")] internal void Invalidate(bool invalidateTitleOnly) { #if Microsoft_CONTROL if(Chart != null) { // Set dirty flag Chart.dirtyFlag = true; // Invalidate chart if(invalidateTitleOnly) { // Calculate the position of the title Rectangle invalRect = Chart.ClientRectangle; if(this.Position.Width != 0 && this.Position.Height != 0 ) { // Convert relative coordinates to absolute coordinates invalRect.X = (int)(this.Position.X * (Common.ChartPicture.Width - 1) / 100F); invalRect.Y = (int)(this.Position.Y * (Common.ChartPicture.Height - 1) / 100F); invalRect.Width = (int)(this.Position.Width * (Common.ChartPicture.Width - 1) / 100F); invalRect.Height = (int)(this.Position.Height * (Common.ChartPicture.Height - 1) / 100F); // Inflate rectangle size using border size and shadow size invalRect.Inflate(this.BorderWidth + this.ShadowOffset + 1, this.BorderWidth + this.ShadowOffset + 1); } // Invalidate title rectangle only Chart.Invalidate(invalRect); } else { Invalidate(); } } #endif // #if Microsoft_CONTROL } #endregion #region Painting and Selection Methods /// /// Paints title using chart graphics object. /// /// The graph provides drawing object to the display device. A Graphics object is associated with a specific device context. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")] internal void Paint(ChartGraphics chartGraph ) { // check if title is visible if(!this.IsVisible()) { return; } // Title text string titleText = this.Text; //*************************************************************** //** Calculate title relative position //*************************************************************** RectangleF titlePosition = this.Position.ToRectangleF(); // Auto set the title position if width or height is not set for custom position if(!this.Position.Auto && Common != null && Common.ChartPicture != null) { if(titlePosition.Width == 0 || titlePosition.Height == 0) { // Calculate text layout area SizeF layoutArea = new SizeF( (titlePosition.Width == 0) ? Common.ChartPicture.Width : titlePosition.Width, (titlePosition.Height == 0) ? Common.ChartPicture.Height : titlePosition.Height); if (this.IsTextVertical) { float tempValue = layoutArea.Width; layoutArea.Width = layoutArea.Height; layoutArea.Height = tempValue; } // Measure text size layoutArea = chartGraph.GetAbsoluteSize(layoutArea); SizeF titleSize = chartGraph.MeasureString( "W" + titleText.Replace("\\n", "\n"), this.Font, layoutArea, StringFormat.GenericDefault, this.GetTextOrientation()); // Increase text size by 4 pixels if(this.BackGroundIsVisible) { titleSize.Width += titleBorderSpacing; titleSize.Height += titleBorderSpacing; } // Switch width and height for vertical text if (this.IsTextVertical) { float tempValue = titleSize.Width; titleSize.Width = titleSize.Height; titleSize.Height = tempValue; } // Convert text size to relative coordinates titleSize = chartGraph.GetRelativeSize(titleSize); // Update custom position if(titlePosition.Width == 0) { titlePosition.Width = titleSize.Width; if(this.Alignment == ContentAlignment.BottomRight || this.Alignment == ContentAlignment.MiddleRight || this.Alignment == ContentAlignment.TopRight) { titlePosition.X = titlePosition.X - titlePosition.Width; } else if(this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.TopCenter) { titlePosition.X = titlePosition.X - titlePosition.Width/2f; } } if(titlePosition.Height == 0) { titlePosition.Height = titleSize.Height; if(this.Alignment == ContentAlignment.BottomRight || this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.BottomLeft) { titlePosition.Y = titlePosition.Y - titlePosition.Height; } else if(this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.MiddleLeft || this.Alignment == ContentAlignment.MiddleRight) { titlePosition.Y = titlePosition.Y - titlePosition.Height/2f; } } } } //*************************************************************** //** Convert title position to absolute coordinates //*************************************************************** RectangleF absPosition = new RectangleF(titlePosition.Location, titlePosition.Size); absPosition = chartGraph.GetAbsoluteRectangle(absPosition); //*************************************************************** //** Draw title background, border and shadow //*************************************************************** if(this.BackGroundIsVisible && Common.ProcessModePaint ) { chartGraph.FillRectangleRel( titlePosition, BackColor, BackHatchStyle, BackImage, BackImageWrapMode, BackImageTransparentColor, BackImageAlignment, BackGradientStyle, BackSecondaryColor, BorderColor, BorderWidth, BorderDashStyle, ShadowColor, ShadowOffset, PenAlignment.Inset); } else { // Adjust text position to be only around the text itself SizeF titleArea = chartGraph.GetAbsoluteSize(titlePosition.Size); SizeF titleSize = chartGraph.MeasureString( "W" + titleText.Replace("\\n", "\n"), this.Font, titleArea, StringFormat.GenericDefault, this.GetTextOrientation()); // Convert text size to relative coordinates titleSize = chartGraph.GetRelativeSize(titleSize); // Adjust position depending on alignment RectangleF exactTitleRect = new RectangleF( titlePosition.X, titlePosition.Y, titleSize.Width, titleSize.Height); if(this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.BottomLeft || this.Alignment == ContentAlignment.BottomRight ) { exactTitleRect.Y = titlePosition.Bottom - exactTitleRect.Height; } else if(this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.MiddleLeft || this.Alignment == ContentAlignment.MiddleRight ) { exactTitleRect.Y = titlePosition.Y + titlePosition.Height / 2f - exactTitleRect.Height / 2f; } if(this.Alignment == ContentAlignment.BottomRight || this.Alignment == ContentAlignment.MiddleRight || this.Alignment == ContentAlignment.TopRight ) { exactTitleRect.X = titlePosition.Right - exactTitleRect.Width; } else if(this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.TopCenter ) { exactTitleRect.X = titlePosition.X + titlePosition.Width / 2f - exactTitleRect.Width / 2f; } // NOTE: This approach for text selection can not be used with // Flash animations because of the bug in Flash viewer. When the // button shape is placed in the last frame the Alpha value of the // color is ignored. // NOTE: Feature tested again with Flash Player 7 and it seems to be // working fine. Code below is commented to enable selection in flash // through transparent rectangle. // Fixes issue #4172. bool drawRect = true; // Draw transparent rectangle in the text position if(drawRect) { chartGraph.FillRectangleRel( exactTitleRect, Color.FromArgb(0, Color.White), ChartHatchStyle.None, String.Empty, ChartImageWrapMode.Tile, BackImageTransparentColor, BackImageAlignment, GradientStyle.None, BackSecondaryColor, Color.Transparent, 0, BorderDashStyle, Color.Transparent, 0, PenAlignment.Inset); } // End Selection mode chartGraph.EndHotRegion( ); } if( Common.ProcessModePaint) Common.Chart.CallOnPrePaint(new ChartPaintEventArgs(this, chartGraph, Common, Position)); //*************************************************************** //** Add spacing between text and border //*************************************************************** if(this.BackGroundIsVisible) { absPosition.Width -= this.titleBorderSpacing; absPosition.Height -= this.titleBorderSpacing; absPosition.X += this.titleBorderSpacing / 2f; absPosition.Y += this.titleBorderSpacing / 2f; } //*************************************************************** //** Create string format //*************************************************************** using (StringFormat format = new StringFormat()) { format.Alignment = StringAlignment.Center; format.LineAlignment = StringAlignment.Center; if (this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.BottomLeft || this.Alignment == ContentAlignment.BottomRight) { format.LineAlignment = StringAlignment.Far; } else if (this.Alignment == ContentAlignment.TopCenter || this.Alignment == ContentAlignment.TopLeft || this.Alignment == ContentAlignment.TopRight) { format.LineAlignment = StringAlignment.Near; } if (this.Alignment == ContentAlignment.BottomLeft || this.Alignment == ContentAlignment.MiddleLeft || this.Alignment == ContentAlignment.TopLeft) { format.Alignment = StringAlignment.Near; } else if (this.Alignment == ContentAlignment.BottomRight || this.Alignment == ContentAlignment.MiddleRight || this.Alignment == ContentAlignment.TopRight) { format.Alignment = StringAlignment.Far; } //*************************************************************** //** Draw text shadow for the default style when background is not drawn anf ShadowOffset is not null //*************************************************************** Color textShadowColor = ChartGraphics.GetGradientColor(this.ForeColor, Color.Black, 0.8); int textShadowOffset = 1; TextStyle textStyle = this.TextStyle; if ((textStyle == TextStyle.Default || textStyle == TextStyle.Shadow) && !this.BackGroundIsVisible && ShadowOffset != 0) { // Draw shadowed text textStyle = TextStyle.Shadow; textShadowColor = ShadowColor; textShadowOffset = ShadowOffset; } if (textStyle == TextStyle.Shadow) { textShadowColor = (textShadowColor.A != 255) ? textShadowColor : Color.FromArgb(textShadowColor.A / 2, textShadowColor); } //*************************************************************** //** Replace new line characters //*************************************************************** titleText = titleText.Replace("\\n", "\n"); //*************************************************************** //** Define text angle depending on the docking //*************************************************************** Matrix oldTransform = null; if (this.IsTextVertical) { if (this.GetTextOrientation() == TextOrientation.Rotated270) { // IMPORTANT ! // Right to Left flag has to be used because of bug with .net with multi line vertical text. As soon as .net bug is fixed this flag HAS TO be removed. Bug number 1870. format.FormatFlags |= StringFormatFlags.DirectionVertical | StringFormatFlags.DirectionRightToLeft; // Save old graphics transformation oldTransform = chartGraph.Transform.Clone(); // Rotate tile 180 degrees at center PointF center = PointF.Empty; center.X = absPosition.X + absPosition.Width / 2F; center.Y = absPosition.Y + absPosition.Height / 2F; // Create and set new transformation matrix Matrix newMatrix = chartGraph.Transform.Clone(); newMatrix.RotateAt(180, center); chartGraph.Transform = newMatrix; } else if (this.GetTextOrientation() == TextOrientation.Rotated90) { // IMPORTANT ! // Right to Left flag has to be used because of bug with .net with multi line vertical text. As soon as .net bug is fixed this flag HAS TO be removed. Bug number 1870. format.FormatFlags |= StringFormatFlags.DirectionVertical | StringFormatFlags.DirectionRightToLeft; } } try { chartGraph.IsTextClipped = !Position.Auto; Title.DrawStringWithStyle(chartGraph, titleText, textStyle, this.Font, absPosition, this.ForeColor, textShadowColor, textShadowOffset, format, this.GetTextOrientation()); } finally { chartGraph.IsTextClipped = false; } // Call Paint event if (Common.ProcessModePaint) Common.Chart.CallOnPostPaint(new ChartPaintEventArgs(this, chartGraph, Common, Position)); //*************************************************************** //** Restore old transformation //*************************************************************** if(oldTransform != null) { chartGraph.Transform = oldTransform; } if( Common.ProcessModeRegions ) { #if !Microsoft_CONTROL Common.HotRegionsList.AddHotRegion( titlePosition, this.ToolTip, this.Url, this.MapAreaAttributes, this.PostBackValue, this, ChartElementType.Title, string.Empty ); #else Common.HotRegionsList.AddHotRegion( titlePosition, this.ToolTip, null, null, null, this, ChartElementType.Title, null ); #endif // !Microsoft_CONTROL } } } /// /// Draws the string with style. /// /// The chart graph. /// The title text. /// The text style. /// The font. /// The abs position. /// Color of the fore. /// Color of the shadow. /// The shadow offset. /// The format. /// The orientation. internal static void DrawStringWithStyle( ChartGraphics chartGraph, string titleText, TextStyle textStyle, Font font, RectangleF absPosition, Color foreColor, Color shadowColor, int shadowOffset, StringFormat format, TextOrientation orientation ) { //*************************************************************** //** Draw title text //*************************************************************** if (titleText.Length > 0) { if (textStyle == TextStyle.Default) { using (SolidBrush brush = new SolidBrush(foreColor)) { chartGraph.DrawString(titleText, font, brush, absPosition, format, orientation); } } else if (textStyle == TextStyle.Frame) { using (GraphicsPath graphicsPath = new GraphicsPath()) { graphicsPath.AddString( titleText, font.FontFamily, (int)font.Style, font.Size * 1.3f, absPosition, format); graphicsPath.CloseAllFigures(); using (Pen pen = new Pen(foreColor, 1)) { chartGraph.DrawPath(pen, graphicsPath); } } } else if (textStyle == TextStyle.Embed) { // Draw shadow RectangleF shadowPosition = new RectangleF(absPosition.Location, absPosition.Size); shadowPosition.X -= 1; shadowPosition.Y -= 1; using (SolidBrush brush = new SolidBrush(shadowColor)) { chartGraph.DrawString(titleText, font, brush, shadowPosition, format, orientation); } // Draw highlighting shadowPosition.X += 2; shadowPosition.Y += 2; Color texthighlightColor = ChartGraphics.GetGradientColor(Color.White, foreColor, 0.3); using (SolidBrush brush = new SolidBrush(texthighlightColor)) { chartGraph.DrawString(titleText, font, brush, shadowPosition, format, orientation); } using (SolidBrush brush = new SolidBrush(foreColor)) { // Draw text chartGraph.DrawString(titleText, font, brush, absPosition, format, orientation); } } else if (textStyle == TextStyle.Emboss) { // Draw shadow RectangleF shadowPosition = new RectangleF(absPosition.Location, absPosition.Size); shadowPosition.X += 1; shadowPosition.Y += 1; using (SolidBrush brush = new SolidBrush(shadowColor)) { chartGraph.DrawString(titleText, font, brush, shadowPosition, format, orientation); } // Draw highlighting shadowPosition.X -= 2; shadowPosition.Y -= 2; Color texthighlightColor = ChartGraphics.GetGradientColor(Color.White, foreColor, 0.3); using (SolidBrush brush = new SolidBrush(texthighlightColor)) { chartGraph.DrawString(titleText, font, brush, shadowPosition, format, orientation); } // Draw text using (SolidBrush brush = new SolidBrush(foreColor)) { chartGraph.DrawString(titleText, font, brush, absPosition, format, orientation); } } else if (textStyle == TextStyle.Shadow) { // Draw shadow RectangleF shadowPosition = new RectangleF(absPosition.Location, absPosition.Size); shadowPosition.X += shadowOffset; shadowPosition.Y += shadowOffset; using (SolidBrush brush = new SolidBrush(shadowColor)) { chartGraph.DrawString(titleText, font, brush, shadowPosition, format, orientation); } // Draw text using (SolidBrush brush = new SolidBrush(foreColor)) { chartGraph.DrawString(titleText, font, brush, absPosition, format, orientation); } } } } #endregion #region Position Calculation Methods /// /// Recalculates title position. /// /// Chart graphics used. /// Area where the title should be docked. /// Position of the title in the frame. /// Spacing size in percentage of the area. internal void CalcTitlePosition( ChartGraphics chartGraph, ref RectangleF chartAreasRectangle, ref RectangleF frameTitlePosition, float elementSpacing) { // Special case for the first title docked to the top when the title frame is used if(!frameTitlePosition.IsEmpty && this.Position.Auto && this.Docking == Docking.Top && this.DockedToChartArea == Constants.NotSetValue) { this.Position.SetPositionNoAuto( frameTitlePosition.X + elementSpacing, frameTitlePosition.Y, frameTitlePosition.Width - 2f * elementSpacing, frameTitlePosition.Height); frameTitlePosition = RectangleF.Empty; return; } // Get title size RectangleF titlePosition = new RectangleF(); SizeF layoutArea = new SizeF(chartAreasRectangle.Width, chartAreasRectangle.Height); // Switch width and height for vertical text if (this.IsTextVertical) { float tempValue = layoutArea.Width; layoutArea.Width = layoutArea.Height; layoutArea.Height = tempValue; } // Meausure text size layoutArea.Width -= 2f * elementSpacing; layoutArea.Height -= 2f * elementSpacing; layoutArea = chartGraph.GetAbsoluteSize(layoutArea); SizeF titleSize = chartGraph.MeasureString( "W" + this.Text.Replace("\\n", "\n"), this.Font, layoutArea, StringFormat.GenericDefault, this.GetTextOrientation()); // Increase text size by 4 pixels if(this.BackGroundIsVisible) { titleSize.Width += titleBorderSpacing; titleSize.Height += titleBorderSpacing; } // Switch width and height for vertical text if (this.IsTextVertical) { float tempValue = titleSize.Width; titleSize.Width = titleSize.Height; titleSize.Height = tempValue; } // Convert text size to relative coordinates titleSize = chartGraph.GetRelativeSize(titleSize); titlePosition.Height = titleSize.Height; titlePosition.Width = titleSize.Width; if(float.IsNaN(titleSize.Height) || float.IsNaN(titleSize.Width)) { return; } // Calculate title position if(this.Docking == Docking.Top) { titlePosition.Y = chartAreasRectangle.Y + elementSpacing; titlePosition.X = chartAreasRectangle.X + elementSpacing; titlePosition.Width = chartAreasRectangle.Right - titlePosition.X - elementSpacing; if(titlePosition.Width < 0) { titlePosition.Width = 0; } // Adjust position of the chart area(s) chartAreasRectangle.Height -= titlePosition.Height + elementSpacing; chartAreasRectangle.Y = titlePosition.Bottom; } else if(this.Docking == Docking.Bottom) { titlePosition.Y = chartAreasRectangle.Bottom - titleSize.Height - elementSpacing; titlePosition.X = chartAreasRectangle.X + elementSpacing; titlePosition.Width = chartAreasRectangle.Right - titlePosition.X - elementSpacing; if(titlePosition.Width < 0) { titlePosition.Width = 0; } // Adjust position of the chart area(s) chartAreasRectangle.Height -= titlePosition.Height + elementSpacing; } if(this.Docking == Docking.Left) { titlePosition.X = chartAreasRectangle.X + elementSpacing; titlePosition.Y = chartAreasRectangle.Y + elementSpacing; titlePosition.Height = chartAreasRectangle.Bottom - titlePosition.Y - elementSpacing; if(titlePosition.Height < 0) { titlePosition.Height = 0; } // Adjust position of the chart area(s) chartAreasRectangle.Width -= titlePosition.Width + elementSpacing; chartAreasRectangle.X = titlePosition.Right; } if(this.Docking == Docking.Right) { titlePosition.X = chartAreasRectangle.Right - titleSize.Width - elementSpacing; titlePosition.Y = chartAreasRectangle.Y + elementSpacing; titlePosition.Height = chartAreasRectangle.Bottom - titlePosition.Y - elementSpacing; if(titlePosition.Height < 0) { titlePosition.Height = 0; } // Adjust position of the chart area(s) chartAreasRectangle.Width -= titlePosition.Width + elementSpacing; } // Offset calculated docking position if(this.DockingOffset != 0) { if(this.Docking == Docking.Top || this.Docking == Docking.Bottom) { titlePosition.Y += this.DockingOffset; } else { titlePosition.X += this.DockingOffset; } } this.Position.SetPositionNoAuto(titlePosition.X, titlePosition.Y, titlePosition.Width, titlePosition.Height); } #endregion #region IDisposable Members /// /// Releases unmanaged and - optionally - managed resources /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected override void Dispose(bool disposing) { if (disposing) { if (_fontCache != null) { _fontCache.Dispose(); _fontCache = null; } if (_position != null) { _position.Dispose(); _position = null; } } } #endregion } /// /// The TitleCollection class is a strongly typed collection of Title classes. /// Indexer of this collection can take the title index (integer) or unique /// title name (string) as a parameter. /// [ SRDescription("DescriptionAttributeTitles"), ] #if ASPPERM_35 [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] #endif public class TitleCollection : ChartNamedElementCollection { #region Constructors /// <summary> /// TitleCollection constructor. /// </summary> /// <param name="parent">Parent chart element.</param> internal TitleCollection(IChartElement parent) : base(parent) { } #endregion #region Methods /// <summary> /// Creates a new Title with the specified name and adds it to the collection. /// </summary> /// <param name="name">The new chart area name.</param> /// <returns>New title</returns> public Title Add(string name) { Title title = new Title(name); this.Add(title); return title; } /// <summary> /// Recalculates title position in the collection for titles docked outside of chart area. /// </summary> /// <param name="chartPicture">Chart picture object.</param> /// <param name="chartGraph">Chart graphics used.</param> /// <param name="area">Area the title is docked to.</param> /// <param name="chartAreasRectangle">Area where the title should be positioned.</param> /// <param name="elementSpacing">Spacing size in percentage of the area.</param> internal static void CalcOutsideTitlePosition( ChartPicture chartPicture, ChartGraphics chartGraph, ChartArea area, ref RectangleF chartAreasRectangle, float elementSpacing) { if(chartPicture != null) { // Get elemets spacing float areaSpacing = Math.Min((chartAreasRectangle.Height/100F) * elementSpacing, (chartAreasRectangle.Width/100F) * elementSpacing); // Loop through all titles foreach(Title title in chartPicture.Titles) { // Check if title visible if(!title.IsVisible()) { continue; } // Check if all chart area names are valid if (title.DockedToChartArea != Constants.NotSetValue && chartPicture.ChartAreas.IndexOf(title.DockedToChartArea)<0) { throw (new ArgumentException(SR.ExceptionChartTitleDockedChartAreaIsMissing((string)title.DockedToChartArea))); } // Process only titles docked to specified area if(title.IsDockedInsideChartArea == false && title.DockedToChartArea == area.Name && title.Position.Auto) { // Calculate title position RectangleF frameRect = RectangleF.Empty; RectangleF prevChartAreasRectangle = chartAreasRectangle; title.CalcTitlePosition(chartGraph, ref chartAreasRectangle, ref frameRect, areaSpacing); // Adjust title position RectangleF titlePosition = title.Position.ToRectangleF(); if(title.Docking == Docking.Top) { titlePosition.Y -= areaSpacing; if(!area.Position.Auto) { titlePosition.Y -= titlePosition.Height; prevChartAreasRectangle.Y -= titlePosition.Height + areaSpacing; prevChartAreasRectangle.Height += titlePosition.Height + areaSpacing; } } else if(title.Docking == Docking.Bottom) { titlePosition.Y += areaSpacing; if(!area.Position.Auto) { titlePosition.Y = prevChartAreasRectangle.Bottom + areaSpacing; prevChartAreasRectangle.Height += titlePosition.Height +areaSpacing; } } if(title.Docking == Docking.Left) { titlePosition.X -= areaSpacing; if(!area.Position.Auto) { titlePosition.X -= titlePosition.Width; prevChartAreasRectangle.X -= titlePosition.Width + areaSpacing; prevChartAreasRectangle.Width += titlePosition.Width + areaSpacing; } } if(title.Docking == Docking.Right) { titlePosition.X += areaSpacing; if(!area.Position.Auto) { titlePosition.X = prevChartAreasRectangle.Right + areaSpacing; prevChartAreasRectangle.Width += titlePosition.Width + areaSpacing; } } // Set title position without changing the 'Auto' flag title.Position.SetPositionNoAuto(titlePosition.X, titlePosition.Y, titlePosition.Width, titlePosition.Height); // If custom position is used in the chart area reset the curent adjusted position if (!area.Position.Auto) { chartAreasRectangle = prevChartAreasRectangle; } } } } } /// <summary> /// Recalculates all titles position inside chart area in the collection. /// </summary> /// <param name="chartPicture">Chart picture object.</param> /// <param name="chartGraph">Chart graphics used.</param> /// <param name="elementSpacing">Spacing size in percentage of the area.</param> internal static void CalcInsideTitlePosition( ChartPicture chartPicture, ChartGraphics chartGraph, float elementSpacing) { if(chartPicture != null) { // Check if all chart area names are valid foreach(Title title in chartPicture.Titles) { // Check if title visible if(!title.IsVisible()) { continue; } if (title.DockedToChartArea != Constants.NotSetValue) { try { ChartArea area = chartPicture.ChartAreas[title.DockedToChartArea]; } catch { throw(new ArgumentException( SR.ExceptionChartTitleDockedChartAreaIsMissing( (string)title.DockedToChartArea ) ) ); } } } // Loop through all chart areas foreach(ChartArea area in chartPicture.ChartAreas) { // Check if chart area is visible if(area.Visible) { // Get area position RectangleF titlePlottingRectangle = area.PlotAreaPosition.ToRectangleF(); // Get elemets spacing float areaSpacing = Math.Min((titlePlottingRectangle.Height/100F) * elementSpacing, (titlePlottingRectangle.Width/100F) * elementSpacing); // Loop through all titles foreach(Title title in chartPicture.Titles) { if(title.IsDockedInsideChartArea == true && title.DockedToChartArea == area.Name && title.Position.Auto) { // Calculate title position RectangleF frameRect = RectangleF.Empty; title.CalcTitlePosition(chartGraph, ref titlePlottingRectangle, ref frameRect, areaSpacing); } } } } } } #endregion #region Event handlers internal void ChartAreaNameReferenceChanged(object sender, NameReferenceChangedEventArgs e) { //If all the chart areas are removed and then the first one is added we don't want to dock the titles if (e.OldElement == null) return; foreach (Title title in this) if (title.DockedToChartArea == e.OldName) title.DockedToChartArea = e.NewName; } #endregion } }