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 } } }