using System;
using System.Linq;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Research.DynamicDataDisplay.Charts;
using Microsoft.Research.DynamicDataDisplay.Charts.Navigation;
using Microsoft.Research.DynamicDataDisplay.Navigation;
using Microsoft.Research.DynamicDataDisplay.Common;
using Microsoft.Research.DynamicDataDisplay.Charts.Axes;
namespace Microsoft.Research.DynamicDataDisplay
{
///
/// Chart plotter is a plotter that renders axis and grid
///
public class ChartPlotter : Plotter2D
{
private GeneralAxis horizontalAxis = new HorizontalAxis();
private GeneralAxis verticalAxis = new VerticalAxis();
private AxisGrid axisGrid = new AxisGrid();
private Legend legend = new Legend();
public ItemsPanelTemplate LegendPanelTemplate
{
get { return legend.ItemsPanel; }
set
{
if (legend == null)
throw new ArgumentNullException("LegendPanelTemplate");
legend.ItemsPanel = value;
}
}
public Style LegendStyle
{
get { return legend.Style; }
set { legend.Style = value; }
}
///
/// Sets a value indicating whether to enable smooth axes panning for numeric axes.
///
///
/// true if enable smooth axes panning for numeric axes; otherwise, false.
///
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool EnableSmoothPanningForNumericAxes
{
// todo improve returned value
get { return false; }// throw new NotImplementedException(); }
set
{
foreach (var axis in Children.OfType())
{
axis.UseSmoothPanning = value;
}
}
}
///
/// Initializes a new instance of the class.
///
public ChartPlotter()
: base()
{
horizontalAxis.TicksChanged += OnHorizontalAxisTicksChanged;
verticalAxis.TicksChanged += OnVerticalAxisTicksChanged;
SetIsDefaultAxis(horizontalAxis as DependencyObject, true);
SetIsDefaultAxis(verticalAxis as DependencyObject, true);
mouseNavigation = new MouseNavigation();
keyboardNavigation = new KeyboardNavigation();
defaultContextMenu = new DefaultContextMenu();
horizontalAxisNavigation = new AxisNavigation { Placement = AxisPlacement.Bottom };
verticalAxisNavigation = new AxisNavigation { Placement = AxisPlacement.Left };
Children.AddMany(
horizontalAxis,
verticalAxis,
axisGrid,
mouseNavigation,
keyboardNavigation,
defaultContextMenu,
horizontalAxisNavigation,
verticalAxisNavigation,
new LongOperationsIndicator(),
legend
);
#if DEBUG
Children.Add(new DebugMenu());
#endif
SetAllChildrenAsDefault();
}
///
/// Creates generic plotter from this ChartPlotter.
///
///
public GenericChartPlotter GetGenericPlotter()
{
return new GenericChartPlotter(this);
}
///
/// Creates generic plotter from this ChartPlotter.
/// Horizontal and Vertical types of GenericPlotter should correspond to ChartPlotter's actual main axes types.
///
/// The type of horizontal values.
/// The type of vertical values.
/// GenericChartPlotter, associated to this ChartPlotter.
public GenericChartPlotter GetGenericPlotter()
{
return new GenericChartPlotter(this);
}
///
/// Creates generic plotter from this ChartPlotter.
///
/// The type of the horizontal axis.
/// The type of the vertical axis.
/// The horizontal axis to use as data conversion source.
/// The vertical axis to use as data conversion source.
/// GenericChartPlotter, associated to this ChartPlotter
public GenericChartPlotter GetGenericPlotter(AxisBase horizontalAxis, AxisBase verticalAxis)
{
return new GenericChartPlotter(this, horizontalAxis, verticalAxis);
}
protected ChartPlotter(PlotterLoadMode loadMode) : base(loadMode) { }
///
/// Creates empty plotter without any axes, navigation, etc.
///
/// Empty plotter without any axes, navigation, etc.
public static ChartPlotter CreateEmpty()
{
return new ChartPlotter(PlotterLoadMode.OnlyViewport);
}
public void BeginLongOperation()
{
LongOperationsIndicator.BeginLongOperation(this);
}
public void EndLongOperation()
{
LongOperationsIndicator.EndLongOperation(this);
}
#region Default charts
private MouseNavigation mouseNavigation;
///
/// Gets the default mouse navigation of ChartPlotter.
///
/// The mouse navigation.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public MouseNavigation MouseNavigation
{
get { return mouseNavigation; }
}
private KeyboardNavigation keyboardNavigation;
///
/// Gets the default keyboard navigation of ChartPlotter.
///
/// The keyboard navigation.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public KeyboardNavigation KeyboardNavigation
{
get { return keyboardNavigation; }
}
private DefaultContextMenu defaultContextMenu;
///
/// Gets the default context menu of ChartPlotter.
///
/// The default context menu.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public DefaultContextMenu DefaultContextMenu
{
get { return defaultContextMenu; }
}
private AxisNavigation horizontalAxisNavigation;
///
/// Gets the default horizontal axis navigation of ChartPlotter.
///
/// The horizontal axis navigation.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public AxisNavigation HorizontalAxisNavigation
{
get { return horizontalAxisNavigation; }
}
private AxisNavigation verticalAxisNavigation;
///
/// Gets the default vertical axis navigation of ChartPlotter.
///
/// The vertical axis navigation.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public AxisNavigation VerticalAxisNavigation
{
get { return verticalAxisNavigation; }
}
///
/// Gets the default axis grid of ChartPlotter.
///
/// The axis grid.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public AxisGrid AxisGrid
{
get { return axisGrid; }
}
#endregion
private void OnHorizontalAxisTicksChanged(object sender, EventArgs e)
{
GeneralAxis axis = (GeneralAxis)sender;
UpdateHorizontalTicks(axis);
}
private void UpdateHorizontalTicks(GeneralAxis axis)
{
axisGrid.BeginTicksUpdate();
if (axis != null)
{
axisGrid.HorizontalTicks = axis.ScreenTicks;
axisGrid.MinorHorizontalTicks = axis.MinorScreenTicks;
}
else
{
axisGrid.HorizontalTicks = null;
axisGrid.MinorHorizontalTicks = null;
}
axisGrid.EndTicksUpdate();
}
private void OnVerticalAxisTicksChanged(object sender, EventArgs e)
{
GeneralAxis axis = (GeneralAxis)sender;
UpdateVerticalTicks(axis);
}
private void UpdateVerticalTicks(GeneralAxis axis)
{
axisGrid.BeginTicksUpdate();
if (axis != null)
{
axisGrid.VerticalTicks = axis.ScreenTicks;
axisGrid.MinorVerticalTicks = axis.MinorScreenTicks;
}
else
{
axisGrid.VerticalTicks = null;
axisGrid.MinorVerticalTicks = null;
}
axisGrid.EndTicksUpdate();
}
bool keepOldAxis = false;
bool updatingAxis = false;
///
/// Gets or sets the main vertical axis of ChartPlotter.
/// Main vertical axis of ChartPlotter is axis which ticks are used to draw horizontal lines on AxisGrid.
/// Value can be set to null to completely remove main vertical axis.
///
/// The main vertical axis.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public GeneralAxis MainVerticalAxis
{
get { return verticalAxis; }
set
{
if (updatingAxis)
return;
if (value == null && verticalAxis != null)
{
if (!keepOldAxis)
{
Children.Remove(verticalAxis);
}
verticalAxis.TicksChanged -= OnVerticalAxisTicksChanged;
verticalAxis = null;
UpdateVerticalTicks(verticalAxis);
return;
}
VerifyAxisType(value.Placement, AxisType.Vertical);
if (value != verticalAxis)
{
ValidateVerticalAxis(value);
updatingAxis = true;
if (verticalAxis != null)
{
verticalAxis.TicksChanged -= OnVerticalAxisTicksChanged;
SetIsDefaultAxis(verticalAxis, false);
if (!keepOldAxis)
{
Children.Remove(verticalAxis);
}
value.Visibility = verticalAxis.Visibility;
}
SetIsDefaultAxis(value, true);
verticalAxis = value;
verticalAxis.TicksChanged += OnVerticalAxisTicksChanged;
if (!Children.Contains(value))
{
Children.Add(value);
}
UpdateVerticalTicks(value);
OnVerticalAxisChanged();
updatingAxis = false;
}
}
}
protected virtual void OnVerticalAxisChanged() { }
protected virtual void ValidateVerticalAxis(GeneralAxis axis) { }
///
/// Gets or sets the main horizontal axis visibility.
///
/// The main horizontal axis visibility.
public Visibility MainHorizontalAxisVisibility
{
get { return MainHorizontalAxis != null ? ((UIElement)MainHorizontalAxis).Visibility : Visibility.Hidden; }
set
{
if (MainHorizontalAxis != null)
{
((UIElement)MainHorizontalAxis).Visibility = value;
}
}
}
///
/// Gets or sets the main vertical axis visibility.
///
/// The main vertical axis visibility.
public Visibility MainVerticalAxisVisibility
{
get { return MainVerticalAxis != null ? ((UIElement)MainVerticalAxis).Visibility : Visibility.Hidden; }
set
{
if (MainVerticalAxis != null)
{
((UIElement)MainVerticalAxis).Visibility = value;
}
}
}
///
/// Gets or sets the main horizontal axis of ChartPlotter.
/// Main horizontal axis of ChartPlotter is axis which ticks are used to draw vertical lines on AxisGrid.
/// Value can be set to null to completely remove main horizontal axis.
///
/// The main horizontal axis.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public GeneralAxis MainHorizontalAxis
{
get { return horizontalAxis; }
set
{
if (updatingAxis)
return;
if (value == null && horizontalAxis != null)
{
Children.Remove(horizontalAxis);
horizontalAxis.TicksChanged -= OnHorizontalAxisTicksChanged;
horizontalAxis = null;
UpdateHorizontalTicks(horizontalAxis);
return;
}
VerifyAxisType(value.Placement, AxisType.Horizontal);
if (value != horizontalAxis)
{
ValidateHorizontalAxis(value);
updatingAxis = true;
if (horizontalAxis != null)
{
horizontalAxis.TicksChanged -= OnHorizontalAxisTicksChanged;
SetIsDefaultAxis(horizontalAxis, false);
if (!keepOldAxis)
{
Children.Remove(horizontalAxis);
}
value.Visibility = horizontalAxis.Visibility;
}
SetIsDefaultAxis(value, true);
horizontalAxis = value;
horizontalAxis.TicksChanged += OnHorizontalAxisTicksChanged;
if (!Children.Contains(value))
{
Children.Add(value);
}
UpdateHorizontalTicks(value);
OnHorizontalAxisChanged();
updatingAxis = false;
}
}
}
protected virtual void OnHorizontalAxisChanged() { }
protected virtual void ValidateHorizontalAxis(GeneralAxis axis) { }
private static void VerifyAxisType(AxisPlacement axisPlacement, AxisType axisType)
{
bool result = false;
switch (axisPlacement)
{
case AxisPlacement.Left:
case AxisPlacement.Right:
result = axisType == AxisType.Vertical;
break;
case AxisPlacement.Top:
case AxisPlacement.Bottom:
result = axisType == AxisType.Horizontal;
break;
default:
break;
}
if (!result)
throw new ArgumentException(Strings.Exceptions.InvalidAxisPlacement);
}
protected override void OnIsDefaultAxisChangedCore(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
GeneralAxis axis = d as GeneralAxis;
if (axis != null)
{
bool value = (bool)e.NewValue;
bool oldKeepOldAxis = keepOldAxis;
bool horizontal = axis.Placement == AxisPlacement.Bottom || axis.Placement == AxisPlacement.Top;
keepOldAxis = true;
if (value && horizontal)
{
MainHorizontalAxis = axis;
}
else if (value && !horizontal)
{
MainVerticalAxis = axis;
}
else if (!value && horizontal)
{
MainHorizontalAxis = null;
}
else if (!value && !horizontal)
{
MainVerticalAxis = null;
}
keepOldAxis = oldKeepOldAxis;
}
}
///
/// Gets the default legend of ChartPlotter.
///
/// The legend.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Legend Legend
{
get { return legend; }
}
///
/// Gets or sets the visibility of legend.
///
/// The legend visibility.
public Visibility LegendVisibility
{
get { return legend.Visibility; }
set { legend.Visibility = value; }
}
public bool LegendVisible
{
get { return legend.LegendVisible; }
set { legend.LegendVisible = value; }
}
private enum AxisType
{
Horizontal,
Vertical
}
}
}