|
//-------------------------------------------------------------
// <copyright company=’Microsoft Corporation’>
// Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
// File: DataManager.cs
//
// Namespace: System.Web.UI.WebControls[Windows.Forms].Charting.Data
//
// Classes: DataManager
//
// Purpose: Series storage and manipulation class.
//
// Reviewed: AG - Aug 1, 2002; GS - Aug 7, 2002
//
//===================================================================
#region Used namespaces
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
#if Microsoft_CONTROL
using System.Windows.Forms.DataVisualization.Charting;
using System.Windows.Forms.DataVisualization.Charting.Data;
using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
using System.Windows.Forms.DataVisualization.Charting.Utilities;
using System.Windows.Forms.DataVisualization.Charting.Borders3D;
#else
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.DataVisualization.Charting;
using System.Web.UI.DataVisualization.Charting.Data;
using System.Web.UI.DataVisualization.Charting.Utilities;
using System.Web.UI.DataVisualization.Charting.ChartTypes;
#endif
#endregion
#if Microsoft_CONTROL
namespace System.Windows.Forms.DataVisualization.Charting.Data
#else
namespace System.Web.UI.DataVisualization.Charting.Data
#endif
{
/// <summary>
/// Data Manager.
/// </summary>
internal class DataManager : ChartElement, IServiceProvider
{
#region Fields
// Series collection
private SeriesCollection _series = null;
// Servise container reference
internal IServiceContainer serviceContainer = null;
// Chart color palette
private ChartColorPalette _colorPalette = ChartColorPalette.BrightPastel;
#endregion
#region Constructors and initialization
/// <summary>
/// Data manager public constructor
/// </summary>
/// <param name="container">Service container object.</param>
public DataManager(IServiceContainer container)
{
if(container == null)
{
throw(new ArgumentNullException(SR.ExceptionInvalidServiceContainer));
}
serviceContainer = container;
Common = new CommonElements(container);
_series = new SeriesCollection(this);
}
/// <summary>
/// Returns Data Manager service object.
/// </summary>
/// <param name="serviceType">Service type requested.</param>
/// <returns>Data Manager service object.</returns>
[EditorBrowsableAttribute(EditorBrowsableState.Never)]
object IServiceProvider.GetService(Type serviceType)
{
if(serviceType == typeof(DataManager))
{
return this;
}
throw (new ArgumentException( SR.ExceptionDataManagerUnsupportedType(serviceType.ToString())));
}
/// <summary>
/// Initialize data manger object
/// </summary>
internal void Initialize()
{
// Attach to the Chart Picture painting events
ChartImage chartPicture = (ChartImage)serviceContainer.GetService(typeof(ChartImage));
chartPicture.BeforePaint += new EventHandler<ChartPaintEventArgs>(this.ChartPicture_BeforePaint);
chartPicture.AfterPaint += new EventHandler<ChartPaintEventArgs>(this.ChartPicture_AfterPaint);
}
#endregion
#region Chart picture painting events hanlers
internal override void Invalidate()
{
base.Invalidate();
#if Microsoft_CONTROL
if (Chart!=null)
Chart.Invalidate();
#endif
}
/// <summary>
/// Event fired when chart picture is going to be painted.
/// </summary>
/// <param name="sender">Sender object.</param>
/// <param name="e">Event arguments.</param>
private void ChartPicture_BeforePaint(object sender, ChartPaintEventArgs e)
{
// Prepare series for drawing
int markerIndex = 1;
for(int index = 0; index < this.Series.Count; index++)
{
Series series = this.Series[index];
// Reset series "X values are zeros" flag
series.xValuesZerosChecked = false;
series.xValuesZeros = false;
// Set series colors from palette
IChartType chartType = e.CommonElements.ChartTypeRegistry.GetChartType(series.ChartTypeName);
bool paletteColorsInPoints = chartType.ApplyPaletteColorsToPoints;
// if the series palette is set the we can color all data points, even on column chart.
if (series.Palette != ChartColorPalette.None)
{
paletteColorsInPoints = true;
}
this.PrepareData(
paletteColorsInPoints,
series.Name);
// Clear temp. marker style
if(series.tempMarkerStyleIsSet)
{
series.MarkerStyle = MarkerStyle.None;
series.tempMarkerStyleIsSet = false;
}
// Set marker style for chart types based on markes
if(chartType.GetLegendImageStyle(series) == LegendImageStyle.Marker && series.MarkerStyle == MarkerStyle.None)
{
series.MarkerStyle = (MarkerStyle)markerIndex++;
series.tempMarkerStyleIsSet = true;
if(markerIndex > 9)
{
markerIndex = 1;
}
}
}
}
/// <summary>
/// Event fired after chart picture was painted.
/// </summary>
/// <param name="sender">Sender object.</param>
/// <param name="e">Event arguments.</param>
private void ChartPicture_AfterPaint(object sender, ChartPaintEventArgs e)
{
Chart control = (Chart)serviceContainer.GetService(typeof(Chart));
if(control != null)
{
// Clean up series after drawing
for(int index = 0; index < this.Series.Count; index++)
{
Series series = this.Series[index];
if(series.UnPrepareData(control.Site))
{
--index;
}
}
}
}
#endregion
#region Series data preparation methods
/// <summary>
/// Apply palette colors to the data series if UsePaletteColors property is set.
/// </summary>
internal void ApplyPaletteColors()
{
ChartColorPalette palette = this.Palette;
// switch to default pallette if is none and custom collors array is empty.
if (palette == ChartColorPalette.None && this.PaletteCustomColors.Length == 0)
{
palette = ChartColorPalette.BrightPastel;
}
// Get palette colors
int colorIndex = 0;
Color[] paletteColors = (palette == ChartColorPalette.None) ?
this.PaletteCustomColors : ChartPaletteColors.GetPaletteColors(palette);
foreach (Series dataSeries in _series)
{
// Check if chart area name is valid
bool validAreaName = false;
if (Chart!=null)
{
validAreaName = Chart.ChartAreas.IsNameReferenceValid(dataSeries.ChartArea);
}
// Change color of the series only if valid chart area name is specified
if(validAreaName)
{
// Change color of the series only if default color is set
if(dataSeries.Color == Color.Empty || dataSeries.tempColorIsSet)
{
dataSeries.color = paletteColors[colorIndex++];
dataSeries.tempColorIsSet = true;
if(colorIndex >= paletteColors.Length)
{
colorIndex = 0;
}
}
}
}
}
/// <summary>
/// Called just before the data from the series to be used to perform these operations:
/// - apply palette colors to the data series
/// - prepare data in series
/// </summary>
/// <param name="pointsApplyPaletteColors">If true each data point will be assigned a color from the palette (if it's set)</param>
/// <param name="series">List of series indexes, which requires data preparation</param>
internal void PrepareData(bool pointsApplyPaletteColors, params string[] series)
{
this.ApplyPaletteColors();
// Prepare data in series
Chart control = (Chart)serviceContainer.GetService(typeof(Chart));
if(control != null)
{
foreach(string seriesName in series)
{
this.Series[seriesName].PrepareData(pointsApplyPaletteColors);
}
}
}
#endregion
#region Series Min/Max values methods
/// <summary>
/// This method checks if data point should be skipped. This
/// method will return true if data point is empty.
/// </summary>
/// <param name="point">Data point</param>
/// <returns>This method returns true if data point is empty.</returns>
private bool IsPointSkipped( DataPoint point )
{
if( point.IsEmpty )
{
return true;
}
return false;
}
/// <summary>
/// Gets max number of data points in specified series.
/// </summary>
/// <param name="series">Series IDs</param>
/// <returns>Maximum number of data points</returns>
internal int GetNumberOfPoints(params string[] series)
{
int numberOfPoints = 0;
foreach(string seriesName in series)
{
numberOfPoints = Math.Max(numberOfPoints, this._series[seriesName].Points.Count);
}
return numberOfPoints;
}
/// <summary>
/// Gets maximum Y value from many series
/// </summary>
/// <param name="valueIndex">Index of Y value to use</param>
/// <param name="series">Series IDs</param>
/// <returns>Maximum Y value</returns>
internal double GetMaxYValue(int valueIndex, params string[] series)
{
double returnValue = Double.MinValue;
foreach(string seriesName in series)
{
foreach(DataPoint seriesPoint in this._series[seriesName].Points)
{
// The empty point
if( IsPointSkipped( seriesPoint ) )
{
continue;
}
if(!double.IsNaN(seriesPoint.YValues[valueIndex]))
{
returnValue = Math.Max(returnValue, seriesPoint.YValues[valueIndex]);
}
}
}
return returnValue;
}
/// <summary>
/// Get Maximum value for Y and and Radius (Y2) ( used for bubble chart )
/// </summary>
/// <param name="area">Chart Area</param>
/// <param name="series">Series IDs</param>
/// <returns>Maximum Y value</returns>
internal double GetMaxYWithRadiusValue( ChartArea area, params string[] series )
{
double returnValue = Double.MinValue;
foreach(string seriesName in series)
{
foreach(DataPoint seriesPoint in this._series[seriesName].Points)
{
// The empty point
if( IsPointSkipped( seriesPoint ) )
{
continue;
}
if(!double.IsNaN(seriesPoint.YValues[0]))
{
if (seriesPoint.YValues.Length > 1)
{
returnValue = Math.Max(returnValue, seriesPoint.YValues[0] + BubbleChart.AxisScaleBubbleSize(area.Common, area, seriesPoint.YValues[1], true));
}
else
{
returnValue = Math.Max(returnValue, seriesPoint.YValues[0]);
}
}
}
}
return returnValue;
}
/// <summary>
/// Get Maximum value for X and Radius (Y2) ( used for bubble chart )
/// </summary>
/// <param name="area">Chart Area</param>
/// <param name="series">Series IDs</param>
/// <returns>Maximum X value</returns>
internal double GetMaxXWithRadiusValue( ChartArea area, params string[] series )
{
double returnValue = Double.MinValue;
foreach(string seriesName in series)
{
foreach(DataPoint seriesPoint in this._series[seriesName].Points)
{
// The empty point
if( IsPointSkipped( seriesPoint ) )
{
continue;
}
if(!double.IsNaN(seriesPoint.XValue))
{
if (seriesPoint.YValues.Length > 1)
{
returnValue = Math.Max(returnValue, seriesPoint.XValue + BubbleChart.AxisScaleBubbleSize(area.Common, area, seriesPoint.XValue, false));
}
else
{
returnValue = Math.Max(returnValue, seriesPoint.XValue);
}
}
}
}
return returnValue;
}
/// <summary>
/// Get Minimum value for X and Radius Y2 ( used for bubble chart )
/// </summary>
/// <param name="area">Chart Area</param>
/// <param name="series">Series IDs</param>
/// <returns>Minimum X value</returns>
internal double GetMinXWithRadiusValue( ChartArea area, params string[] series )
{
double returnValue = Double.MaxValue;
foreach(string seriesName in series)
{
foreach(DataPoint seriesPoint in this._series[seriesName].Points)
{
// The empty point
if( IsPointSkipped( seriesPoint ) )
{
continue;
}
if(!double.IsNaN(seriesPoint.XValue))
{
if (seriesPoint.YValues.Length > 1)
{
returnValue = Math.Min(returnValue, seriesPoint.XValue - BubbleChart.AxisScaleBubbleSize(area.Common, area, seriesPoint.YValues[1], false));
}
else
{
returnValue = Math.Min(returnValue, seriesPoint.XValue);
}
}
}
}
return returnValue;
}
/// <summary>
/// Gets maximum Y value from many series
/// </summary>
/// <param name="series">Series IDs</param>
/// <returns>Maximum Y value</returns>
internal double GetMaxYValue(params string[] series)
{
double returnValue = Double.MinValue;
foreach(string seriesName in series)
{
foreach(DataPoint seriesPoint in this._series[seriesName].Points)
{
// The empty point
if( IsPointSkipped( seriesPoint ) )
{
continue;
}
foreach( double y in seriesPoint.YValues )
{
if(!double.IsNaN(y))
{
returnValue = Math.Max(returnValue, y);
}
}
}
}
return returnValue;
}
/// <summary>
/// Gets maximum X value from many series
/// </summary>
/// <param name="series">Series IDs</param>
/// <returns>Maximum X value</returns>
internal double GetMaxXValue(params string[] series)
{
double returnValue = Double.MinValue;
foreach(string seriesName in series)
{
foreach(DataPoint seriesPoint in this._series[seriesName].Points)
{
returnValue = Math.Max(returnValue, seriesPoint.XValue);
}
}
return returnValue;
}
/// <summary>
/// Gets minimum and maximum X value from many series.
/// </summary>
/// <param name="min">Returns maximum X value.</param>
/// <param name="max">Returns minimum X value.</param>
/// <param name="series">Series IDs</param>
internal void GetMinMaxXValue(out double min, out double max, params string[] series)
{
max = Double.MinValue;
min = Double.MaxValue;
foreach(string seriesName in series)
{
foreach(DataPoint seriesPoint in this._series[seriesName].Points)
{
max = Math.Max(max, seriesPoint.XValue);
min = Math.Min(min, seriesPoint.XValue);
}
}
}
/// <summary>
/// Gets minimum and maximum Y value from many series.
/// </summary>
/// <param name="valueIndex">Index of Y value to use.</param>
/// <param name="min">Returns maximum Y value.</param>
/// <param name="max">Returns minimum Y value.</param>
/// <param name="series">Series IDs</param>
internal void GetMinMaxYValue(int valueIndex, out double min, out double max, params string[] series)
{
max = Double.MinValue;
min = Double.MaxValue;
foreach(string seriesName in series)
{
foreach(DataPoint seriesPoint in this._series[seriesName].Points)
{
// Skip empty point
if( IsPointSkipped( seriesPoint ) )
{
continue;
}
double yValue = seriesPoint.YValues[valueIndex];
if(!double.IsNaN(yValue))
{
max = Math.Max(max, yValue);
min = Math.Min(min, yValue);
}
}
}
}
/// <summary>
/// Gets minimum and maximum Y value from many series.
/// </summary>
/// <param name="min">Returns maximum Y value.</param>
/// <param name="max">Returns minimum Y value.</param>
/// <param name="series">Series IDs</param>
internal void GetMinMaxYValue(out double min, out double max, params string[] series)
{
max = Double.MinValue;
min = Double.MaxValue;
foreach(string seriesName in series)
{
foreach(DataPoint seriesPoint in this._series[seriesName].Points)
{
// Skip empty point
if( IsPointSkipped( seriesPoint ) )
{
continue;
}
// Iterate through all Y values
foreach( double y in seriesPoint.YValues )
{
if(!double.IsNaN(y))
{
max = Math.Max(max, y);
min = Math.Min(min, y);
}
}
}
}
}
/// <summary>
/// Gets minimum and maximum Y value from many series.
/// </summary>
/// <param name="seriesList">Series objects list.</param>
/// <param name="min">Returns maximum Y value.</param>
/// <param name="max">Returns minimum Y value.</param>
internal void GetMinMaxYValue(System.Collections.ArrayList seriesList, out double min, out double max)
{
max = Double.MinValue;
min = Double.MaxValue;
foreach(Series series in seriesList)
{
foreach(DataPoint seriesPoint in series.Points)
{
// Skip empty point
if( IsPointSkipped( seriesPoint ) )
{
continue;
}
// Iterate through all Y values
foreach( double y in seriesPoint.YValues )
{
if(!double.IsNaN(y))
{
max = Math.Max(max, y);
min = Math.Min(min, y);
}
}
}
}
}
/// <summary>
/// Gets maximum stacked Y value from many series
/// </summary>
/// <param name="valueIndex">Index of Y value to use</param>
/// <param name="series">Series IDs</param>
/// <returns>Maximum stacked Y value</returns>
internal double GetMaxStackedYValue(int valueIndex, params string[] series)
{
double returnValue = 0;
double numberOfPoints = GetNumberOfPoints(series);
for(int pointIndex = 0; pointIndex < numberOfPoints; pointIndex++)
{
double stackedMax = 0;
double noStackedMax = 0;
foreach(string seriesName in series)
{
if(this._series[seriesName].Points.Count > pointIndex)
{
// Take chart type from the series
ChartTypeRegistry chartTypeRegistry = (ChartTypeRegistry)serviceContainer.GetService(typeof(ChartTypeRegistry));
IChartType chartType = chartTypeRegistry.GetChartType(this._series[seriesName].ChartTypeName);
// If stacked area
if( !chartType.StackSign )
continue;
if( chartType.Stacked )
{
if(this._series[seriesName].Points[pointIndex].YValues[valueIndex] > 0)
{
stackedMax += this._series[seriesName].Points[pointIndex].YValues[valueIndex];
}
}
else
{
noStackedMax = Math.Max(noStackedMax,this._series[seriesName].Points[pointIndex].YValues[valueIndex]);
}
}
}
stackedMax = Math.Max(stackedMax, noStackedMax);
returnValue = Math.Max(returnValue, stackedMax);
}
return returnValue;
}
/// <summary>
/// Gets maximum Unsigned stacked Y value from many series ( Stacked Area chart )
/// </summary>
/// <param name="valueIndex">Index of Y value to use</param>
/// <param name="series">Series IDs</param>
/// <returns>Maximum stacked Y value</returns>
internal double GetMaxUnsignedStackedYValue(int valueIndex, params string[] series)
{
double returnValue = 0;
double maxValue = Double.MinValue;
double numberOfPoints = GetNumberOfPoints(series);
for(int pointIndex = 0; pointIndex < numberOfPoints; pointIndex++)
{
double stackedMax = 0;
double noStackedMax = 0;
foreach(string seriesName in series)
{
if (this._series[seriesName].Points.Count > pointIndex)
{
// Take chart type from the series
ChartTypeRegistry chartTypeRegistry = (ChartTypeRegistry)serviceContainer.GetService(typeof(ChartTypeRegistry));
IChartType chartType = chartTypeRegistry.GetChartType(this._series[seriesName].ChartTypeName);
// If stacked column and bar
if (chartType.StackSign || double.IsNaN(this._series[seriesName].Points[pointIndex].YValues[valueIndex]))
{
continue;
}
if (chartType.Stacked)
{
maxValue = Double.MinValue;
stackedMax += this._series[seriesName].Points[pointIndex].YValues[valueIndex];
if (stackedMax > maxValue)
maxValue = stackedMax;
}
else
{
noStackedMax = Math.Max(noStackedMax, this._series[seriesName].Points[pointIndex].YValues[valueIndex]);
}
}
}
maxValue = Math.Max(maxValue, noStackedMax);
returnValue = Math.Max(returnValue, maxValue);
}
return returnValue;
}
/// <summary>
/// Gets maximum stacked X value from many series
/// </summary>
/// <param name="series">Series IDs</param>
/// <returns>Maximum stacked X value</returns>
internal double GetMaxStackedXValue(params string[] series)
{
double returnValue = 0;
double numberOfPoints = GetNumberOfPoints(series);
for(int pointIndex = 0; pointIndex < numberOfPoints; pointIndex++)
{
double doubleIndexValue = 0;
foreach(string seriesName in series)
{
if (this._series[seriesName].Points.Count > pointIndex)
{
if (this._series[seriesName].Points[pointIndex].XValue > 0)
{
doubleIndexValue += this._series[seriesName].Points[pointIndex].XValue;
}
}
}
returnValue = Math.Max(returnValue, doubleIndexValue);
}
return returnValue;
}
/// <summary>
/// Gets minimum Y value from many series
/// </summary>
/// <param name="valueIndex">Index of Y value to use</param>
/// <param name="series">Series IDs</param>
/// <returns>Minimum Y value</returns>
internal double GetMinYValue(int valueIndex, params string[] series)
{
double returnValue = Double.MaxValue;
foreach(string seriesName in series)
{
foreach(DataPoint seriesPoint in this._series[seriesName].Points)
{
// The empty point
if( IsPointSkipped( seriesPoint ) )
{
continue;
}
if(!double.IsNaN(seriesPoint.YValues[valueIndex]))
{
returnValue = Math.Min(returnValue, seriesPoint.YValues[valueIndex]);
}
}
}
return returnValue;
}
/// <summary>
/// Get Minimum value for Y and and Radius (Y2) ( used for bubble chart )
/// </summary>
/// <param name="area">Chart Area</param>
/// <param name="series">Series IDs</param>
/// <returns>Minimum Y value</returns>
internal double GetMinYWithRadiusValue( ChartArea area, params string[] series )
{
double returnValue = Double.MaxValue;
foreach(string seriesName in series)
{
foreach(DataPoint seriesPoint in this._series[seriesName].Points)
{
// The empty point
if( IsPointSkipped( seriesPoint ) )
{
continue;
}
if(!double.IsNaN(seriesPoint.YValues[0]))
{
if (seriesPoint.YValues.Length > 1)
{
returnValue = Math.Min(returnValue, seriesPoint.YValues[0] - BubbleChart.AxisScaleBubbleSize(area.Common, area, seriesPoint.YValues[1], true));
}
else
{
returnValue = Math.Min(returnValue, seriesPoint.YValues[0]);
}
}
}
}
return returnValue;
}
/// <summary>
/// Gets minimum Y value from many series
/// </summary>
/// <param name="series">Series IDs</param>
/// <returns>Minimum Y value</returns>
internal double GetMinYValue(params string[] series)
{
double returnValue = Double.MaxValue;
foreach(string seriesName in series)
{
foreach(DataPoint seriesPoint in this._series[seriesName].Points)
{
// The empty point
if( IsPointSkipped( seriesPoint ) )
{
continue;
}
foreach(double y in seriesPoint.YValues)
{
if(!double.IsNaN(y))
{
returnValue = Math.Min(returnValue, y);
}
}
}
}
return returnValue;
}
/// <summary>
/// Gets minimum X value from many series
/// </summary>
/// <param name="series">Series IDs</param>
/// <returns>Minimum X value</returns>
internal double GetMinXValue(params string[] series)
{
double returnValue = Double.MaxValue;
foreach(string seriesName in series)
{
foreach(DataPoint seriesPoint in this._series[seriesName].Points)
{
returnValue = Math.Min(returnValue, seriesPoint.XValue);
}
}
return returnValue;
}
/// <summary>
/// Gets minimum stacked Y value from many series
/// </summary>
/// <param name="valueIndex">Index of Y value to use</param>
/// <param name="series">Series IDs</param>
/// <returns>Minimum stacked Y value</returns>
internal double GetMinStackedYValue(int valueIndex, params string[] series)
{
double returnValue = Double.MaxValue;
double numberOfPoints = GetNumberOfPoints(series);
for(int pointIndex = 0; pointIndex < numberOfPoints; pointIndex++)
{
double stackedMin = 0;
double noStackedMin = 0;
foreach(string seriesName in series)
{
if(this._series[seriesName].Points.Count > pointIndex)
{
// Take chart type from the series
ChartTypeRegistry chartTypeRegistry = (ChartTypeRegistry)serviceContainer.GetService(typeof(ChartTypeRegistry));
IChartType chartType = chartTypeRegistry.GetChartType(this._series[seriesName].ChartTypeName);
// If stacked area
if( !chartType.StackSign || double.IsNaN(this._series[seriesName].Points[pointIndex].YValues[valueIndex]))
continue;
if( chartType.Stacked )
{
if(this._series[seriesName].Points[pointIndex].YValues[valueIndex] < 0)
{
stackedMin += this._series[seriesName].Points[pointIndex].YValues[valueIndex];
}
}
else
{
noStackedMin = Math.Min(noStackedMin,this._series[seriesName].Points[pointIndex].YValues[valueIndex]);
}
}
}
stackedMin = Math.Min(stackedMin, noStackedMin);
if( stackedMin == 0 )
{
stackedMin = this._series[series[0]].Points[this._series[series[0]].Points.Count - 1].YValues[valueIndex];
}
returnValue = Math.Min(returnValue, stackedMin);
}
return returnValue;
}
/// <summary>
/// Gets minimum Unsigned stacked Y value from many series
/// </summary>
/// <param name="valueIndex">Index of Y value to use</param>
/// <param name="series">Series IDs</param>
/// <returns>Minimum stacked Y value</returns>
internal double GetMinUnsignedStackedYValue(int valueIndex, params string[] series)
{
double returnValue = Double.MaxValue;
double minValue = Double.MaxValue;
double numberOfPoints = GetNumberOfPoints(series);
for(int pointIndex = 0; pointIndex < numberOfPoints; pointIndex++)
{
double stackedMin = 0;
double noStackedMin = 0;
minValue = Double.MaxValue;
foreach(string seriesName in series)
{
if (this._series[seriesName].Points.Count > pointIndex)
{
// Take chart type from the series
ChartTypeRegistry chartTypeRegistry = (ChartTypeRegistry)serviceContainer.GetService(typeof(ChartTypeRegistry));
IChartType chartType = chartTypeRegistry.GetChartType(this._series[seriesName].ChartTypeName);
// If stacked column and bar
if (chartType.StackSign || double.IsNaN(this._series[seriesName].Points[pointIndex].YValues[valueIndex]))
{
continue;
}
if (chartType.Stacked)
{
if (this._series[seriesName].Points[pointIndex].YValues[valueIndex] < 0)
{
stackedMin += this._series[seriesName].Points[pointIndex].YValues[valueIndex];
if (stackedMin < minValue)
minValue = stackedMin;
}
}
else
{
noStackedMin = Math.Min(noStackedMin, this._series[seriesName].Points[pointIndex].YValues[valueIndex]);
}
}
}
minValue = Math.Min(noStackedMin, minValue);
returnValue = Math.Min(returnValue, minValue);
}
return returnValue;
}
/// <summary>
/// Gets minimum stacked X value from many series
/// </summary>
/// <param name="series">Series IDs</param>
/// <returns>Minimum stacked X value</returns>
internal double GetMinStackedXValue(params string[] series)
{
double returnValue = 0;
double numberOfPoints = GetNumberOfPoints(series);
for(int pointIndex = 0; pointIndex < numberOfPoints; pointIndex++)
{
double doubleIndexValue = 0;
foreach(string seriesName in series)
{
if(this._series[seriesName].Points[pointIndex].XValue < 0)
{
doubleIndexValue += this._series[seriesName].Points[pointIndex].XValue;
}
}
returnValue = Math.Min(returnValue, doubleIndexValue);
}
return returnValue;
}
/// <summary>
/// Gets maximum hundred percent stacked Y value
/// </summary>
/// <param name="supportNegative">Indicates that negative values are shown on the other side of the axis.</param>
/// <param name="series">Series names</param>
/// <returns>Maximum 100% stacked Y value</returns>
internal double GetMaxHundredPercentStackedYValue(bool supportNegative, params string[] series)
{
double returnValue = 0;
// Convert array of series names into array of series
Series[] seriesArray = new Series[series.Length];
int seriesIndex = 0;
foreach(string seriesName in series)
{
seriesArray[seriesIndex++] = this._series[seriesName];
}
// Loop through all dat points
try
{
for(int pointIndex = 0; pointIndex < this._series[series[0]].Points.Count; pointIndex++)
{
// Calculate the total for all series
double totalPerPoint = 0;
double positiveTotalPerPoint = 0;
foreach(Series ser in seriesArray)
{
if(supportNegative)
{
totalPerPoint += Math.Abs(ser.Points[pointIndex].YValues[0]);
}
else
{
totalPerPoint += ser.Points[pointIndex].YValues[0];
}
if(ser.Points[pointIndex].YValues[0] > 0 || supportNegative == false)
{
positiveTotalPerPoint += ser.Points[pointIndex].YValues[0];
}
}
totalPerPoint = Math.Abs(totalPerPoint);
// Calculate percentage of total
if(totalPerPoint != 0)
{
returnValue = Math.Max(returnValue,
(positiveTotalPerPoint / totalPerPoint) * 100.0);
}
}
}
catch(System.Exception)
{
throw (new InvalidOperationException(SR.ExceptionDataManager100StackedSeriesPointsNumeberMismatch));
}
return returnValue;
}
/// <summary>
/// Gets minimum hundred percent stacked Y value
/// </summary>
/// <param name="supportNegative">Indicates that negative values are shown on the other side of the axis.</param>
/// <param name="series">Series names</param>
/// <returns>Minimum 100% stacked Y value</returns>
internal double GetMinHundredPercentStackedYValue(bool supportNegative, params string[] series)
{
double returnValue = 0.0;
// Convert array of series names into array of series
Series[] seriesArray = new Series[series.Length];
int seriesIndex = 0;
foreach(string seriesName in series)
{
seriesArray[seriesIndex++] = this._series[seriesName];
}
// Loop through all dat points
try
{
for(int pointIndex = 0; pointIndex < this._series[series[0]].Points.Count; pointIndex++)
{
// Calculate the total for all series
double totalPerPoint = 0;
double negativeTotalPerPoint = 0;
foreach(Series ser in seriesArray)
{
if(supportNegative)
{
totalPerPoint += Math.Abs(ser.Points[pointIndex].YValues[0]);
}
else
{
totalPerPoint += ser.Points[pointIndex].YValues[0];
}
if(ser.Points[pointIndex].YValues[0] < 0 || supportNegative == false)
{
negativeTotalPerPoint += ser.Points[pointIndex].YValues[0];
}
}
totalPerPoint = Math.Abs(totalPerPoint);
// Calculate percentage of total
if(totalPerPoint != 0)
{
returnValue = Math.Min(returnValue,
(negativeTotalPerPoint / totalPerPoint) * 100.0);
}
}
}
catch(System.Exception)
{
throw (new InvalidOperationException(SR.ExceptionDataManager100StackedSeriesPointsNumeberMismatch));
}
return returnValue;
}
#endregion
#region DataManager Properties
/// <summary>
/// Chart series collection.
/// </summary>
[
SRCategory("CategoryAttributeData"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.InnerProperty),
#endif
Editor(Editors.SeriesCollectionEditor.Editor, Editors.SeriesCollectionEditor.Base),
Bindable(true)
]
public SeriesCollection Series
{
get
{
return _series;
}
}
/// <summary>
/// Color palette to use
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Bindable(true),
SRDescription("DescriptionAttributePalette"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.InnerProperty),
#endif
DefaultValue(ChartColorPalette.BrightPastel),
Editor(Editors.ColorPaletteEditor.Editor, Editors.ColorPaletteEditor.Base)
]
public ChartColorPalette Palette
{
get
{
return _colorPalette;
}
set
{
_colorPalette = value;
}
}
// Array of custom palette colors.
private Color[] _paletteCustomColors = new Color[0];
/// <summary>
/// Array of custom palette colors.
/// </summary>
/// <remarks>
/// When this custom colors array is non-empty the <b>Palette</b> property is ignored.
/// </remarks>
[
SRCategory("CategoryAttributeAppearance"),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
SerializationVisibilityAttribute(SerializationVisibility.Attribute),
SRDescription("DescriptionAttributeDataManager_PaletteCustomColors"),
TypeConverter(typeof(ColorArrayConverter))
]
public Color[] PaletteCustomColors
{
set
{
this._paletteCustomColors = value;
}
get
{
return this._paletteCustomColors;
}
}
#endregion
#region IDisposable Members
/// <summary>
/// Releases unmanaged and - optionally - managed resources
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_series != null)
{
_series.Dispose();
_series = null;
}
}
}
#endregion
}
}
|