Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GrammaticalOptimization/DynamicDataDisplay/Charts/Navigation/CursorCoordinateGraph.xaml.cs @ 13398

Last change on this file since 13398 was 12503, checked in by aballeit, 10 years ago

#2283 added GUI and charts; fixed MCTS

File size: 12.1 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.Windows;
6using System.Windows.Controls;
7using System.Windows.Data;
8using System.Windows.Documents;
9using System.Windows.Input;
10using System.Windows.Media;
11using System.Windows.Media.Imaging;
12using System.Windows.Navigation;
13using System.Windows.Shapes;
14using System.Diagnostics;
15using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
16using Microsoft.Research.DynamicDataDisplay;
17using System.ComponentModel;
18using System.Diagnostics.CodeAnalysis;
19using Microsoft.Research.DynamicDataDisplay.Common;
20
21namespace Microsoft.Research.DynamicDataDisplay.Charts.Navigation
22{
23  /// <summary>
24  /// Adds to ChartPlotter two crossed lines, bound to mouse cursor position, and two labels near axes with mouse position in its text.
25  /// </summary>
26  public partial class CursorCoordinateGraph : ContentGraph
27  {
28    /// <summary>
29    /// Initializes a new instance of the <see cref="CursorCoordinateGraph"/> class.
30    /// </summary>
31    public CursorCoordinateGraph()
32    {
33      InitializeComponent();
34    }
35
36    Vector blockShift = new Vector(3, 3);
37
38    #region Plotter
39
40    protected override void OnPlotterAttached()
41    {
42      UIElement parent = (UIElement)Parent;
43
44      parent.MouseMove += parent_MouseMove;
45      parent.MouseEnter += Parent_MouseEnter;
46      parent.MouseLeave += Parent_MouseLeave;
47
48      UpdateVisibility();
49      UpdateUIRepresentation();
50    }
51
52    protected override void OnPlotterDetaching()
53    {
54      UIElement parent = (UIElement)Parent;
55
56      parent.MouseMove -= parent_MouseMove;
57      parent.MouseEnter -= Parent_MouseEnter;
58      parent.MouseLeave -= Parent_MouseLeave;
59    }
60
61    #endregion
62
63    private bool autoHide = true;
64    /// <summary>
65    /// Gets or sets a value indicating whether to hide automatically cursor lines when mouse leaves plotter.
66    /// </summary>
67    /// <value><c>true</c> if auto hide; otherwise, <c>false</c>.</value>
68    public bool AutoHide
69    {
70      get { return autoHide; }
71      set { autoHide = value; }
72    }
73
74    private void Parent_MouseEnter(object sender, MouseEventArgs e)
75    {
76      if (autoHide)
77      {
78        UpdateVisibility();
79      }
80    }
81
82    private void UpdateVisibility()
83    {
84      horizLine.Visibility = vertGrid.Visibility = GetHorizontalVisibility();
85      vertLine.Visibility = horizGrid.Visibility = GetVerticalVisibility();
86    }
87
88    private Visibility GetHorizontalVisibility()
89    {
90      return showHorizontalLine ? Visibility.Visible : Visibility.Hidden;
91    }
92
93    private Visibility GetVerticalVisibility()
94    {
95      return showVerticalLine ? Visibility.Visible : Visibility.Hidden;
96    }
97
98    private void Parent_MouseLeave(object sender, MouseEventArgs e)
99    {
100      if (autoHide)
101      {
102        horizLine.Visibility = Visibility.Hidden;
103        vertLine.Visibility = Visibility.Hidden;
104        horizGrid.Visibility = Visibility.Hidden;
105        vertGrid.Visibility = Visibility.Hidden;
106      }
107    }
108
109    private bool followMouse = true;
110    /// <summary>
111    /// Gets or sets a value indicating whether lines are following mouse cursor position.
112    /// </summary>
113    /// <value><c>true</c> if lines are following mouse cursor position; otherwise, <c>false</c>.</value>
114    public bool FollowMouse
115    {
116      get { return followMouse; }
117      set
118      {
119        followMouse = value;
120
121        if (!followMouse)
122        {
123          AutoHide = false;
124        }
125
126        UpdateUIRepresentation();
127      }
128    }
129
130    private void parent_MouseMove(object sender, MouseEventArgs e)
131    {
132      if (followMouse)
133      {
134        UpdateUIRepresentation();
135      }
136    }
137
138    protected override void OnViewportPropertyChanged(ExtendedPropertyChangedEventArgs e)
139    {
140      UpdateUIRepresentation();
141    }
142
143    private string customXFormat = null;
144    /// <summary>
145    /// Gets or sets the custom format string of x label.
146    /// </summary>
147    /// <value>The custom X format.</value>
148    public string CustomXFormat
149    {
150      get { return customXFormat; }
151      set
152      {
153        if (customXFormat != value)
154        {
155          customXFormat = value;
156          UpdateUIRepresentation();
157        }
158      }
159    }
160
161    private string customYFormat = null;
162    /// <summary>
163    /// Gets or sets the custom format string of y label.
164    /// </summary>
165    /// <value>The custom Y format.</value>
166    public string CustomYFormat
167    {
168      get { return customYFormat; }
169      set
170      {
171        if (customYFormat != value)
172        {
173          customYFormat = value;
174          UpdateUIRepresentation();
175        }
176      }
177    }
178
179    private Func<double, string> xTextMapping = null;
180    /// <summary>
181    /// Gets or sets the text mapping of x label - function that builds text from x-coordinate of mouse in data.
182    /// </summary>
183    /// <value>The X text mapping.</value>
184    public Func<double, string> XTextMapping
185    {
186      get { return xTextMapping; }
187      set
188      {
189        if (xTextMapping != value)
190        {
191          xTextMapping = value;
192          UpdateUIRepresentation();
193        }
194      }
195    }
196
197    private Func<double, string> yTextMapping = null;
198    /// <summary>
199    /// Gets or sets the text mapping of y label - function that builds text from y-coordinate of mouse in data.
200    /// </summary>
201    /// <value>The Y text mapping.</value>
202    public Func<double, string> YTextMapping
203    {
204      get { return yTextMapping; }
205      set
206      {
207        if (yTextMapping != value)
208        {
209          yTextMapping = value;
210          UpdateUIRepresentation();
211        }
212      }
213    }
214
215    private bool showHorizontalLine = true;
216    /// <summary>
217    /// Gets or sets a value indicating whether to show horizontal line.
218    /// </summary>
219    /// <value><c>true</c> if horizontal line is shown; otherwise, <c>false</c>.</value>
220    public bool ShowHorizontalLine
221    {
222      get { return showHorizontalLine; }
223      set
224      {
225        if (showHorizontalLine != value)
226        {
227          showHorizontalLine = value;
228          UpdateVisibility();
229        }
230      }
231    }
232
233    private bool showVerticalLine = true;
234    /// <summary>
235    /// Gets or sets a value indicating whether to show vertical line.
236    /// </summary>
237    /// <value><c>true</c> if vertical line is shown; otherwise, <c>false</c>.</value>
238    public bool ShowVerticalLine
239    {
240      get { return showVerticalLine; }
241      set
242      {
243        if (showVerticalLine != value)
244        {
245          showVerticalLine = value;
246          UpdateVisibility();
247        }
248      }
249    }
250
251    private void UpdateUIRepresentation()
252    {
253      Point position = followMouse ? Mouse.GetPosition(this) : Position;
254      UpdateUIRepresentation(position);
255    }
256
257    private void UpdateUIRepresentation(Point mousePos)
258    {
259      if (Plotter2D == null) return;
260
261      var transform = Plotter2D.Viewport.Transform;
262      DataRect visible = Plotter2D.Viewport.Visible;
263      Rect output = Plotter2D.Viewport.Output;
264
265      if (!output.Contains(mousePos))
266      {
267        if (autoHide)
268        {
269          horizGrid.Visibility = horizLine.Visibility = vertGrid.Visibility = vertLine.Visibility = Visibility.Hidden;
270        }
271        return;
272      }
273
274      if (!followMouse)
275      {
276        mousePos = mousePos.DataToScreen(transform);
277      }
278
279      horizLine.X1 = output.Left;
280      horizLine.X2 = output.Right;
281      horizLine.Y1 = mousePos.Y;
282      horizLine.Y2 = mousePos.Y;
283
284      vertLine.X1 = mousePos.X;
285      vertLine.X2 = mousePos.X;
286      vertLine.Y1 = output.Top;
287      vertLine.Y2 = output.Bottom;
288
289      if (UseDashOffset)
290      {
291        horizLine.StrokeDashOffset = (output.Right - mousePos.X) / 2;
292        vertLine.StrokeDashOffset = (output.Bottom - mousePos.Y) / 2;
293      }
294
295      Point mousePosInData = mousePos.ScreenToData(transform);
296
297      string text = null;
298
299      if (showVerticalLine)
300      {
301        double xValue = mousePosInData.X;
302        if (xTextMapping != null)
303          text = xTextMapping(xValue);
304
305        // doesnot have xTextMapping or it returned null
306        if (text == null)
307          text = GetRoundedValue(visible.XMin, visible.XMax, xValue);
308
309        if (!String.IsNullOrEmpty(customXFormat))
310          text = String.Format(customXFormat, text);
311        horizTextBlock.Text = text;
312      }
313
314      double width = horizGrid.ActualWidth;
315      double x = mousePos.X + blockShift.X;
316      if (x + width > output.Right)
317      {
318        x = mousePos.X - blockShift.X - width;
319      }
320      Canvas.SetLeft(horizGrid, x);
321
322      if (showHorizontalLine)
323      {
324        double yValue = mousePosInData.Y;
325        text = null;
326        if (yTextMapping != null)
327          text = yTextMapping(yValue);
328
329        if (text == null)
330          text = GetRoundedValue(visible.YMin, visible.YMax, yValue);
331
332        if (!String.IsNullOrEmpty(customYFormat))
333          text = String.Format(customYFormat, text);
334        vertTextBlock.Text = text;
335      }
336
337      // by default vertGrid is positioned on the top of line.
338      double height = vertGrid.ActualHeight;
339      double y = mousePos.Y - blockShift.Y - height;
340      if (y < output.Top)
341      {
342        y = mousePos.Y + blockShift.Y;
343      }
344      Canvas.SetTop(vertGrid, y);
345
346      if (followMouse)
347        Position = mousePos;
348    }
349
350    /// <summary>
351    /// Gets or sets the mouse position in screen coordinates.
352    /// </summary>
353    /// <value>The position.</value>
354    public Point Position
355    {
356      get { return (Point)GetValue(PositionProperty); }
357      set { SetValue(PositionProperty, value); }
358    }
359
360    /// <summary>
361    /// Identifies Position dependency property.
362    /// </summary>
363    public static readonly DependencyProperty PositionProperty = DependencyProperty.Register(
364      "Position",
365      typeof(Point),
366      typeof(CursorCoordinateGraph),
367      new UIPropertyMetadata(new Point(), OnPositionChanged));
368
369    private static void OnPositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
370    {
371      CursorCoordinateGraph graph = (CursorCoordinateGraph)d;
372      graph.UpdateUIRepresentation((Point)e.NewValue);
373    }
374
375    private string GetRoundedValue(double min, double max, double value)
376    {
377      double roundedValue = value;
378      var log = RoundingHelper.GetDifferenceLog(min, max);
379      string format = "G3";
380      double diff = Math.Abs(max - min);
381      if (1E3 < diff && diff < 1E6)
382      {
383        format = "F0";
384      }
385      if (log < 0)
386        format = "G" + (-log + 2).ToString();
387
388      return roundedValue.ToString(format);
389    }
390
391    #region UseDashOffset property
392
393    public bool UseDashOffset
394    {
395      get { return (bool)GetValue(UseDashOffsetProperty); }
396      set { SetValue(UseDashOffsetProperty, value); }
397    }
398
399    public static readonly DependencyProperty UseDashOffsetProperty = DependencyProperty.Register(
400      "UseDashOffset",
401      typeof(bool),
402      typeof(CursorCoordinateGraph),
403      new FrameworkPropertyMetadata(true, UpdateUIRepresentation));
404
405    private static void UpdateUIRepresentation(DependencyObject d, DependencyPropertyChangedEventArgs e)
406    {
407      CursorCoordinateGraph graph = (CursorCoordinateGraph)d;
408      if ((bool)e.NewValue)
409      {
410        graph.UpdateUIRepresentation();
411      }
412      else
413      {
414        graph.vertLine.ClearValue(Line.StrokeDashOffsetProperty);
415        graph.horizLine.ClearValue(Line.StrokeDashOffsetProperty);
416      }
417    }
418
419    #endregion
420
421    #region LineStroke property
422
423    public Brush LineStroke
424    {
425      get { return (Brush)GetValue(LineStrokeProperty); }
426      set { SetValue(LineStrokeProperty, value); }
427    }
428
429    public static readonly DependencyProperty LineStrokeProperty = DependencyProperty.Register(
430      "LineStroke",
431      typeof(Brush),
432      typeof(CursorCoordinateGraph),
433      new PropertyMetadata(new SolidColorBrush(Color.FromArgb(170, 86, 86, 86))));
434
435    #endregion
436
437    #region LineStrokeThickness property
438
439    public double LineStrokeThickness
440    {
441      get { return (double)GetValue(LineStrokeThicknessProperty); }
442      set { SetValue(LineStrokeThicknessProperty, value); }
443    }
444
445    public static readonly DependencyProperty LineStrokeThicknessProperty = DependencyProperty.Register(
446      "LineStrokeThickness",
447      typeof(double),
448      typeof(CursorCoordinateGraph),
449      new PropertyMetadata(2.0));
450
451    #endregion
452
453    #region LineStrokeDashArray property
454
455    [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
456    public DoubleCollection LineStrokeDashArray
457    {
458      get { return (DoubleCollection)GetValue(LineStrokeDashArrayProperty); }
459      set { SetValue(LineStrokeDashArrayProperty, value); }
460    }
461
462    public static readonly DependencyProperty LineStrokeDashArrayProperty = DependencyProperty.Register(
463      "LineStrokeDashArray",
464      typeof(DoubleCollection),
465      typeof(CursorCoordinateGraph),
466      new FrameworkPropertyMetadata(DoubleCollectionHelper.Create(3, 3)));
467
468    #endregion
469  }
470}
Note: See TracBrowser for help on using the repository browser.