Initial Commit
This commit is contained in:
113
Charts/Axes/DateTime/DateTimeAxis.cs
Normal file
113
Charts/Axes/DateTime/DateTimeAxis.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Charts/Axes/DateTime/DateTimeAxisControl.cs
Normal file
27
Charts/Axes/DateTime/DateTimeAxisControl.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Charts/Axes/DateTime/DateTimeLabelProvider.cs
Normal file
48
Charts/Axes/DateTime/DateTimeLabelProvider.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
59
Charts/Axes/DateTime/DateTimeLabelProviderBase.cs
Normal file
59
Charts/Axes/DateTime/DateTimeLabelProviderBase.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
307
Charts/Axes/DateTime/DateTimeTicksProvider.cs
Normal file
307
Charts/Axes/DateTime/DateTimeTicksProvider.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
134
Charts/Axes/DateTime/DateTimeTicksProviderBase.cs
Normal file
134
Charts/Axes/DateTime/DateTimeTicksProviderBase.cs
Normal 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
|
||||
}
|
||||
}
|
||||
39
Charts/Axes/DateTime/DateTimeToDoubleConversion.cs
Normal file
39
Charts/Axes/DateTime/DateTimeToDoubleConversion.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Charts/Axes/DateTime/DifferenceIn.cs
Normal file
22
Charts/Axes/DateTime/DifferenceIn.cs
Normal 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
|
||||
}
|
||||
}
|
||||
28
Charts/Axes/DateTime/HorizontalDateTimeAxis.cs
Normal file
28
Charts/Axes/DateTime/HorizontalDateTimeAxis.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
133
Charts/Axes/DateTime/MajorDateTimeLabelProvider.cs
Normal file
133
Charts/Axes/DateTime/MajorDateTimeLabelProvider.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
114
Charts/Axes/DateTime/MinorTimeProviderBase.cs
Normal file
114
Charts/Axes/DateTime/MinorTimeProviderBase.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Charts/Axes/DateTime/Strategies/DelegateStrategy.cs
Normal file
30
Charts/Axes/DateTime/Strategies/DelegateStrategy.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
Charts/Axes/DateTime/Strategies/ExtendedDaysStrategy.cs
Normal file
67
Charts/Axes/DateTime/Strategies/ExtendedDaysStrategy.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
Charts/Axes/DateTime/Strategies/IDateTimeTicksStrategy.cs
Normal file
14
Charts/Axes/DateTime/Strategies/IDateTimeTicksStrategy.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
269
Charts/Axes/DateTime/TimePeriodTicksProvider.cs
Normal file
269
Charts/Axes/DateTime/TimePeriodTicksProvider.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Charts/Axes/DateTime/VerticalDateTimeAxis.cs
Normal file
23
Charts/Axes/DateTime/VerticalDateTimeAxis.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user