//------------------------------------------------------------- // // Copyright © Microsoft Corporation. All Rights Reserved. // //------------------------------------------------------------- // @owner=alexgor, deliant //================================================================= // File: DataSries.cs // // Namespace: System.Web.UI.WebControls[Windows.Forms].Charting.Data // // Classes: SeriesCollection, Series // // Purpose: Chart series collection class and series properties class. // // Reviewed: AG - Aug 1, 2002; // GS - Aug 7, 2002 // //=================================================================== #region Used namespaces using System; using System.ComponentModel; using System.ComponentModel.Design; using System.Collections.Generic; using System.Collections; using System.Data; using System.Drawing; using System.Drawing.Design; using System.Globalization; using System.Diagnostics.CodeAnalysis; #if Microsoft_CONTROL using System.Windows.Forms.DataVisualization.Charting.Data; using System.Windows.Forms.DataVisualization.Charting.ChartTypes; using System.Windows.Forms.DataVisualization.Charting.Utilities; using System.Windows.Forms.DataVisualization.Charting.Borders3D; using System.Windows.Forms.DataVisualization.Charting; using System.ComponentModel.Design.Serialization; using System.Reflection; #else using System.Web; using System.Web.UI; using System.Web.UI.DataVisualization.Charting; using System.Web.UI.DataVisualization.Charting.ChartTypes; using System.Web.UI.DataVisualization.Charting.Utilities; using System.Web.UI.DataVisualization.Charting.Data; #endif #endregion #if Microsoft_CONTROL namespace System.Windows.Forms.DataVisualization.Charting #else namespace System.Web.UI.DataVisualization.Charting #endif { #region Series enumerations /// /// Chart axis type (Primary or Secondary). /// public enum AxisType { /// /// Primary axis. For X axis - bottom, for Y axis - left. /// Primary, /// /// Secondary axis. For X axis - top, for Y axis - right. /// Secondary }; /// /// Sorting order (Ascending or Descending). /// public enum PointSortOrder { /// /// Ascending sorting order /// Ascending, /// /// Descending sorting order /// Descending } #endregion /// /// Data series collection /// [ SRDescription("DescriptionAttributeSeriesCollection_SeriesCollection"), ] #if ASPPERM_35 [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] #endif public class SeriesCollection : ChartNamedElementCollection { #region Constructors /// /// Data series collection object constructor. /// internal SeriesCollection(DataManager dataManager) : base(dataManager) { } #endregion #region Methods /// /// Creates a new Series with the specified name and adds it to the collection. /// /// The new chart area name. /// New series public Series Add(string name) { Series series = new Series(name); this.Add(series); return series; } /// /// Fixes the name references of the item. /// /// Item to verify and fix. internal override void FixNameReferences(Series item) { if (item != null && Chart != null) { if (String.IsNullOrEmpty(item.ChartArea) && Chart.ChartAreas != null) { item.ChartArea = Chart.ChartAreas.DefaultNameReference; } if (String.IsNullOrEmpty(item.Legend) && Chart.Legends != null) { item.Legend = Chart.Legends.DefaultNameReference; } } } #endregion #region Event handlers /// /// Updates the Series' references to ChartAreas. /// /// The sender. /// The instance containing the event data. internal void ChartAreaNameReferenceChanged(object sender, NameReferenceChangedEventArgs e) { foreach (Series series in this) if (series.ChartArea == e.OldName) series.ChartArea = e.NewName; } /// /// Updates the Series' references to Legends. /// /// The sender. /// The instance containing the event data. internal void LegendNameReferenceChanged(object sender, NameReferenceChangedEventArgs e) { foreach (Series series in this) if (series.Legend == e.OldName) series.Legend = e.NewName; } #endregion } /// /// The class stores the data points and the default series properties. /// [ SRDescription("DescriptionAttributeSeries_Series"), DefaultProperty("Points"), ] #if ASPPERM_35 [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] #endif public class Series : DataPointCustomProperties { #region Fields // Private data members, which store properties values private ChartValueType _xValueType = ChartValueType.Auto; private ChartValueType _yValueType = ChartValueType.Auto; private bool _isXValueIndexed = false; private int _yValuesPerPoint = 1; private int _markersStep = 1; private ChartColorPalette _colorPalette = ChartColorPalette.None; private AxisType _xAxisType = AxisType.Primary; private AxisType _yAxisType = AxisType.Primary; #if SUBAXES private string _ySubAxisName = string.Empty; private string _xSubAxisName = string.Empty; #endif // SUBAXES private DataPointCustomProperties _emptyPointCustomProperties = null; private DataPointCollection _points; private int _shadowOffset = 0; private Color _shadowColor = Color.FromArgb(128, 0, 0, 0); private string _chartType = ChartTypeNames.Column; private string _chartArea = String.Empty; // Series enabled flag private bool _enabled = true; // Legend name used by this series private string _legend = String.Empty; // Member of the chart data source used to data bind to the X value of the series. private string _dataSourceXMember = String.Empty; // Members of the chart data source used to data bind to the Y values of the series. private string _dataSourceYMembers = String.Empty; // Automatic values type flags internal bool autoXValueType = false; internal bool autoYValueType = false; // Total Y value of all data points private double _totalYvalue = double.NaN; // Array of dummy data used at design time private double[] _dummyDoubleValues = null; // X value type if X value is indexed internal ChartValueType indexedXValueType = ChartValueType.Auto; // Default properties static internal DataPointCustomProperties defaultCustomProperties = InitializeDefaultCustomProperties(); // Indicates that a temp. marker style was set for drawing internal bool tempMarkerStyleIsSet = false; // Indicates that number of Y values should be checked private bool _checkPointsNumber = true; // SmartLabelStyle style private SmartLabelStyle _smartLabelStyle = null; // Indicates that there is no custom axis labels in data points or series internal bool noLabelsInPoints = true; // Indicates if series has all X values set to 0 internal bool xValuesZeros = false; // Indicates if check for series X zero values was done internal bool xValuesZerosChecked = false; // fake data points for selector service in design time. // note: in design time fake points are generated // with short life time - during painting. // this collection keep a copy of design time datapoints. internal DataPointCollection fakeDataPoints; #endregion #region Series properties fields /// /// Data point label text. /// internal string label = ""; /// /// Data point X axis label text. /// internal string axisLabel = ""; /// /// Data point label format string /// internal string labelFormat = ""; /// /// If true shows point's value as a label. /// internal bool showLabelAsValue = false; /// /// Data point color /// internal Color color = Color.Empty; /// /// Data point border color /// internal Color borderColor = Color.Empty; /// /// Data point border style /// internal ChartDashStyle borderDashStyle = ChartDashStyle.Solid; /// /// Data point border width /// internal int borderWidth = 1; /// /// Data point marker border width /// internal int markerBorderWidth = 1; /// /// Data point background image /// internal string backImage = ""; /// /// Data point background image drawing mode. /// internal ChartImageWrapMode backImageWrapMode = ChartImageWrapMode.Tile; /// /// Background image transparent color. /// internal Color backImageTransparentColor = Color.Empty; /// /// Background image alignment used by ClampUnscale drawing mode. /// internal ChartImageAlignmentStyle backImageAlignment = ChartImageAlignmentStyle.TopLeft; /// /// Data point background gradient type. /// internal GradientStyle backGradientStyle = GradientStyle.None; /// /// Data point background gradient end color /// internal Color backSecondaryColor = Color.Empty; /// /// Data point hatch style /// internal ChartHatchStyle backHatchStyle = ChartHatchStyle.None; /// /// Font cache for the fonts used in the Series and DataPoint /// private FontCache _fontCache = new FontCache(); /// /// Data point font /// internal Font font = null; /// /// Data point line color /// internal Color fontColor = Color.Black; /// /// Data point font angle /// internal int fontAngle = 0; /// /// Data point marker style /// internal MarkerStyle markerStyle = MarkerStyle.None; /// /// Data point marker size /// internal int markerSize = 5; /// /// Data point marker image /// internal string markerImage = ""; /// /// Data point marker image transparent color. /// internal Color markerImageTransparentColor = Color.Empty; /// /// Data point marker color /// internal Color markerColor = Color.Empty; /// /// Data point marker border color /// internal Color markerBorderColor = Color.Empty; /// /// The tooltip. /// internal string toolTip = ""; #if !Microsoft_CONTROL /// /// URL target of the area. /// internal string url = ""; /// /// Other attributes of the area. /// internal string mapAreaAttributes = ""; /// /// Other attributes of the area. /// internal string postbackValue = ""; #endif /// /// Indicates that item is shown in the legend. /// internal bool showInLegend = true; /// /// Text of the item in the legend /// internal string legendText = ""; /// /// Tooltip of the item in the legend /// internal string legendToolTip = ""; /// /// Data point label back color /// internal Color labelBackColor = Color.Empty; /// /// Data point label border color /// internal Color labelBorderColor = Color.Empty; /// /// Data point label border style /// internal ChartDashStyle labelBorderDashStyle = ChartDashStyle.Solid; /// /// Data point label border width /// internal int labelBorderWidth = 1; /// /// Tooltip of the data point label /// internal string labelToolTip = ""; #if !Microsoft_CONTROL /// /// URL target of the data point label. /// internal string labelUrl = ""; /// /// Other attributes of the data point label. /// internal string labelMapAreaAttributes = ""; /// /// Other attributes of the area. /// internal string labelPostbackValue = ""; /// /// URL target of the item in the legend. /// internal string legendUrl = ""; /// /// Other attributes of the legend map area. /// internal string legendMapAreaAttributes = ""; /// /// Other attributes of the area. /// internal string legendPostbackValue = ""; #endif #endregion #region Constructors and initialization /// /// Initializes the default custom properties field. /// /// A DataPointCustomProperties initialized to defaults private static DataPointCustomProperties InitializeDefaultCustomProperties() { DataPointCustomProperties customProperties = new DataPointCustomProperties(null, false); customProperties.SetDefault(true); customProperties.pointCustomProperties = true; return customProperties; } /// /// Series object constructor. /// public Series() : base(null, false) { InitProperties(null, 0); } /// /// Series object constructor. /// /// Name of the data series public Series(string name) : base(null, false) { if(name == null) { throw (new ArgumentNullException(SR.ExceptionDataSeriesNameIsEmpty)); } InitProperties(name, 0); } /// /// Series object constructor. /// /// Name of the data series. /// Number of y values per data point. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "Y is a cartesian coordinate and well understood")] public Series(string name, int yValues) : base(null, false) { if(name == null) { throw (new ArgumentNullException("name", SR.ExceptionDataSeriesNameIsEmpty)); } if(YValuesPerPoint < 1) { throw (new ArgumentOutOfRangeException("yValues", SR.ExceptionDataSeriesYValuesPerPointIsZero)); } InitProperties(name, yValues); } /// /// Initialize series properties /// private void InitProperties(string name, int YValuesPerPoint) { this.font = _fontCache.DefaultFont; this.series = this; this._emptyPointCustomProperties = new DataPointCustomProperties(this, false); this._emptyPointCustomProperties.series = this; // Initialize properties _points = new DataPointCollection(this); fakeDataPoints = new DataPointCollection(this); if(name != null) { base.Name = name; } if(YValuesPerPoint != 0) { _yValuesPerPoint = YValuesPerPoint; } base.SetDefault(true); _emptyPointCustomProperties.SetDefault(true); _emptyPointCustomProperties.pointCustomProperties = true; // #if !SQLRS_CONTROL // Use transparent colors for empty points emptyPointAttributes.Color = Color.Transparent; emptyPointAttributes.BorderColor = Color.Transparent; emptyPointAttributes.FontColor = Color.Transparent; emptyPointAttributes.MarkerColor = Color.Transparent; emptyPointAttributes.MarkerBorderColor = Color.Transparent; #endif //!SQLRS_CONTROL // Create SmartLabelStyle style object _smartLabelStyle = new SmartLabelStyle(this); } #endregion #region Helper methods /// /// Gets series caption that may not be the same as series name. /// /// Series caption string. internal string GetCaption() { if (this.IsCustomPropertySet("SeriesCaption")) { return this["SeriesCaption"]; } return this.Name; } /// /// Gets custom points depth and gap depth from series properties. /// /// Chart graphics. /// Cate----cal axis. /// Returns point depth. /// Return point gap depth. internal void GetPointDepthAndGap( ChartGraphics graph, Axis axis, ref double pointDepth, ref double pointGapDepth) { // Check if series provide custom value for point depth in pixels string attribValue = this[CustomPropertyName.PixelPointDepth]; if(attribValue != null) { try { pointDepth = CommonElements.ParseDouble(attribValue); } catch { throw (new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid2("PixelPointDepth"))); } if (pointDepth <= 0) { throw (new InvalidOperationException(SR.ExceptionCustomAttributeIsNotLargerThenZiro("PixelPointDepth"))); } if (pointDepth > CustomPropertyRegistry.MaxValueOfPixelAttribute) { throw (new InvalidOperationException(SR.ExceptionCustomAttributeMustBeInRange("PixelPointDepth", (0).ToString(CultureInfo.CurrentCulture), CustomPropertyRegistry.MaxValueOfPixelAttribute.ToString(CultureInfo.CurrentCulture)))); } SizeF relativeSize = graph.GetRelativeSize(new SizeF((float)pointDepth, (float)pointDepth)); pointDepth = relativeSize.Width; if(axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right) { pointDepth = relativeSize.Height; } } // Check if series provide custom value for point gap depth in pixels attribValue = this[CustomPropertyName.PixelPointGapDepth]; if(attribValue != null) { try { pointGapDepth = CommonElements.ParseDouble(attribValue); } catch { throw (new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid2("PixelPointGapDepth"))); } if (pointGapDepth <= 0) { throw (new InvalidOperationException(SR.ExceptionCustomAttributeIsNotLargerThenZiro("PixelPointGapDepth"))); } if (pointGapDepth > CustomPropertyRegistry.MaxValueOfPixelAttribute) { throw (new InvalidOperationException(SR.ExceptionCustomAttributeMustBeInRange("PixelPointGapDepth", (0).ToString(CultureInfo.CurrentCulture), CustomPropertyRegistry.MaxValueOfPixelAttribute.ToString(CultureInfo.CurrentCulture)))); } SizeF relativeSize = graph.GetRelativeSize(new SizeF((float)pointGapDepth, (float)pointGapDepth)); pointGapDepth = relativeSize.Width; if(axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right) { pointGapDepth = relativeSize.Height; } } } /// /// Gets data point width in relative coordinates. /// /// Chart graphics. /// Axis object. /// Current minimum axis interval. /// Default width in percentage of interval. /// Point width. internal double GetPointWidth( ChartGraphics graph, Axis axis, double interval, double defaultWidth) { double pointPercentageWidth = defaultWidth; double pointWidth = 0.0; // Check if series provide custom value for point width in percentage of interval string strWidth = this[CustomPropertyName.PointWidth]; if(strWidth != null) { pointPercentageWidth = CommonElements.ParseDouble(strWidth); } // Get column width in relative and pixel coordinates pointWidth = axis.GetPixelInterval( interval * pointPercentageWidth ); SizeF pointSize = graph.GetAbsoluteSize(new SizeF((float)pointWidth, (float)pointWidth)); double pixelPointWidth = pointSize.Width; if(axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right) { pixelPointWidth = pointSize.Height; } // Check if series provide custom value for Min point width in pixels bool usePixelWidth = false; string attribValue = this[CustomPropertyName.MinPixelPointWidth]; if(attribValue != null) { double minPixelPointWidth = 0.0; try { minPixelPointWidth = CommonElements.ParseDouble(attribValue); } catch { throw(new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid2("MinPixelPointWidth"))); } if(minPixelPointWidth <= 0.0) { throw(new InvalidOperationException(SR.ExceptionCustomAttributeIsNotLargerThenZiro("MinPixelPointWidth"))); } if (minPixelPointWidth > CustomPropertyRegistry.MaxValueOfPixelAttribute) { throw (new InvalidOperationException(SR.ExceptionCustomAttributeMustBeInRange("MinPixelPointWidth", (0).ToString(CultureInfo.CurrentCulture), CustomPropertyRegistry.MaxValueOfPixelAttribute.ToString(CultureInfo.CurrentCulture)))); } if(pixelPointWidth < minPixelPointWidth) { usePixelWidth = true; pixelPointWidth = minPixelPointWidth; } } // Check if series provide custom value for Max point width in pixels attribValue = this[CustomPropertyName.MaxPixelPointWidth]; if(attribValue != null) { double maxPixelPointWidth = 0.0; try { maxPixelPointWidth = CommonElements.ParseDouble(attribValue); } catch { throw(new InvalidOperationException( SR.ExceptionCustomAttributeValueInvalid2("MaxPixelPointWidth"))); } if(maxPixelPointWidth <= 0) { throw(new InvalidOperationException(SR.ExceptionCustomAttributeIsNotLargerThenZiro("MaxPixelPointWidth"))); } if(pixelPointWidth > maxPixelPointWidth) { usePixelWidth = true; pixelPointWidth = maxPixelPointWidth; } } // Check if series provide custom value for point width in pixels attribValue = this[CustomPropertyName.PixelPointWidth]; if(attribValue != null) { usePixelWidth = true; pixelPointWidth = 0.0; try { pixelPointWidth = CommonElements.ParseDouble(attribValue); } catch { throw(new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid2("PixelPointWidth"))); } if(pixelPointWidth <= 0) { throw(new InvalidOperationException(SR.ExceptionCustomAttributeIsNotLargerThenZiro("PixelPointWidth"))); } if (pixelPointWidth > CustomPropertyRegistry.MaxValueOfPixelAttribute) { throw (new InvalidOperationException(SR.ExceptionCustomAttributeMustBeInRange("PixelPointWidth", (0).ToString(CultureInfo.CurrentCulture), CustomPropertyRegistry.MaxValueOfPixelAttribute.ToString(CultureInfo.CurrentCulture)))); } } // Translate pixel width to relative coordinates if(usePixelWidth) { SizeF pointRelativeSize = graph.GetRelativeSize(new SizeF((float)pixelPointWidth, (float)pixelPointWidth)); pointWidth = pointRelativeSize.Width; if(axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right) { pointWidth = pointRelativeSize.Height; } } return pointWidth; } /// /// Get chart type name by it's type /// /// Chart type. /// Chart type name. static internal string GetChartTypeName(SeriesChartType type) { if(type == SeriesChartType.StackedArea100) return ChartTypeNames.OneHundredPercentStackedArea; if(type == SeriesChartType.StackedBar100) return ChartTypeNames.OneHundredPercentStackedBar; if(type == SeriesChartType.StackedColumn100) return ChartTypeNames.OneHundredPercentStackedColumn; return Enum.GetName(typeof(SeriesChartType), type); } /// /// Checks if Y values of the series represent date-time. /// /// True if date-time. internal bool IsYValueDateTime() { if(this.YValueType == ChartValueType.Date || this.YValueType == ChartValueType.DateTime || this.YValueType == ChartValueType.Time || this.YValueType == ChartValueType.DateTimeOffset) { return true; } return false; } /// /// Checks if X values of the series represent date-time. /// /// True if date-time. internal bool IsXValueDateTime() { if(this.XValueType == ChartValueType.Date || this.XValueType == ChartValueType.DateTime || this.XValueType == ChartValueType.Time || this.XValueType == ChartValueType.DateTimeOffset) { return true; } return false; } /// /// Checks if series is visible. /// /// True if series is visible. internal bool IsVisible() { // Check if enabled flag is set and the ChartArea is defined if(this.Enabled && !String.IsNullOrEmpty(this.ChartArea)) { return true; } return false; } /// /// Checks if series chart type uses a "Fast" mode chart type. /// /// True if series uses "Fast" mode chart type. internal bool IsFastChartType() { // Check if fast mode chart type is used in the series if(this.ChartType == SeriesChartType.FastLine) { return true; } // Check if fast mode chart type is used in the series if(this.ChartType == SeriesChartType.FastPoint) { return true; } return false; } /// /// Throws exception if specified value type is not supported. /// /// Value type to check. internal void CheckSupportedTypes(Type type) { // Check parameters type if(type == typeof(Double) || type == typeof(DateTime) || type == typeof(String) || type == typeof(Int32) || type == typeof(UInt32) || type == typeof(Decimal) || type == typeof(Single) || type == typeof(Int16) || type == typeof(UInt16) || type == typeof(Int64) || type == typeof(UInt64) || type == typeof(Byte) || type == typeof(SByte) || type == typeof(System.DBNull) || type == typeof(Boolean) ) { return; } // Unsupported parameter type throw(new ArgumentException(SR.ExceptionDataSeriesPointTypeUnsupported( type.ToString() ) )); } /// /// Apply palette colors to the data series points if UsePaletteColors property is set. /// internal void ApplyPaletteColors() { // Use Series or Data Manager palette DataManager dataManager = this.Common.DataManager; ChartColorPalette currentPalette = (this.Palette == ChartColorPalette.None) ? dataManager.Palette : this.Palette; // if it is still none - check if custom colors pallete is empty. if ( currentPalette == ChartColorPalette.None && dataManager.PaletteCustomColors.Length == 0 ) { currentPalette = ChartColorPalette.BrightPastel; } // Get palette colors int colorIndex = 0; Color[] paletteColors = (currentPalette == ChartColorPalette.None) ? dataManager.PaletteCustomColors : ChartPaletteColors.GetPaletteColors(currentPalette); foreach(DataPoint dataPoint in _points) { // Change color of the series data points only if no color is set if((!dataPoint.IsCustomPropertySet(CommonCustomProperties.Color) || dataPoint.tempColorIsSet ) && !dataPoint.IsEmpty) { dataPoint.SetAttributeObject(CommonCustomProperties.Color, paletteColors[colorIndex]); dataPoint.tempColorIsSet = true; ++colorIndex; if(colorIndex >= paletteColors.Length) { colorIndex = 0; } } } } /// /// Gets design time dummy data. /// /// AxisName of the data to get. /// Dummy data for chart in design-time. internal IEnumerable GetDummyData(ChartValueType type) { string[] stringValues = { "abc1", "abc2", "abc3", "abc4", "abc5", "abc6" }; DateTime[] dateValues = { DateTime.Now.Date, DateTime.Now.Date.AddDays(1), DateTime.Now.Date.AddDays(2), DateTime.Now.Date.AddDays(3), DateTime.Now.Date.AddDays(4), DateTime.Now.Date.AddDays(4) }; // Fill array of random data if(_dummyDoubleValues == null) { #if !SQLRS_CONTROL Random random2 = new Random(unchecked((int)DateTime.Now.Ticks + this.Color.B + this.Color.G + this.Color.R)); #else int seed = 0; for (int index = 0; index < this.Name.Length; index++) seed += (int)this.Name[index]; Random random2 = new Random(seed); #endif _dummyDoubleValues = new double[6]; for(int valueIndex = 0; valueIndex < 6; valueIndex++) { _dummyDoubleValues[valueIndex] = random2.Next(10, 100); } } // Return dummy data if(type == ChartValueType.DateTime || type == ChartValueType.Date || type == ChartValueType.DateTimeOffset) { return dateValues; } else if(type == ChartValueType.Time) { dateValues = new DateTime[] { DateTime.Now, DateTime.Now.AddMinutes(1), DateTime.Now.AddMinutes(2), DateTime.Now.AddMinutes(3), DateTime.Now.AddMinutes(4), DateTime.Now.AddMinutes(4) }; return dateValues; } else if(type == ChartValueType.String) { return stringValues; } return _dummyDoubleValues; } /// /// Returns total of the Y values. /// /// Y values total. internal double GetTotalYValue() { return this.GetTotalYValue(0); } /// /// Returns total of the Y values. /// /// Index of the Y value to use /// Y values total. internal double GetTotalYValue(int yValueIndex) { if(yValueIndex == 0) { // Total was already calculated if(!double.IsNaN(_totalYvalue)) { return _totalYvalue; } // Calculate total _totalYvalue = 0; foreach(DataPoint point in this.Points) { _totalYvalue += point.YValues[yValueIndex]; } return _totalYvalue; } // Check if series has enough Y values if(yValueIndex >= this.YValuesPerPoint) { throw(new InvalidOperationException( SR.ExceptionDataSeriesYValueIndexNotExists(yValueIndex.ToString(CultureInfo.InvariantCulture), this.Name ) ) ); } // Calculate total double yValue = 0; foreach(DataPoint point in this.Points) { yValue += point.YValues[yValueIndex]; } return yValue; } /// /// Replaces predefined keyword inside the string with their values. /// /// Original string with keywords. /// Modified string. internal override string ReplaceKeywords(string strOriginal) { // Nothing to process if(strOriginal == null || strOriginal.Length == 0) return strOriginal; // Replace all "\n" strings with '\n' character string result = strOriginal.Replace("\\n", "\n"); // #SERIESNAME - series name result = result.Replace(KeywordName.SeriesName, this.Name); result = result.Replace(KeywordName.Ser, this.Name); // #SER Depricated Keyword // #CUSTOMPROPERTY - one of the custom attributes by name result = DataPoint.ReplaceCustomPropertyKeyword(result, this); // #TOTAL - total of Y values result = ReplaceOneKeyword( this.Chart, this, this.Tag, ChartElementType.Nothing, result, KeywordName.Total, SeriesValuesFormulaType.Total, this.YValueType, ""); // #AVG - total of Y values result = ReplaceOneKeyword( this.Chart, this, this.Tag, ChartElementType.Nothing, result, KeywordName.Avg, SeriesValuesFormulaType.Average, this.YValueType, ""); // #MAX - total of Y values result = ReplaceOneKeyword( this.Chart, this, this.Tag, ChartElementType.Nothing, result, KeywordName.Max, SeriesValuesFormulaType.Maximum, this.YValueType, ""); // #MIN - total of Y values result = ReplaceOneKeyword( this.Chart, this, this.Tag, ChartElementType.Nothing, result, KeywordName.Min, SeriesValuesFormulaType.Minimum, this.YValueType, ""); // #FIRST - total of Y values result = ReplaceOneKeyword( this.Chart, this, this.Tag, ChartElementType.Nothing, result, KeywordName.First, SeriesValuesFormulaType.First, this.YValueType, ""); // #LAST - total of Y values result = ReplaceOneKeyword( this.Chart, this, this.Tag, ChartElementType.Nothing, result, KeywordName.Last, SeriesValuesFormulaType.Last, this.YValueType, ""); // #LEGENDTEXT - series name result = result.Replace(KeywordName.LegendText, this.LegendText); return result; } /// /// Helper function which replaces one keyword. /// /// Chart object reference. /// Chart element type. /// Object being formatted. /// Additional object tag. /// Original string. /// Keyword to replace. /// Formula used to calculate the value. /// AxisName of value. /// Default format string. /// Result string. internal string ReplaceOneKeyword( Chart chart, object obj, object objTag, ChartElementType elementType, string strOriginal, string keyword, SeriesValuesFormulaType formulaType, ChartValueType valueType, string defaultFormat) { string result = strOriginal; int keyIndex = -1; while((keyIndex = result.IndexOf(keyword, StringComparison.Ordinal)) != -1) { int keyEndIndex = keyIndex + keyword.Length; // Get optional Y value index int yValueIndex = 0; if(result.Length > keyEndIndex + 1 && result[keyEndIndex] == 'Y' && char.IsDigit(result[keyEndIndex + 1])) { yValueIndex = int.Parse(result.Substring(keyEndIndex + 1, 1), CultureInfo.InvariantCulture); keyEndIndex += 2; } // Get optional format string format = defaultFormat; if(result.Length > keyEndIndex && result[keyEndIndex] == '{') { int formatEnd = result.IndexOf('}', keyEndIndex); if(formatEnd == -1) { throw(new InvalidOperationException( SR.ExceptionDataSeriesKeywordFormatInvalid( result ))); } format = result.Substring(keyEndIndex, formatEnd - keyEndIndex).Trim('{', '}'); keyEndIndex = formatEnd + 1; } // Remove keyword string (with optional format) result = result.Remove(keyIndex, keyEndIndex - keyIndex); // Calculate value double totalValue = this.GetTotalYValue(yValueIndex); double keywordValue = 0.0; switch(formulaType) { case(SeriesValuesFormulaType.Average): { if(this.Points.Count > 0) { keywordValue = totalValue / this.Points.Count; } break; } case(SeriesValuesFormulaType.First): { if(this.Points.Count > 0) { keywordValue = this.Points[0].YValues[yValueIndex]; } break; } case(SeriesValuesFormulaType.Last): { if(this.Points.Count > 0) { keywordValue = this.Points[this.Points.Count - 1].YValues[yValueIndex]; } break; } case(SeriesValuesFormulaType.Maximum): { if (this.Points.Count > 0) { keywordValue = double.MinValue; foreach (DataPoint point in this.Points) { keywordValue = Math.Max(keywordValue, point.YValues[yValueIndex]); } } break; } case(SeriesValuesFormulaType.Minimum): { if (this.Points.Count > 0) { keywordValue = double.MaxValue; foreach (DataPoint point in this.Points) { keywordValue = Math.Min(keywordValue, point.YValues[yValueIndex]); } } break; } case(SeriesValuesFormulaType.Total): { keywordValue = totalValue; break; } } // Insert value result = result.Insert(keyIndex, ValueConverter.FormatValue(chart, obj, objTag, keywordValue, format, valueType, elementType)); } return result; } /// /// Helper function which replaces one keyword. /// /// Chart object reference. /// Chart element type. /// Object being formatted. /// Additional object tag. /// Original string. /// Keyword to replace. /// Value to replace with. /// AxisName of value. /// Default format string. /// Result string. internal string ReplaceOneKeyword(Chart chart, object obj, object objTag, ChartElementType elementType, string strOriginal, string keyword, double value, ChartValueType valueType, string defaultFormat) { string result = strOriginal; int keyIndex = -1; while((keyIndex = result.IndexOf(keyword, StringComparison.Ordinal)) != -1) { // Get optional format int keyEndIndex = keyIndex + keyword.Length; string format = defaultFormat; if(result.Length > keyEndIndex && result[keyEndIndex] == '{') { int formatEnd = result.IndexOf('}', keyEndIndex); if(formatEnd == -1) { throw(new InvalidOperationException( SR.ExceptionDataSeriesKeywordFormatInvalid(result))); } format = result.Substring(keyEndIndex, formatEnd - keyEndIndex).Trim('{', '}'); keyEndIndex = formatEnd + 1; } // Remove keyword string (with optional format) result = result.Remove(keyIndex, keyEndIndex - keyIndex); // Insert value result = result.Insert(keyIndex, ValueConverter.FormatValue(chart, obj, objTag, value, format, valueType, elementType)); } return result; } #endregion #region Points sorting methods /// /// Sorts the points in the series. /// /// Sorting order. /// Value used for sorting (X, Y, Y2, ...). public void Sort(PointSortOrder pointSortOrder, string sortBy) { // Check arguments if (sortBy==null) throw new ArgumentNullException("sortBy"); // Sort items using data points comparer class DataPointComparer comparer = new DataPointComparer(this, pointSortOrder, sortBy); this.Points.ItemList.Sort(comparer); // Invalidate chart area only this.Invalidate(true, false); } /// /// Sorts the points in the series. /// /// Sorting order. public void Sort(PointSortOrder pointSortOrder) { Sort(pointSortOrder, "Y"); } /// /// Sorts the points in the series using IComparer interface. /// /// IComparer interface. public void Sort(IComparer comparer) { // Check arguments if (comparer == null) throw new ArgumentNullException("comparer"); // Sort points this.Points.ItemList.Sort(comparer); // Invalidate chart area only this.Invalidate(true, false); } #endregion #region Series preparation/cleanup for drawing /// /// Moves the position markers. /// /// From series. /// To series. internal static void MovePositionMarkers(Series fromSeries, Series toSeries) { foreach (DataPoint dp in fromSeries.Points) { if (dp.IsCustomPropertySet("OriginalPointIndex")) { int index = -1; if (Int32.TryParse(dp["OriginalPointIndex"], NumberStyles.Integer, CultureInfo.InvariantCulture, out index)) { if (index > -1 && index < toSeries.Points.Count) { toSeries.Points[index].positionRel = dp.positionRel; } } } } } /// /// Called after the series was drawn. /// /// Site interface of the control. /// True if series was removed from collection. [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "This parameter is used when compiling for the Microsoft version of Chart")] internal bool UnPrepareData(ISite controlSite) { bool result = false; // Process Renko chart type data calculations if(RenkoChart.UnPrepareData(this)) { result = true; } // Process ThreeLineBreak chart type data calculations if(ThreeLineBreakChart.UnPrepareData(this)) { result = true; } // Process Kagi chart type data calculations if(KagiChart.UnPrepareData(this)) { result = true; } // Process PointAndFigure chart type data calculations if(PointAndFigureChart.UnPrepareData(this)) { result = true; } // Undo all changes done for the collected slice support if(PieChart.UnPrepareData(this)) { result = true; } // Reset original value type which was temp. set to String if(_isXValueIndexed) { _xValueType = indexedXValueType; } // Reset auro values only at design time bool reset = false; if(controlSite != null && controlSite.DesignMode) { reset = true; } ResetAutoValues(reset); return result; } /// /// Reset auto calculated series values. /// internal void ResetAutoValues() { ResetAutoValues(true); } /// /// Reset auto calculated series values. /// /// Indicates that value types should be reset. internal void ResetAutoValues(bool reset) { // If temporary data attribute is set - remove all data points if(this.IsCustomPropertySet("TempDesignData")) { this.DeleteCustomProperty("TempDesignData"); // save the fake DataPoints for selector service bool savePoints = true; if (this.Chart != null && !this.Chart.IsDesignMode()) { savePoints = false; } if ( savePoints ) { fakeDataPoints.Clear(); foreach (DataPoint p in this.Points) { fakeDataPoints.Add(p); } } this.Points.Clear(); } // Reset series color if(this.tempColorIsSet) { this.tempColorIsSet = false; this.Color = Color.Empty; } // Reset series marker if(this.tempMarkerStyleIsSet) { this.tempMarkerStyleIsSet = false; this.MarkerStyle = MarkerStyle.None; } // Reset points color foreach(DataPoint dataPoint in _points) { if(dataPoint.tempColorIsSet) { dataPoint.Color = Color.Empty; } } // Reset value type to Auto (if not Serializing data) if(reset) { if(this.Chart == null || this.Chart.serializing == false) { if(autoXValueType) { _xValueType = ChartValueType.Auto; autoXValueType = false; } if(autoYValueType) { _yValueType = ChartValueType.Auto; autoYValueType = false; } } } } /// /// Called just before the data from the series to be used to perform these operations: /// - apply palette colors to the data points /// - fill empty data points /// - provide fake data in design mode /// - retrieving data from the DataSource /// /// If true each data point will be assigned a color from the palette (if it's set) internal void PrepareData(bool applyPaletteColors) { if(!this.IsVisible()) { return; } // Series chart area name can be empty or a valid area name Chart.ChartAreas.VerifyNameReference(this.ChartArea); // Check if sereis data points have required number of Y values if(this.Points.Count > 0 && this.Points[0].YValues.Length < this.YValuesPerPoint) { // Resize data points Y value(s) arrays foreach(DataPoint dp in this.Points) { dp.ResizeYValueArray(this.YValuesPerPoint); } } // Get series data source bool fillTempData = false; if(this.Points.Count == 0) { // If there is no points defined in design-time if(Chart.IsDesignMode()) { fillTempData = true; } else if(this.IsCustomPropertySet("UseDummyData")) { if(String.Compare(this["UseDummyData"], "True", StringComparison.OrdinalIgnoreCase) == 0) { fillTempData = true; } } } // Create dummy data only if there was no points if(fillTempData) { if(this.IsXValueDateTime() || _xValueType == ChartValueType.String) { this.Points.DataBindXY(GetDummyData(_xValueType), GetDummyData(_yValueType)); } else { double[] xValues = new double[] { 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 }; if(this.ChartType == SeriesChartType.Polar) { xValues = new double[] { 0.0, 45.0, 115.0, 145.0, 180.0, 220.0 }; } this.Points.DataBindXY(xValues, GetDummyData(_yValueType)); } // If point has more than one Y value - copy the data from first value if(this.YValuesPerPoint > 1) { foreach(DataPoint point in this.Points) { for(int valueIndex = 1; valueIndex < this.YValuesPerPoint; valueIndex++) { point.YValues[valueIndex] = point.YValues[0]; } if(this.YValuesPerPoint >= 2) { point.YValues[1] = point.YValues[0] / 2 - 1; } if(this.YValuesPerPoint >= 4) { point.YValues[2] = point.YValues[1] + (point.YValues[0] - point.YValues[1]) / 3; point.YValues[3] = point.YValues[2] + (point.YValues[0] - point.YValues[1]) / 3; } if(this.YValuesPerPoint >= 6) { point.YValues[4] = point.YValues[2] + (point.YValues[3] - point.YValues[2]) / 2; point.YValues[5] = point.YValues[2] + (point.YValues[3] - point.YValues[2]) / 3; } } } // Set data series attribute that data is temporary this["TempDesignData"] = "true"; } // If value type was not Auto detected - set it to double if(_xValueType == ChartValueType.Auto) { _xValueType = ChartValueType.Double; autoXValueType = true; } if(_yValueType == ChartValueType.Auto) { _yValueType = ChartValueType.Double; autoYValueType = true; } // Use data point index as X value indexedXValueType = _xValueType; // Reset total Y value _totalYvalue = double.NaN; // Supress zero and negative values with logarithmic axis exceptions if(this.Chart != null && this.Chart.chartPicture.SuppressExceptions) { // Get series axis Axis axisY = this.Chart.ChartAreas[this.ChartArea].GetAxis(AxisName.Y, this.YAxisType, this.YSubAxisName); foreach(DataPoint point in this.Points) { for(int yValueIndex = 0; yValueIndex < point.YValues.Length; yValueIndex++) { if(axisY.IsLogarithmic) { // Look for Y values less or equal to Zero if(point.YValues[yValueIndex] <= 0.0) { point.YValues[yValueIndex] = 1.0; point.IsEmpty = true; } } // Check All Y values for NaN if(double.IsNaN(point.YValues[yValueIndex])) { point.YValues[yValueIndex] = 0.0; point.IsEmpty = true; } } } } // Process Error Bar chart type data linking and calculations ErrorBarChart.GetDataFromLinkedSeries(this); ErrorBarChart.CalculateErrorAmount(this); // Process Box chart type data calculations BoxPlotChart.CalculateBoxPlotFromLinkedSeries(this); // Process Renko chart type data calculations RenkoChart.PrepareData(this); // Process ThreeLineBreak chart type data calculations ThreeLineBreakChart.PrepareData(this); // Process Kagi chart type data calculations KagiChart.PrepareData(this); // Process PointAndFigure chart type data calculations PointAndFigureChart.PrepareData(this); // Check if Collected slice should be displayed in Pie/Doughnut charts PieChart.PrepareData(this); // Apply palette colors to the data points if (applyPaletteColors) { this.ApplyPaletteColors(); } } #endregion #region Series Properties /// /// Data series name. /// [ SRCategory("CategoryAttributeData"), Bindable(true), SRDescription("DescriptionAttributeSeries_Name"), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public override string Name { get { return base.Name; } set { base.Name = value; } } /// /// Member of the chart data source used to data bind to the X value of the series. /// [ SRCategory("CategoryAttributeDataSource"), Bindable(true), SRDescription("DescriptionAttributeSeries_ValueMemberX"), DefaultValue(""), #if !Microsoft_CONTROL TypeConverter(Editors.SeriesDataFieldXConvertor.Convertor) #else TypeConverter(typeof(SeriesDataSourceMemberConverter)) #endif ] public string XValueMember { get { return _dataSourceXMember; } set { if(value == "(none)") { _dataSourceXMember = String.Empty; } else { _dataSourceXMember = value; } // Reset data bound flag if(this.Common!=null && this.Common.ChartPicture!=null) { this.Common.ChartPicture.boundToDataSource = false; } } } /// /// Members of the chart data source used to data bind to the Y values of the series. /// [ SRCategory("CategoryAttributeDataSource"), Bindable(true), SRDescription("DescriptionAttributeSeries_ValueMembersY"), DefaultValue(""), #if !Microsoft_CONTROL TypeConverter(Editors.SeriesDataFieldYConvertor.Convertor), Editor(Editors.SeriesDataFieldValueAxisUITypeEditor.Editor, Editors.SeriesDataFieldValueAxisUITypeEditor.Base) #else TypeConverter(typeof(SeriesDataSourceMemberConverter)), Editor(Editors.SeriesDataSourceMemberValueAxisUITypeEditor.Editor, Editors.SeriesDataSourceMemberValueAxisUITypeEditor.Base) #endif ] public string YValueMembers { get { return _dataSourceYMembers; } set { if(value == "(none)") { _dataSourceYMembers = String.Empty; } else { _dataSourceYMembers = value; } // Reset data bound flag if(this.Common != null && this.Common.ChartPicture!=null) { this.Common.ChartPicture.boundToDataSource = false; } } } /// /// Name of the Chart legend used by the series. /// [ SRCategory("CategoryAttributeLegend"), Bindable(true), SRDescription("DescriptionAttributeSeries_Legend"), DefaultValue(""), TypeConverter(typeof(SeriesLegendNameConverter)) ] public string Legend { get { return _legend; } set { if (value != _legend) { if (Chart != null && Chart.Legends != null) { Chart.Legends.VerifyNameReference(value); } _legend = value; this.Invalidate(false, true); } } } /// /// The value type of the X axis. /// [ SRCategory("CategoryAttributeData"), Bindable(true), SRDescription("DescriptionAttributeSeries_XValueType"), DefaultValue(ChartValueType.Auto), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public ChartValueType XValueType { get { return _xValueType; } set { _xValueType = value; this.autoXValueType = false; this.Invalidate(true, false); } } /// /// Indicates whether a data point index (1,2,...) will be used for the X value. /// [ SRCategory("CategoryAttributeData"), Bindable(true), SRDescription("DescriptionAttributeSeries_XValueIndexed"), DefaultValue(false), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public bool IsXValueIndexed { get { return _isXValueIndexed; } set { _isXValueIndexed = value; this.Invalidate(true, false); } } /// /// The value type of the Y axis. /// [ SRCategory("CategoryAttributeData"), Bindable(true), SRDescription("DescriptionAttributeSeries_YValueType"), DefaultValue(ChartValueType.Auto), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute), #endif TypeConverter(typeof(SeriesYValueTypeConverter)), ] public ChartValueType YValueType { get { return _yValueType; } set { _yValueType = value; this.autoYValueType = false; this.Invalidate(true, false); } } /// /// Number of Y values stored for each Data Point. /// [ SRCategory("CategoryAttributeData"), Bindable(true), SRDescription("DescriptionAttributeSeries_YValuesPerPoint"), DefaultValue(1), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public int YValuesPerPoint { get { // If number of Y value(s) is not set - get one from the chart type if(this._checkPointsNumber && this.ChartTypeName.Length > 0 && this.Common != null) { _checkPointsNumber = false; ChartTypeRegistry chartTypeRegistry = this.Common.ChartTypeRegistry; IChartType chartType = chartTypeRegistry.GetChartType(this.ChartTypeName); if(chartType.YValuesPerPoint > _yValuesPerPoint) { _yValuesPerPoint = chartType.YValuesPerPoint; // Resize Y value(s) array of data points if(_points.Count > 0) { // Resize data points Y value(s) arrays foreach(DataPoint dp in _points) { dp.ResizeYValueArray(_yValuesPerPoint); } } } } return _yValuesPerPoint; } set { // Check if argument is in range if(value < 1 || value > 32) { throw (new ArgumentOutOfRangeException("value", SR.ExceptionDataSeriesYValueNumberInvalid)); } _checkPointsNumber = true; // Resize Y value(s) array of data points if(_points.Count > 0) { // Resize data points Y value(s) arrays foreach(DataPoint dp in _points) { dp.ResizeYValueArray(value); } } _yValuesPerPoint = value; this.Invalidate(true, false); } } /// /// Collection of data points in the series. /// [ SRCategory("CategoryAttributeData"), Bindable(true), SRDescription("DescriptionAttributeSeries_Points"), #if Microsoft_CONTROL DesignerSerializationVisibility(DesignerSerializationVisibility.Content), #else Themeable(false), PersistenceMode(PersistenceMode.InnerProperty), #endif Editor(Editors.DataPointCollectionEditor.Editor, Editors.DataPointCollectionEditor.Base) ] public DataPointCollection Points { get { return _points; } } /// /// Default properties of an empty data point. /// [ SRCategory("CategoryAttributeEmptyPoints"), Bindable(true), SRDescription("DescriptionAttributeSeries_EmptyPointStyle"), #if Microsoft_CONTROL DesignerSerializationVisibility(DesignerSerializationVisibility.Content), #else PersistenceMode(PersistenceMode.InnerProperty), #endif ] public DataPointCustomProperties EmptyPointStyle { get { return _emptyPointCustomProperties; } set { if (value.series == null && _emptyPointCustomProperties.series != null) { value.series = _emptyPointCustomProperties.series; } _emptyPointCustomProperties = value; _emptyPointCustomProperties.pointCustomProperties = false; _emptyPointCustomProperties.SetDefault(false); _emptyPointCustomProperties.pointCustomProperties = true; _emptyPointCustomProperties.Parent = this; this.Invalidate(true, false); } } /// /// Color palette to use. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), SRDescription("DescriptionAttributePalette"), DefaultValue(ChartColorPalette.None), Editor(Editors.ColorPaletteEditor.Editor, Editors.ColorPaletteEditor.Base) ] public ChartColorPalette Palette { get { return _colorPalette; } set { _colorPalette = value; this.Invalidate(true, true); } } /// /// Specify how often to display data point markers. /// [ SRCategory("CategoryAttributeMarker"), Bindable(true), SRDescription("DescriptionAttributeSeries_MarkerStep"), DefaultValue(1) ] public int MarkerStep { get { return _markersStep; } set { if(value <= 0) { throw(new ArgumentException( SR.ExceptionMarkerStepNegativeValue, "value")); } _markersStep = value; this.Invalidate(true, false); } } /// /// Shadow offset of series. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), SRDescription("DescriptionAttributeShadowOffset"), DefaultValue(0) ] public int ShadowOffset { get { return _shadowOffset; } set { _shadowOffset = value; this.Invalidate(true, true); } } /// /// Shadow color of series. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(typeof(Color), "128,0,0,0"), SRDescription("DescriptionAttributeShadowColor"), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public Color ShadowColor { get { return _shadowColor; } set { _shadowColor = value; this.Invalidate(true, true); } } #if SUBAXES /// /// Name of the Y sub-axis this series is attached to. /// [ SRCategory("CategoryAttributeAxes"), Bindable(true), SRDescription("DescriptionAttributeSeries_YSubAxisName"), DefaultValue("") ] public string YSubAxisName { get { return this._ySubAxisName; } set { this._ySubAxisName = value; this.Invalidate(true, false); } } /// /// Name of the X sub-axis this series is attached to. /// [ SRCategory("CategoryAttributeAxes"), Bindable(true), SRDescription("DescriptionAttributeSeries_XSubAxisName"), DefaultValue("") ] public string XSubAxisName { get { return this._xSubAxisName; } set { this._xSubAxisName = value; this.Invalidate(true, false); } } #else // SUBAXES /// /// Name of the Y sub-axis this series is attached to. /// [ SRCategory("CategoryAttributeAxes"), Bindable(true), SRDescription("DescriptionAttributeSeries_YSubAxisName"), DefaultValue(""), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "value") ] internal string YSubAxisName { get { return string.Empty; } set { } } /// /// Name of the X sub-axis this series is attached to. /// [ SRCategory("CategoryAttributeAxes"), Bindable(true), SRDescription("DescriptionAttributeSeries_XSubAxisName"), DefaultValue(""), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "value") ] internal string XSubAxisName { get { return string.Empty; } set { } } #endif // SUBAXES /// /// Axis type of horizontal axes. /// [ SRCategory("CategoryAttributeAxes"), Bindable(true), SRDescription("DescriptionAttributeSeries_XAxisType"), DefaultValue(AxisType.Primary) ] public AxisType XAxisType { get { return _xAxisType; } set { _xAxisType = value; this.Invalidate(true, false); } } /// /// Axis type of vertical axes. /// [ SRCategory("CategoryAttributeAxes"), Bindable(true), SRDescription("DescriptionAttributeSeries_YAxisType"), DefaultValue(AxisType.Primary) ] public AxisType YAxisType { get { return _yAxisType; } set { _yAxisType = value; this.Invalidate(true, false); } } /// /// Gets or sets a flag which indicates whether the series is enabled. /// [ SRCategory("CategoryAttributeAppearance"), Bindable(true), DefaultValue(true), SRDescription("DescriptionAttributeSeries_Enabled"), NotifyParentPropertyAttribute(true), ParenthesizePropertyNameAttribute(true), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] public bool Enabled { get { return _enabled; } set { _enabled = value; this.Invalidate(true, true); } } /// /// Chart type used to draw the series. /// [ SRCategory("CategoryAttributeChart"), Bindable(true), SRDescription("DescriptionAttributeSeries_Type"), DefaultValue(SeriesChartType.Column), RefreshProperties(RefreshProperties.All), Editor(Editors.ChartTypeEditor.Editor, Editors.ChartTypeEditor.Base) ] public SeriesChartType ChartType { get { SeriesChartType type = SeriesChartType.Column; if(String.Compare(this.ChartTypeName, ChartTypeNames.OneHundredPercentStackedArea, StringComparison.OrdinalIgnoreCase) == 0) { type = SeriesChartType.StackedArea100; } else if (String.Compare(this.ChartTypeName, ChartTypeNames.OneHundredPercentStackedBar, StringComparison.OrdinalIgnoreCase) == 0) { type = SeriesChartType.StackedBar100; } else if (String.Compare(this.ChartTypeName, ChartTypeNames.OneHundredPercentStackedColumn, StringComparison.OrdinalIgnoreCase) == 0) { type = SeriesChartType.StackedColumn100; } else { try { type = (SeriesChartType)Enum.Parse(typeof(SeriesChartType), this.ChartTypeName, true); } catch (ArgumentException) { } } return type; } set { this.ChartTypeName = Series.GetChartTypeName(value); } } /// /// Chart type used to draw the series. /// [ Browsable(false), EditorBrowsableAttribute(EditorBrowsableState.Never), SRCategory("CategoryAttributeChart"), Bindable(true), SRDescription("DescriptionAttributeSeries_Type"), DefaultValue(ChartTypeNames.Column), TypeConverter(typeof(ChartTypeConverter)), Editor(Editors.ChartTypeEditor.Editor, Editors.ChartTypeEditor.Base), RefreshProperties(RefreshProperties.All), SerializationVisibilityAttribute(SerializationVisibility.Hidden), DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden) ] public string ChartTypeName { get { return _chartType; } set { if(_chartType != value && value.Length > 0) { if(Common != null) { ChartTypeRegistry chartTypeRegistry = Common.ChartTypeRegistry; if(chartTypeRegistry != null) { IChartType type = chartTypeRegistry.GetChartType(value); if(_yValuesPerPoint < type.YValuesPerPoint) { // Set minimum Y values number for the chart type _yValuesPerPoint = type.YValuesPerPoint; // Resize Y value(s) array of data points if(_points.Count > 0) { // Resize data points Y value(s) arrays foreach(DataPoint dp in _points) { dp.ResizeYValueArray(_yValuesPerPoint); } } } #if Microsoft_CONTROL // Refresh Minimum and Maximum from data // after recalc and set data if(Chart != null && Chart.chartPicture != null) { Chart.chartPicture.ResetMinMaxFromData(); } #endif } } } _chartType = value; this.Invalidate(false, true); } } /// /// Chart area in which this series is drawn. /// [ SRCategory("CategoryAttributeChart"), Bindable(true), SRDescription("DescriptionAttributeSeries_ChartArea"), DefaultValue(""), TypeConverter(typeof(SeriesAreaNameConverter)) ] public string ChartArea { get { return _chartArea; } set { if (value != _chartArea) { if (Chart != null && Chart.ChartAreas != null) { Chart.ChartAreas.VerifyNameReference(value); } _chartArea = value; this.Invalidate(false, true); } } } /* /// /// If set to true, each data point of the series will use a random color from the palette. /// [ SRCategory("CategoryAttributeChart"), Bindable(true), SRDescription("DescriptionAttributeDataSeriesGroupID"), PersistenceModeAttribute(PersistenceMode.Attribute), DefaultValue("") ] public string GroupID { get { return groupID; } set { groupID = value; } } */ /// /// Text of X axis label. /// [ Browsable(false), SRCategory("CategoryAttributeMisc"), Bindable(true), DefaultValue(""), SRDescription("DescriptionAttributeAxisLabel"), #if !Microsoft_CONTROL PersistenceMode(PersistenceMode.Attribute) #endif ] override public string AxisLabel { get { return base.AxisLabel; } set { base.AxisLabel = value; this.Invalidate(true, false); } } /// /// Style of the SmartLabel. /// [ Browsable(true), SRCategory("CategoryAttributeLabel"), Bindable(true), SRDescription("DescriptionAttributeSeries_SmartLabels"), #if Microsoft_CONTROL DesignerSerializationVisibility(DesignerSerializationVisibility.Content), #else PersistenceMode(PersistenceMode.InnerProperty), #endif ] public SmartLabelStyle SmartLabelStyle { get { return _smartLabelStyle; } set { value.chartElement = this; _smartLabelStyle = value; this.Invalidate(false, false); } } /// /// Series font cache is reused by points. /// /// The font cache. internal FontCache FontCache { get { return _fontCache; } } #endregion #region Invalidating method /// /// Invalidate chart or just a chart area and/or legend when collection is changed /// /// Invalidate chart area only. /// Invalidate legend area only. [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "This parameter is used when compiling for the Microsoft version of Chart")] internal void Invalidate(bool invalidateAreaOnly, bool invalidateLegend) { #if Microsoft_CONTROL if(Chart != null) { if(!invalidateAreaOnly) { this.Invalidate(); } else { // Invalidate one chart area (area with this name may not exist) try { Chart.ChartAreas[this.ChartArea].Invalidate(); } catch(ArgumentException) { // occurs if the chart area is not found in the collection } // Invalidate legend if(invalidateLegend && Chart.Legends.IndexOf(this.Legend) >= 0) { Chart.Legends[this.Legend].Invalidate(true); } } } #endif } #endregion #region Series Enumeration /// /// Series values formula type used in the keywords /// internal enum SeriesValuesFormulaType { Total, Average, Maximum, Minimum, First, Last } #endregion // Series Enumeration #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 (this._emptyPointCustomProperties != null) { this._emptyPointCustomProperties.Dispose(); this._emptyPointCustomProperties = null; } if (this._points != null) { this._points.Dispose(); this._points = null; } if (this.fakeDataPoints != null) { this.fakeDataPoints.Dispose(); this.fakeDataPoints = null; } } base.Dispose(disposing); } #endregion } }