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

1459 lines
36 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

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

//-------------------------------------------------------------
// <copyright company=Microsoft Corporation>
// Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
// File: 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
/// <summary>
/// An enumeration that specifies a label alignment.
/// </summary>
[
Flags
]
public enum LabelAlignmentStyles
{
/// <summary>
/// Label is aligned to the top of the data point.
/// </summary>
Top = 1,
/// <summary>
/// Label is aligned to the bottom of the data point.
/// </summary>
Bottom = 2,
/// <summary>
/// Label is aligned to the right of the data point.
/// </summary>
Right = 4,
/// <summary>
/// Label is aligned to the left of the data point.
/// </summary>
Left = 8,
/// <summary>
/// Label is aligned to the top-left corner of the data point.
/// </summary>
TopLeft = 16,
/// <summary>
/// Label is aligned to the top-right corner of the data point.
/// </summary>
TopRight = 32,
/// <summary>
/// Label is aligned to the bottom-left of the data point.
/// </summary>
BottomLeft = 64,
/// <summary>
/// Label is aligned to the bottom-right of the data point.
/// </summary>
BottomRight = 128,
/// <summary>
/// Label is aligned to the center of the data point.
/// </summary>
Center = 256,
}
/// <summary>
/// An enumeration of chart types.
/// </summary>
public enum SeriesChartType
{
/// <summary>
/// Point chart type.
/// </summary>
Point,
/// <summary>
/// FastPoint chart type.
/// </summary>
FastPoint,
/// <summary>
/// Bubble chart type.
/// </summary>
Bubble,
/// <summary>
/// Line chart type.
/// </summary>
Line,
/// <summary>
/// Spline chart type.
/// </summary>
Spline,
/// <summary>
/// StepLine chart type.
/// </summary>
StepLine,
/// <summary>
/// FastLine chart type.
/// </summary>
FastLine,
/// <summary>
/// Bar chart type.
/// </summary>
Bar,
/// <summary>
/// Stacked bar chart type.
/// </summary>
StackedBar,
/// <summary>
/// Hundred percent stacked bar chart type.
/// </summary>
StackedBar100,
/// <summary>
/// Column chart type.
/// </summary>
Column,
/// <summary>
/// Stacked column chart type.
/// </summary>
StackedColumn,
/// <summary>
/// Hundred percent stacked column chart type.
/// </summary>
StackedColumn100,
/// <summary>
/// Area chart type.
/// </summary>
Area,
/// <summary>
/// Spline area chart type.
/// </summary>
SplineArea,
/// <summary>
/// Stacked area chart type.
/// </summary>
StackedArea,
/// <summary>
/// Hundred percent stacked area chart type.
/// </summary>
StackedArea100,
/// <summary>
/// Pie chart type.
/// </summary>
Pie,
/// <summary>
/// Doughnut chart type.
/// </summary>
Doughnut,
/// <summary>
/// Stock chart type.
/// </summary>
Stock,
/// <summary>
/// CandleStick chart type.
/// </summary>
Candlestick,
/// <summary>
/// Range chart type.
/// </summary>
Range,
/// <summary>
/// Spline range chart type.
/// </summary>
SplineRange,
/// <summary>
/// RangeBar chart type.
/// </summary>
RangeBar,
/// <summary>
/// Range column chart type.
/// </summary>
RangeColumn,
/// <summary>
/// Radar chart type.
/// </summary>
Radar,
/// <summary>
/// Polar chart type.
/// </summary>
Polar,
/// <summary>
/// Error bar chart type.
/// </summary>
ErrorBar,
/// <summary>
/// Box plot chart type.
/// </summary>
BoxPlot,
/// <summary>
/// Renko chart type.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Renko")]
Renko,
/// <summary>
/// ThreeLineBreak chart type.
/// </summary>
ThreeLineBreak,
/// <summary>
/// Kagi chart type.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Kagi")]
Kagi,
/// <summary>
/// PointAndFigure chart type.
/// </summary>
PointAndFigure,
/// <summary>
/// Funnel chart type.
/// </summary>
Funnel,
/// <summary>
/// Pyramid chart type.
/// </summary>
Pyramid,
}
/// <summary>
/// Axis Arrow orientation
/// </summary>
internal enum ArrowOrientation
{
/// <summary>
/// Arrow direction is Right - Left
/// </summary>
Left,
/// <summary>
/// Arrow direction is Left - Right
/// </summary>
Right,
/// <summary>
/// Arrow direction is Bottom - Top
/// </summary>
Top,
/// <summary>
/// Arrow direction is Top - Bottom
/// </summary>
Bottom
}
/// <summary>
/// An enumeration of image alignment.
/// </summary>
public enum ChartImageAlignmentStyle
{
/// <summary>
/// The mage is aligned to the top left corner of the chart element.
/// </summary>
TopLeft,
/// <summary>
/// The image is aligned to the top boundary of the chart element.
/// </summary>
Top,
/// <summary>
/// The image is aligned to the top right corner of the chart element.
/// </summary>
TopRight,
/// <summary>
/// The image is aligned to the right boundary of the chart element.
/// </summary>
Right,
/// <summary>
/// The image is aligned to the bottom right corner of the chart element.
/// </summary>
BottomRight,
/// <summary>
/// The image is aligned to the bottom boundary of the chart element.
/// </summary>
Bottom,
/// <summary>
/// The image is aligned to the bottom left corner of the chart element.
/// </summary>
BottomLeft,
/// <summary>
/// The image is aligned to the left boundary of the chart element.
/// </summary>
Left,
/// <summary>
/// The image is aligned in the center of the chart element.
/// </summary>
Center
};
/// <summary>
/// An enumeration that specifies a background image drawing mode.
/// </summary>
public enum ChartImageWrapMode
{
/// <summary>
/// Background image is scaled to fit the entire chart element.
/// </summary>
Scaled = WrapMode.Clamp,
/// <summary>
/// Background image is tiled to fit the entire chart element.
/// </summary>
Tile = WrapMode.Tile,
/// <summary>
/// Every other tiled image is reversed around the X-axis.
/// </summary>
TileFlipX = WrapMode.TileFlipX,
/// <summary>
/// Every other tiled image is reversed around the X-axis and Y-axis.
/// </summary>
TileFlipXY = WrapMode.TileFlipXY,
/// <summary>
/// Every other tiled image is reversed around the Y-axis.
/// </summary>
TileFlipY = WrapMode.TileFlipY,
/// <summary>
/// Background image is not scaled.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unscaled")]
Unscaled = 100
};
/// <summary>
/// An enumeration that specifies the state of an axis.
/// </summary>
public enum AxisEnabled
{
/// <summary>
/// The axis is only enabled if it used to plot a Series.
/// </summary>
Auto,
/// <summary>
/// The axis is always enabled.
/// </summary>
True,
/// <summary>
/// The axis is never enabled.
/// </summary>
False
};
/// <summary>
/// An enumeration of units of measurement of an interval.
/// </summary>
public enum DateTimeIntervalType
{
/// <summary>
/// Automatically determined by the Chart control.
/// </summary>
Auto,
/// <summary>
/// The interval is numerical.
/// </summary>
Number,
/// <summary>
/// The interval is years.
/// </summary>
Years,
/// <summary>
/// The interval is months.
/// </summary>
Months,
/// <summary>
/// The interval is weeks.
/// </summary>
Weeks,
/// <summary>
/// The interval is days.
/// </summary>
Days,
/// <summary>
/// The interval is hours.
/// </summary>
Hours,
/// <summary>
/// The interval is minutes.
/// </summary>
Minutes,
/// <summary>
/// The interval is seconds.
/// </summary>
Seconds,
/// <summary>
/// The interval is milliseconds.
/// </summary>
Milliseconds,
/// <summary>
/// The interval type is not defined.
/// </summary>
NotSet,
}
/// <summary>
/// An enumeration that specifies value types for various chart properties
/// </summary>
public enum ChartValueType
{
/// <summary>
/// Property type is set automatically by the Chart control.
/// </summary>
Auto,
/// <summary>
/// Double value.
/// </summary>
Double,
/// <summary>
/// Single value.
/// </summary>
Single,
/// <summary>
/// Int32 value.
/// </summary>
Int32,
/// <summary>
/// Int64 value.
/// </summary>
Int64,
/// <summary>
/// UInt32 value.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly",
Justification = "These names are patterned after the standard CLR types for consistency")]
UInt32,
/// <summary>
/// UInt64 value.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly",
Justification = "These names are patterned after the standard CLR types for consistency")]
UInt64,
/// <summary>
/// String value.
/// </summary>
String,
/// <summary>
/// DateTime value.
/// </summary>
DateTime,
/// <summary>
/// Date portion of the DateTime value.
/// </summary>
Date,
/// <summary>
/// Time portion of the DateTime value.
/// </summary>
Time,
/// <summary>
/// DateTime with offset
/// </summary>
DateTimeOffset
};
/// <summary>
/// An enumeration that specifies a hatching style.
/// </summary>
public enum ChartHatchStyle
{
/// <summary>
/// No hatching style.
/// </summary>
None,
/// <summary>
/// Backward diagonal style.
/// </summary>
BackwardDiagonal,
/// <summary>
/// Cross style.
/// </summary>
Cross,
/// <summary>
/// Dark downward diagonal style.
/// </summary>
DarkDownwardDiagonal,
/// <summary>
/// Dark horizontal style.
/// </summary>
DarkHorizontal,
/// <summary>
/// Dark upward diagonal style.
/// </summary>
DarkUpwardDiagonal,
/// <summary>
/// Dark vertical style.
/// </summary>
DarkVertical,
/// <summary>
/// Dashed downward diagonal style.
/// </summary>
DashedDownwardDiagonal,
/// <summary>
/// Dashed horizontal style.
/// </summary>
DashedHorizontal,
/// <summary>
/// Dashed upward diagonal style.
/// </summary>
DashedUpwardDiagonal,
/// <summary>
/// Dashed vertical style.
/// </summary>
DashedVertical,
/// <summary>
/// Diagonal brick style.
/// </summary>
DiagonalBrick,
/// <summary>
/// Diagonal cross style.
/// </summary>
DiagonalCross,
/// <summary>
/// Divot style.
/// </summary>
Divot,
/// <summary>
/// Dotted diamond style.
/// </summary>
DottedDiamond,
/// <summary>
/// Dotted grid style.
/// </summary>
DottedGrid,
/// <summary>
/// Forward diagonal style.
/// </summary>
ForwardDiagonal,
/// <summary>
/// Horizontal style.
/// </summary>
Horizontal,
/// <summary>
/// Horizontal brick style.
/// </summary>
HorizontalBrick,
/// <summary>
/// Large checker board style.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "CheckerBoard")]
LargeCheckerBoard,
/// <summary>
/// Large confetti style.
/// </summary>
LargeConfetti,
/// <summary>
/// Large grid style.
/// </summary>
LargeGrid,
/// <summary>
/// Light downward diagonal style.
/// </summary>
LightDownwardDiagonal,
/// <summary>
/// Light horizontal style.
/// </summary>
LightHorizontal,
/// <summary>
/// Light upward diagonal style.
/// </summary>
LightUpwardDiagonal,
/// <summary>
/// Light vertical style.
/// </summary>
LightVertical,
/// <summary>
/// Narrow horizontal style.
/// </summary>
NarrowHorizontal,
/// <summary>
/// Narrow vertical style.
/// </summary>
NarrowVertical,
/// <summary>
/// Outlined diamond style.
/// </summary>
OutlinedDiamond,
/// <summary>
/// Percent05 style.
/// </summary>
Percent05,
/// <summary>
/// Percent10 style.
/// </summary>
Percent10,
/// <summary>
/// Percent20 style.
/// </summary>
Percent20,
/// <summary>
/// Percent25 style.
/// </summary>
Percent25,
/// <summary>
/// Percent30 style.
/// </summary>
Percent30,
/// <summary>
/// Percent40 style.
/// </summary>
Percent40,
/// <summary>
/// Percent50 style.
/// </summary>
Percent50,
/// <summary>
/// Percent60 style.
/// </summary>
Percent60,
/// <summary>
/// Percent70 style.
/// </summary>
Percent70,
/// <summary>
/// Percent75 style.
/// </summary>
Percent75,
/// <summary>
/// Percent80 style.
/// </summary>
Percent80,
/// <summary>
/// Percent90 style.
/// </summary>
Percent90,
/// <summary>
/// Plaid style.
/// </summary>
Plaid,
/// <summary>
/// Shingle style.
/// </summary>
Shingle,
/// <summary>
/// Small checker board style.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "CheckerBoard")]
SmallCheckerBoard,
/// <summary>
/// Small confetti style.
/// </summary>
SmallConfetti,
/// <summary>
/// Small grid style.
/// </summary>
SmallGrid,
/// <summary>
/// Solid diamond style.
/// </summary>
SolidDiamond,
/// <summary>
/// Sphere style.
/// </summary>
Sphere,
/// <summary>
/// Trellis style.
/// </summary>
Trellis,
/// <summary>
/// Vertical style.
/// </summary>
Vertical,
/// <summary>
/// Wave style.
/// </summary>
Wave,
/// <summary>
/// Weave style.
/// </summary>
Weave,
/// <summary>
/// Wide downward diagonal style.
/// </summary>
WideDownwardDiagonal,
/// <summary>
/// Wide upward diagonal style.
/// </summary>
WideUpwardDiagonal,
/// <summary>
/// ZigZag style.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "ZigZag")]
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Zig")]
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Zag")]
ZigZag
};
/// <summary>
/// An enumeration that specifies the level of anti-aliasing quality.
/// </summary>
public enum TextAntiAliasingQuality
{
/// <summary>
/// Normal anti-aliasing quality.
/// </summary>
Normal,
/// <summary>
/// High anti-aliasing quality.
/// </summary>
High,
/// <summary>
/// System default anti-aliasing quality.
/// </summary>
SystemDefault
}
/// <summary>
/// An enumeration of anti-aliasing flags.
/// </summary>
[Flags]
public enum AntiAliasingStyles
{
/// <summary>
/// No anti-aliasing.
/// </summary>
None = 0,
/// <summary>
/// Use anti-aliasing when drawing text.
/// </summary>
Text = 1,
/// <summary>
/// Use anti-aliasing when drawing grahics primitives (e.g. lines, rectangle)
/// </summary>
Graphics = 2,
/// <summary>
/// Use anti-alias for everything.
/// </summary>
All = Text | Graphics
};
/// <summary>
/// An enumeration of marker styles.
/// </summary>
public enum MarkerStyle
{
/// <summary>
/// No marker is displayed for the series/data point.
/// </summary>
None = 0,
/// <summary>
/// A square marker is displayed.
/// </summary>
Square = 1,
/// <summary>
/// A circle marker is displayed.
/// </summary>
Circle = 2,
/// <summary>
/// A diamond-shaped marker is displayed.
/// </summary>
Diamond = 3,
/// <summary>
/// A triangular marker is displayed.
/// </summary>
Triangle = 4,
/// <summary>
/// A cross-shaped marker is displayed.
/// </summary>
Cross = 5,
/// <summary>
/// A 4-point star-shaped marker is displayed.
/// </summary>
Star4 = 6,
/// <summary>
/// A 5-point star-shaped marker is displayed.
/// </summary>
Star5 = 7,
/// <summary>
/// A 6-point star-shaped marker is displayed.
/// </summary>
Star6 = 8,
/// <summary>
/// A 10-point star-shaped marker is displayed.
/// </summary>
Star10 = 9
};
/// <summary>
/// An enumeration of gradient styles.
/// </summary>
public enum GradientStyle
{
/// <summary>
/// No gradient is used.
/// </summary>
None,
/// <summary>
/// Gradient is applied from left to right.
/// </summary>
LeftRight,
/// <summary>
/// Gradient is applied from top to bottom.
/// </summary>
TopBottom,
/// <summary>
/// Gradient is applied from the center outwards.
/// </summary>
Center,
/// <summary>
/// Gradient is applied diagonally from left to right.
/// </summary>
DiagonalLeft,
/// <summary>
/// Gradient is applied diagonally from right to left.
/// </summary>
DiagonalRight,
/// <summary>
/// Gradient is applied horizontally from the center outwards.
/// </summary>
HorizontalCenter,
/// <summary>
/// Gradient is applied vertically from the center outwards.
/// </summary>
VerticalCenter
};
#endregion
#region ChartElement
/// <summary>
/// Common chart helper methods used across different chart elements.
/// </summary>
internal class ChartHelper
{
#region Fields
/// <summary>
/// Maximum number of grid lines per Axis
/// </summary>
internal const int MaxNumOfGridlines = 10000;
#endregion // Fields
#region Constructor
/// <summary>
/// Private constructor to avoid instantiating the class
/// </summary>
private ChartHelper() { }
#endregion // Constructor
#region Methods
/// <summary>
/// Adjust the beginnin of the first interval depending on the type and size.
/// </summary>
/// <param name="start">Original start point.</param>
/// <param name="intervalSize">Interval size.</param>
/// <param name="type">AxisName of the interval (Month, Year, ...).</param>
/// <returns>Adjusted interval start position as double.</returns>
internal static double AlignIntervalStart(double start, double intervalSize, DateTimeIntervalType type)
{
return AlignIntervalStart(start, intervalSize, type, null);
}
/// <summary>
/// Adjust the beginnin of the first interval depending on the type and size.
/// </summary>
/// <param name="start">Original start point.</param>
/// <param name="intervalSize">Interval size.</param>
/// <param name="type">AxisName of the interval (Month, Year, ...).</param>
/// <param name="series">First series connected to the axis.</param>
/// <returns>Adjusted interval start position as double.</returns>
internal static double AlignIntervalStart(double start, double intervalSize, DateTimeIntervalType type, Series series)
{
return AlignIntervalStart( start, intervalSize, type, series, true );
}
/// <summary>
/// Adjust the beginnin of the first interval depending on the type and size.
/// </summary>
/// <param name="start">Original start point.</param>
/// <param name="intervalSize">Interval size.</param>
/// <param name="type">AxisName of the interval (Month, Year, ...).</param>
/// <param name="series">First series connected to the axis.</param>
/// <param name="majorInterval">Interval is used for major gridlines or tickmarks.</param>
/// <returns>Adjusted interval start position as double.</returns>
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();
}
}
/// <summary>
/// Gets interval size as double number.
/// </summary>
/// <param name="current">Current value.</param>
/// <param name="interval">Interval size.</param>
/// <param name="type">AxisName of the interval (Month, Year, ...).</param>
/// <returns>Interval size as double.</returns>
internal static double GetIntervalSize(double current, double interval, DateTimeIntervalType type)
{
return GetIntervalSize(
current,
interval,
type,
null,
0,
DateTimeIntervalType.Number,
true,
true);
}
/// <summary>
/// Gets interval size as double number.
/// </summary>
/// <param name="current">Current value.</param>
/// <param name="interval">Interval size.</param>
/// <param name="type">AxisName of the interval (Month, Year, ...).</param>
/// <param name="series">First series connected to the axis.</param>
/// <param name="intervalOffset">Offset size.</param>
/// <param name="intervalOffsetType">Offset type(Month, Year, ...).</param>
/// <param name="forceIntIndex">Force Integer indexed</param>
/// <returns>Interval size as double.</returns>
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);
}
/// <summary>
/// Gets interval size as double number.
/// </summary>
/// <param name="current">Current value.</param>
/// <param name="interval">Interval size.</param>
/// <param name="type">AxisName of the interval (Month, Year, ...).</param>
/// <param name="series">First series connected to the axis.</param>
/// <param name="intervalOffset">Offset size.</param>
/// <param name="intervalOffsetType">Offset type(Month, Year, ...).</param>
/// <param name="forceIntIndex">Force Integer indexed</param>
/// <param name="forceAbsInterval">Force Integer indexed</param>
/// <returns>Interval size as double.</returns>
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;
}
}
/// <summary>
/// Check if series is indexed. IsXValueIndexed flag is set or all X values are zeros.
/// </summary>
/// <param name="series">Data series to test.</param>
/// <returns>True if series is indexed.</returns>
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);
}
/// <summary>
/// Check if all data points in the series have X value set to 0.
/// </summary>
/// <param name="series">Data series to check.</param>
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;
}
/// <summary>
/// Check if any series is indexed. IsXValueIndexed flag is set or all X values are zeros.
/// </summary>
/// <param name="common">Reference to common chart classes.</param>
/// <param name="series">Data series names.</param>
/// <returns>True if any series is indexed.</returns>
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;
}
/// <summary>
/// Check if all data points in many series have X value set to 0.
/// </summary>
/// <param name="common">Reference to common chart classes.</param>
/// <param name="series">Data series.</param>
/// <returns>True if all data points have value 0.</returns>
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
}