Advertisement
Guest User

Extended DateTimeAxis for Silverlight

a guest
Mar 14th, 2011
384
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 45.57 KB | None | 0 0
  1.     using System;
  2.     using System.Collections.Generic;
  3.     using System.ComponentModel;
  4.     using System.Diagnostics.CodeAnalysis;
  5.     using System.Linq;
  6.     using System.Windows;
  7.     using System.Windows.Controls;
  8.     using System.Windows.Shapes;
  9.     using EF = System.Windows.Controls.DataVisualization.EnumerableFunctions;
  10.     using System.Windows.Controls.DataVisualization.Charting;
  11.     using System.Windows.Controls.DataVisualization;
  12.    
  13.     namespace SilverlightApplication3
  14.     {
  15.         /// <summary>
  16.         /// An axis that displays numeric values.
  17.         /// </summary>
  18.         [StyleTypedProperty(Property = "GridLineStyle", StyleTargetType = typeof(Line))]
  19.         [StyleTypedProperty(Property = "MajorTickMarkStyle", StyleTargetType = typeof(Line))]
  20.         [StyleTypedProperty(Property = "MinorTickMarkStyle", StyleTargetType = typeof(Line))]
  21.         [StyleTypedProperty(Property = "AxisLabelStyle", StyleTargetType = typeof(DateTimeAxisLabel))]
  22.         [StyleTypedProperty(Property = "TitleStyle", StyleTargetType = typeof(Title))]
  23.         [TemplatePart(Name = AxisGridName, Type = typeof(Grid))]
  24.         [TemplatePart(Name = AxisTitleName, Type = typeof(Title))]
  25.         public class DateTimeAxis : RangeAxis
  26.         {
  27.             #region public DateTime? ActualMaximum
  28.             /// <summary>
  29.             /// Gets the actual maximum value plotted on the chart.
  30.             /// </summary>
  31.             public DateTime? ActualMaximum
  32.             {
  33.                 get { return (DateTime?)GetValue(ActualMaximumProperty); }
  34.                 private set { SetValue(ActualMaximumProperty, value); }
  35.             }
  36.    
  37.             /// <summary>
  38.             /// Identifies the ActualMaximum dependency property.
  39.             /// </summary>
  40.             public static readonly DependencyProperty ActualMaximumProperty =
  41.                 DependencyProperty.Register(
  42.                     "ActualMaximum",
  43.                     typeof(DateTime?),
  44.                     typeof(DateTimeAxis),
  45.                     null);
  46.             #endregion public DateTime? ActualMaximum
  47.    
  48.             #region public DateTime? ActualMinimum
  49.             /// <summary>
  50.             /// Gets the actual maximum value plotted on the chart.
  51.             /// </summary>
  52.             public DateTime? ActualMinimum
  53.             {
  54.                 get { return (DateTime?)GetValue(ActualMinimumProperty); }
  55.                 private set { SetValue(ActualMinimumProperty, value); }
  56.             }
  57.    
  58.             /// <summary>
  59.             /// Identifies the ActualMinimum dependency property.
  60.             /// </summary>
  61.             public static readonly DependencyProperty ActualMinimumProperty =
  62.                 DependencyProperty.Register(
  63.                     "ActualMinimum",
  64.                     typeof(DateTime?),
  65.                     typeof(DateTimeAxis),
  66.                     null);
  67.             #endregion public DateTime? ActualMinimum
  68.    
  69.             #region public DateTime? Maximum
  70.             /// <summary>
  71.             /// Gets or sets the maximum value plotted on the axis.
  72.             /// </summary>
  73.             [TypeConverter(typeof(NullableConverter<DateTime>))]
  74.             public DateTime? Maximum
  75.             {
  76.                 get { return (DateTime?)GetValue(MaximumProperty); }
  77.                 set { SetValue(MaximumProperty, value); }
  78.             }
  79.    
  80.             /// <summary>
  81.             /// Identifies the Maximum dependency property.
  82.             /// </summary>
  83.             public static readonly DependencyProperty MaximumProperty =
  84.                 DependencyProperty.Register(
  85.                     "Maximum",
  86.                     typeof(DateTime?),
  87.                     typeof(DateTimeAxis),
  88.                     new PropertyMetadata(null, OnMaximumPropertyChanged));
  89.    
  90.             /// <summary>
  91.             /// MaximumProperty property changed handler.
  92.             /// </summary>
  93.             /// <param name="d">DateTimeAxis2 that changed its Maximum.</param>
  94.             /// <param name="e">Event arguments.</param>
  95.             private static void OnMaximumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  96.             {
  97.                 DateTimeAxis source = (DateTimeAxis)d;
  98.                 DateTime? newValue = (DateTime?)e.NewValue;
  99.                 source.OnMaximumPropertyChanged(newValue);
  100.             }
  101.    
  102.             /// <summary>
  103.             /// MaximumProperty property changed handler.
  104.             /// </summary>
  105.             /// <param name="newValue">New value.</param>
  106.             private void OnMaximumPropertyChanged(DateTime? newValue)
  107.             {
  108.                 this.ProtectedMaximum = newValue;
  109.             }
  110.             #endregion public DateTime? Maximum
  111.    
  112.             #region public DateTime? Minimum
  113.             /// <summary>
  114.             /// Gets or sets the minimum value to plot on the axis.
  115.             /// </summary>
  116.             [TypeConverter(typeof(NullableConverter<DateTime>))]
  117.             public DateTime? Minimum
  118.             {
  119.                 get { return (DateTime?)GetValue(MinimumProperty); }
  120.                 set { SetValue(MinimumProperty, value); }
  121.             }
  122.    
  123.             /// <summary>
  124.             /// Identifies the Minimum dependency property.
  125.             /// </summary>
  126.             public static readonly DependencyProperty MinimumProperty =
  127.                 DependencyProperty.Register(
  128.                     "Minimum",
  129.                     typeof(DateTime?),
  130.                     typeof(DateTimeAxis),
  131.                     new PropertyMetadata(null, OnMinimumPropertyChanged));
  132.    
  133.             /// <summary>
  134.             /// MinimumProperty property changed handler.
  135.             /// </summary>
  136.             /// <param name="d">DateTimeAxis2 that changed its Minimum.</param>
  137.             /// <param name="e">Event arguments.</param>
  138.             private static void OnMinimumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  139.             {
  140.                 DateTimeAxis source = (DateTimeAxis)d;
  141.                 DateTime? newValue = (DateTime?)e.NewValue;
  142.                 source.OnMinimumPropertyChanged(newValue);
  143.             }
  144.    
  145.             /// <summary>
  146.             /// MinimumProperty property changed handler.
  147.             /// </summary>
  148.             /// <param name="newValue">New value.</param>
  149.             private void OnMinimumPropertyChanged(DateTime? newValue)
  150.             {
  151.                 this.ProtectedMinimum = newValue;
  152.             }
  153.             #endregion public DateTime? Minimum
  154.    
  155.             #region public double? Interval
  156.             /// <summary>
  157.             /// Gets or sets the axis interval.
  158.             /// </summary>
  159.             [TypeConverter(typeof(NullableConverter<double>))]
  160.             public double? Interval
  161.             {
  162.                 get { return (double?)GetValue(IntervalProperty); }
  163.                 set { SetValue(IntervalProperty, value); }
  164.             }
  165.    
  166.             /// <summary>
  167.             /// Identifies the Interval dependency property.
  168.             /// </summary>
  169.             public static readonly DependencyProperty IntervalProperty =
  170.                 DependencyProperty.Register(
  171.                     "Interval",
  172.                     typeof(double?),
  173.                     typeof(DateTimeAxis),
  174.                     new PropertyMetadata(null, OnIntervalPropertyChanged));
  175.    
  176.             /// <summary>
  177.             /// IntervalProperty property changed handler.
  178.             /// </summary>
  179.             /// <param name="d">DateTimeAxis2 that changed its Interval.</param>
  180.             /// <param name="e">Event arguments.</param>
  181.             private static void OnIntervalPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  182.             {
  183.                 DateTimeAxis source = (DateTimeAxis)d;
  184.                 source.OnIntervalPropertyChanged();
  185.             }
  186.    
  187.             /// <summary>
  188.             /// IntervalProperty property changed handler.
  189.             /// </summary>
  190.             private void OnIntervalPropertyChanged()
  191.             {
  192.                 Invalidate();
  193.             }
  194.             #endregion public double? Interval
  195.    
  196.             #region public double ActualInterval
  197.             /// <summary>
  198.             /// Gets the actual interval.
  199.             /// </summary>
  200.             public double ActualInterval
  201.             {
  202.                 get { return (double)GetValue(ActualIntervalProperty); }
  203.                 private set { SetValue(ActualIntervalProperty, value); }
  204.             }
  205.    
  206.             /// <summary>
  207.             /// Identifies the ActualInterval dependency property.
  208.             /// </summary>
  209.             public static readonly DependencyProperty ActualIntervalProperty =
  210.                 DependencyProperty.Register(
  211.                     "ActualInterval",
  212.                     typeof(double),
  213.                     typeof(DateTimeAxis),
  214.                     new PropertyMetadata(double.NaN));
  215.    
  216.             #endregion public double ActualInterval
  217.    
  218.             #region public DateTimeIntervalType IntervalType
  219.             /// <summary>
  220.             /// Gets or sets the interval to use for the axis.
  221.             /// </summary>
  222.             public ExtendedDateTimeIntervalType IntervalType
  223.             {
  224.                 get { return (ExtendedDateTimeIntervalType)GetValue(IntervalTypeProperty); }
  225.                 set { SetValue(IntervalTypeProperty, value); }
  226.             }
  227.    
  228.             /// <summary>
  229.             /// Identifies the InternalIntervalType dependency property.
  230.             /// </summary>
  231.             public static readonly DependencyProperty IntervalTypeProperty =
  232.                 DependencyProperty.Register(
  233.                     "IntervalType",
  234.                     typeof(ExtendedDateTimeIntervalType),
  235.                     typeof(DateTimeAxis),
  236.                     new PropertyMetadata(ExtendedDateTimeIntervalType.Auto, OnIntervalTypePropertyChanged));
  237.    
  238.             /// <summary>
  239.             /// IntervalTypeProperty property changed handler.
  240.             /// </summary>
  241.             /// <param name="d">DateTimeAxis that changed its InternalIntervalType.</param>
  242.             /// <param name="e">Event arguments.</param>
  243.             private static void OnIntervalTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  244.             {
  245.                 DateTimeAxis source = (DateTimeAxis)d;
  246.                 ExtendedDateTimeIntervalType newValue = (ExtendedDateTimeIntervalType)e.NewValue;
  247.                 source.OnIntervalTypePropertyChanged(newValue);
  248.             }
  249.    
  250.             /// <summary>
  251.             /// IntervalTypeProperty property changed handler.
  252.             /// </summary>
  253.             /// <param name="newValue">New value.</param>
  254.             private void OnIntervalTypePropertyChanged(ExtendedDateTimeIntervalType newValue)
  255.             {
  256.                 this.ActualIntervalType = newValue;
  257.                 Invalidate();
  258.             }
  259.             #endregion public DateTimeIntervalType IntervalType
  260.    
  261.             #region public DateTimeIntervalType ActualIntervalType
  262.             /// <summary>
  263.             /// Gets or sets the actual interval type.
  264.             /// </summary>
  265.             private ExtendedDateTimeIntervalType ActualIntervalType
  266.             {
  267.                 get { return (ExtendedDateTimeIntervalType)GetValue(ActualIntervalTypeProperty); }
  268.                 set { SetValue(ActualIntervalTypeProperty, value); }
  269.             }
  270.    
  271.             /// <summary>
  272.             /// Identifies the ActualIntervalType dependency property.
  273.             /// </summary>
  274.             private static readonly DependencyProperty ActualIntervalTypeProperty =
  275.                 DependencyProperty.Register(
  276.                     "ActualIntervalType",
  277.                     typeof(ExtendedDateTimeIntervalType),
  278.                     typeof(DateTimeAxis),
  279.                     new PropertyMetadata(ExtendedDateTimeIntervalType.Auto));
  280.    
  281.             #endregion public DateTimeIntervalType ActualIntervalType
  282.    
  283.             /// <summary>
  284.             /// Gets the origin value on the axis.
  285.             /// </summary>
  286.             protected override IComparable Origin
  287.             {
  288.                 get { return null; }
  289.             }
  290.    
  291.             /// <summary>
  292.             /// Instantiates a new instance of the DateTimeAxis2 class.
  293.             /// </summary>
  294.             public DateTimeAxis()
  295.             {
  296.                 int year = DateTime.Now.Year;
  297.                 this.ActualRange = new Range<IComparable>(new DateTime(year, 1, 1), new DateTime(year + 1, 1, 1));
  298.             }
  299.    
  300.             /// <summary>
  301.             /// Creates a new instance of the DateTimeAxisLabel class.
  302.             /// </summary>
  303.             /// <returns>Returns  a new instance of the DateTimeAxisLabel class.
  304.             /// </returns>
  305.             protected override Control CreateAxisLabel()
  306.             {
  307.                 return new DateTimeAxisLabel();
  308.             }
  309.    
  310.             /// <summary>
  311.             /// Prepares an instance of the DateTimeAxisLabel class by setting its
  312.             /// IntervalType property.
  313.             /// </summary>
  314.             /// <param name="label">An instance of the DateTimeAxisLabel class.
  315.             /// </param>
  316.             /// <param name="dataContext">The data context to assign to the label.
  317.             /// </param>
  318.             protected override void PrepareAxisLabel(Control label, object dataContext)
  319.             {
  320.                 DateTimeAxisLabel dateTimeAxisLabel = label as DateTimeAxisLabel;
  321.    
  322.                 if (dateTimeAxisLabel != null)
  323.                 {
  324.                     if (ActualIntervalType == ExtendedDateTimeIntervalType.OddDays)
  325.                         dateTimeAxisLabel.IntervalType = DateTimeIntervalType.Days;
  326.                     else
  327.                         dateTimeAxisLabel.IntervalType = (DateTimeIntervalType)(int)ActualIntervalType;
  328.                 }
  329.                 base.PrepareAxisLabel(label, dataContext);
  330.             }
  331.    
  332.             /// <summary>
  333.             /// Gets the actual range of DateTime values.
  334.             /// </summary>
  335.             protected Range<DateTime> ActualDateTimeRange { get; private set; }
  336.    
  337.             /// <summary>
  338.             /// Updates the typed actual maximum and minimum properties when the
  339.             /// actual range changes.
  340.             /// </summary>
  341.             /// <param name="range">The actual range.</param>
  342.             protected override void OnActualRangeChanged(Range<IComparable> range)
  343.             {
  344.                 ActualDateTimeRange = range.ToDateTimeRange();
  345.    
  346.                 if (range.HasData)
  347.                 {
  348.                     this.ActualMaximum = (DateTime)range.Maximum;
  349.                     this.ActualMinimum = (DateTime)range.Minimum;
  350.                 }
  351.                 else
  352.                 {
  353.                     this.ActualMaximum = null;
  354.                     this.ActualMinimum = null;
  355.                 }
  356.    
  357.                 base.OnActualRangeChanged(range);
  358.             }
  359.    
  360.             /// <summary>
  361.             /// Returns a value indicating whether a value can plot.
  362.             /// </summary>
  363.             /// <param name="value">The value to plot.</param>
  364.             /// <returns>A value indicating whether a value can plot.</returns>
  365.             public override bool CanPlot(object value)
  366.             {
  367.                 DateTime val;
  368.                 return ValueHelper.TryConvert(value, out val);
  369.             }
  370.    
  371.             /// <summary>
  372.             /// Returns the plot area coordinate of a value.
  373.             /// </summary>
  374.             /// <param name="value">The value to plot.</param>
  375.             /// <param name="length">The length of the axis.</param>
  376.             /// <returns>The plot area coordinate of a value.</returns>
  377.             protected override UnitValue GetPlotAreaCoordinate(object value, double length)
  378.             {
  379.                 return GetPlotAreaCoordinate(value, ActualDateTimeRange, length);
  380.             }
  381.    
  382.             /// <summary>
  383.             /// Returns the plot area coordinate of a value.
  384.             /// </summary>
  385.             /// <param name="value">The value to plot.</param>
  386.             /// <param name="currentRange">The range to use determine the coordinate.</param>
  387.             /// <param name="length">The length of the axis.</param>
  388.             /// <returns>The plot area coordinate of a value.</returns>
  389.             protected override UnitValue GetPlotAreaCoordinate(object value, Range<IComparable> currentRange, double length)
  390.             {
  391.                 return GetPlotAreaCoordinate(value, currentRange.ToDateTimeRange(), length);
  392.             }
  393.    
  394.             /// <summary>
  395.             /// Returns the plot area coordinate of a value.
  396.             /// </summary>
  397.             /// <param name="value">The value to plot.</param>
  398.             /// <param name="currentRange">The range to use determine the coordinate.</param>
  399.             /// <param name="length">The length of the axis.</param>
  400.             /// <returns>The plot area coordinate of a value.</returns>
  401.             private static UnitValue GetPlotAreaCoordinate(object value, Range<DateTime> currentRange, double length)
  402.             {
  403.                 if (currentRange.HasData)
  404.                 {
  405.                     DateTime dateTimeValue = ValueHelper.ToDateTime(value);
  406.    
  407.                     double rangelength = currentRange.Maximum.ToOADate() - currentRange.Minimum.ToOADate();
  408.                     double pixelLength = Math.Max(length - 1, 0);
  409.    
  410.                     return new UnitValue((dateTimeValue.ToOADate() - currentRange.Minimum.ToOADate()) * (pixelLength / rangelength), Unit.Pixels);
  411.                 }
  412.    
  413.                 return UnitValue.NaN();
  414.             }
  415.    
  416.             /// <summary>
  417.             /// Returns the actual interval to use to determine which values are
  418.             /// displayed in the axis.
  419.             /// </summary>
  420.             /// <param name="availableSize">The available size.</param>
  421.             /// <returns>The actual interval to use to determine which values are
  422.             /// displayed in the axis.
  423.             /// </returns>
  424.             private double CalculateActualInterval(Size availableSize)
  425.             {
  426.                 if (Interval != null)
  427.                 {
  428.                     return Interval.Value;
  429.                 }
  430.    
  431.                 ExtendedDateTimeIntervalType intervalType;
  432.                 double interval = CalculateDateTimeInterval(ActualDateTimeRange.Minimum, ActualDateTimeRange.Maximum, out intervalType, availableSize);
  433.                 ActualIntervalType = intervalType;
  434.                 return interval;
  435.             }
  436.    
  437.             /// <summary>
  438.             /// Returns a sequence of major values.
  439.             /// </summary>
  440.             /// <param name="availableSize">The available size.</param>
  441.             /// <returns>A sequence of major values.</returns>
  442.             protected virtual IEnumerable<DateTime> GetMajorAxisValues(Size availableSize)
  443.             {
  444.                 if (!ActualRange.HasData || ValueHelper.Compare(ActualRange.Minimum, ActualRange.Maximum) == 0 || GetLength(availableSize) == 0.0)
  445.                 {
  446.                     yield break;
  447.                 }
  448.    
  449.                 this.ActualInterval = CalculateActualInterval(availableSize);
  450.                 DateTime date = ActualDateTimeRange.Minimum;
  451.    
  452.                 DateTime start = AlignIntervalStart(date, this.ActualInterval, ActualIntervalType);
  453.                 while (start < date)
  454.                 {
  455.                     start = IncrementDateTime(start, this.ActualInterval);
  456.                 }
  457.    
  458.                 IEnumerable<DateTime> intermediateDates =
  459.                     EnumerableFunctions
  460.                         .Iterate(start, next => IncrementDateTime(next, this.ActualInterval))
  461.                         .TakeWhile(current => ActualDateTimeRange.Contains(current));
  462.    
  463.                 foreach (DateTime current in intermediateDates)
  464.                 {
  465.                     yield return current;
  466.                 }
  467.             }
  468.    
  469.             /// <summary>
  470.             /// Returns a sequence of values to create major tick marks for.
  471.             /// </summary>
  472.             /// <param name="availableSize">The available size.</param>
  473.             /// <returns>A sequence of values to create major tick marks for.
  474.             /// </returns>
  475.             protected override IEnumerable<IComparable> GetMajorTickMarkValues(Size availableSize)
  476.             {
  477.                 return GetMajorAxisValues(availableSize).CastWrapper<IComparable>();
  478.             }
  479.    
  480.             /// <summary>
  481.             /// Returns a sequence of values to plot on the axis.
  482.             /// </summary>
  483.             /// <param name="availableSize">The available size.</param>
  484.             /// <returns>A sequence of values to plot on the axis.</returns>
  485.             protected override IEnumerable<IComparable> GetLabelValues(Size availableSize)
  486.             {
  487.                 return GetMajorAxisValues(availableSize).CastWrapper<IComparable>();
  488.             }
  489.    
  490.             /// <summary>
  491.             /// This method accepts a date time and increments it.
  492.             /// </summary>
  493.             /// <param name="date">A date time.</param>
  494.             /// <param name="interval">The interval used to increment the date time.
  495.             /// </param>
  496.             /// <returns>The new date time.</returns>
  497.             private DateTime IncrementDateTime(DateTime date, double interval)
  498.             {
  499.                 ExtendedDateTimeIntervalType intervalType = this.ActualIntervalType;
  500.                 TimeSpan span = new TimeSpan(0);
  501.                 DateTime result;
  502.    
  503.    
  504.                 if (intervalType == ExtendedDateTimeIntervalType.Days)
  505.                 {
  506.                     span = TimeSpan.FromDays(interval);
  507.                 }
  508.                 else if (intervalType == ExtendedDateTimeIntervalType.Hours)
  509.                 {
  510.                     span = TimeSpan.FromHours(interval);
  511.                 }
  512.                 else if (intervalType == ExtendedDateTimeIntervalType.Milliseconds)
  513.                 {
  514.                     span = TimeSpan.FromMilliseconds(interval);
  515.                 }
  516.                 else if (intervalType == ExtendedDateTimeIntervalType.Seconds)
  517.                 {
  518.                     span = TimeSpan.FromSeconds(interval);
  519.                 }
  520.                 else if (intervalType == ExtendedDateTimeIntervalType.Minutes)
  521.                 {
  522.                     span = TimeSpan.FromMinutes(interval);
  523.                 }
  524.                 else if (intervalType == ExtendedDateTimeIntervalType.Weeks)
  525.                 {
  526.                     span = TimeSpan.FromDays(7.0 * interval);
  527.                 }
  528.                 else if (intervalType == ExtendedDateTimeIntervalType.Months)
  529.                 {
  530.                     // Special case handling when current date point
  531.                     // to the last day of the month
  532.                     bool lastMonthDay = false;
  533.                     if (date.Day == DateTime.DaysInMonth(date.Year, date.Month))
  534.                     {
  535.                         lastMonthDay = true;
  536.                     }
  537.    
  538.                     // Add specified amount of months
  539.                     date = date.AddMonths((int)Math.Floor(interval));
  540.                     span = TimeSpan.FromDays(30.0 * (interval - Math.Floor(interval)));
  541.    
  542.                     // Check if last month of the day was used
  543.                     if (lastMonthDay && span.Ticks == 0)
  544.                     {
  545.                         // Make sure the last day of the month is selected
  546.                         int daysInMobth = DateTime.DaysInMonth(date.Year, date.Month);
  547.                         date = date.AddDays(daysInMobth - date.Day);
  548.                     }
  549.                 }
  550.                 else if (intervalType == ExtendedDateTimeIntervalType.Years)
  551.                 {
  552.                     date = date.AddYears((int)Math.Floor(interval));
  553.                     span = TimeSpan.FromDays(365.0 * (interval - Math.Floor(interval)));
  554.                 }
  555.    
  556.                 if (this.IntervalType == ExtendedDateTimeIntervalType.OddDays)
  557.                 {
  558.                     DateTime newDate;
  559.                     if(span != TimeSpan.Zero)
  560.                         newDate = date.Add(span);
  561.                     else newDate = date.AddDays(interval);
  562.    
  563.                     while (newDate.Day % 2 != 1)
  564.                         newDate = newDate.AddDays(1);
  565.                     span = newDate - date;
  566.                 }
  567.    
  568.                 result = date.Add(span);
  569.    
  570.                 return result;
  571.             }
  572.    
  573.             /// <summary>
  574.             /// Adjusts the beginning of the first interval depending on the type and size.
  575.             /// </summary>
  576.             /// <param name="start">Original start point.</param>
  577.             /// <param name="intervalSize">Interval size.</param>
  578.             /// <param name="type">Type of the interval (Month, Year, ...).</param>
  579.             /// <returns>
  580.             /// Adjusted interval start position.
  581.             /// </returns>
  582.             private static DateTime AlignIntervalStart(DateTime start, double intervalSize, ExtendedDateTimeIntervalType type)
  583.             {
  584.                 // Do not adjust start position for these interval type
  585.                 if (type == ExtendedDateTimeIntervalType.Auto)
  586.                 {
  587.                     return start;
  588.                 }
  589.    
  590.                 // Get the beginning of the interval depending on type
  591.                 DateTime newStartDate = start;
  592.    
  593.                 // Adjust the months interval depending on size
  594.                 if (intervalSize > 0.0 && intervalSize != 1.0)
  595.                 {
  596.                     if (type == ExtendedDateTimeIntervalType.Months && intervalSize <= 12.0 && intervalSize > 1)
  597.                     {
  598.                         // Make sure that the beginning is aligned correctly for cases
  599.                         // like quarters and half years
  600.                         DateTime resultDate = newStartDate;
  601.                         DateTime sizeAdjustedDate = new DateTime(newStartDate.Year, 1, 1, 0, 0, 0);
  602.                         while (sizeAdjustedDate < newStartDate)
  603.                         {
  604.                             resultDate = sizeAdjustedDate;
  605.                             sizeAdjustedDate = sizeAdjustedDate.AddMonths((int)intervalSize);
  606.                         }
  607.    
  608.                         newStartDate = resultDate;
  609.                         return newStartDate;
  610.                     }
  611.                 }
  612.    
  613.                 // Check interval type
  614.                 switch (type)
  615.                 {
  616.                     case ExtendedDateTimeIntervalType.Years:
  617.                         int year = (int)((int)(newStartDate.Year / intervalSize) * intervalSize);
  618.                         if (year <= 0)
  619.                         {
  620.                             year = 1;
  621.                         }
  622.                         newStartDate = new DateTime(year, 1, 1, 0, 0, 0);
  623.                         break;
  624.    
  625.                     case ExtendedDateTimeIntervalType.Months:
  626.                         int month = (int)((int)(newStartDate.Month / intervalSize) * intervalSize);
  627.                         if (month <= 0)
  628.                         {
  629.                             month = 1;
  630.                         }
  631.                         newStartDate = new DateTime(newStartDate.Year, month, 1, 0, 0, 0);
  632.                         break;
  633.    
  634.                     case ExtendedDateTimeIntervalType.Days:
  635.                     case ExtendedDateTimeIntervalType.OddDays:
  636.                         int day = (int)((int)(newStartDate.Day / intervalSize) * intervalSize);
  637.                         if (day <= 0)
  638.                         {
  639.                             day = 1;
  640.                         }
  641.                         newStartDate = new DateTime(newStartDate.Year, newStartDate.Month, day, 0, 0, 0);
  642.                         break;
  643.    
  644.                     case ExtendedDateTimeIntervalType.Hours:
  645.                         int hour = (int)((int)(newStartDate.Hour / intervalSize) * intervalSize);
  646.                         newStartDate = new DateTime(
  647.                             newStartDate.Year,
  648.                             newStartDate.Month,
  649.                             newStartDate.Day,
  650.                             hour,
  651.                             0,
  652.                             0);
  653.                         break;
  654.    
  655.                     case ExtendedDateTimeIntervalType.Minutes:
  656.                         int minute = (int)((int)(newStartDate.Minute / intervalSize) * intervalSize);
  657.                         newStartDate = new DateTime(
  658.                             newStartDate.Year,
  659.                             newStartDate.Month,
  660.                             newStartDate.Day,
  661.                             newStartDate.Hour,
  662.                             minute,
  663.                             0);
  664.                         break;
  665.    
  666.                     case ExtendedDateTimeIntervalType.Seconds:
  667.                         int second = (int)((int)(newStartDate.Second / intervalSize) * intervalSize);
  668.                         newStartDate = new DateTime(
  669.                             newStartDate.Year,
  670.                             newStartDate.Month,
  671.                             newStartDate.Day,
  672.                             newStartDate.Hour,
  673.                             newStartDate.Minute,
  674.                             second,
  675.                             0);
  676.                         break;
  677.    
  678.                     case ExtendedDateTimeIntervalType.Milliseconds:
  679.                         int milliseconds = (int)((int)(newStartDate.Millisecond / intervalSize) * intervalSize);
  680.                         newStartDate = new DateTime(
  681.                             newStartDate.Year,
  682.                             newStartDate.Month,
  683.                             newStartDate.Day,
  684.                             newStartDate.Hour,
  685.                             newStartDate.Minute,
  686.                             newStartDate.Second,
  687.                             milliseconds);
  688.                         break;
  689.    
  690.                     case ExtendedDateTimeIntervalType.Weeks:
  691.    
  692.                         // Elements that have interval set to weeks should be aligned to the
  693.                         // nearest start of week no matter how many weeks is the interval.
  694.                         newStartDate = new DateTime(
  695.                             newStartDate.Year,
  696.                             newStartDate.Month,
  697.                             newStartDate.Day,
  698.                             0,
  699.                             0,
  700.                             0);
  701.    
  702.                         newStartDate = newStartDate.AddDays(-((int)newStartDate.DayOfWeek));
  703.                         break;
  704.                 }
  705.    
  706.                 return newStartDate;
  707.             }
  708.    
  709.             /// <summary>
  710.             /// Returns the value range given a plot area coordinate.
  711.             /// </summary>
  712.             /// <param name="value">The position.</param>
  713.             /// <returns>A range of values at that plot area coordinate.</returns>
  714.             protected override IComparable GetValueAtPosition(UnitValue value)
  715.             {
  716.                 if (ActualRange.HasData && ActualLength != 0.0)
  717.                 {
  718.                     double coordinate = value.Value;
  719.                     if (value.Unit == Unit.Pixels)
  720.                     {
  721.                         double minimumAsDouble = ActualDateTimeRange.Minimum.ToOADate();
  722.                         double rangelength = ActualDateTimeRange.Maximum.ToOADate() - minimumAsDouble;
  723.                         DateTime output = DateTime.FromOADate((coordinate * (rangelength / ActualLength)) + minimumAsDouble);
  724.    
  725.                         return output;
  726.                     }
  727.                     else
  728.                     {
  729.                         throw new NotImplementedException();
  730.                     }
  731.                 }
  732.    
  733.                 return null;
  734.             }
  735.    
  736.             /// <summary>
  737.             /// Recalculates a DateTime interval obtained from maximum and minimum.
  738.             /// </summary>
  739.             /// <param name="minimum">The minimum.</param>
  740.             /// <param name="maximum">The maximum.</param>
  741.             /// <param name="type">Date time interval type.</param>
  742.             /// <param name="availableSize">The available size.</param>
  743.             /// <returns>Auto Interval.</returns>
  744.             [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "The method should inspect all variations of time span (millisec to year) and contains long case. Otherwise is simple and readable.")]
  745.             private double CalculateDateTimeInterval(DateTime minimum, DateTime maximum, out ExtendedDateTimeIntervalType type, Size availableSize)
  746.             {
  747.                 DateTime dateTimeMin = minimum;
  748.                 DateTime dateTimeMax = maximum;
  749.                 TimeSpan timeSpan = dateTimeMax.Subtract(dateTimeMin);
  750.    
  751.                 // this algorithm is designed to return close to 10 intervals.
  752.                 // we need to align the time span for PrefferedNumberOfIntervals
  753.                 double maxIntervals = Orientation == AxisOrientation.X ? MaximumAxisIntervalsPer200Pixels * 0.8 : MaximumAxisIntervalsPer200Pixels;
  754.                 double rangeMultiplicator = GetLength(availableSize) / (200 * 10 / maxIntervals);
  755.                 timeSpan = new TimeSpan((long)((double)timeSpan.Ticks / rangeMultiplicator));
  756.    
  757.                 // Minutes
  758.                 double inter = timeSpan.TotalMinutes;
  759.    
  760.                 // For Range less than 60 seconds interval is 5 sec
  761.                 if (inter <= 1.0)
  762.                 {
  763.                     // Milli Seconds
  764.                     double milliSeconds = timeSpan.TotalMilliseconds;
  765.                     if (milliSeconds <= 10)
  766.                     {
  767.                         type = ExtendedDateTimeIntervalType.Milliseconds;
  768.                         return 1;
  769.                     }
  770.                     if (milliSeconds <= 50)
  771.                     {
  772.                         type = ExtendedDateTimeIntervalType.Milliseconds;
  773.                         return 4;
  774.                     }
  775.                     if (milliSeconds <= 200)
  776.                     {
  777.                         type = ExtendedDateTimeIntervalType.Milliseconds;
  778.                         return 20;
  779.                     }
  780.                     if (milliSeconds <= 500)
  781.                     {
  782.                         type = ExtendedDateTimeIntervalType.Milliseconds;
  783.                         return 50;
  784.                     }
  785.    
  786.                     // Seconds
  787.                     double seconds = timeSpan.TotalSeconds;
  788.    
  789.                     if (seconds <= 7)
  790.                     {
  791.                         type = ExtendedDateTimeIntervalType.Seconds;
  792.                         return 1;
  793.                     }
  794.                     else if (seconds <= 15)
  795.                     {
  796.                         type = ExtendedDateTimeIntervalType.Seconds;
  797.                         return 2;
  798.                     }
  799.                     else if (seconds <= 30)
  800.                     {
  801.                         type = ExtendedDateTimeIntervalType.Seconds;
  802.                         return 5;
  803.                     }
  804.                     else if (seconds <= 60)
  805.                     {
  806.                         type = ExtendedDateTimeIntervalType.Seconds;
  807.                         return 10;
  808.                     }
  809.                 }
  810.                 else if (inter <= 2.0)
  811.                 {
  812.                     // For Range less than 120 seconds interval is 10 sec
  813.                     type = ExtendedDateTimeIntervalType.Seconds;
  814.                     return 20;
  815.                 }
  816.                 else if (inter <= 3.0)
  817.                 {
  818.                     // For Range less than 180 seconds interval is 30 sec
  819.                     type = ExtendedDateTimeIntervalType.Seconds;
  820.                     return 30;
  821.                 }
  822.                 else if (inter <= 10)
  823.                 {
  824.                     // For Range less than 10 minutes interval is 1 min
  825.                     type = ExtendedDateTimeIntervalType.Minutes;
  826.                     return 1;
  827.                 }
  828.                 else if (inter <= 20)
  829.                 {
  830.                     // For Range less than 20 minutes interval is 1 min
  831.                     type = ExtendedDateTimeIntervalType.Minutes;
  832.                     return 2;
  833.                 }
  834.                 else if (inter <= 60)
  835.                 {
  836.                     // For Range less than 60 minutes interval is 5 min
  837.                     type = ExtendedDateTimeIntervalType.Minutes;
  838.                     return 5;
  839.                 }
  840.                 else if (inter <= 120)
  841.                 {
  842.                     // For Range less than 120 minutes interval is 10 min
  843.                     type = ExtendedDateTimeIntervalType.Minutes;
  844.                     return 10;
  845.                 }
  846.                 else if (inter <= 180)
  847.                 {
  848.                     // For Range less than 180 minutes interval is 30 min
  849.                     type = ExtendedDateTimeIntervalType.Minutes;
  850.                     return 30;
  851.                 }
  852.                 else if (inter <= 60 * 12)
  853.                 {
  854.                     // For Range less than 12 hours interval is 1 hour
  855.                     type = ExtendedDateTimeIntervalType.Hours;
  856.                     return 1;
  857.                 }
  858.                 else if (inter <= 60 * 24)
  859.                 {
  860.                     // For Range less than 24 hours interval is 4 hour
  861.                     type = ExtendedDateTimeIntervalType.Hours;
  862.                     return 4;
  863.                 }
  864.                 else if (inter <= 60 * 24 * 2)
  865.                 {
  866.                     // For Range less than 2 days interval is 6 hour
  867.                     type = ExtendedDateTimeIntervalType.Hours;
  868.                     return 6;
  869.                 }
  870.                 else if (inter <= 60 * 24 * 3)
  871.                 {
  872.                     // For Range less than 3 days interval is 12 hour
  873.                     type = ExtendedDateTimeIntervalType.Hours;
  874.                     return 12;
  875.                 }
  876.                 else if (inter <= 60 * 24 * 10)
  877.                 {
  878.                     // For Range less than 10 days interval is 1 day
  879.                     type = ExtendedDateTimeIntervalType.Days;
  880.                     return 1;
  881.                 }
  882.                 else if (inter <= 60 * 24 * 20)
  883.                 {
  884.                     // For Range less than 20 days interval is 2 day
  885.                     type = ExtendedDateTimeIntervalType.Days;
  886.                     return 2;
  887.                 }
  888.                 else if (inter <= 60 * 24 * 30)
  889.                 {
  890.                     // For Range less than 30 days interval is 3 day
  891.                     type = ExtendedDateTimeIntervalType.Days;
  892.                     return 3;
  893.                 }
  894.                 else if (inter <= 60 * 24 * 30.5 * 2)
  895.                 {
  896.                     // For Range less than 2 months interval is 1 week
  897.                     type = ExtendedDateTimeIntervalType.Weeks;
  898.                     return 1;
  899.                 }
  900.                 else if (inter <= 60 * 24 * 30.5 * 5)
  901.                 {
  902.                     // For Range less than 5 months interval is 2weeks
  903.                     type = ExtendedDateTimeIntervalType.Weeks;
  904.                     return 2;
  905.                 }
  906.                 else if (inter <= 60 * 24 * 30.5 * 12)
  907.                 {
  908.                     // For Range less than 12 months interval is 1 month
  909.                     type = ExtendedDateTimeIntervalType.Months;
  910.                     return 1;
  911.                 }
  912.                 else if (inter <= 60 * 24 * 30.5 * 24)
  913.                 {
  914.                     // For Range less than 24 months interval is 3 month
  915.                     type = ExtendedDateTimeIntervalType.Months;
  916.                     return 3;
  917.                 }
  918.                 else if (inter <= 60 * 24 * 30.5 * 48)
  919.                 {
  920.                     // For Range less than 48 months interval is 6 months
  921.                     type = ExtendedDateTimeIntervalType.Months;
  922.                     return 6;
  923.                 }
  924.    
  925.                 // For Range more than 48 months interval is year
  926.                 type = ExtendedDateTimeIntervalType.Years;
  927.                 double years = inter / 60 / 24 / 365;
  928.                 if (years < 5)
  929.                 {
  930.                     return 1;
  931.                 }
  932.                 else if (years < 10)
  933.                 {
  934.                     return 2;
  935.                 }
  936.    
  937.                 // Make a correction of the interval
  938.                 return Math.Floor(years / 5);
  939.             }
  940.    
  941.             /// <summary>
  942.             /// Overrides the actual range to ensure that it is never set to an
  943.             /// empty range.
  944.             /// </summary>
  945.             /// <param name="range">The range to override.</param>
  946.             /// <returns>The overridden range.</returns>
  947.             [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "This method is very difficult to break up cleanly.")]
  948.             protected override Range<IComparable> OverrideDataRange(Range<IComparable> range)
  949.             {
  950.                 Range<IComparable> overriddenActualRange = range;
  951.    
  952.                 if (!overriddenActualRange.HasData)
  953.                 {
  954.                     int year = DateTime.Now.Year;
  955.                     return new Range<IComparable>(new DateTime(year, 1, 1), new DateTime(year + 1, 1, 1));
  956.                 }
  957.                 else if (ValueHelper.Compare(overriddenActualRange.Minimum, overriddenActualRange.Maximum) == 0)
  958.                 {
  959.                     DateTime minimum = ValueHelper.ToDateTime(overriddenActualRange.Minimum);
  960.                     DateTime midpoint = ((DateTime.MinValue == minimum) ? DateTime.Now : minimum).Date;
  961.                     return new Range<IComparable>(midpoint.AddMonths(-6), midpoint.AddMonths(6));
  962.                 }
  963.    
  964.                 //// ActualLength of 1.0 or less maps all points to the same coordinate
  965.                 //if (range.HasData && this.ActualLength > 1.0)
  966.                 //{
  967.                 //    IList<ValueMarginCoordinateAndOverlap> valueMargins = new List<ValueMarginCoordinateAndOverlap>();
  968.                 //    foreach (ValueMargin valueMargin in
  969.                 //        this.RegisteredListeners
  970.                 //            .OfType<IValueMarginProvider>()
  971.                 //            .SelectMany(provider => provider.GetValueMargins(this)))
  972.                 //    {
  973.                 //        valueMargins.Add(
  974.                 //            new ValueMarginCoordinateAndOverlap
  975.                 //            {
  976.                 //                ValueMargin = valueMargin,
  977.                 //            });
  978.                 //    }
  979.    
  980.                 //    if (valueMargins.Count > 0)
  981.                 //    {
  982.                 //        double maximumPixelMarginLength =
  983.                 //            valueMargins
  984.                 //            .Select(valueMargin => valueMargin.ValueMargin.LowMargin + valueMargin.ValueMargin.HighMargin)
  985.                 //            .MaxOrNullable().Value;
  986.    
  987.                 //        // Requested margin is larger than the axis so give up
  988.                 //        // trying to find a range that will fit it.
  989.                 //        if (maximumPixelMarginLength > this.ActualLength)
  990.                 //        {
  991.                 //            return range;
  992.                 //        }
  993.    
  994.                 //        Range<DateTime> currentRange = range.ToDateTimeRange();
  995.    
  996.                 //        // Ensure range is not empty.
  997.                 //        if (currentRange.Minimum == currentRange.Maximum)
  998.                 //        {
  999.                 //            int year = DateTime.Now.Year;
  1000.                 //            currentRange = new Range<DateTime>(new DateTime(year, 1, 1), new DateTime(year + 1, 1, 1));
  1001.                 //        }
  1002.    
  1003.                 //        // priming the loop
  1004.                 //        double actualLength = this.ActualLength;
  1005.                 //        ValueMarginCoordinateAndOverlap maxLeftOverlapValueMargin;
  1006.                 //        ValueMarginCoordinateAndOverlap maxRightOverlapValueMargin;
  1007.                 //        UpdateValueMargins(valueMargins, currentRange.ToComparableRange());
  1008.                 //        GetMaxLeftAndRightOverlap(valueMargins, out maxLeftOverlapValueMargin, out maxRightOverlapValueMargin);
  1009.    
  1010.                 //        while (maxLeftOverlapValueMargin.LeftOverlap > 0 || maxRightOverlapValueMargin.RightOverlap > 0)
  1011.                 //        {
  1012.                 //            long unitOverPixels = currentRange.GetLength().Value.Ticks / ((long) actualLength);
  1013.                 //            DateTime newMinimum = new DateTime(currentRange.Minimum.Ticks - (long)((maxLeftOverlapValueMargin.LeftOverlap + 0.5) * unitOverPixels));
  1014.                 //            DateTime newMaximum = new DateTime(currentRange.Maximum.Ticks + (long)((maxRightOverlapValueMargin.RightOverlap + 0.5) * unitOverPixels));
  1015.    
  1016.                 //            currentRange = new Range<DateTime>(newMinimum, newMaximum);
  1017.                 //            UpdateValueMargins(valueMargins, currentRange.ToComparableRange());
  1018.                 //            GetMaxLeftAndRightOverlap(valueMargins, out maxLeftOverlapValueMargin, out maxRightOverlapValueMargin);
  1019.                 //        }
  1020.    
  1021.                 //        return currentRange.ToComparableRange();
  1022.                 //    }
  1023.                 //}
  1024.    
  1025.                 return range;
  1026.             }
  1027.         }
  1028.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement