Initial Commit

This commit is contained in:
2024-02-23 00:46:06 -05:00
commit 2bbedc0178
470 changed files with 46035 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Research.DynamicDataDisplay.ViewportRestrictions;
using System.Windows.Media;
using System.Windows;
using System.Windows.Data;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
/// <summary>
/// Represents an axis with ticks of <see cref="System.DateTime"/> type.
/// </summary>
public class DateTimeAxis : AxisBase<DateTime>
{
/// <summary>
/// Initializes a new instance of the <see cref="DateTimeAxis"/> class.
/// </summary>
public DateTimeAxis()
: base(new DateTimeAxisControl(), DoubleToDate,
dt => dt.Ticks / 10000000000.0)
{
AxisControl.SetBinding(MajorLabelBackgroundBrushProperty, new Binding("MajorLabelBackgroundBrush") { Source = this });
AxisControl.SetBinding(MajorLabelRectangleBorderPropertyProperty, new Binding("MajorLabelRectangleBorderProperty") { Source = this });
}
#region VisualProperties
/// <summary>
/// Gets or sets the major tick labels' background brush. This is a DependencyProperty.
/// </summary>
/// <value>The major label background brush.</value>
public Brush MajorLabelBackgroundBrush
{
get { return (Brush)GetValue(MajorLabelBackgroundBrushProperty); }
set { SetValue(MajorLabelBackgroundBrushProperty, value); }
}
public static readonly DependencyProperty MajorLabelBackgroundBrushProperty = DependencyProperty.Register(
"MajorLabelBackgroundBrush",
typeof(Brush),
typeof(DateTimeAxis),
new FrameworkPropertyMetadata(Brushes.Beige));
public Brush MajorLabelRectangleBorderProperty
{
get { return (Brush)GetValue(MajorLabelRectangleBorderPropertyProperty); }
set { SetValue(MajorLabelRectangleBorderPropertyProperty, value); }
}
public static readonly DependencyProperty MajorLabelRectangleBorderPropertyProperty = DependencyProperty.Register(
"MajorLabelRectangleBorderProperty",
typeof(Brush),
typeof(DateTimeAxis),
new FrameworkPropertyMetadata(Brushes.Peru));
#endregion // end of VisualProperties
private ViewportRestriction restriction = new DateTimeHorizontalAxisRestriction();
protected ViewportRestriction Restriction
{
get { return restriction; }
set { restriction = value; }
}
protected override void OnPlotterAttached(Plotter2D plotter)
{
base.OnPlotterAttached(plotter);
plotter.Viewport.Restrictions.Add(restriction);
}
protected override void OnPlotterDetaching(Plotter2D plotter)
{
plotter.Viewport.Restrictions.Remove(restriction);
base.OnPlotterDetaching(plotter);
}
private static readonly long minTicks = DateTime.MinValue.Ticks;
private static readonly long maxTicks = DateTime.MaxValue.Ticks;
private static DateTime DoubleToDate(double d)
{
long ticks = (long)(d * 10000000000L);
// todo should we throw an exception if number of ticks is too big or small?
if (ticks < minTicks)
ticks = minTicks;
else if (ticks > maxTicks)
ticks = maxTicks;
return new DateTime(ticks);
}
/// <summary>
/// Sets conversions of axis - functions used to convert values of axis type to and from double values of viewport.
/// Sets both ConvertToDouble and ConvertFromDouble properties.
/// </summary>
/// <param name="min">The minimal viewport value.</param>
/// <param name="minValue">The value of axis type, corresponding to minimal viewport value.</param>
/// <param name="max">The maximal viewport value.</param>
/// <param name="maxValue">The value of axis type, corresponding to maximal viewport value.</param>
public override void SetConversion(double min, DateTime minValue, double max, DateTime maxValue)
{
var conversion = new DateTimeToDoubleConversion(min, minValue, max, maxValue);
ConvertToDouble = conversion.ToDouble;
ConvertFromDouble = conversion.FromDouble;
}
}
}

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
/// <summary>
/// AxisControl for DateTime axes.
/// </summary>
public class DateTimeAxisControl : AxisControl<DateTime>
{
/// <summary>
/// Initializes a new instance of the <see cref="DateTimeAxisControl"/> class.
/// </summary>
public DateTimeAxisControl()
{
LabelProvider = new DateTimeLabelProvider();
TicksProvider = new DateTimeTicksProvider();
MajorLabelProvider = new MajorDateTimeLabelProvider();
ConvertToDouble = dt => dt.Ticks;
Range = new Range<DateTime>(DateTime.Now, DateTime.Now.AddYears(1));
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Research.DynamicDataDisplay.Charts.Axes;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
/// <summary>
/// Represents a label provider for <see cref="System.DateTime"/> ticks.
/// </summary>
public class DateTimeLabelProvider : DateTimeLabelProviderBase
{
/// <summary>
/// Initializes a new instance of the <see cref="DateTimeLabelProvider"/> class.
/// </summary>
public DateTimeLabelProvider() { }
public override UIElement[] CreateLabels(ITicksInfo<DateTime> ticksInfo)
{
object info = ticksInfo.Info;
var ticks = ticksInfo.Ticks;
if (info is DifferenceIn)
{
DifferenceIn diff = (DifferenceIn)info;
DateFormat = GetDateFormat(diff);
}
LabelTickInfo<DateTime> tickInfo = new LabelTickInfo<DateTime> { Info = info };
UIElement[] res = new UIElement[ticks.Length];
for (int i = 0; i < ticks.Length; i++)
{
tickInfo.Tick = ticks[i];
string tickText = GetString(tickInfo);
UIElement label = new TextBlock { Text = tickText, ToolTip = ticks[i] };
ApplyCustomView(tickInfo, label);
res[i] = label;
}
return res;
}
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Microsoft.Research.DynamicDataDisplay.Charts.Axes;
using System.Globalization;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
public abstract class DateTimeLabelProviderBase : LabelProviderBase<DateTime>
{
private string dateFormat;
protected string DateFormat
{
get { return dateFormat; }
set { dateFormat = value; }
}
protected override string GetStringCore(LabelTickInfo<DateTime> tickInfo)
{
return tickInfo.Tick.ToString(dateFormat);
}
protected virtual string GetDateFormat(DifferenceIn diff)
{
string format = null;
switch (diff)
{
case DifferenceIn.Year:
format = "yyyy";
break;
case DifferenceIn.Month:
format = "MMM";
break;
case DifferenceIn.Day:
format = "%d";
break;
case DifferenceIn.Hour:
format = "HH:mm";
break;
case DifferenceIn.Minute:
format = "%m";
break;
case DifferenceIn.Second:
format = "ss";
break;
case DifferenceIn.Millisecond:
format = "fff";
break;
default:
break;
}
return format;
}
}
}

View File

@@ -0,0 +1,307 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Globalization;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
/// <summary>
/// Represents a ticks provider for ticks of <see cref="T:System.DateTime"/> type.
/// </summary>
public class DateTimeTicksProvider : TimeTicksProviderBase<DateTime>
{
/// <summary>
/// Initializes a new instance of the <see cref="DateTimeTicksProvider"/> class.
/// </summary>
public DateTimeTicksProvider() { }
static DateTimeTicksProvider()
{
Providers.Add(DifferenceIn.Year, new YearDateTimeProvider());
Providers.Add(DifferenceIn.Month, new MonthDateTimeProvider());
Providers.Add(DifferenceIn.Day, new DayDateTimeProvider());
Providers.Add(DifferenceIn.Hour, new HourDateTimeProvider());
Providers.Add(DifferenceIn.Minute, new MinuteDateTimeProvider());
Providers.Add(DifferenceIn.Second, new SecondDateTimeProvider());
Providers.Add(DifferenceIn.Millisecond, new MillisecondDateTimeProvider());
MinorProviders.Add(DifferenceIn.Year, new MinorDateTimeProvider(new YearDateTimeProvider()));
MinorProviders.Add(DifferenceIn.Month, new MinorDateTimeProvider(new MonthDateTimeProvider()));
MinorProviders.Add(DifferenceIn.Day, new MinorDateTimeProvider(new DayDateTimeProvider()));
MinorProviders.Add(DifferenceIn.Hour, new MinorDateTimeProvider(new HourDateTimeProvider()));
MinorProviders.Add(DifferenceIn.Minute, new MinorDateTimeProvider(new MinuteDateTimeProvider()));
MinorProviders.Add(DifferenceIn.Second, new MinorDateTimeProvider(new SecondDateTimeProvider()));
MinorProviders.Add(DifferenceIn.Millisecond, new MinorDateTimeProvider(new MillisecondDateTimeProvider()));
}
protected sealed override TimeSpan GetDifference(DateTime start, DateTime end)
{
return end - start;
}
}
internal static class DateTimeArrayExtensions
{
internal static int GetIndex(this DateTime[] array, DateTime value)
{
for (int i = 0; i < array.Length - 1; i++)
{
if (array[i] <= value && value < array[i + 1])
return i;
}
return array.Length - 1;
}
}
internal sealed class MinorDateTimeProvider : MinorTimeProviderBase<DateTime>
{
public MinorDateTimeProvider(ITicksProvider<DateTime> owner) : base(owner) { }
protected override bool IsInside(DateTime value, Range<DateTime> range)
{
return range.Min < value && value < range.Max;
}
}
internal sealed class YearDateTimeProvider : DatePeriodTicksProvider
{
protected override DifferenceIn GetDifferenceCore()
{
return DifferenceIn.Year;
}
protected override int[] GetTickCountsCore()
{
return new int[] { 20, 10, 5, 4, 2, 1 };
}
protected override int GetSpecificValue(DateTime start, DateTime dt)
{
return dt.Year;
}
protected override DateTime GetStart(DateTime start, int value, int step)
{
int year = start.Year;
int newYear = (year / step) * step;
if (newYear == 0) newYear = 1;
return new DateTime(newYear, 1, 1);
}
protected override bool IsMinDate(DateTime dt)
{
return dt.Year == DateTime.MinValue.Year;
}
protected override DateTime AddStep(DateTime dt, int step)
{
if (dt.Year + step > DateTime.MaxValue.Year)
return DateTime.MaxValue;
return dt.AddYears(step);
}
}
internal sealed class MonthDateTimeProvider : DatePeriodTicksProvider
{
protected override DifferenceIn GetDifferenceCore()
{
return DifferenceIn.Month;
}
protected override int[] GetTickCountsCore()
{
return new int[] { 12, 6, 4, 3, 2, 1 };
}
protected override int GetSpecificValue(DateTime start, DateTime dt)
{
return dt.Month + (dt.Year - start.Year) * 12;
}
protected override DateTime GetStart(DateTime start, int value, int step)
{
return new DateTime(start.Year, 1, 1);
}
protected override bool IsMinDate(DateTime dt)
{
return dt.Month == DateTime.MinValue.Month;
}
protected override DateTime AddStep(DateTime dt, int step)
{
return dt.AddMonths(step);
}
}
internal sealed class DayDateTimeProvider : DatePeriodTicksProvider
{
protected override DifferenceIn GetDifferenceCore()
{
return DifferenceIn.Day;
}
protected override int[] GetTickCountsCore()
{
return new int[] { 30, 15, 10, 5, 2, 1 };
}
protected override int GetSpecificValue(DateTime start, DateTime dt)
{
return (dt - start).Days;
}
protected override DateTime GetStart(DateTime start, int value, int step)
{
return start.Date;
}
protected override bool IsMinDate(DateTime dt)
{
return dt.Day == 1;
}
protected override DateTime AddStep(DateTime dt, int step)
{
return dt.AddDays(step);
}
}
internal sealed class HourDateTimeProvider : DatePeriodTicksProvider
{
protected override DifferenceIn GetDifferenceCore()
{
return DifferenceIn.Hour;
}
protected override int[] GetTickCountsCore()
{
return new int[] { 24, 12, 6, 4, 3, 2, 1 };
}
protected override int GetSpecificValue(DateTime start, DateTime dt)
{
return (int)(dt - start).TotalHours;
}
protected override DateTime GetStart(DateTime start, int value, int step)
{
return start.Date;
}
protected override bool IsMinDate(DateTime dt)
{
return false;
}
protected override DateTime AddStep(DateTime dt, int step)
{
return dt.AddHours(step);
}
}
internal sealed class MinuteDateTimeProvider : DatePeriodTicksProvider
{
protected override DifferenceIn GetDifferenceCore()
{
return DifferenceIn.Minute;
}
protected override int[] GetTickCountsCore()
{
return new int[] { 60, 30, 20, 15, 10, 5, 4, 3, 2 };
}
protected override int GetSpecificValue(DateTime start, DateTime dt)
{
return (int)(dt - start).TotalMinutes;
}
protected override DateTime GetStart(DateTime start, int value, int step)
{
return start.Date.AddHours(start.Hour);
}
protected override bool IsMinDate(DateTime dt)
{
return false;
}
protected override DateTime AddStep(DateTime dt, int step)
{
return dt.AddMinutes(step);
}
}
internal sealed class SecondDateTimeProvider : DatePeriodTicksProvider
{
protected override DifferenceIn GetDifferenceCore()
{
return DifferenceIn.Second;
}
protected override int[] GetTickCountsCore()
{
return new int[] { 60, 30, 20, 15, 10, 5, 4, 3, 2 };
}
protected override int GetSpecificValue(DateTime start, DateTime dt)
{
return (int)(dt - start).TotalSeconds;
}
protected override DateTime GetStart(DateTime start, int value, int step)
{
return start.Date.AddHours(start.Hour).AddMinutes(start.Minute);
}
protected override bool IsMinDate(DateTime dt)
{
return false;
}
protected override DateTime AddStep(DateTime dt, int step)
{
return dt.AddSeconds(step);
}
}
internal sealed class MillisecondDateTimeProvider : DatePeriodTicksProvider
{
protected override DifferenceIn GetDifferenceCore()
{
return DifferenceIn.Millisecond;
}
protected override int[] GetTickCountsCore()
{
return new int[] { 100, 50, 40, 25, 20, 10, 5, 4, 2 };
}
protected override int GetSpecificValue(DateTime start, DateTime dt)
{
return (int)(dt - start).TotalMilliseconds;
}
protected override DateTime GetStart(DateTime start, int value, int step)
{
return start.Date.AddHours(start.Hour).AddMinutes(start.Minute).AddSeconds(start.Second);
}
protected override bool IsMinDate(DateTime dt)
{
return false;
}
protected override DateTime AddStep(DateTime dt, int step)
{
return dt.AddMilliseconds(step);
}
}
}

View File

@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
public abstract class DateTimeTicksProviderBase : ITicksProvider<DateTime>
{
public event EventHandler Changed;
protected void RaiseChanged()
{
if (Changed != null)
{
Changed(this, EventArgs.Empty);
}
}
protected static DateTime Shift(DateTime dateTime, DifferenceIn diff)
{
DateTime res = dateTime;
switch (diff)
{
case DifferenceIn.Year:
res = res.AddYears(1);
break;
case DifferenceIn.Month:
res = res.AddMonths(1);
break;
case DifferenceIn.Day:
res = res.AddDays(1);
break;
case DifferenceIn.Hour:
res = res.AddHours(1);
break;
case DifferenceIn.Minute:
res = res.AddMinutes(1);
break;
case DifferenceIn.Second:
res = res.AddSeconds(1);
break;
case DifferenceIn.Millisecond:
res = res.AddMilliseconds(1);
break;
default:
break;
}
return res;
}
protected static DateTime RoundDown(DateTime dateTime, DifferenceIn diff)
{
DateTime res = dateTime;
switch (diff)
{
case DifferenceIn.Year:
res = new DateTime(dateTime.Year, 1, 1);
break;
case DifferenceIn.Month:
res = new DateTime(dateTime.Year, dateTime.Month, 1);
break;
case DifferenceIn.Day:
res = dateTime.Date;
break;
case DifferenceIn.Hour:
res = dateTime.Date.AddHours(dateTime.Hour);
break;
case DifferenceIn.Minute:
res = dateTime.Date.AddHours(dateTime.Hour).AddMinutes(dateTime.Minute);
break;
case DifferenceIn.Second:
res = dateTime.Date.AddHours(dateTime.Hour).AddMinutes(dateTime.Minute).AddSeconds(dateTime.Second);
break;
case DifferenceIn.Millisecond:
res = dateTime.Date.AddHours(dateTime.Hour).AddMinutes(dateTime.Minute).AddSeconds(dateTime.Second).AddMilliseconds(dateTime.Millisecond);
break;
default:
break;
}
DebugVerify.Is(res <= dateTime);
return res;
}
protected static DateTime RoundUp(DateTime dateTime, DifferenceIn diff)
{
DateTime res = RoundDown(dateTime, diff);
switch (diff)
{
case DifferenceIn.Year:
res = res.AddYears(1);
break;
case DifferenceIn.Month:
res = res.AddMonths(1);
break;
case DifferenceIn.Day:
res = res.AddDays(1);
break;
case DifferenceIn.Hour:
res = res.AddHours(1);
break;
case DifferenceIn.Minute:
res = res.AddMinutes(1);
break;
case DifferenceIn.Second:
res = res.AddSeconds(1);
break;
case DifferenceIn.Millisecond:
res = res.AddMilliseconds(1);
break;
default:
break;
}
return res;
}
#region ITicksProvider<DateTime> Members
public abstract ITicksInfo<DateTime> GetTicks(Range<DateTime> range, int ticksCount);
public abstract int DecreaseTickCount(int ticksCount);
public abstract int IncreaseTickCount(int ticksCount);
public abstract ITicksProvider<DateTime> MinorProvider { get; }
public abstract ITicksProvider<DateTime> MajorProvider { get; }
#endregion
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
internal sealed class DateTimeToDoubleConversion
{
public DateTimeToDoubleConversion(double min, DateTime minDate, double max, DateTime maxDate)
{
this.min = min;
this.length = max - min;
this.ticksMin = minDate.Ticks;
this.ticksLength = maxDate.Ticks - ticksMin;
}
private double min;
private double length;
private long ticksMin;
private long ticksLength;
internal DateTime FromDouble(double d)
{
double ratio = (d - min) / length;
long tick = (long)(ticksMin + ticksLength * ratio);
tick = MathHelper.Clamp(tick, DateTime.MinValue.Ticks, DateTime.MaxValue.Ticks);
return new DateTime(tick);
}
internal double ToDouble(DateTime dt)
{
double ratio = (dt.Ticks - ticksMin) / (double)ticksLength;
return min + ratio * length;
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
public enum DifferenceIn
{
Biggest = Year,
Year = 6,
Month = 5,
Day = 4,
Hour = 3,
Minute = 2,
Second = 1,
Millisecond = 0,
Smallest = Millisecond
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
/// <summary>
/// Represents an axis with ticks of <see cref="System.DateTime"/> type, which can be placed only from bottom or top of <see cref="Plotter"/>.
/// By default is placed from bottom.
/// </summary>
public class HorizontalDateTimeAxis : DateTimeAxis
{
/// <summary>
/// Initializes a new instance of the <see cref="HorizontalDateTimeAxis"/> class.
/// </summary>
public HorizontalDateTimeAxis()
{
Placement = AxisPlacement.Bottom;
}
protected override void ValidatePlacement(AxisPlacement newPlacement)
{
if (newPlacement == AxisPlacement.Left || newPlacement == AxisPlacement.Right)
throw new ArgumentException(Strings.Exceptions.HorizontalAxisCannotBeVertical);
}
}
}

View File

@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Diagnostics;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
using Microsoft.Research.DynamicDataDisplay.Charts.Axes;
using System.Windows.Data;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
/// <summary>
/// Represents a label provider for major ticks of <see cref="System.DateTime"/> type.
/// </summary>
public class MajorDateTimeLabelProvider : DateTimeLabelProviderBase
{
/// <summary>
/// Initializes a new instance of the <see cref="MajorDateTimeLabelProvider"/> class.
/// </summary>
public MajorDateTimeLabelProvider() { }
public override UIElement[] CreateLabels(ITicksInfo<DateTime> ticksInfo)
{
object info = ticksInfo.Info;
var ticks = ticksInfo.Ticks;
UIElement[] res = new UIElement[ticks.Length - 1];
int labelsNum = 3;
if (info is DifferenceIn)
{
DifferenceIn diff = (DifferenceIn)info;
DateFormat = GetDateFormat(diff);
}
else if (info is MajorLabelsInfo)
{
MajorLabelsInfo mInfo = (MajorLabelsInfo)info;
DifferenceIn diff = (DifferenceIn)mInfo.Info;
DateFormat = GetDateFormat(diff);
labelsNum = mInfo.MajorLabelsCount + 1;
//DebugVerify.Is(labelsNum < 100);
}
DebugVerify.Is(ticks.Length < 10);
LabelTickInfo<DateTime> tickInfo = new LabelTickInfo<DateTime>();
for (int i = 0; i < ticks.Length - 1; i++)
{
tickInfo.Info = info;
tickInfo.Tick = ticks[i];
string tickText = GetString(tickInfo);
Grid grid = new Grid { };
// doing binding as described at http://sdolha.spaces.live.com/blog/cns!4121802308C5AB4E!3724.entry?wa=wsignin1.0&sa=835372863
grid.SetBinding(Grid.BackgroundProperty, new Binding { Path = new PropertyPath("(0)", DateTimeAxis.MajorLabelBackgroundBrushProperty), RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor) { AncestorType = typeof(AxisControlBase) } });
Rectangle rect = new Rectangle
{
StrokeThickness = 2
};
rect.SetBinding(Rectangle.StrokeProperty, new Binding { Path = new PropertyPath("(0)", DateTimeAxis.MajorLabelRectangleBorderPropertyProperty), RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor) { AncestorType = typeof(AxisControlBase) } });
Grid.SetColumn(rect, 0);
Grid.SetColumnSpan(rect, labelsNum);
for (int j = 0; j < labelsNum; j++)
{
grid.ColumnDefinitions.Add(new ColumnDefinition());
}
grid.Children.Add(rect);
for (int j = 0; j < labelsNum; j++)
{
var tb = new TextBlock
{
Text = tickText,
HorizontalAlignment = HorizontalAlignment.Center,
Margin = new Thickness(0, 3, 0, 3)
};
Grid.SetColumn(tb, j);
grid.Children.Add(tb);
}
ApplyCustomView(tickInfo, grid);
res[i] = grid;
}
return res;
}
protected override string GetDateFormat(DifferenceIn diff)
{
string format = null;
switch (diff)
{
case DifferenceIn.Year:
format = "yyyy";
break;
case DifferenceIn.Month:
format = "MMMM yyyy";
break;
case DifferenceIn.Day:
format = "%d MMMM yyyy";
break;
case DifferenceIn.Hour:
format = "HH:mm %d MMMM yyyy";
break;
case DifferenceIn.Minute:
format = "HH:mm %d MMMM yyyy";
break;
case DifferenceIn.Second:
format = "HH:mm:ss %d MMMM yyyy";
break;
case DifferenceIn.Millisecond:
format = "fff";
break;
default:
break;
}
return format;
}
}
}

View File

@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
internal abstract class MinorTimeProviderBase<T> : ITicksProvider<T>
{
public event EventHandler Changed;
protected void RaiseChanged()
{
if (Changed != null)
{
Changed(this, EventArgs.Empty);
}
}
private readonly ITicksProvider<T> provider;
public MinorTimeProviderBase(ITicksProvider<T> provider)
{
this.provider = provider;
}
private T[] majorTicks = new T[] { };
internal void SetTicks(T[] ticks)
{
this.majorTicks = ticks;
}
private double ticksSize = 0.5;
public ITicksInfo<T> GetTicks(Range<T> range, int ticksCount)
{
if (majorTicks.Length == 0)
return new TicksInfo<T>();
ticksCount /= majorTicks.Length;
if (ticksCount == 0)
ticksCount = 2;
var ticks = majorTicks.GetPairs().Select(r => Clip(provider.GetTicks(r, ticksCount), r)).
SelectMany(t => t.Ticks).ToArray();
var res = new TicksInfo<T>
{
Ticks = ticks,
TickSizes = ArrayExtensions.CreateArray(ticks.Length, ticksSize)
};
return res;
}
private ITicksInfo<T> Clip(ITicksInfo<T> ticks, Range<T> range)
{
var newTicks = new List<T>(ticks.Ticks.Length);
var newSizes = new List<double>(ticks.TickSizes.Length);
for (int i = 0; i < ticks.Ticks.Length; i++)
{
T tick = ticks.Ticks[i];
if (IsInside(tick, range))
{
newTicks.Add(tick);
newSizes.Add(ticks.TickSizes[i]);
}
}
return new TicksInfo<T>
{
Ticks = newTicks.ToArray(),
TickSizes = newSizes.ToArray(),
Info = ticks.Info
};
}
protected abstract bool IsInside(T value, Range<T> range);
public int DecreaseTickCount(int ticksCount)
{
if (majorTicks.Length > 0)
ticksCount /= majorTicks.Length;
int minorTicksCount = provider.DecreaseTickCount(ticksCount);
if (majorTicks.Length > 0)
minorTicksCount *= majorTicks.Length;
return minorTicksCount;
}
public int IncreaseTickCount(int ticksCount)
{
if (majorTicks.Length > 0)
ticksCount /= majorTicks.Length;
int minorTicksCount = provider.IncreaseTickCount(ticksCount);
if (majorTicks.Length > 0)
minorTicksCount *= majorTicks.Length;
return minorTicksCount;
}
public ITicksProvider<T> MinorProvider
{
get { return null; }
}
public ITicksProvider<T> MajorProvider
{
get { return null; }
}
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
public class DefaultDateTimeTicksStrategy : IDateTimeTicksStrategy
{
public virtual DifferenceIn GetDifference(TimeSpan span)
{
span = span.Duration();
DifferenceIn diff;
if (span.Days > 365)
diff = DifferenceIn.Year;
else if (span.Days > 30)
diff = DifferenceIn.Month;
else if (span.Days > 0)
diff = DifferenceIn.Day;
else if (span.Hours > 0)
diff = DifferenceIn.Hour;
else if (span.Minutes > 0)
diff = DifferenceIn.Minute;
else if (span.Seconds > 0)
diff = DifferenceIn.Second;
else
diff = DifferenceIn.Millisecond;
return diff;
}
public virtual bool TryGetLowerDiff(DifferenceIn diff, out DifferenceIn lowerDiff)
{
lowerDiff = diff;
int code = (int)diff;
bool res = code > (int)DifferenceIn.Smallest;
if (res)
{
lowerDiff = (DifferenceIn)(code - 1);
}
return res;
}
public virtual bool TryGetBiggerDiff(DifferenceIn diff, out DifferenceIn biggerDiff)
{
biggerDiff = diff;
int code = (int)diff;
bool res = code < (int)DifferenceIn.Biggest;
if (res)
{
biggerDiff = (DifferenceIn)(code + 1);
}
return res;
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts.Axes.DateTime.Strategies
{
public class DelegateDateTimeStrategy : DefaultDateTimeTicksStrategy
{
private readonly Func<TimeSpan, DifferenceIn?> function;
public DelegateDateTimeStrategy(Func<TimeSpan, DifferenceIn?> function)
{
if (function == null)
throw new ArgumentNullException("function");
this.function = function;
}
public override DifferenceIn GetDifference(TimeSpan span)
{
DifferenceIn? customResult = function(span);
DifferenceIn result = customResult.HasValue ?
customResult.Value :
base.GetDifference(span);
return result;
}
}
}

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
public class ExtendedDaysStrategy : IDateTimeTicksStrategy
{
private static readonly DifferenceIn[] diffs = new DifferenceIn[] {
DifferenceIn.Year,
DifferenceIn.Day,
DifferenceIn.Hour,
DifferenceIn.Minute,
DifferenceIn.Second,
DifferenceIn.Millisecond
};
public DifferenceIn GetDifference(TimeSpan span)
{
span = span.Duration();
DifferenceIn diff;
if (span.Days > 365)
diff = DifferenceIn.Year;
else if (span.Days > 0)
diff = DifferenceIn.Day;
else if (span.Hours > 0)
diff = DifferenceIn.Hour;
else if (span.Minutes > 0)
diff = DifferenceIn.Minute;
else if (span.Seconds > 0)
diff = DifferenceIn.Second;
else
diff = DifferenceIn.Millisecond;
return diff;
}
public bool TryGetLowerDiff(DifferenceIn diff, out DifferenceIn lowerDiff)
{
lowerDiff = diff;
int index = Array.IndexOf(diffs, diff);
if (index == -1)
return false;
if (index == diffs.Length - 1)
return false;
lowerDiff = diffs[index + 1];
return true;
}
public bool TryGetBiggerDiff(DifferenceIn diff, out DifferenceIn biggerDiff)
{
biggerDiff = diff;
int index = Array.IndexOf(diffs, diff);
if (index == -1 || index == 0)
return false;
biggerDiff = diffs[index - 1];
return true;
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
public interface IDateTimeTicksStrategy
{
DifferenceIn GetDifference(TimeSpan span);
bool TryGetLowerDiff(DifferenceIn diff, out DifferenceIn lowerDiff);
bool TryGetBiggerDiff(DifferenceIn diff, out DifferenceIn biggerDiff);
}
}

View File

@@ -0,0 +1,269 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
internal abstract class TimePeriodTicksProvider<T> : ITicksProvider<T>
{
public event EventHandler Changed;
protected void RaiseChanged()
{
if (Changed != null)
{
Changed(this, EventArgs.Empty);
}
}
protected abstract T RoundUp(T time, DifferenceIn diff);
protected abstract T RoundDown(T time, DifferenceIn diff);
private bool differenceInited = false;
private DifferenceIn difference;
protected DifferenceIn Difference
{
get
{
if (!differenceInited)
{
difference = GetDifferenceCore();
differenceInited = true;
}
return difference;
}
}
protected abstract DifferenceIn GetDifferenceCore();
private int[] tickCounts = null;
protected int[] TickCounts
{
get
{
if (tickCounts == null)
tickCounts = GetTickCountsCore();
return tickCounts;
}
}
protected abstract int[] GetTickCountsCore();
public int DecreaseTickCount(int ticksCount)
{
if (ticksCount > TickCounts[0]) return TickCounts[0];
for (int i = 0; i < TickCounts.Length; i++)
if (ticksCount > TickCounts[i])
return TickCounts[i];
return TickCounts.Last();
}
public int IncreaseTickCount(int ticksCount)
{
if (ticksCount >= TickCounts[0]) return TickCounts[0];
for (int i = TickCounts.Length - 1; i >= 0; i--)
if (ticksCount < TickCounts[i])
return TickCounts[i];
return TickCounts.Last();
}
protected abstract int GetSpecificValue(T start, T dt);
protected abstract T GetStart(T start, int value, int step);
protected abstract bool IsMinDate(T dt);
protected abstract T AddStep(T dt, int step);
public ITicksInfo<T> GetTicks(Range<T> range, int ticksCount)
{
T start = range.Min;
T end = range.Max;
DifferenceIn diff = Difference;
start = RoundDown(start, end);
end = RoundUp(start, end);
RoundingInfo bounds = RoundingHelper.CreateRoundedRange(
GetSpecificValue(start, start),
GetSpecificValue(start, end));
int delta = (int)(bounds.Max - bounds.Min);
if (delta == 0)
return new TicksInfo<T> { Ticks = new T[] { start } };
int step = delta / ticksCount;
if (step == 0) step = 1;
T tick = GetStart(start, (int)bounds.Min, step);
bool isMinDateTime = IsMinDate(tick) && step != 1;
if (isMinDateTime)
step--;
List<T> ticks = new List<T>();
T finishTick = AddStep(range.Max, step);
while (Continue(tick, finishTick))
{
ticks.Add(tick);
tick = AddStep(tick, step);
if (isMinDateTime)
{
isMinDateTime = false;
step++;
}
}
ticks = Trim(ticks, range);
TicksInfo<T> res = new TicksInfo<T> { Ticks = ticks.ToArray(), Info = diff };
return res;
}
protected abstract bool Continue(T current, T end);
protected abstract T RoundUp(T start, T end);
protected abstract T RoundDown(T start, T end);
protected abstract List<T> Trim(List<T> ticks, Range<T> range);
public ITicksProvider<T> MinorProvider
{
get { throw new NotSupportedException(); }
}
public ITicksProvider<T> MajorProvider
{
get { throw new NotSupportedException(); }
}
}
internal abstract class DatePeriodTicksProvider : TimePeriodTicksProvider<DateTime>
{
protected sealed override bool Continue(DateTime current, DateTime end)
{
return current < end;
}
protected sealed override List<DateTime> Trim(List<DateTime> ticks, Range<DateTime> range)
{
int startIndex = 0;
for (int i = 0; i < ticks.Count - 1; i++)
{
if (ticks[i] <= range.Min && range.Min <= ticks[i + 1])
{
startIndex = i;
break;
}
}
int endIndex = ticks.Count - 1;
for (int i = ticks.Count - 1; i >= 1; i--)
{
if (ticks[i] >= range.Max && range.Max > ticks[i - 1])
{
endIndex = i;
break;
}
}
List<DateTime> res = new List<DateTime>(endIndex - startIndex + 1);
for (int i = startIndex; i <= endIndex; i++)
{
res.Add(ticks[i]);
}
return res;
}
protected sealed override DateTime RoundUp(DateTime start, DateTime end)
{
bool isPositive = (end - start).Ticks > 0;
return isPositive ? SafelyRoundUp(end) : RoundDown(end, Difference);
}
private DateTime SafelyRoundUp(DateTime dt)
{
if (AddStep(dt, 1) == DateTime.MaxValue)
return DateTime.MaxValue;
return RoundUp(dt, Difference);
}
protected sealed override DateTime RoundDown(DateTime start, DateTime end)
{
bool isPositive = (end - start).Ticks > 0;
return isPositive ? RoundDown(start, Difference) : SafelyRoundUp(start);
}
protected sealed override DateTime RoundDown(DateTime time, DifferenceIn diff)
{
DateTime res = time;
switch (diff)
{
case DifferenceIn.Year:
res = new DateTime(time.Year, 1, 1);
break;
case DifferenceIn.Month:
res = new DateTime(time.Year, time.Month, 1);
break;
case DifferenceIn.Day:
res = time.Date;
break;
case DifferenceIn.Hour:
res = time.Date.AddHours(time.Hour);
break;
case DifferenceIn.Minute:
res = time.Date.AddHours(time.Hour).AddMinutes(time.Minute);
break;
case DifferenceIn.Second:
res = time.Date.AddHours(time.Hour).AddMinutes(time.Minute).AddSeconds(time.Second);
break;
case DifferenceIn.Millisecond:
res = time.Date.AddHours(time.Hour).AddMinutes(time.Minute).AddSeconds(time.Second).AddMilliseconds(time.Millisecond);
break;
default:
break;
}
DebugVerify.Is(res <= time);
return res;
}
protected override DateTime RoundUp(DateTime dateTime, DifferenceIn diff)
{
DateTime res = RoundDown(dateTime, diff);
switch (diff)
{
case DifferenceIn.Year:
res = res.AddYears(1);
break;
case DifferenceIn.Month:
res = res.AddMonths(1);
break;
case DifferenceIn.Day:
res = res.AddDays(1);
break;
case DifferenceIn.Hour:
res = res.AddHours(1);
break;
case DifferenceIn.Minute:
res = res.AddMinutes(1);
break;
case DifferenceIn.Second:
res = res.AddSeconds(1);
break;
case DifferenceIn.Millisecond:
res = res.AddMilliseconds(1);
break;
default:
break;
}
return res;
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Research.DynamicDataDisplay.ViewportRestrictions;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
public class VerticalDateTimeAxis : DateTimeAxis
{
public VerticalDateTimeAxis()
{
Placement = AxisPlacement.Left;
Restriction = new DateTimeVerticalAxisRestriction();
}
protected override void ValidatePlacement(AxisPlacement newPlacement)
{
if (newPlacement == AxisPlacement.Bottom || newPlacement == AxisPlacement.Top)
throw new ArgumentException(Strings.Exceptions.VerticalAxisCannotBeHorizontal);
}
}
}