Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GrammaticalOptimization/DynamicDataDisplay/Charts/DataFollowChart.cs @ 12503

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

#2283 added GUI and charts; fixed MCTS

File size: 9.9 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.Windows;
6using System.Windows.Controls;
7using System.Windows.Shapes;
8using System.Windows.Media;
9using System.Windows.Input;
10using Microsoft.Research.DynamicDataDisplay.Common.DataSearch;
11using System.Diagnostics;
12using System.Windows.Markup;
13using System.ComponentModel;
14using System.Diagnostics.Contracts;
15
16namespace Microsoft.Research.DynamicDataDisplay.Charts
17{
18  /// <summary>
19  /// Represents a marker with position.X bound to mouse cursor's position and position.Y is determined by interpolation of <see cref="MarkerPointsGraph"/>'s points.
20  /// </summary>
21  [ContentProperty("MarkerTemplate")]
22  public class DataFollowChart : ViewportHostPanel, INotifyPropertyChanged
23  {
24    /// <summary>
25    /// Initializes a new instance of the <see cref="DataFollowChart"/> class.
26    /// </summary>
27    public DataFollowChart()
28    {
29      Marker = CreateDefaultMarker();
30      SetX(marker, 0);
31      SetY(marker, 0);
32      Children.Add(marker);
33    }
34
35    private static Ellipse CreateDefaultMarker()
36    {
37      return new Ellipse
38      {
39        Width = 10,
40        Height = 10,
41        Stroke = Brushes.Green,
42        StrokeThickness = 1,
43        Fill = Brushes.LightGreen,
44        Visibility = Visibility.Hidden
45      };
46    }
47
48    /// <summary>
49    /// Initializes a new instance of the <see cref="DataFollowChart"/> class, bound to specified <see cref="PointsGraphBase"/>.
50    /// </summary>
51    /// <param name="pointSource">The point source.</param>
52    public DataFollowChart(PointsGraphBase pointSource)
53      : this()
54    {
55      PointSource = pointSource;
56    }
57
58    #region MarkerTemplate property
59
60    /// <summary>
61    /// Gets or sets the template, used to create a marker. This is a dependency property.
62    /// </summary>
63    /// <value>The marker template.</value>
64    public DataTemplate MarkerTemplate
65    {
66      get { return (DataTemplate)GetValue(MarkerTemplateProperty); }
67      set { SetValue(MarkerTemplateProperty, value); }
68    }
69
70    /// <summary>
71    /// Identifies the <see cref="MarkerTemplate"/> dependency property.
72    /// </summary>
73    public static readonly DependencyProperty MarkerTemplateProperty = DependencyProperty.Register(
74      "MarkerTemplate",
75      typeof(DataTemplate),
76      typeof(DataFollowChart),
77      new FrameworkPropertyMetadata(null, OnMarkerTemplateChanged));
78
79    private static void OnMarkerTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
80    {
81      DataFollowChart chart = (DataFollowChart)d;
82      DataTemplate template = (DataTemplate)e.NewValue;
83
84      FrameworkElement marker;
85      if (template != null)
86      {
87        marker = (FrameworkElement)template.LoadContent();
88      }
89      else
90      {
91        marker = CreateDefaultMarker();
92      }
93
94      chart.Children.Remove(chart.marker);
95      chart.Marker = marker;
96      chart.Children.Add(marker);
97    }
98
99    #endregion
100
101    #region Point sources
102
103    /// <summary>
104    /// Gets or sets the source of points.
105    /// Can be null.
106    /// </summary>
107    /// <value>The point source.</value>
108    public PointsGraphBase PointSource
109    {
110      get { return (PointsGraphBase)GetValue(PointSourceProperty); }
111      set { SetValue(PointSourceProperty, value); }
112    }
113
114    /// <summary>
115    /// Identifies the <see cref="PointSource"/> dependency property.
116    /// </summary>
117    public static readonly DependencyProperty PointSourceProperty = DependencyProperty.Register(
118      "PointSource",
119      typeof(PointsGraphBase),
120      typeof(DataFollowChart),
121      new FrameworkPropertyMetadata(null, OnPointSourceChanged));
122
123    private static void OnPointSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
124    {
125      DataFollowChart chart = (DataFollowChart)d;
126
127      PointsGraphBase previous = e.OldValue as PointsGraphBase;
128      if (previous != null)
129      {
130        previous.VisiblePointsChanged -= chart.Source_VisiblePointsChanged;
131      }
132
133      PointsGraphBase current = e.NewValue as PointsGraphBase;
134      if (current != null)
135      {
136        current.ProvideVisiblePoints = true;
137        current.VisiblePointsChanged += chart.Source_VisiblePointsChanged;
138        if (current.VisiblePoints != null)
139        {
140          chart.searcher = new SortedXSearcher1d(current.VisiblePoints);
141        }
142      }
143
144      chart.UpdateUIRepresentation();
145    }
146
147    private SearchResult1d searchResult = SearchResult1d.Empty;
148    private SortedXSearcher1d searcher;
149    private FrameworkElement marker;
150
151    [NotNull]
152    public FrameworkElement Marker
153    {
154      get { return marker; }
155      protected set
156      {
157        Contract.Assert(value != null);
158
159        marker = value;
160        marker.DataContext = followDataContext;
161        PropertyChanged.Raise(this, "Marker");
162      }
163    }
164
165    private FollowDataContext followDataContext = new FollowDataContext();
166    public FollowDataContext FollowDataContext
167    {
168      get { return followDataContext; }
169    }
170
171    private void UpdateUIRepresentation()
172    {
173      if (Plotter == null)
174        return;
175
176      PointsGraphBase source = this.PointSource;
177
178      if (source == null || (source != null && source.VisiblePoints == null))
179      {
180        SetValue(MarkerPositionPropertyKey, new Point(Double.NaN, Double.NaN));
181        marker.Visibility = Visibility.Hidden;
182        return;
183      }
184      else
185      {
186        Point mousePos = Mouse.GetPosition(Plotter.CentralGrid);
187
188        var transform = Plotter.Transform;
189        Point viewportPos = mousePos.ScreenToViewport(transform);
190
191        double x = viewportPos.X;
192        searchResult = searcher.SearchXBetween(x, searchResult);
193        SetValue(ClosestPointIndexPropertyKey, searchResult.Index);
194        if (!searchResult.IsEmpty)
195        {
196          marker.Visibility = Visibility.Visible;
197
198          IList<Point> points = source.VisiblePoints;
199          Point ptBefore = points[searchResult.Index];
200          Point ptAfter = points[searchResult.Index + 1];
201
202          double ratio = (x - ptBefore.X) / (ptAfter.X - ptBefore.X);
203          double y = ptBefore.Y + (ptAfter.Y - ptBefore.Y) * ratio;
204
205          Point temp = new Point(x, y);
206          SetX(marker, temp.X);
207          SetY(marker, temp.Y);
208
209          Point markerPosition = temp;
210          followDataContext.Position = markerPosition;
211          SetValue(MarkerPositionPropertyKey, markerPosition);
212        }
213        else
214        {
215          SetValue(MarkerPositionPropertyKey, new Point(Double.NaN, Double.NaN));
216          marker.Visibility = Visibility.Hidden;
217        }
218      }
219    }
220
221    #region ClosestPointIndex property
222
223    private static readonly DependencyPropertyKey ClosestPointIndexPropertyKey = DependencyProperty.RegisterReadOnly(
224      "ClosestPointIndex",
225      typeof(int),
226      typeof(DataFollowChart),
227      new PropertyMetadata(-1)
228      );
229
230    public static readonly DependencyProperty ClosestPointIndexProperty = ClosestPointIndexPropertyKey.DependencyProperty;
231
232    public int ClosestPointIndex
233    {
234      get { return (int)GetValue(ClosestPointIndexProperty); }
235    }
236
237    #endregion
238
239    #region MarkerPositionProperty
240
241    private static readonly DependencyPropertyKey MarkerPositionPropertyKey = DependencyProperty.RegisterReadOnly(
242      "MarkerPosition",
243      typeof(Point),
244      typeof(DataFollowChart),
245      new PropertyMetadata(new Point(), OnMarkerPositionChanged));
246
247    private static void OnMarkerPositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
248    {
249      DataFollowChart chart = (DataFollowChart)d;
250      chart.MarkerPositionChanged.Raise(chart);
251    }
252
253    /// <summary>
254    /// Identifies the <see cref="MarkerPosition"/> dependency property.
255    /// </summary>
256    public static readonly DependencyProperty MarkerPositionProperty = MarkerPositionPropertyKey.DependencyProperty;
257
258    /// <summary>
259    /// Gets the marker position.
260    /// </summary>
261    /// <value>The marker position.</value>
262    public Point MarkerPosition
263    {
264      get { return (Point)GetValue(MarkerPositionProperty); }
265    }
266
267    /// <summary>
268    /// Occurs when marker position changes.
269    /// </summary>
270    public event EventHandler MarkerPositionChanged;
271
272    #endregion
273
274    public override void OnPlotterAttached(Plotter plotter)
275    {
276      base.OnPlotterAttached(plotter);
277      plotter.MainGrid.MouseMove += MainGrid_MouseMove;
278    }
279
280    private void MainGrid_MouseMove(object sender, MouseEventArgs e)
281    {
282      UpdateUIRepresentation();
283    }
284
285    public override void OnPlotterDetaching(Plotter plotter)
286    {
287      plotter.MainGrid.MouseMove -= MainGrid_MouseMove;
288      base.OnPlotterDetaching(plotter);
289    }
290
291    protected override void Viewport_PropertyChanged(object sender, ExtendedPropertyChangedEventArgs e)
292    {
293      base.Viewport_PropertyChanged(sender, e);
294      UpdateUIRepresentation();
295    }
296
297    private void Source_VisiblePointsChanged(object sender, EventArgs e)
298    {
299      PointsGraphBase source = (PointsGraphBase)sender;
300      if (source.VisiblePoints != null)
301      {
302        searcher = new SortedXSearcher1d(source.VisiblePoints);
303      }
304      UpdateUIRepresentation();
305    }
306
307    #endregion
308
309    #region INotifyPropertyChanged Members
310
311    /// <summary>
312    /// Occurs when a property value changes.
313    /// </summary>
314    public event PropertyChangedEventHandler PropertyChanged;
315
316    #endregion
317  }
318
319  /// <summary>
320  /// Represents a special data context, which encapsulates marker's position and custom data.
321  /// Used in <see cref="DataFollowChart"/>.
322  /// </summary>
323  public class FollowDataContext : INotifyPropertyChanged
324  {
325    private Point position;
326    /// <summary>
327    /// Gets or sets the position of marker.
328    /// </summary>
329    /// <value>The position.</value>
330    public Point Position
331    {
332      get { return position; }
333      set
334      {
335        position = value;
336        PropertyChanged.Raise(this, "Position");
337      }
338    }
339
340    private object data;
341    /// <summary>
342    /// Gets or sets the additional custom data.
343    /// </summary>
344    /// <value>The data.</value>
345    public object Data
346    {
347      get { return data; }
348      set
349      {
350        data = value;
351        PropertyChanged.Raise(this, "Data");
352      }
353    }
354
355    #region INotifyPropertyChanged Members
356
357    /// <summary>
358    /// Occurs when a property value changes.
359    /// </summary>
360    public event PropertyChangedEventHandler PropertyChanged;
361
362    #endregion
363  }
364}
Note: See TracBrowser for help on using the repository browser.