PageRenderTime 23ms CodeModel.GetById 6ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/Main/src/DynamicDataDisplay/ChartPlotter.cs

#
C# | 526 lines | 364 code | 74 blank | 88 comment | 55 complexity | ca590ef526836dbaf92113a00c203eb6 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1using System;
  2using System.Linq;
  3using System.ComponentModel;
  4using System.Windows;
  5using System.Windows.Controls;
  6using Microsoft.Research.DynamicDataDisplay.Charts;
  7using Microsoft.Research.DynamicDataDisplay.Charts.Navigation;
  8using Microsoft.Research.DynamicDataDisplay.Navigation;
  9using Microsoft.Research.DynamicDataDisplay.Common;
 10using Microsoft.Research.DynamicDataDisplay.Charts.Axes;
 11
 12namespace Microsoft.Research.DynamicDataDisplay
 13{
 14	/// <summary>
 15	/// Chart plotter is a plotter that renders axis and grid
 16	/// </summary>
 17	public class ChartPlotter : Plotter2D
 18	{
 19		private GeneralAxis horizontalAxis = new HorizontalAxis();
 20		private GeneralAxis verticalAxis = new VerticalAxis();
 21		private AxisGrid axisGrid = new AxisGrid();
 22
 23		private Legend legend = new Legend();
 24
 25		public ItemsPanelTemplate LegendPanelTemplate
 26		{
 27			get { return legend.ItemsPanel; }
 28			set
 29			{
 30				if (legend == null)
 31					throw new ArgumentNullException("LegendPanelTemplate");
 32
 33				legend.ItemsPanel = value;
 34			}
 35		}
 36
 37		public Style LegendStyle
 38		{
 39			get { return legend.Style; }
 40			set { legend.Style = value; }
 41		}
 42
 43		/// <summary>
 44		/// Sets a value indicating whether to enable smooth axes panning for numeric axes.
 45		/// </summary>
 46		/// <value>
 47		/// 	<c>true</c> if enable smooth axes panning for numeric axes; otherwise, <c>false</c>.
 48		/// </value>
 49		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
 50		public bool EnableSmoothPanningForNumericAxes
 51		{
 52			// todo improve returned value
 53			get { return false; }// throw new NotImplementedException(); }
 54			set
 55			{
 56				foreach (var axis in Children.OfType<NumericAxis>())
 57				{
 58					axis.UseSmoothPanning = value;
 59				}
 60			}
 61		}
 62
 63		/// <summary>
 64		/// Initializes a new instance of the <see cref="ChartPlotter"/> class.
 65		/// </summary>
 66		public ChartPlotter()
 67			: base()
 68		{
 69			horizontalAxis.TicksChanged += OnHorizontalAxisTicksChanged;
 70			verticalAxis.TicksChanged += OnVerticalAxisTicksChanged;
 71
 72			SetIsDefaultAxis(horizontalAxis as DependencyObject, true);
 73			SetIsDefaultAxis(verticalAxis as DependencyObject, true);
 74
 75			mouseNavigation = new MouseNavigation();
 76			keyboardNavigation = new KeyboardNavigation();
 77			defaultContextMenu = new DefaultContextMenu();
 78			horizontalAxisNavigation = new AxisNavigation { Placement = AxisPlacement.Bottom };
 79			verticalAxisNavigation = new AxisNavigation { Placement = AxisPlacement.Left };
 80
 81			Children.AddMany(
 82				horizontalAxis,
 83				verticalAxis,
 84				axisGrid,
 85				mouseNavigation,
 86				keyboardNavigation,
 87				defaultContextMenu,
 88				horizontalAxisNavigation,
 89				verticalAxisNavigation,
 90				new LongOperationsIndicator(),
 91				legend
 92				);
 93
 94#if DEBUG
 95			Children.Add(new DebugMenu());
 96#endif
 97
 98			SetAllChildrenAsDefault();
 99		}
100
101		/// <summary>
102		/// Creates generic plotter from this ChartPlotter.
103		/// </summary>
104		/// <returns></returns>
105		public GenericChartPlotter<double, double> GetGenericPlotter()
106		{
107			return new GenericChartPlotter<double, double>(this);
108		}
109
110		/// <summary>
111		/// Creates generic plotter from this ChartPlotter.
112		/// Horizontal and Vertical types of GenericPlotter should correspond to ChartPlotter's actual main axes types.
113		/// </summary>
114		/// <typeparam name="THorizontal">The type of horizontal values.</typeparam>
115		/// <typeparam name="TVertical">The type of vertical values.</typeparam>
116		/// <returns>GenericChartPlotter, associated to this ChartPlotter.</returns>
117		public GenericChartPlotter<THorizontal, TVertical> GetGenericPlotter<THorizontal, TVertical>()
118		{
119			return new GenericChartPlotter<THorizontal, TVertical>(this);
120		}
121
122		/// <summary>
123		/// Creates generic plotter from this ChartPlotter.
124		/// </summary>
125		/// <typeparam name="THorizontal">The type of the horizontal axis.</typeparam>
126		/// <typeparam name="TVertical">The type of the vertical axis.</typeparam>
127		/// <param name="horizontalAxis">The horizontal axis to use as data conversion source.</param>
128		/// <param name="verticalAxis">The vertical axis to use as data conversion source.</param>
129		/// <returns>GenericChartPlotter, associated to this ChartPlotter</returns>
130		public GenericChartPlotter<THorizontal, TVertical> GetGenericPlotter<THorizontal, TVertical>(AxisBase<THorizontal> horizontalAxis, AxisBase<TVertical> verticalAxis)
131		{
132			return new GenericChartPlotter<THorizontal, TVertical>(this, horizontalAxis, verticalAxis);
133		}
134
135		protected ChartPlotter(PlotterLoadMode loadMode) : base(loadMode) { }
136
137		/// <summary>
138		/// Creates empty plotter without any axes, navigation, etc.
139		/// </summary>
140		/// <returns>Empty plotter without any axes, navigation, etc.</returns>
141		public static ChartPlotter CreateEmpty()
142		{
143			return new ChartPlotter(PlotterLoadMode.OnlyViewport);
144		}
145
146		public void BeginLongOperation()
147		{
148			LongOperationsIndicator.BeginLongOperation(this);
149		}
150
151		public void EndLongOperation()
152		{
153			LongOperationsIndicator.EndLongOperation(this);
154		}
155
156		#region Default charts
157
158		private MouseNavigation mouseNavigation;
159		/// <summary>
160		/// Gets the default mouse navigation of ChartPlotter.
161		/// </summary>
162		/// <value>The mouse navigation.</value>
163		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
164		public MouseNavigation MouseNavigation
165		{
166			get { return mouseNavigation; }
167		}
168
169		private KeyboardNavigation keyboardNavigation;
170		/// <summary>
171		/// Gets the default keyboard navigation of ChartPlotter.
172		/// </summary>
173		/// <value>The keyboard navigation.</value>
174		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
175		public KeyboardNavigation KeyboardNavigation
176		{
177			get { return keyboardNavigation; }
178		}
179
180		private DefaultContextMenu defaultContextMenu;
181		/// <summary>
182		/// Gets the default context menu of ChartPlotter.
183		/// </summary>
184		/// <value>The default context menu.</value>
185		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
186		public DefaultContextMenu DefaultContextMenu
187		{
188			get { return defaultContextMenu; }
189		}
190
191		private AxisNavigation horizontalAxisNavigation;
192		/// <summary>
193		/// Gets the default horizontal axis navigation of ChartPlotter.
194		/// </summary>
195		/// <value>The horizontal axis navigation.</value>
196		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
197		public AxisNavigation HorizontalAxisNavigation
198		{
199			get { return horizontalAxisNavigation; }
200		}
201
202		private AxisNavigation verticalAxisNavigation;
203		/// <summary>
204		/// Gets the default vertical axis navigation of ChartPlotter.
205		/// </summary>
206		/// <value>The vertical axis navigation.</value>
207		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
208		public AxisNavigation VerticalAxisNavigation
209		{
210			get { return verticalAxisNavigation; }
211		}
212
213		/// <summary>
214		/// Gets the default axis grid of ChartPlotter.
215		/// </summary>
216		/// <value>The axis grid.</value>
217		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
218		public AxisGrid AxisGrid
219		{
220			get { return axisGrid; }
221		}
222
223		#endregion
224
225		private void OnHorizontalAxisTicksChanged(object sender, EventArgs e)
226		{
227			GeneralAxis axis = (GeneralAxis)sender;
228			UpdateHorizontalTicks(axis);
229		}
230
231		private void UpdateHorizontalTicks(GeneralAxis axis)
232		{
233			axisGrid.BeginTicksUpdate();
234
235			if (axis != null)
236			{
237				axisGrid.HorizontalTicks = axis.ScreenTicks;
238				axisGrid.MinorHorizontalTicks = axis.MinorScreenTicks;
239			}
240			else
241			{
242				axisGrid.HorizontalTicks = null;
243				axisGrid.MinorHorizontalTicks = null;
244			}
245
246			axisGrid.EndTicksUpdate();
247		}
248
249		private void OnVerticalAxisTicksChanged(object sender, EventArgs e)
250		{
251			GeneralAxis axis = (GeneralAxis)sender;
252			UpdateVerticalTicks(axis);
253		}
254
255		private void UpdateVerticalTicks(GeneralAxis axis)
256		{
257			axisGrid.BeginTicksUpdate();
258
259			if (axis != null)
260			{
261				axisGrid.VerticalTicks = axis.ScreenTicks;
262				axisGrid.MinorVerticalTicks = axis.MinorScreenTicks;
263			}
264			else
265			{
266				axisGrid.VerticalTicks = null;
267				axisGrid.MinorVerticalTicks = null;
268			}
269
270			axisGrid.EndTicksUpdate();
271		}
272
273		bool keepOldAxis = false;
274		bool updatingAxis = false;
275
276		/// <summary>
277		/// Gets or sets the main vertical axis of ChartPlotter.
278		/// Main vertical axis of ChartPlotter is axis which ticks are used to draw horizontal lines on AxisGrid.
279		/// Value can be set to null to completely remove main vertical axis.
280		/// </summary>
281		/// <value>The main vertical axis.</value>
282		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
283		public GeneralAxis MainVerticalAxis
284		{
285			get { return verticalAxis; }
286			set
287			{
288				if (updatingAxis)
289					return;
290
291				if (value == null && verticalAxis != null)
292				{
293					if (!keepOldAxis)
294					{
295						Children.Remove(verticalAxis);
296					}
297					verticalAxis.TicksChanged -= OnVerticalAxisTicksChanged;
298					verticalAxis = null;
299
300					UpdateVerticalTicks(verticalAxis);
301
302					return;
303				}
304
305				VerifyAxisType(value.Placement, AxisType.Vertical);
306
307				if (value != verticalAxis)
308				{
309					ValidateVerticalAxis(value);
310
311					updatingAxis = true;
312
313					if (verticalAxis != null)
314					{
315						verticalAxis.TicksChanged -= OnVerticalAxisTicksChanged;
316						SetIsDefaultAxis(verticalAxis, false);
317						if (!keepOldAxis)
318						{
319							Children.Remove(verticalAxis);
320						}
321						value.Visibility = verticalAxis.Visibility;
322					}
323					SetIsDefaultAxis(value, true);
324
325					verticalAxis = value;
326					verticalAxis.TicksChanged += OnVerticalAxisTicksChanged;
327
328					if (!Children.Contains(value))
329					{
330						Children.Add(value);
331					}
332
333					UpdateVerticalTicks(value);
334					OnVerticalAxisChanged();
335
336					updatingAxis = false;
337				}
338			}
339		}
340
341		protected virtual void OnVerticalAxisChanged() { }
342		protected virtual void ValidateVerticalAxis(GeneralAxis axis) { }
343
344		/// <summary>
345		/// Gets or sets the main horizontal axis visibility.
346		/// </summary>
347		/// <value>The main horizontal axis visibility.</value>
348		public Visibility MainHorizontalAxisVisibility
349		{
350			get { return MainHorizontalAxis != null ? ((UIElement)MainHorizontalAxis).Visibility : Visibility.Hidden; }
351			set
352			{
353				if (MainHorizontalAxis != null)
354				{
355					((UIElement)MainHorizontalAxis).Visibility = value;
356				}
357			}
358		}
359
360		/// <summary>
361		/// Gets or sets the main vertical axis visibility.
362		/// </summary>
363		/// <value>The main vertical axis visibility.</value>
364		public Visibility MainVerticalAxisVisibility
365		{
366			get { return MainVerticalAxis != null ? ((UIElement)MainVerticalAxis).Visibility : Visibility.Hidden; }
367			set
368			{
369				if (MainVerticalAxis != null)
370				{
371					((UIElement)MainVerticalAxis).Visibility = value;
372				}
373			}
374		}
375
376		/// <summary>
377		/// Gets or sets the main horizontal axis of ChartPlotter.
378		/// Main horizontal axis of ChartPlotter is axis which ticks are used to draw vertical lines on AxisGrid.
379		/// Value can be set to null to completely remove main horizontal axis.
380		/// </summary>
381		/// <value>The main horizontal axis.</value>
382		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
383		public GeneralAxis MainHorizontalAxis
384		{
385			get { return horizontalAxis; }
386			set
387			{
388				if (updatingAxis)
389					return;
390
391				if (value == null && horizontalAxis != null)
392				{
393					Children.Remove(horizontalAxis);
394					horizontalAxis.TicksChanged -= OnHorizontalAxisTicksChanged;
395					horizontalAxis = null;
396
397					UpdateHorizontalTicks(horizontalAxis);
398
399					return;
400				}
401
402				VerifyAxisType(value.Placement, AxisType.Horizontal);
403
404				if (value != horizontalAxis)
405				{
406					ValidateHorizontalAxis(value);
407
408					updatingAxis = true;
409
410					if (horizontalAxis != null)
411					{
412						horizontalAxis.TicksChanged -= OnHorizontalAxisTicksChanged;
413						SetIsDefaultAxis(horizontalAxis, false);
414						if (!keepOldAxis)
415						{
416							Children.Remove(horizontalAxis);
417						}
418						value.Visibility = horizontalAxis.Visibility;
419					}
420					SetIsDefaultAxis(value, true);
421
422					horizontalAxis = value;
423					horizontalAxis.TicksChanged += OnHorizontalAxisTicksChanged;
424
425					if (!Children.Contains(value))
426					{
427						Children.Add(value);
428					}
429
430					UpdateHorizontalTicks(value);
431					OnHorizontalAxisChanged();
432
433					updatingAxis = false;
434				}
435			}
436		}
437
438		protected virtual void OnHorizontalAxisChanged() { }
439		protected virtual void ValidateHorizontalAxis(GeneralAxis axis) { }
440
441		private static void VerifyAxisType(AxisPlacement axisPlacement, AxisType axisType)
442		{
443			bool result = false;
444			switch (axisPlacement)
445			{
446				case AxisPlacement.Left:
447				case AxisPlacement.Right:
448					result = axisType == AxisType.Vertical;
449					break;
450				case AxisPlacement.Top:
451				case AxisPlacement.Bottom:
452					result = axisType == AxisType.Horizontal;
453					break;
454				default:
455					break;
456			}
457
458			if (!result)
459				throw new ArgumentException(Strings.Exceptions.InvalidAxisPlacement);
460		}
461
462		protected override void OnIsDefaultAxisChangedCore(DependencyObject d, DependencyPropertyChangedEventArgs e)
463		{
464			GeneralAxis axis = d as GeneralAxis;
465			if (axis != null)
466			{
467				bool value = (bool)e.NewValue;
468				bool oldKeepOldAxis = keepOldAxis;
469
470				bool horizontal = axis.Placement == AxisPlacement.Bottom || axis.Placement == AxisPlacement.Top;
471				keepOldAxis = true;
472
473				if (value && horizontal)
474				{
475					MainHorizontalAxis = axis;
476				}
477				else if (value && !horizontal)
478				{
479					MainVerticalAxis = axis;
480				}
481				else if (!value && horizontal)
482				{
483					MainHorizontalAxis = null;
484				}
485				else if (!value && !horizontal)
486				{
487					MainVerticalAxis = null;
488				}
489
490				keepOldAxis = oldKeepOldAxis;
491			}
492		}
493
494		/// <summary>
495		/// Gets the default legend of ChartPlotter.
496		/// </summary>
497		/// <value>The legend.</value>
498		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
499		public Legend Legend
500		{
501			get { return legend; }
502		}
503
504		/// <summary>
505		/// Gets or sets the visibility of legend.
506		/// </summary>
507		/// <value>The legend visibility.</value>
508		public Visibility LegendVisibility
509		{
510			get { return legend.Visibility; }
511			set { legend.Visibility = value; }
512		}
513
514		public bool LegendVisible
515		{
516			get { return legend.LegendVisible; }
517			set { legend.LegendVisible = value; }
518		}
519
520		private enum AxisType
521		{
522			Horizontal,
523			Vertical
524		}
525	}
526}