536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
1184 lines
35 KiB
C#
1184 lines
35 KiB
C#
//-------------------------------------------------------------
|
||
// <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
|
||
}
|
||
}
|