123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- //
- // Purpose: Series storage and manipulation class.
- //
- using System;
- using System.ComponentModel;
- using System.ComponentModel.Design;
- using System.Drawing;
- using System.Drawing.Design;
- using FastReport.DataVisualization.Charting.ChartTypes;
- using FastReport.DataVisualization.Charting.Utilities;
- namespace FastReport.DataVisualization.Charting.Data
- {
- /// <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 (Chart!=null)
- Chart.Invalidate();
- }
- /// <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 DESIGNER
- Editor(typeof(SeriesCollectionEditor), typeof(UITypeEditor)),
- #endif
- Bindable(true)
- ]
- public SeriesCollection Series
- {
- get
- {
- return _series;
- }
- }
- /// <summary>
- /// Color palette to use
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- SRDescription("DescriptionAttributePalette"),
- DefaultValue(ChartColorPalette.BrightPastel),
- #if DESIGNER
- Editor(typeof(ColorPaletteEditor), typeof(UITypeEditor))
- #endif
- ]
- 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
- }
- }
|