using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary; using System.Windows.Markup; namespace Microsoft.Research.DynamicDataDisplay.Charts.Axes.Numeric { [ContentProperty("TicksProvider")] public class CustomBaseNumericTicksProvider : ITicksProvider { private double customBase = 2; /// /// Gets or sets the custom base. /// /// The custom base. public double CustomBase { get { return customBase; } set { if (Double.IsNaN(value)) throw new ArgumentException(Strings.Exceptions.CustomBaseTicksProviderBaseIsNaN); if (value <= 0) throw new ArgumentOutOfRangeException(Strings.Exceptions.CustomBaseTicksProviderBaseIsTooSmall); customBase = value; } } /// /// Initializes a new instance of the class. /// public CustomBaseNumericTicksProvider() : this(2.0) { } /// /// Initializes a new instance of the class. /// /// The custom base, e.g. Math.PI public CustomBaseNumericTicksProvider(double customBase) : this(customBase, new NumericTicksProvider()) { } private CustomBaseNumericTicksProvider(double customBase, ITicksProvider ticksProvider) { if (ticksProvider == null) throw new ArgumentNullException("ticksProvider"); CustomBase = customBase; TicksProvider = ticksProvider; } private void ticksProvider_Changed(object sender, EventArgs e) { Changed.Raise(this); } private ITicksProvider ticksProvider = null; public ITicksProvider TicksProvider { get { return ticksProvider; } set { if (value == null) throw new ArgumentNullException("value"); if (ticksProvider != null) ticksProvider.Changed -= ticksProvider_Changed; ticksProvider = value; ticksProvider.Changed += ticksProvider_Changed; if (minorTicksProvider != null) minorTicksProvider.Changed -= minorTicksProvider_Changed; minorTicksProvider = new MinorProviderWrapper(this); minorTicksProvider.Changed += minorTicksProvider_Changed; Changed.Raise(this); } } void minorTicksProvider_Changed(object sender, EventArgs e) { Changed.Raise(this); } private Range TransformRange(Range range) { double min = range.Min / customBase; double max = range.Max / customBase; return new Range(min, max); } #region ITicksProvider Members private double[] tickMarks; public ITicksInfo GetTicks(Range range, int ticksCount) { var ticks = ticksProvider.GetTicks(TransformRange(range), ticksCount); TransformTicks(ticks); tickMarks = ticks.Ticks; return ticks; } private void TransformTicks(ITicksInfo ticks) { for (int i = 0; i < ticks.Ticks.Length; i++) { ticks.Ticks[i] *= customBase; } } public int DecreaseTickCount(int ticksCount) { return ticksProvider.DecreaseTickCount(ticksCount); } public int IncreaseTickCount(int ticksCount) { return ticksProvider.IncreaseTickCount(ticksCount); } private ITicksProvider minorTicksProvider; public ITicksProvider MinorProvider { get { return minorTicksProvider; } } /// /// Gets the major provider, used to generate major ticks - for example, years for common ticks as months. /// /// The major provider. public ITicksProvider MajorProvider { get { return null; } } public event EventHandler Changed; #endregion private sealed class MinorProviderWrapper : ITicksProvider { private readonly CustomBaseNumericTicksProvider owner; public MinorProviderWrapper(CustomBaseNumericTicksProvider owner) { this.owner = owner; MinorTicksProvider.Changed += MinorTicksProvider_Changed; } private void MinorTicksProvider_Changed(object sender, EventArgs e) { Changed.Raise(this); } private ITicksProvider MinorTicksProvider { get { return owner.ticksProvider.MinorProvider; } } #region ITicksProvider Members public ITicksInfo GetTicks(Range range, int ticksCount) { var minorProvider = MinorTicksProvider; var ticks = minorProvider.GetTicks(range, ticksCount); return ticks; } public int DecreaseTickCount(int ticksCount) { return MinorTicksProvider.DecreaseTickCount(ticksCount); } public int IncreaseTickCount(int ticksCount) { return MinorTicksProvider.IncreaseTickCount(ticksCount); } public ITicksProvider MinorProvider { get { return MinorTicksProvider.MinorProvider; } } public ITicksProvider MajorProvider { get { return owner; } } public event EventHandler Changed; #endregion } } }