Xamarin Public Jenkins (auto-signing) 536cd135cc Imported Upstream version 5.4.0.167
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
2017-08-21 15:34:15 +00:00

1184 lines
35 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//-------------------------------------------------------------
// <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
}
}