//-------------------------------------------------------------
//
// Copyright © Microsoft Corporation. All Rights Reserved.
//
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
// File: ChartElement.cs
//
// Namespace: System.Web.UI.WebControls[Windows.Forms].Charting
//
// Classes: ChartHelper
//
// Purpose: The chart element is base class for the big number
// of classes. It stores common methods and data.
//
// Reviewed: GS - August 2, 2002
// AG - August 8, 2002
// AG - Microsoft 16, 2007
//
//===================================================================
#region Used namespaces
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Collections.Generic;
using System.Collections.ObjectModel;
#endregion
#if Microsoft_CONTROL
namespace System.Windows.Forms.DataVisualization.Charting
#else
namespace System.Web.UI.DataVisualization.Charting
#endif
{
#region Enumerations
///
/// An enumeration that specifies a label alignment.
///
[
Flags
]
public enum LabelAlignmentStyles
{
///
/// Label is aligned to the top of the data point.
///
Top = 1,
///
/// Label is aligned to the bottom of the data point.
///
Bottom = 2,
///
/// Label is aligned to the right of the data point.
///
Right = 4,
///
/// Label is aligned to the left of the data point.
///
Left = 8,
///
/// Label is aligned to the top-left corner of the data point.
///
TopLeft = 16,
///
/// Label is aligned to the top-right corner of the data point.
///
TopRight = 32,
///
/// Label is aligned to the bottom-left of the data point.
///
BottomLeft = 64,
///
/// Label is aligned to the bottom-right of the data point.
///
BottomRight = 128,
///
/// Label is aligned to the center of the data point.
///
Center = 256,
}
///
/// An enumeration of chart types.
///
public enum SeriesChartType
{
///
/// Point chart type.
///
Point,
///
/// FastPoint chart type.
///
FastPoint,
///
/// Bubble chart type.
///
Bubble,
///
/// Line chart type.
///
Line,
///
/// Spline chart type.
///
Spline,
///
/// StepLine chart type.
///
StepLine,
///
/// FastLine chart type.
///
FastLine,
///
/// Bar chart type.
///
Bar,
///
/// Stacked bar chart type.
///
StackedBar,
///
/// Hundred percent stacked bar chart type.
///
StackedBar100,
///
/// Column chart type.
///
Column,
///
/// Stacked column chart type.
///
StackedColumn,
///
/// Hundred percent stacked column chart type.
///
StackedColumn100,
///
/// Area chart type.
///
Area,
///
/// Spline area chart type.
///
SplineArea,
///
/// Stacked area chart type.
///
StackedArea,
///
/// Hundred percent stacked area chart type.
///
StackedArea100,
///
/// Pie chart type.
///
Pie,
///
/// Doughnut chart type.
///
Doughnut,
///
/// Stock chart type.
///
Stock,
///
/// CandleStick chart type.
///
Candlestick,
///
/// Range chart type.
///
Range,
///
/// Spline range chart type.
///
SplineRange,
///
/// RangeBar chart type.
///
RangeBar,
///
/// Range column chart type.
///
RangeColumn,
///
/// Radar chart type.
///
Radar,
///
/// Polar chart type.
///
Polar,
///
/// Error bar chart type.
///
ErrorBar,
///
/// Box plot chart type.
///
BoxPlot,
///
/// Renko chart type.
///
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Renko")]
Renko,
///
/// ThreeLineBreak chart type.
///
ThreeLineBreak,
///
/// Kagi chart type.
///
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Kagi")]
Kagi,
///
/// PointAndFigure chart type.
///
PointAndFigure,
///
/// Funnel chart type.
///
Funnel,
///
/// Pyramid chart type.
///
Pyramid,
}
///
/// Axis Arrow orientation
///
internal enum ArrowOrientation
{
///
/// Arrow direction is Right - Left
///
Left,
///
/// Arrow direction is Left - Right
///
Right,
///
/// Arrow direction is Bottom - Top
///
Top,
///
/// Arrow direction is Top - Bottom
///
Bottom
}
///
/// An enumeration of image alignment.
///
public enum ChartImageAlignmentStyle
{
///
/// The mage is aligned to the top left corner of the chart element.
///
TopLeft,
///
/// The image is aligned to the top boundary of the chart element.
///
Top,
///
/// The image is aligned to the top right corner of the chart element.
///
TopRight,
///
/// The image is aligned to the right boundary of the chart element.
///
Right,
///
/// The image is aligned to the bottom right corner of the chart element.
///
BottomRight,
///
/// The image is aligned to the bottom boundary of the chart element.
///
Bottom,
///
/// The image is aligned to the bottom left corner of the chart element.
///
BottomLeft,
///
/// The image is aligned to the left boundary of the chart element.
///
Left,
///
/// The image is aligned in the center of the chart element.
///
Center
};
///
/// An enumeration that specifies a background image drawing mode.
///
public enum ChartImageWrapMode
{
///
/// Background image is scaled to fit the entire chart element.
///
Scaled = WrapMode.Clamp,
///
/// Background image is tiled to fit the entire chart element.
///
Tile = WrapMode.Tile,
///
/// Every other tiled image is reversed around the X-axis.
///
TileFlipX = WrapMode.TileFlipX,
///
/// Every other tiled image is reversed around the X-axis and Y-axis.
///
TileFlipXY = WrapMode.TileFlipXY,
///
/// Every other tiled image is reversed around the Y-axis.
///
TileFlipY = WrapMode.TileFlipY,
///
/// Background image is not scaled.
///
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unscaled")]
Unscaled = 100
};
///
/// An enumeration that specifies the state of an axis.
///
public enum AxisEnabled
{
///
/// The axis is only enabled if it used to plot a Series.
///
Auto,
///
/// The axis is always enabled.
///
True,
///
/// The axis is never enabled.
///
False
};
///
/// An enumeration of units of measurement of an interval.
///
public enum DateTimeIntervalType
{
///
/// Automatically determined by the Chart control.
///
Auto,
///
/// The interval is numerical.
///
Number,
///
/// The interval is years.
///
Years,
///
/// The interval is months.
///
Months,
///
/// The interval is weeks.
///
Weeks,
///
/// The interval is days.
///
Days,
///
/// The interval is hours.
///
Hours,
///
/// The interval is minutes.
///
Minutes,
///
/// The interval is seconds.
///
Seconds,
///
/// The interval is milliseconds.
///
Milliseconds,
///
/// The interval type is not defined.
///
NotSet,
}
///
/// An enumeration that specifies value types for various chart properties
///
public enum ChartValueType
{
///
/// Property type is set automatically by the Chart control.
///
Auto,
///
/// Double value.
///
Double,
///
/// Single value.
///
Single,
///
/// Int32 value.
///
Int32,
///
/// Int64 value.
///
Int64,
///
/// UInt32 value.
///
[SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly",
Justification = "These names are patterned after the standard CLR types for consistency")]
UInt32,
///
/// UInt64 value.
///
[SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly",
Justification = "These names are patterned after the standard CLR types for consistency")]
UInt64,
///
/// String value.
///
String,
///
/// DateTime value.
///
DateTime,
///
/// Date portion of the DateTime value.
///
Date,
///
/// Time portion of the DateTime value.
///
Time,
///
/// DateTime with offset
///
DateTimeOffset
};
///
/// An enumeration that specifies a hatching style.
///
public enum ChartHatchStyle
{
///
/// No hatching style.
///
None,
///
/// Backward diagonal style.
///
BackwardDiagonal,
///
/// Cross style.
///
Cross,
///
/// Dark downward diagonal style.
///
DarkDownwardDiagonal,
///
/// Dark horizontal style.
///
DarkHorizontal,
///
/// Dark upward diagonal style.
///
DarkUpwardDiagonal,
///
/// Dark vertical style.
///
DarkVertical,
///
/// Dashed downward diagonal style.
///
DashedDownwardDiagonal,
///
/// Dashed horizontal style.
///
DashedHorizontal,
///
/// Dashed upward diagonal style.
///
DashedUpwardDiagonal,
///
/// Dashed vertical style.
///
DashedVertical,
///
/// Diagonal brick style.
///
DiagonalBrick,
///
/// Diagonal cross style.
///
DiagonalCross,
///
/// Divot style.
///
Divot,
///
/// Dotted diamond style.
///
DottedDiamond,
///
/// Dotted grid style.
///
DottedGrid,
///
/// Forward diagonal style.
///
ForwardDiagonal,
///
/// Horizontal style.
///
Horizontal,
///
/// Horizontal brick style.
///
HorizontalBrick,
///
/// Large checker board style.
///
[SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "CheckerBoard")]
LargeCheckerBoard,
///
/// Large confetti style.
///
LargeConfetti,
///
/// Large grid style.
///
LargeGrid,
///
/// Light downward diagonal style.
///
LightDownwardDiagonal,
///
/// Light horizontal style.
///
LightHorizontal,
///
/// Light upward diagonal style.
///
LightUpwardDiagonal,
///
/// Light vertical style.
///
LightVertical,
///
/// Narrow horizontal style.
///
NarrowHorizontal,
///
/// Narrow vertical style.
///
NarrowVertical,
///
/// Outlined diamond style.
///
OutlinedDiamond,
///
/// Percent05 style.
///
Percent05,
///
/// Percent10 style.
///
Percent10,
///
/// Percent20 style.
///
Percent20,
///
/// Percent25 style.
///
Percent25,
///
/// Percent30 style.
///
Percent30,
///
/// Percent40 style.
///
Percent40,
///
/// Percent50 style.
///
Percent50,
///
/// Percent60 style.
///
Percent60,
///
/// Percent70 style.
///
Percent70,
///
/// Percent75 style.
///
Percent75,
///
/// Percent80 style.
///
Percent80,
///
/// Percent90 style.
///
Percent90,
///
/// Plaid style.
///
Plaid,
///
/// Shingle style.
///
Shingle,
///
/// Small checker board style.
///
[SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "CheckerBoard")]
SmallCheckerBoard,
///
/// Small confetti style.
///
SmallConfetti,
///
/// Small grid style.
///
SmallGrid,
///
/// Solid diamond style.
///
SolidDiamond,
///
/// Sphere style.
///
Sphere,
///
/// Trellis style.
///
Trellis,
///
/// Vertical style.
///
Vertical,
///
/// Wave style.
///
Wave,
///
/// Weave style.
///
Weave,
///
/// Wide downward diagonal style.
///
WideDownwardDiagonal,
///
/// Wide upward diagonal style.
///
WideUpwardDiagonal,
///
/// ZigZag style.
///
[SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "ZigZag")]
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Zig")]
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Zag")]
ZigZag
};
///
/// An enumeration that specifies the level of anti-aliasing quality.
///
public enum TextAntiAliasingQuality
{
///
/// Normal anti-aliasing quality.
///
Normal,
///
/// High anti-aliasing quality.
///
High,
///
/// System default anti-aliasing quality.
///
SystemDefault
}
///
/// An enumeration of anti-aliasing flags.
///
[Flags]
public enum AntiAliasingStyles
{
///
/// No anti-aliasing.
///
None = 0,
///
/// Use anti-aliasing when drawing text.
///
Text = 1,
///
/// Use anti-aliasing when drawing grahics primitives (e.g. lines, rectangle)
///
Graphics = 2,
///
/// Use anti-alias for everything.
///
All = Text | Graphics
};
///
/// An enumeration of marker styles.
///
public enum MarkerStyle
{
///
/// No marker is displayed for the series/data point.
///
None = 0,
///
/// A square marker is displayed.
///
Square = 1,
///
/// A circle marker is displayed.
///
Circle = 2,
///
/// A diamond-shaped marker is displayed.
///
Diamond = 3,
///
/// A triangular marker is displayed.
///
Triangle = 4,
///
/// A cross-shaped marker is displayed.
///
Cross = 5,
///
/// A 4-point star-shaped marker is displayed.
///
Star4 = 6,
///
/// A 5-point star-shaped marker is displayed.
///
Star5 = 7,
///
/// A 6-point star-shaped marker is displayed.
///
Star6 = 8,
///
/// A 10-point star-shaped marker is displayed.
///
Star10 = 9
};
///
/// An enumeration of gradient styles.
///
public enum GradientStyle
{
///
/// No gradient is used.
///
None,
///
/// Gradient is applied from left to right.
///
LeftRight,
///
/// Gradient is applied from top to bottom.
///
TopBottom,
///
/// Gradient is applied from the center outwards.
///
Center,
///
/// Gradient is applied diagonally from left to right.
///
DiagonalLeft,
///
/// Gradient is applied diagonally from right to left.
///
DiagonalRight,
///
/// Gradient is applied horizontally from the center outwards.
///
HorizontalCenter,
///
/// Gradient is applied vertically from the center outwards.
///
VerticalCenter
};
#endregion
#region ChartElement
///
/// Common chart helper methods used across different chart elements.
///
internal class ChartHelper
{
#region Fields
///
/// Maximum number of grid lines per Axis
///
internal const int MaxNumOfGridlines = 10000;
#endregion // Fields
#region Constructor
///
/// Private constructor to avoid instantiating the class
///
private ChartHelper() { }
#endregion // Constructor
#region Methods
///
/// Adjust the beginnin of the first interval depending on the type and size.
///
/// Original start point.
/// Interval size.
/// AxisName of the interval (Month, Year, ...).
/// Adjusted interval start position as double.
internal static double AlignIntervalStart(double start, double intervalSize, DateTimeIntervalType type)
{
return AlignIntervalStart(start, intervalSize, type, null);
}
///
/// Adjust the beginnin of the first interval depending on the type and size.
///
/// Original start point.
/// Interval size.
/// AxisName of the interval (Month, Year, ...).
/// First series connected to the axis.
/// Adjusted interval start position as double.
internal static double AlignIntervalStart(double start, double intervalSize, DateTimeIntervalType type, Series series)
{
return AlignIntervalStart( start, intervalSize, type, series, true );
}
///
/// Adjust the beginnin of the first interval depending on the type and size.
///
/// Original start point.
/// Interval size.
/// AxisName of the interval (Month, Year, ...).
/// First series connected to the axis.
/// Interval is used for major gridlines or tickmarks.
/// Adjusted interval start position as double.
internal static double AlignIntervalStart(double start, double intervalSize, DateTimeIntervalType type, Series series, bool majorInterval)
{
// Special case for indexed series
if(series != null && series.IsXValueIndexed)
{
if(type == DateTimeIntervalType.Auto ||
type == DateTimeIntervalType.Number)
{
if( majorInterval )
{
return 1;
}
else
{
return 0;
}
}
return -(series.Points.Count + 1);
}
// Non indexed series
else
{
// Do not adjust start position for these interval type
if(type == DateTimeIntervalType.Auto ||
type == DateTimeIntervalType.Number)
{
return start;
}
// Get the beginning of the interval depending on type
DateTime newStartDate = DateTime.FromOADate(start);
// Adjust the months interval depending on size
if(intervalSize > 0.0 && intervalSize != 1.0)
{
if(type == DateTimeIntervalType.Months && intervalSize <= 12.0 && intervalSize > 1)
{
// Make sure that the beginning is aligned correctly for cases
// like quarters and half years
DateTime resultDate = newStartDate;
DateTime sizeAdjustedDate = new DateTime(newStartDate.Year, 1, 1, 0, 0, 0);
while(sizeAdjustedDate < newStartDate)
{
resultDate = sizeAdjustedDate;
sizeAdjustedDate = sizeAdjustedDate.AddMonths((int)intervalSize);
}
newStartDate = resultDate;
return newStartDate.ToOADate();
}
}
// Check interval type
switch(type)
{
case(DateTimeIntervalType.Years):
int year = (int)((int)(newStartDate.Year / intervalSize) * intervalSize);
if(year <= 0)
{
year = 1;
}
newStartDate = new DateTime(year,
1, 1, 0, 0, 0);
break;
case(DateTimeIntervalType.Months):
int month = (int)((int)(newStartDate.Month / intervalSize) * intervalSize);
if(month <= 0)
{
month = 1;
}
newStartDate = new DateTime(newStartDate.Year,
month, 1, 0, 0, 0);
break;
case(DateTimeIntervalType.Days):
int day = (int)((int)(newStartDate.Day / intervalSize) * intervalSize);
if(day <= 0)
{
day = 1;
}
newStartDate = new DateTime(newStartDate.Year,
newStartDate.Month, day, 0, 0, 0);
break;
case(DateTimeIntervalType.Hours):
int hour = (int)((int)(newStartDate.Hour / intervalSize) * intervalSize);
newStartDate = new DateTime(newStartDate.Year,
newStartDate.Month, newStartDate.Day, hour, 0, 0);
break;
case(DateTimeIntervalType.Minutes):
int minute = (int)((int)(newStartDate.Minute / intervalSize) * intervalSize);
newStartDate = new DateTime(newStartDate.Year,
newStartDate.Month,
newStartDate.Day,
newStartDate.Hour,
minute,
0);
break;
case(DateTimeIntervalType.Seconds):
int second = (int)((int)(newStartDate.Second / intervalSize) * intervalSize);
newStartDate = new DateTime(newStartDate.Year,
newStartDate.Month,
newStartDate.Day,
newStartDate.Hour,
newStartDate.Minute,
second,
0);
break;
case(DateTimeIntervalType.Milliseconds):
int milliseconds = (int)((int)(newStartDate.Millisecond / intervalSize) * intervalSize);
newStartDate = new DateTime(newStartDate.Year,
newStartDate.Month,
newStartDate.Day,
newStartDate.Hour,
newStartDate.Minute,
newStartDate.Second,
milliseconds);
break;
case(DateTimeIntervalType.Weeks):
// NOTE: Code below was changed to fix issue #5962
// Elements that have interval set to weeks should be aligned to the
// nearest Monday no matter how many weeks is the interval.
//newStartDate = newStartDate.AddDays(-((int)newStartDate.DayOfWeek * intervalSize));
newStartDate = newStartDate.AddDays(-((int)newStartDate.DayOfWeek));
newStartDate = new DateTime(newStartDate.Year,
newStartDate.Month, newStartDate.Day, 0, 0, 0);
break;
}
return newStartDate.ToOADate();
}
}
///
/// Gets interval size as double number.
///
/// Current value.
/// Interval size.
/// AxisName of the interval (Month, Year, ...).
/// Interval size as double.
internal static double GetIntervalSize(double current, double interval, DateTimeIntervalType type)
{
return GetIntervalSize(
current,
interval,
type,
null,
0,
DateTimeIntervalType.Number,
true,
true);
}
///
/// Gets interval size as double number.
///
/// Current value.
/// Interval size.
/// AxisName of the interval (Month, Year, ...).
/// First series connected to the axis.
/// Offset size.
/// Offset type(Month, Year, ...).
/// Force Integer indexed
/// Interval size as double.
internal static double GetIntervalSize(
double current,
double interval,
DateTimeIntervalType type,
Series series,
double intervalOffset,
DateTimeIntervalType intervalOffsetType,
bool forceIntIndex)
{
return GetIntervalSize(
current,
interval,
type,
series,
intervalOffset,
intervalOffsetType,
forceIntIndex,
true);
}
///
/// Gets interval size as double number.
///
/// Current value.
/// Interval size.
/// AxisName of the interval (Month, Year, ...).
/// First series connected to the axis.
/// Offset size.
/// Offset type(Month, Year, ...).
/// Force Integer indexed
/// Force Integer indexed
/// Interval size as double.
internal static double GetIntervalSize(
double current,
double interval,
DateTimeIntervalType type,
Series series,
double intervalOffset,
DateTimeIntervalType intervalOffsetType,
bool forceIntIndex,
bool forceAbsInterval)
{
// AxisName is not date.
if( type == DateTimeIntervalType.Number || type == DateTimeIntervalType.Auto )
{
return interval;
}
// Special case for indexed series
if(series != null && series.IsXValueIndexed)
{
// Check point index
int pointIndex = (int)Math.Ceiling(current - 1);
if(pointIndex < 0)
{
pointIndex = 0;
}
if(pointIndex >= series.Points.Count || series.Points.Count <= 1)
{
return interval;
}
// Get starting and ending values of the closest interval
double adjuster = 0;
double xValue = series.Points[pointIndex].XValue;
xValue = AlignIntervalStart(xValue, 1, type, null);
double xEndValue = xValue + GetIntervalSize(xValue, interval, type);
xEndValue += GetIntervalSize(xEndValue, intervalOffset, intervalOffsetType);
xValue += GetIntervalSize(xValue, intervalOffset, intervalOffsetType);
if(intervalOffset < 0)
{
xValue = xValue + GetIntervalSize(xValue, interval, type);
xEndValue = xEndValue + GetIntervalSize(xEndValue, interval, type);
}
// The first point in the series
if(pointIndex == 0 && current < 0)
{
// Round the first point value depending on the interval type
DateTime dateValue = DateTime.FromOADate(series.Points[pointIndex].XValue);
DateTime roundedDateValue = dateValue;
switch(type)
{
case(DateTimeIntervalType.Years): // Ignore hours,...
roundedDateValue = new DateTime(dateValue.Year,
dateValue.Month, dateValue.Day, 0, 0, 0);
break;
case(DateTimeIntervalType.Months): // Ignore hours,...
roundedDateValue = new DateTime(dateValue.Year,
dateValue.Month, dateValue.Day, 0, 0, 0);
break;
case(DateTimeIntervalType.Days): // Ignore hours,...
roundedDateValue = new DateTime(dateValue.Year,
dateValue.Month, dateValue.Day, 0, 0, 0);
break;
case(DateTimeIntervalType.Hours): //
roundedDateValue = new DateTime(dateValue.Year,
dateValue.Month, dateValue.Day, dateValue.Hour,
dateValue.Minute, 0);
break;
case(DateTimeIntervalType.Minutes):
roundedDateValue = new DateTime(dateValue.Year,
dateValue.Month,
dateValue.Day,
dateValue.Hour,
dateValue.Minute,
dateValue.Second);
break;
case(DateTimeIntervalType.Seconds):
roundedDateValue = new DateTime(dateValue.Year,
dateValue.Month,
dateValue.Day,
dateValue.Hour,
dateValue.Minute,
dateValue.Second,
0);
break;
case(DateTimeIntervalType.Weeks):
roundedDateValue = new DateTime(dateValue.Year,
dateValue.Month, dateValue.Day, 0, 0, 0);
break;
}
// The first point value is exactly on the interval boundaries
if(roundedDateValue.ToOADate() == xValue || roundedDateValue.ToOADate() == xEndValue)
{
return - current + 1;
}
}
// Adjuster of 0.5 means that position should be between points
++pointIndex;
while(pointIndex < series.Points.Count)
{
if(series.Points[pointIndex].XValue >= xEndValue)
{
if(series.Points[pointIndex].XValue > xEndValue && !forceIntIndex)
{
adjuster = -0.5;
}
break;
}
++pointIndex;
}
// If last point outside of the max series index
if(pointIndex == series.Points.Count)
{
pointIndex += series.Points.Count/5 + 1;
}
double size = (pointIndex + 1) - current + adjuster;
return (size != 0) ? size : interval;
}
// Non indexed series
else
{
DateTime date = DateTime.FromOADate(current);
TimeSpan span = new TimeSpan(0);
if(type == DateTimeIntervalType.Days)
{
span = TimeSpan.FromDays(interval);
}
else if(type == DateTimeIntervalType.Hours)
{
span = TimeSpan.FromHours(interval);
}
else if(type == DateTimeIntervalType.Milliseconds)
{
span = TimeSpan.FromMilliseconds(interval);
}
else if(type == DateTimeIntervalType.Seconds)
{
span = TimeSpan.FromSeconds(interval);
}
else if(type == DateTimeIntervalType.Minutes)
{
span = TimeSpan.FromMinutes(interval);
}
else if(type == DateTimeIntervalType.Weeks)
{
span = TimeSpan.FromDays(7.0 * interval);
}
else if(type == DateTimeIntervalType.Months)
{
// Special case handling when current date points
// to the last day of the month
bool lastMonthDay = false;
if(date.Day == DateTime.DaysInMonth(date.Year, date.Month))
{
lastMonthDay = true;
}
// Add specified amount of months
date = date.AddMonths((int)Math.Floor(interval));
span = TimeSpan.FromDays(30.0 * ( interval - Math.Floor(interval) ));
// Check if last month of the day was used
if(lastMonthDay && span.Ticks == 0)
{
// Make sure the last day of the month is selected
int daysInMobth = DateTime.DaysInMonth(date.Year, date.Month);
date = date.AddDays(daysInMobth - date.Day);
}
}
else if(type == DateTimeIntervalType.Years)
{
date = date.AddYears((int)Math.Floor(interval));
span = TimeSpan.FromDays(365.0 * ( interval - Math.Floor(interval) ));
}
// Check if an absolute interval size must be returned
double result = date.Add(span).ToOADate() - current;
if(forceAbsInterval)
{
result = Math.Abs(result);
}
return result;
}
}
///
/// Check if series is indexed. IsXValueIndexed flag is set or all X values are zeros.
///
/// Data series to test.
/// True if series is indexed.
static internal bool IndexedSeries( Series series)
{
// X value indexed flag set
if (series.IsXValueIndexed)
{
return true;
}
if (Utilities.CustomPropertyRegistry.IsXAxisQuantitativeChartTypes.Contains(series.ChartType) &&
series.IsCustomPropertySet(Utilities.CustomPropertyName.IsXAxisQuantitative))
{
string attribValue = series[Utilities.CustomPropertyName.IsXAxisQuantitative];
if (String.Compare(attribValue, "True", StringComparison.OrdinalIgnoreCase) == 0)
{
return false;
}
}
// Check if series has all X values set to zero
return SeriesXValuesZeros(series);
}
///
/// Check if all data points in the series have X value set to 0.
///
/// Data series to check.
static private bool SeriesXValuesZeros( Series series )
{
// Check if X value zeros check was already done
if(series.xValuesZerosChecked)
{
return series.xValuesZeros;
}
// Data point loop
series.xValuesZerosChecked = true;
series.xValuesZeros = true;
foreach( DataPoint point in series.Points )
{
if( point.XValue != 0.0 )
{
// If any data point has value different than 0 return false
series.xValuesZeros = false;
break;
}
}
return series.xValuesZeros;
}
///
/// Check if any series is indexed. IsXValueIndexed flag is set or all X values are zeros.
///
/// Reference to common chart classes.
/// Data series names.
/// True if any series is indexed.
static internal bool IndexedSeries(CommonElements common, params string[] series)
{
// Data series loop
bool zeroXValues = true;
foreach (string ser in series)
{
Series localSeries = common.DataManager.Series[ser];
// Check series indexed flag
if (localSeries.IsXValueIndexed)
{
// If flag set in at least one series - all series are indexed
return true;
}
// Check if series has all X values set to zero
if (zeroXValues && !IndexedSeries(localSeries))
{
zeroXValues = false;
}
}
return zeroXValues;
}
///
/// Check if all data points in many series have X value set to 0.
///
/// Reference to common chart classes.
/// Data series.
/// True if all data points have value 0.
static internal bool SeriesXValuesZeros(CommonElements common, params string[] series)
{
// Data series loop
foreach( string ser in series )
{
// Check one series X values
if(!SeriesXValuesZeros(common.DataManager.Series[ ser ]))
{
return false;
}
}
return true;
}
#endregion
}
#endregion //ChartElement
}