PageRenderTime 65ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

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