|
//-------------------------------------------------------------
// <copyright company=’Microsoft Corporation’>
// Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @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
/// <summary>
/// Chart axis type (Primary or Secondary).
/// </summary>
public enum AxisType
{
/// <summary>
/// Primary axis. For X axis - bottom, for Y axis - left.
/// </summary>
Primary,
/// <summary>
/// Secondary axis. For X axis - top, for Y axis - right.
/// </summary>
Secondary
};
/// <summary>
/// Sorting order (Ascending or Descending).
/// </summary>
public enum PointSortOrder
{
/// <summary>
/// Ascending sorting order
/// </summary>
Ascending,
/// <summary>
/// Descending sorting order
/// </summary>
Descending
}
#endregion
/// <summary>
/// Data series collection
/// </summary>
[
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<Series>
{
#region Constructors
/// <summary>
/// Data series collection object constructor.
/// </summary>
internal SeriesCollection(DataManager dataManager)
: base(dataManager)
{
}
#endregion
#region Methods
/// <summary>
/// Creates a new Series with the specified name and adds it to the collection.
/// </summary>
/// <param name="name">The new chart area name.</param>
/// <returns>New series</returns>
public Series Add(string name)
{
Series series = new Series(name);
this.Add(series);
return series;
}
/// <summary>
/// Fixes the name references of the item.
/// </summary>
/// <param name="item">Item to verify and fix.</param>
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
/// <summary>
/// Updates the Series' references to ChartAreas.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="Charting.NameReferenceChangedEventArgs"/> instance containing the event data.</param>
internal void ChartAreaNameReferenceChanged(object sender, NameReferenceChangedEventArgs e)
{
foreach (Series series in this)
if (series.ChartArea == e.OldName)
series.ChartArea = e.NewName;
}
/// <summary>
/// Updates the Series' references to Legends.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="Charting.NameReferenceChangedEventArgs"/> instance containing the event data.</param>
internal void LegendNameReferenceChanged(object sender, NameReferenceChangedEventArgs e)
{
foreach (Series series in this)
if (series.Legend == e.OldName)
series.Legend = e.NewName;
}
#endregion
}
/// <summary>
/// The class stores the data points and the default series properties.
/// </summary>
[
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
/// <summary>
/// Data point label text.
/// </summary>
internal string label = "";
/// <summary>
/// Data point X axis label text.
/// </summary>
internal string axisLabel = "";
/// <summary>
/// Data point label format string
/// </summary>
internal string labelFormat = "";
/// <summary>
/// If true shows point's value as a label.
/// </summary>
internal bool showLabelAsValue = false;
/// <summary>
/// Data point color
/// </summary>
internal Color color = Color.Empty;
/// <summary>
/// Data point border color
/// </summary>
internal Color borderColor = Color.Empty;
/// <summary>
/// Data point border style
/// </summary>
internal ChartDashStyle borderDashStyle = ChartDashStyle.Solid;
/// <summary>
/// Data point border width
/// </summary>
internal int borderWidth = 1;
/// <summary>
/// Data point marker border width
/// </summary>
internal int markerBorderWidth = 1;
/// <summary>
/// Data point background image
/// </summary>
internal string backImage = "";
/// <summary>
/// Data point background image drawing mode.
/// </summary>
internal ChartImageWrapMode backImageWrapMode = ChartImageWrapMode.Tile;
/// <summary>
/// Background image transparent color.
/// </summary>
internal Color backImageTransparentColor = Color.Empty;
/// <summary>
/// Background image alignment used by ClampUnscale drawing mode.
/// </summary>
internal ChartImageAlignmentStyle backImageAlignment = ChartImageAlignmentStyle.TopLeft;
/// <summary>
/// Data point background gradient type.
/// </summary>
internal GradientStyle backGradientStyle = GradientStyle.None;
/// <summary>
/// Data point background gradient end color
/// </summary>
internal Color backSecondaryColor = Color.Empty;
/// <summary>
/// Data point hatch style
/// </summary>
internal ChartHatchStyle backHatchStyle = ChartHatchStyle.None;
/// <summary>
/// Font cache for the fonts used in the Series and DataPoint
/// </summary>
private FontCache _fontCache = new FontCache();
/// <summary>
/// Data point font
/// </summary>
internal Font font = null;
/// <summary>
/// Data point line color
/// </summary>
internal Color fontColor = Color.Black;
/// <summary>
/// Data point font angle
/// </summary>
internal int fontAngle = 0;
/// <summary>
/// Data point marker style
/// </summary>
internal MarkerStyle markerStyle = MarkerStyle.None;
/// <summary>
/// Data point marker size
/// </summary>
internal int markerSize = 5;
/// <summary>
/// Data point marker image
/// </summary>
internal string markerImage = "";
/// <summary>
/// Data point marker image transparent color.
/// </summary>
internal Color markerImageTransparentColor = Color.Empty;
/// <summary>
/// Data point marker color
/// </summary>
internal Color markerColor = Color.Empty;
/// <summary>
/// Data point marker border color
/// </summary>
internal Color markerBorderColor = Color.Empty;
/// <summary>
/// The tooltip.
/// </summary>
internal string toolTip = "";
#if !Microsoft_CONTROL
/// <summary>
/// URL target of the area.
/// </summary>
internal string url = "";
/// <summary>
/// Other attributes of the area.
/// </summary>
internal string mapAreaAttributes = "";
/// <summary>
/// Other attributes of the area.
/// </summary>
internal string postbackValue = "";
#endif
/// <summary>
/// Indicates that item is shown in the legend.
/// </summary>
internal bool showInLegend = true;
/// <summary>
/// Text of the item in the legend
/// </summary>
internal string legendText = "";
/// <summary>
/// Tooltip of the item in the legend
/// </summary>
internal string legendToolTip = "";
/// <summary>
/// Data point label back color
/// </summary>
internal Color labelBackColor = Color.Empty;
/// <summary>
/// Data point label border color
/// </summary>
internal Color labelBorderColor = Color.Empty;
/// <summary>
/// Data point label border style
/// </summary>
internal ChartDashStyle labelBorderDashStyle = ChartDashStyle.Solid;
/// <summary>
/// Data point label border width
/// </summary>
internal int labelBorderWidth = 1;
/// <summary>
/// Tooltip of the data point label
/// </summary>
internal string labelToolTip = "";
#if !Microsoft_CONTROL
/// <summary>
/// URL target of the data point label.
/// </summary>
internal string labelUrl = "";
/// <summary>
/// Other attributes of the data point label.
/// </summary>
internal string labelMapAreaAttributes = "";
/// <summary>
/// Other attributes of the area.
/// </summary>
internal string labelPostbackValue = "";
/// <summary>
/// URL target of the item in the legend.
/// </summary>
internal string legendUrl = "";
/// <summary>
/// Other attributes of the legend map area.
/// </summary>
internal string legendMapAreaAttributes = "";
/// <summary>
/// Other attributes of the area.
/// </summary>
internal string legendPostbackValue = "";
#endif
#endregion
#region Constructors and initialization
/// <summary>
/// Initializes the default custom properties field.
/// </summary>
/// <returns>A DataPointCustomProperties initialized to defaults</returns>
private static DataPointCustomProperties InitializeDefaultCustomProperties()
{
DataPointCustomProperties customProperties = new DataPointCustomProperties(null, false);
customProperties.SetDefault(true);
customProperties.pointCustomProperties = true;
return customProperties;
}
/// <summary>
/// Series object constructor.
/// </summary>
public Series() : base(null, false)
{
InitProperties(null, 0);
}
/// <summary>
/// Series object constructor.
/// </summary>
/// <param name="name">Name of the data series</param>
public Series(string name) : base(null, false)
{
if(name == null)
{
throw (new ArgumentNullException(SR.ExceptionDataSeriesNameIsEmpty));
}
InitProperties(name, 0);
}
/// <summary>
/// Series object constructor.
/// </summary>
/// <param name="name">Name of the data series.</param>
/// <param name="yValues">Number of y values per data point.</param>
[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);
}
/// <summary>
/// Initialize series properties
/// </summary>
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
/// <summary>
/// Gets series caption that may not be the same as series name.
/// </summary>
/// <returns>Series caption string.</returns>
internal string GetCaption()
{
if (this.IsCustomPropertySet("SeriesCaption"))
{
return this["SeriesCaption"];
}
return this.Name;
}
/// <summary>
/// Gets custom points depth and gap depth from series properties.
/// </summary>
/// <param name="graph">Chart graphics.</param>
/// <param name="axis">Cate----cal axis.</param>
/// <param name="pointDepth">Returns point depth.</param>
/// <param name="pointGapDepth">Return point gap depth.</param>
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;
}
}
}
/// <summary>
/// Gets data point width in relative coordinates.
/// </summary>
/// <param name="graph">Chart graphics.</param>
/// <param name="axis">Axis object.</param>
/// <param name="interval">Current minimum axis interval.</param>
/// <param name="defaultWidth">Default width in percentage of interval.</param>
/// <returns>Point width.</returns>
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;
}
/// <summary>
/// Get chart type name by it's type
/// </summary>
/// <param name="type">Chart type.</param>
/// <returns>Chart type name.</returns>
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);
}
/// <summary>
/// Checks if Y values of the series represent date-time.
/// </summary>
/// <returns>True if date-time.</returns>
internal bool IsYValueDateTime()
{
if(this.YValueType == ChartValueType.Date ||
this.YValueType == ChartValueType.DateTime ||
this.YValueType == ChartValueType.Time ||
this.YValueType == ChartValueType.DateTimeOffset)
{
return true;
}
return false;
}
/// <summary>
/// Checks if X values of the series represent date-time.
/// </summary>
/// <returns>True if date-time.</returns>
internal bool IsXValueDateTime()
{
if(this.XValueType == ChartValueType.Date ||
this.XValueType == ChartValueType.DateTime ||
this.XValueType == ChartValueType.Time ||
this.XValueType == ChartValueType.DateTimeOffset)
{
return true;
}
return false;
}
/// <summary>
/// Checks if series is visible.
/// </summary>
/// <returns>True if series is visible.</returns>
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;
}
/// <summary>
/// Checks if series chart type uses a "Fast" mode chart type.
/// </summary>
/// <returns>True if series uses "Fast" mode chart type.</returns>
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;
}
/// <summary>
/// Throws exception if specified value type is not supported.
/// </summary>
/// <param name="type">Value type to check.</param>
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() ) ));
}
/// <summary>
/// Apply palette colors to the data series points if UsePaletteColors property is set.
/// </summary>
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;
}
}
}
}
/// <summary>
/// Gets design time dummy data.
/// </summary>
/// <param name="type">AxisName of the data to get.</param>
/// <returns>Dummy data for chart in design-time.</returns>
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;
}
/// <summary>
/// Returns total of the Y values.
/// </summary>
/// <returns>Y values total.</returns>
internal double GetTotalYValue()
{
return this.GetTotalYValue(0);
}
/// <summary>
/// Returns total of the Y values.
/// </summary>
/// <param name="yValueIndex">Index of the Y value to use</param>
/// <returns>Y values total.</returns>
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;
}
/// <summary>
/// Replaces predefined keyword inside the string with their values.
/// </summary>
/// <param name="strOriginal">Original string with keywords.</param>
/// <returns>Modified string.</returns>
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;
}
/// <summary>
/// Helper function which replaces one keyword.
/// </summary>
/// <param name="chart">Chart object reference.</param>
/// <param name="elementType">Chart element type.</param>
/// <param name="obj">Object being formatted.</param>
/// <param name="objTag">Additional object tag.</param>
/// <param name="strOriginal">Original string.</param>
/// <param name="keyword">Keyword to replace.</param>
/// <param name="formulaType">Formula used to calculate the value.</param>
/// <param name="valueType">AxisName of value.</param>
/// <param name="defaultFormat">Default format string.</param>
/// <returns>Result string.</returns>
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;
}
/// <summary>
/// Helper function which replaces one keyword.
/// </summary>
/// <param name="chart">Chart object reference.</param>
/// <param name="elementType">Chart element type.</param>
/// <param name="obj">Object being formatted.</param>
/// <param name="objTag">Additional object tag.</param>
/// <param name="strOriginal">Original string.</param>
/// <param name="keyword">Keyword to replace.</param>
/// <param name="value">Value to replace with.</param>
/// <param name="valueType">AxisName of value.</param>
/// <param name="defaultFormat">Default format string.</param>
/// <returns>Result string.</returns>
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
/// <summary>
/// Sorts the points in the series.
/// </summary>
/// <param name="pointSortOrder">Sorting order.</param>
/// <param name="sortBy">Value used for sorting (X, Y, Y2, ...).</param>
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);
}
/// <summary>
/// Sorts the points in the series.
/// </summary>
/// <param name="pointSortOrder">Sorting order.</param>
public void Sort(PointSortOrder pointSortOrder)
{
Sort(pointSortOrder, "Y");
}
/// <summary>
/// Sorts the points in the series using IComparer interface.
/// </summary>
/// <param name="comparer">IComparer interface.</param>
public void Sort(IComparer<DataPoint> 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
/// <summary>
/// Moves the position markers.
/// </summary>
/// <param name="fromSeries">From series.</param>
/// <param name="toSeries">To series.</param>
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;
}
}
}
}
}
/// <summary>
/// Called after the series was drawn.
/// </summary>
/// <param name="controlSite">Site interface of the control.</param>
/// <returns>True if series was removed from collection.</returns>
[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;
}
/// <summary>
/// Reset auto calculated series values.
/// </summary>
internal void ResetAutoValues()
{
ResetAutoValues(true);
}
/// <summary>
/// Reset auto calculated series values.
/// </summary>
/// <param name="reset">Indicates that value types should be reset.</param>
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;
}
}
}
}
/// <summary>
/// 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
/// </summary>
/// <param name="applyPaletteColors">If true each data point will be assigned a color from the palette (if it's set)</param>
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
/// <summary>
/// Data series name.
/// </summary>
[
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;
}
}
/// <summary>
/// Member of the chart data source used to data bind to the X value of the series.
/// </summary>
[
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;
}
}
}
/// <summary>
/// Members of the chart data source used to data bind to the Y values of the series.
/// </summary>
[
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;
}
}
}
/// <summary>
/// Name of the Chart legend used by the series.
/// </summary>
[
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);
}
}
}
/// <summary>
/// The value type of the X axis.
/// </summary>
[
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);
}
}
/// <summary>
/// Indicates whether a data point index (1,2,...) will be used for the X value.
/// </summary>
[
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);
}
}
/// <summary>
/// The value type of the Y axis.
/// </summary>
[
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);
}
}
/// <summary>
/// Number of Y values stored for each Data Point.
/// </summary>
[
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);
}
}
/// <summary>
/// Collection of data points in the series.
/// </summary>
[
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;
}
}
/// <summary>
/// Default properties of an empty data point.
/// </summary>
[
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);
}
}
/// <summary>
/// Color palette to use.
/// </summary>
[
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);
}
}
/// <summary>
/// Specify how often to display data point markers.
/// </summary>
[
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);
}
}
/// <summary>
/// Shadow offset of series.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
SRDescription("DescriptionAttributeShadowOffset"),
DefaultValue(0)
]
public int ShadowOffset
{
get
{
return _shadowOffset;
}
set
{
_shadowOffset = value;
this.Invalidate(true, true);
}
}
/// <summary>
/// Shadow color of series.
/// </summary>
[
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
/// <summary>
/// Name of the Y sub-axis this series is attached to.
/// </summary>
[
SRCategory("CategoryAttributeAxes"),
Bindable(true),
SRDescription("DescriptionAttributeSeries_YSubAxisName"),
DefaultValue("")
]
public string YSubAxisName
{
get
{
return this._ySubAxisName;
}
set
{
this._ySubAxisName = value;
this.Invalidate(true, false);
}
}
/// <summary>
/// Name of the X sub-axis this series is attached to.
/// </summary>
[
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
/// <summary>
/// Name of the Y sub-axis this series is attached to.
/// </summary>
[
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
{
}
}
/// <summary>
/// Name of the X sub-axis this series is attached to.
/// </summary>
[
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
/// <summary>
/// Axis type of horizontal axes.
/// </summary>
[
SRCategory("CategoryAttributeAxes"),
Bindable(true),
SRDescription("DescriptionAttributeSeries_XAxisType"),
DefaultValue(AxisType.Primary)
]
public AxisType XAxisType
{
get
{
return _xAxisType;
}
set
{
_xAxisType = value;
this.Invalidate(true, false);
}
}
/// <summary>
/// Axis type of vertical axes.
/// </summary>
[
SRCategory("CategoryAttributeAxes"),
Bindable(true),
SRDescription("DescriptionAttributeSeries_YAxisType"),
DefaultValue(AxisType.Primary)
]
public AxisType YAxisType
{
get
{
return _yAxisType;
}
set
{
_yAxisType = value;
this.Invalidate(true, false);
}
}
/// <summary>
/// Gets or sets a flag which indicates whether the series is enabled.
/// </summary>
[
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);
}
}
/// <summary>
/// Chart type used to draw the series.
/// </summary>
[
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);
}
}
/// <summary>
/// Chart type used to draw the series.
/// </summary>
[
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);
}
}
/// <summary>
/// Chart area in which this series is drawn.
/// </summary>
[
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);
}
}
}
/*
/// <summary>
/// If set to true, each data point of the series will use a random color from the palette.
/// </summary>
[
SRCategory("CategoryAttributeChart"),
Bindable(true),
SRDescription("DescriptionAttributeDataSeriesGroupID"),
PersistenceModeAttribute(PersistenceMode.Attribute),
DefaultValue("")
]
public string GroupID
{
get
{
return groupID;
}
set
{
groupID = value;
}
}
*/
/// <summary>
/// Text of X axis label.
/// </summary>
[
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);
}
}
/// <summary>
/// Style of the SmartLabel.
/// </summary>
[
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);
}
}
/// <summary>
/// Series font cache is reused by points.
/// </summary>
/// <value>The font cache.</value>
internal FontCache FontCache
{
get { return _fontCache; }
}
#endregion
#region Invalidating method
/// <summary>
/// Invalidate chart or just a chart area and/or legend when collection is changed
/// </summary>
/// <param name="invalidateAreaOnly">Invalidate chart area only.</param>
/// <param name="invalidateLegend">Invalidate legend area only.</param>
[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
/// <summary>
/// Series values formula type used in the keywords
/// </summary>
internal enum SeriesValuesFormulaType
{
Total,
Average,
Maximum,
Minimum,
First,
Last
}
#endregion // Series Enumeration
#region IDisposable Members
/// <summary>
/// Releases unmanaged and - optionally - managed resources
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected override void Dispose(bool disposing)
{
if (disposing)
{
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
}
}
|