mirror of https://github.com/mhowlett/nplot.git
648 lines
24 KiB
C#
648 lines
24 KiB
C#
/*
|
|
* NPlot - A charting library for .NET
|
|
*
|
|
* DateTimeAxis.cs
|
|
* Copyright (C) 2003-2006 Matt Howlett and others.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Drawing;
|
|
|
|
// TODO: More control over how labels are displayed.
|
|
// TODO: SkipWeekends property.
|
|
// TODO: Make a relative (as opposed to absolute) TimeAxis.
|
|
|
|
namespace NPlot
|
|
{
|
|
/// <summary>
|
|
/// The DateTimeAxis class
|
|
/// </summary>
|
|
public class DateTimeAxis : Axis
|
|
{
|
|
#region Clone implementation
|
|
|
|
/// <summary>
|
|
/// Deep copy of DateTimeAxis.
|
|
/// </summary>
|
|
/// <returns>A copy of the DateTimeAxis Class.</returns>
|
|
public override object Clone()
|
|
{
|
|
DateTimeAxis a = new DateTimeAxis();
|
|
// ensure that this isn't being called on a derived type. If it is, then oh no!
|
|
if (GetType() != a.GetType())
|
|
{
|
|
throw new NPlotException("Clone not defined in derived type. Help!");
|
|
}
|
|
DoClone(this, a);
|
|
return a;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper method for Clone.
|
|
/// </summary>
|
|
/// <param name="a">The original object to clone.</param>
|
|
/// <param name="b">The cloned object.</param>
|
|
protected static void DoClone(DateTimeAxis b, DateTimeAxis a)
|
|
{
|
|
Axis.DoClone(b, a);
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// this gets set after a get LargeTickPositions.
|
|
/// </summary>
|
|
protected LargeTickLabelType LargeTickLabelType_;
|
|
|
|
private TimeSpan largeTickStep_ = TimeSpan.Zero;
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="a">Axis to construct from</param>
|
|
public DateTimeAxis(Axis a)
|
|
: base(a)
|
|
{
|
|
Init();
|
|
NumberFormat = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Default Constructor
|
|
/// </summary>
|
|
public DateTimeAxis()
|
|
{
|
|
Init();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="worldMin">World min of axis</param>
|
|
/// <param name="worldMax">World max of axis</param>
|
|
public DateTimeAxis(double worldMin, double worldMax)
|
|
: base(worldMin, worldMax)
|
|
{
|
|
Init();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="worldMin">World min of axis</param>
|
|
/// <param name="worldMax">World max of axis</param>
|
|
public DateTimeAxis(long worldMin, long worldMax)
|
|
: base(worldMin, worldMax)
|
|
{
|
|
Init();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="worldMin">World min of axis</param>
|
|
/// <param name="worldMax">World max of axis</param>
|
|
public DateTimeAxis(DateTime worldMin, DateTime worldMax)
|
|
: base(worldMin.Ticks, worldMax.Ticks)
|
|
{
|
|
Init();
|
|
}
|
|
|
|
/// <summary>
|
|
/// The distance between large ticks. If this is set to Zero [default],
|
|
/// this distance will be calculated automatically.
|
|
/// </summary>
|
|
public TimeSpan LargeTickStep
|
|
{
|
|
set { largeTickStep_ = value; }
|
|
get { return largeTickStep_; }
|
|
}
|
|
|
|
private void Init()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draw the ticks.
|
|
/// </summary>
|
|
/// <param name="g">The drawing surface on which to draw.</param>
|
|
/// <param name="physicalMin">The minimum physical extent of the axis.</param>
|
|
/// <param name="physicalMax">The maximum physical extent of the axis.</param>
|
|
/// <param name="boundingBox">out: smallest box that completely encompasses all of the ticks and tick labels.</param>
|
|
/// <param name="labelOffset">out: a suitable offset from the axis to draw the axis label.</param>
|
|
protected override void DrawTicks(
|
|
Graphics g,
|
|
Point physicalMin,
|
|
Point physicalMax,
|
|
out object labelOffset,
|
|
out object boundingBox)
|
|
{
|
|
// TODO: Look at offset and bounding box logic again here. why temp and other vars?
|
|
|
|
Point tLabelOffset;
|
|
Rectangle tBoundingBox;
|
|
|
|
labelOffset = getDefaultLabelOffset(physicalMin, physicalMax);
|
|
boundingBox = null;
|
|
|
|
ArrayList largeTicks;
|
|
ArrayList smallTicks;
|
|
WorldTickPositions(physicalMin, physicalMax, out largeTicks, out smallTicks);
|
|
|
|
// draw small ticks.
|
|
for (int i = 0; i < smallTicks.Count; ++i)
|
|
{
|
|
DrawTick(g, (double) smallTicks[i],
|
|
SmallTickSize, "", new Point(0, 0),
|
|
physicalMin, physicalMax,
|
|
out tLabelOffset, out tBoundingBox);
|
|
// assume label offset and bounding box unchanged by small tick bounds.
|
|
}
|
|
|
|
// draw large ticks.
|
|
for (int i = 0; i < largeTicks.Count; ++i)
|
|
{
|
|
DateTime tickDate = new DateTime((long) ((double) largeTicks[i]));
|
|
string label = LargeTickLabel(tickDate);
|
|
|
|
DrawTick(g, (double) largeTicks[i],
|
|
LargeTickSize, label, new Point(0, 0),
|
|
physicalMin, physicalMax, out tLabelOffset, out tBoundingBox);
|
|
|
|
UpdateOffsetAndBounds(ref labelOffset, ref boundingBox, tLabelOffset, tBoundingBox);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the label corresponding to the provided date time
|
|
/// </summary>
|
|
/// <param name="tickDate">the date time to get the label for</param>
|
|
/// <returns>label for the provided DateTime</returns>
|
|
protected virtual string LargeTickLabel(DateTime tickDate)
|
|
{
|
|
string label = "";
|
|
|
|
if (NumberFormat == null || NumberFormat == String.Empty)
|
|
{
|
|
if (LargeTickLabelType_ == LargeTickLabelType.year)
|
|
{
|
|
label = tickDate.Year.ToString();
|
|
}
|
|
|
|
else if (LargeTickLabelType_ == LargeTickLabelType.month)
|
|
{
|
|
label = tickDate.ToString("MMM");
|
|
label += " ";
|
|
label += tickDate.Year.ToString().Substring(2, 2);
|
|
}
|
|
|
|
else if (LargeTickLabelType_ == LargeTickLabelType.day)
|
|
{
|
|
label = (tickDate.Day).ToString();
|
|
label += " ";
|
|
label += tickDate.ToString("MMM");
|
|
}
|
|
|
|
else if (LargeTickLabelType_ == LargeTickLabelType.hourMinute)
|
|
{
|
|
string minutes = tickDate.Minute.ToString();
|
|
if (minutes.Length == 1)
|
|
{
|
|
minutes = "0" + minutes;
|
|
}
|
|
label = tickDate.Hour.ToString() + ":" + minutes;
|
|
}
|
|
else if (LargeTickLabelType_ == LargeTickLabelType.hourMinuteSeconds)
|
|
{
|
|
string minutes = tickDate.Minute.ToString();
|
|
string seconds = tickDate.Second.ToString();
|
|
if (seconds.Length == 1)
|
|
{
|
|
seconds = "0" + seconds;
|
|
}
|
|
|
|
if (minutes.Length == 1)
|
|
{
|
|
minutes = "0" + minutes;
|
|
}
|
|
label = tickDate.Hour.ToString() + ":" + minutes + "." + seconds;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
label = tickDate.ToString(NumberFormat);
|
|
}
|
|
|
|
return label;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the positions, in world coordinates, of the large ticks. No
|
|
/// small tick marks are currently calculated by this method.
|
|
/// </summary>
|
|
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
|
|
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
|
|
/// <param name="largeTickPositions">ArrayList containing the positions of the large ticks.</param>
|
|
/// <param name="smallTickPositions">null</param>
|
|
internal override void WorldTickPositions_FirstPass(
|
|
Point physicalMin,
|
|
Point physicalMax,
|
|
out ArrayList largeTickPositions,
|
|
out ArrayList smallTickPositions
|
|
)
|
|
{
|
|
smallTickPositions = null;
|
|
|
|
largeTickPositions = new ArrayList();
|
|
|
|
const int daysInMonth = 30;
|
|
|
|
TimeSpan timeLength = new TimeSpan((long) (WorldMax - WorldMin));
|
|
DateTime worldMinDate = new DateTime((long) WorldMin);
|
|
DateTime worldMaxDate = new DateTime((long) WorldMax);
|
|
|
|
if (largeTickStep_ == TimeSpan.Zero)
|
|
{
|
|
// if less than 10 minutes, then large ticks on second spacings.
|
|
|
|
if (timeLength < new TimeSpan(0, 0, 2, 0, 0))
|
|
{
|
|
LargeTickLabelType_ = LargeTickLabelType.hourMinuteSeconds;
|
|
|
|
double secondsSkip;
|
|
|
|
if (timeLength < new TimeSpan(0, 0, 0, 10, 0))
|
|
secondsSkip = 1.0;
|
|
else if (timeLength < new TimeSpan(0, 0, 0, 20, 0))
|
|
secondsSkip = 2.0;
|
|
else if (timeLength < new TimeSpan(0, 0, 0, 50, 0))
|
|
secondsSkip = 5.0;
|
|
else if (timeLength < new TimeSpan(0, 0, 2, 30, 0))
|
|
secondsSkip = 15.0;
|
|
else
|
|
secondsSkip = 30.0;
|
|
|
|
int second = worldMinDate.Second;
|
|
second -= second%(int) secondsSkip;
|
|
|
|
DateTime currentTickDate = new DateTime(
|
|
worldMinDate.Year,
|
|
worldMinDate.Month,
|
|
worldMinDate.Day,
|
|
worldMinDate.Hour,
|
|
worldMinDate.Minute,
|
|
second, 0);
|
|
|
|
while (currentTickDate < worldMaxDate)
|
|
{
|
|
double world = currentTickDate.Ticks;
|
|
|
|
if (world >= WorldMin && world <= WorldMax)
|
|
{
|
|
largeTickPositions.Add(world);
|
|
}
|
|
|
|
currentTickDate = currentTickDate.AddSeconds(secondsSkip);
|
|
}
|
|
}
|
|
|
|
// Less than 2 hours, then large ticks on minute spacings.
|
|
|
|
else if (timeLength < new TimeSpan(0, 2, 0, 0, 0))
|
|
{
|
|
LargeTickLabelType_ = LargeTickLabelType.hourMinute;
|
|
|
|
double minuteSkip;
|
|
|
|
if (timeLength < new TimeSpan(0, 0, 10, 0, 0))
|
|
minuteSkip = 1.0;
|
|
else if (timeLength < new TimeSpan(0, 0, 20, 0, 0))
|
|
minuteSkip = 2.0;
|
|
else if (timeLength < new TimeSpan(0, 0, 50, 0, 0))
|
|
minuteSkip = 5.0;
|
|
else if (timeLength < new TimeSpan(0, 2, 30, 0, 0))
|
|
minuteSkip = 15.0;
|
|
else //( timeLength < new TimeSpan( 0,5,0,0,0) )
|
|
minuteSkip = 30.0;
|
|
|
|
int minute = worldMinDate.Minute;
|
|
minute -= minute%(int) minuteSkip;
|
|
|
|
DateTime currentTickDate = new DateTime(
|
|
worldMinDate.Year,
|
|
worldMinDate.Month,
|
|
worldMinDate.Day,
|
|
worldMinDate.Hour,
|
|
minute, 0, 0);
|
|
|
|
while (currentTickDate < worldMaxDate)
|
|
{
|
|
double world = currentTickDate.Ticks;
|
|
|
|
if (world >= WorldMin && world <= WorldMax)
|
|
{
|
|
largeTickPositions.Add(world);
|
|
}
|
|
|
|
currentTickDate = currentTickDate.AddMinutes(minuteSkip);
|
|
}
|
|
}
|
|
|
|
// Less than 2 days, then large ticks on hour spacings.
|
|
|
|
else if (timeLength < new TimeSpan(2, 0, 0, 0, 0))
|
|
{
|
|
LargeTickLabelType_ = LargeTickLabelType.hourMinute;
|
|
|
|
double hourSkip;
|
|
if (timeLength < new TimeSpan(0, 10, 0, 0, 0))
|
|
hourSkip = 1.0;
|
|
else if (timeLength < new TimeSpan(0, 20, 0, 0, 0))
|
|
hourSkip = 2.0;
|
|
else
|
|
hourSkip = 6.0;
|
|
|
|
int hour = worldMinDate.Hour;
|
|
hour -= hour%(int) hourSkip;
|
|
|
|
DateTime currentTickDate = new DateTime(
|
|
worldMinDate.Year,
|
|
worldMinDate.Month,
|
|
worldMinDate.Day,
|
|
hour, 0, 0, 0);
|
|
|
|
while (currentTickDate < worldMaxDate)
|
|
{
|
|
double world = currentTickDate.Ticks;
|
|
|
|
if (world >= WorldMin && world <= WorldMax)
|
|
{
|
|
largeTickPositions.Add(world);
|
|
}
|
|
|
|
currentTickDate = currentTickDate.AddHours(hourSkip);
|
|
}
|
|
}
|
|
|
|
|
|
// less than 5 months, then large ticks on day spacings.
|
|
|
|
else if (timeLength < new TimeSpan(daysInMonth*4, 0, 0, 0, 0))
|
|
{
|
|
LargeTickLabelType_ = LargeTickLabelType.day;
|
|
|
|
double daySkip;
|
|
if (timeLength < new TimeSpan(10, 0, 0, 0, 0))
|
|
daySkip = 1.0;
|
|
else if (timeLength < new TimeSpan(20, 0, 0, 0, 0))
|
|
daySkip = 2.0;
|
|
else if (timeLength < new TimeSpan(7*10, 0, 0, 0, 0))
|
|
daySkip = 7.0;
|
|
else
|
|
daySkip = 14.0;
|
|
|
|
DateTime currentTickDate = new DateTime(
|
|
worldMinDate.Year,
|
|
worldMinDate.Month,
|
|
worldMinDate.Day);
|
|
|
|
if (daySkip == 2.0)
|
|
{
|
|
TimeSpan timeSinceBeginning = currentTickDate - DateTime.MinValue;
|
|
|
|
if (timeSinceBeginning.Days%2 == 1)
|
|
currentTickDate = currentTickDate.AddDays(-1.0);
|
|
}
|
|
|
|
if (daySkip == 7 || daySkip == 14.0)
|
|
{
|
|
DayOfWeek dow = currentTickDate.DayOfWeek;
|
|
switch (dow)
|
|
{
|
|
case DayOfWeek.Monday:
|
|
break;
|
|
case DayOfWeek.Tuesday:
|
|
currentTickDate = currentTickDate.AddDays(-1.0);
|
|
break;
|
|
case DayOfWeek.Wednesday:
|
|
currentTickDate = currentTickDate.AddDays(-2.0);
|
|
break;
|
|
case DayOfWeek.Thursday:
|
|
currentTickDate = currentTickDate.AddDays(-3.0);
|
|
break;
|
|
case DayOfWeek.Friday:
|
|
currentTickDate = currentTickDate.AddDays(-4.0);
|
|
break;
|
|
case DayOfWeek.Saturday:
|
|
currentTickDate = currentTickDate.AddDays(-5.0);
|
|
break;
|
|
case DayOfWeek.Sunday:
|
|
currentTickDate = currentTickDate.AddDays(-6.0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (daySkip == 14.0f)
|
|
{
|
|
TimeSpan timeSinceBeginning = currentTickDate - DateTime.MinValue;
|
|
|
|
if ((timeSinceBeginning.Days/7)%2 == 1)
|
|
{
|
|
currentTickDate = currentTickDate.AddDays(-7.0);
|
|
}
|
|
}
|
|
|
|
while (currentTickDate < worldMaxDate)
|
|
{
|
|
double world = currentTickDate.Ticks;
|
|
|
|
if (world >= WorldMin && world <= WorldMax)
|
|
{
|
|
largeTickPositions.Add(world);
|
|
}
|
|
|
|
currentTickDate = currentTickDate.AddDays(daySkip);
|
|
}
|
|
}
|
|
|
|
|
|
// else ticks on month or year spacings.
|
|
|
|
else if (timeLength >= new TimeSpan(daysInMonth*4, 0, 0, 0, 0))
|
|
{
|
|
int monthSpacing = 0;
|
|
|
|
if (timeLength.Days < daysInMonth*(12*3 + 6))
|
|
{
|
|
LargeTickLabelType_ = LargeTickLabelType.month;
|
|
|
|
if (timeLength.Days < daysInMonth*10)
|
|
monthSpacing = 1;
|
|
else if (timeLength.Days < daysInMonth*(12*2))
|
|
monthSpacing = 3;
|
|
else // if ( timeLength.Days < daysInMonth*(12*3+6) )
|
|
monthSpacing = 6;
|
|
}
|
|
else
|
|
{
|
|
LargeTickLabelType_ = LargeTickLabelType.year;
|
|
|
|
if (timeLength.Days < daysInMonth*(12*6))
|
|
monthSpacing = 12;
|
|
else if (timeLength.Days < daysInMonth*(12*12))
|
|
monthSpacing = 24;
|
|
else if (timeLength.Days < daysInMonth*(12*30))
|
|
monthSpacing = 60;
|
|
else
|
|
monthSpacing = 120;
|
|
//LargeTickLabelType_ = LargeTickLabelType.none;
|
|
}
|
|
|
|
// truncate start
|
|
DateTime currentTickDate = new DateTime(
|
|
worldMinDate.Year,
|
|
worldMinDate.Month,
|
|
1);
|
|
|
|
if (monthSpacing > 1)
|
|
{
|
|
currentTickDate = currentTickDate.AddMonths(
|
|
-(currentTickDate.Month - 1)%monthSpacing);
|
|
}
|
|
|
|
// Align on 2 or 5 year boundaries if necessary.
|
|
if (monthSpacing >= 24)
|
|
{
|
|
currentTickDate = currentTickDate.AddYears(
|
|
-(currentTickDate.Year)%(monthSpacing/12));
|
|
}
|
|
|
|
//this.firstLargeTick_ = (double)currentTickDate.Ticks;
|
|
|
|
if (LargeTickLabelType_ != LargeTickLabelType.none)
|
|
{
|
|
while (currentTickDate < worldMaxDate)
|
|
{
|
|
double world = currentTickDate.Ticks;
|
|
|
|
if (world >= WorldMin && world <= WorldMax)
|
|
{
|
|
largeTickPositions.Add(world);
|
|
}
|
|
|
|
currentTickDate = currentTickDate.AddMonths(monthSpacing);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (DateTime date = worldMinDate; date < worldMaxDate; date += largeTickStep_)
|
|
{
|
|
largeTickPositions.Add((double) date.Ticks);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compute the small tick positions for largetick size of one or more years.
|
|
/// - inside the domain or the large tick positons, is take the mid-point of pairs of large ticks
|
|
/// - outside the large tick range, check if a half tick is inside the world min/max
|
|
/// This method works only if there are atleast 2 large ticks,
|
|
/// since we don't know if its minutes, hours, month, or yearly divisor.
|
|
/// </summary>
|
|
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
|
|
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
|
|
/// <param name="largeTickPositions">Read in the large tick positions</param>
|
|
/// <param name="smallTickPositions">Fill in the corresponding small tick positions</param>
|
|
/// <remarks>Added by Rosco Hill</remarks>
|
|
internal override void WorldTickPositions_SecondPass(
|
|
Point physicalMin,
|
|
Point physicalMax,
|
|
ArrayList largeTickPositions,
|
|
ref ArrayList smallTickPositions
|
|
)
|
|
{
|
|
if (largeTickPositions.Count < 2 || !(LargeTickLabelType_.Equals(LargeTickLabelType.year)))
|
|
{
|
|
smallTickPositions = new ArrayList();
|
|
;
|
|
}
|
|
else
|
|
{
|
|
smallTickPositions = new ArrayList();
|
|
double diff = 0.5*(((double) largeTickPositions[1]) - ((double) largeTickPositions[0]));
|
|
if (((double) largeTickPositions[0] - diff) > WorldMin)
|
|
{
|
|
smallTickPositions.Add((double) largeTickPositions[0] - diff);
|
|
}
|
|
for (int i = 0; i < largeTickPositions.Count - 1; i++)
|
|
{
|
|
smallTickPositions.Add(((double) largeTickPositions[i]) + diff);
|
|
}
|
|
if (((double) largeTickPositions[largeTickPositions.Count - 1] + diff) < WorldMax)
|
|
{
|
|
smallTickPositions.Add((double) largeTickPositions[largeTickPositions.Count - 1] + diff);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enumerates the different types of tick label possible.
|
|
/// </summary>
|
|
protected enum LargeTickLabelType
|
|
{
|
|
/// <summary>
|
|
/// default - no tick labels.
|
|
/// </summary>
|
|
none = 0,
|
|
|
|
/// <summary>
|
|
/// tick labels should be years
|
|
/// </summary>
|
|
year = 1,
|
|
|
|
/// <summary>
|
|
/// Tick labels should be month names
|
|
/// </summary>
|
|
month = 2,
|
|
|
|
/// <summary>
|
|
/// Tick labels should be day names
|
|
/// </summary>
|
|
day = 3,
|
|
|
|
/// <summary>
|
|
/// Tick labels should be hour / minutes.
|
|
/// </summary>
|
|
hourMinute = 4,
|
|
|
|
/// <summary>
|
|
/// tick labels should be hour / minute / second.
|
|
/// </summary>
|
|
hourMinuteSeconds = 5
|
|
}
|
|
}
|
|
} |