using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Controls; using System.Windows.Shapes; using System.Windows.Input; using System.Windows; using System.Windows.Media; using System.Windows.Data; using Microsoft.Research.DynamicDataDisplay.Common; namespace Microsoft.Research.DynamicDataDisplay.Charts.Navigation { /// /// Adds to ChartPlotter two lines upon axes, showing current cursor position. /// public class AxisCursorGraph : DependencyObject, IPlotterElement { static AxisCursorGraph() { Line.StrokeProperty.AddOwner(typeof(AxisCursorGraph), new FrameworkPropertyMetadata(Brushes.Red)); } /// /// Initializes a new instance of the class. /// public AxisCursorGraph() { } #region ShowVerticalLine property /// /// Gets or sets a value indicating whether to show line upon vertical axis. /// /// true if line upon vertical axis is shown; otherwise, false. public bool ShowVerticalLine { get { return (bool)GetValue(ShowVerticalLineProperty); } set { SetValue(ShowVerticalLineProperty, value); } } /// /// Identifies ShowVerticalLine dependency property. /// public static readonly DependencyProperty ShowVerticalLineProperty = DependencyProperty.Register( "ShowVerticalLine", typeof(bool), typeof(AxisCursorGraph), new FrameworkPropertyMetadata(true, OnShowLinePropertyChanged)); private static void OnShowLinePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { AxisCursorGraph graph = (AxisCursorGraph)d; graph.UpdateUIRepresentation(); } #endregion #region ShowHorizontalLine property /// /// Gets or sets a value indicating whether to show line upon horizontal axis. /// /// true if lien upon horizontal axis is shown; otherwise, false. public bool ShowHorizontalLine { get { return (bool)GetValue(ShowHorizontalLineProperty); } set { SetValue(ShowHorizontalLineProperty, value); } } public static readonly DependencyProperty ShowHorizontalLineProperty = DependencyProperty.Register( "ShowHorizontalLine", typeof(bool), typeof(AxisCursorGraph), new FrameworkPropertyMetadata(true, OnShowLinePropertyChanged)); #endregion #region IPlotterElement Members private Line leftLine; private Line bottomLine; private Canvas leftCanvas; private Canvas bottomCanvas; private Plotter2D plotter; void IPlotterElement.OnPlotterAttached(Plotter plotter) { this.plotter = (Plotter2D)plotter; this.plotter.Viewport.PropertyChanged += Viewport_PropertyChanged; var parent = plotter.MainGrid; parent.MouseMove += parent_MouseMove; parent.MouseEnter += parent_MouseEnter; parent.MouseLeave += parent_MouseLeave; Style lineStyle = new Style(typeof(Line)); AddBindingSetter(lineStyle, Line.StrokeProperty); AddBindingSetter(lineStyle, Line.StrokeThicknessProperty); leftCanvas = new Canvas(); Grid.SetRow(leftCanvas, 1); Grid.SetColumn(leftCanvas, 0); leftLine = new Line { Style = lineStyle, IsHitTestVisible = false }; leftCanvas.Children.Add(leftLine); parent.Children.Add(leftCanvas); bottomCanvas = new Canvas(); Grid.SetRow(bottomCanvas, 2); Grid.SetColumn(bottomCanvas, 1); bottomLine = new Line { Style = lineStyle, IsHitTestVisible = false }; bottomCanvas.Children.Add(bottomLine); parent.Children.Add(bottomCanvas); } private void AddBindingSetter(Style style, DependencyProperty property) { style.Setters.Add(new Setter(property, new Binding { Path = new PropertyPath(property.Name), Source = this })); } void Viewport_PropertyChanged(object sender, ExtendedPropertyChangedEventArgs e) { UpdateUIRepresentation(); } private void UpdateUIRepresentation() { if (plotter == null) return; var transform = plotter.Viewport.Transform; DataRect visible = plotter.Viewport.Visible; Rect output = plotter.Viewport.Output; Point mousePos = Mouse.GetPosition(plotter.CentralGrid); if (ShowVerticalLine) { double y = mousePos.Y; if (output.Top <= y && y <= output.Bottom) { leftLine.Visibility = Visibility.Visible; leftLine.X1 = 0; leftLine.X2 = plotter.LeftPanel.ActualWidth; leftLine.Y1 = leftLine.Y2 = y; } else { leftLine.Visibility = Visibility.Collapsed; } } else { leftLine.Visibility = Visibility.Collapsed; } if (ShowHorizontalLine) { double x = mousePos.X; if (output.Left <= x && x <= output.Right) { bottomLine.Visibility = Visibility.Visible; bottomLine.Y1 = 0; bottomLine.Y2 = plotter.BottomPanel.ActualHeight; bottomLine.X1 = bottomLine.X2 = x; } else { bottomLine.Visibility = Visibility.Collapsed; } } else { bottomLine.Visibility = Visibility.Collapsed; } } void parent_MouseLeave(object sender, MouseEventArgs e) { UpdateUIRepresentation(); } void parent_MouseEnter(object sender, MouseEventArgs e) { UpdateUIRepresentation(); } void parent_MouseMove(object sender, MouseEventArgs e) { UpdateUIRepresentation(); } void IPlotterElement.OnPlotterDetaching(Plotter plotter) { this.plotter.Viewport.PropertyChanged -= Viewport_PropertyChanged; var parent = plotter.MainGrid; parent.MouseMove -= parent_MouseMove; parent.MouseEnter -= parent_MouseEnter; parent.MouseLeave -= parent_MouseLeave; parent.Children.Remove(leftCanvas); parent.Children.Remove(bottomCanvas); this.plotter = null; } Plotter IPlotterElement.Plotter { get { return plotter; } } #endregion } }