Plot.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. // --------------------------------------------------------------------------------------------------------------------
  2. // <copyright file="Plot.cs" company="OxyPlot">
  3. // Copyright (c) 2014 OxyPlot contributors
  4. // </copyright>
  5. // <summary>
  6. // Represents a control that displays a <see cref="PlotModel" />.
  7. // </summary>
  8. // --------------------------------------------------------------------------------------------------------------------
  9. using Avalonia;
  10. namespace OxyPlot.Avalonia
  11. {
  12. using global::Avalonia.Controls;
  13. using global::Avalonia.LogicalTree;
  14. using global::Avalonia.VisualTree;
  15. using System.Collections.ObjectModel;
  16. using System.Collections.Specialized;
  17. using System.Linq;
  18. /// <summary>
  19. /// Represents a control that displays a <see cref="PlotModel" />.
  20. /// </summary>
  21. public partial class Plot : PlotBase, IPlot
  22. {
  23. /// <summary>
  24. /// The internal model.
  25. /// </summary>
  26. private readonly PlotModel internalModel;
  27. /// <summary>
  28. /// The default controller.
  29. /// </summary>
  30. private readonly IPlotController defaultController;
  31. /// <summary>
  32. /// Initializes a new instance of the <see cref="Plot" /> class.
  33. /// </summary>
  34. public Plot()
  35. {
  36. series = new ObservableCollection<Series>();
  37. axes = new ObservableCollection<Axis>();
  38. annotations = new ObservableCollection<Annotation>();
  39. legends = new ObservableCollection<Legend>();
  40. series.CollectionChanged += OnSeriesChanged;
  41. axes.CollectionChanged += OnAxesChanged;
  42. annotations.CollectionChanged += OnAnnotationsChanged;
  43. legends.CollectionChanged += this.OnAnnotationsChanged;
  44. defaultController = new PlotController();
  45. internalModel = new PlotModel();
  46. ((IPlotModel)internalModel).AttachPlotView(this);
  47. }
  48. /// <summary>
  49. /// Gets the annotations.
  50. /// </summary>
  51. /// <value>The annotations.</value>
  52. public ObservableCollection<Annotation> Annotations
  53. {
  54. get
  55. {
  56. return annotations;
  57. }
  58. }
  59. /// <summary>
  60. /// Gets the actual model.
  61. /// </summary>
  62. /// <value>The actual model.</value>
  63. public override PlotModel ActualModel
  64. {
  65. get
  66. {
  67. return internalModel;
  68. }
  69. }
  70. /// <summary>
  71. /// Gets the actual Plot controller.
  72. /// </summary>
  73. /// <value>The actual Plot controller.</value>
  74. public override IPlotController ActualController
  75. {
  76. get
  77. {
  78. return defaultController;
  79. }
  80. }
  81. /// <summary>
  82. /// Updates the model. If Model==<c>null</c>, an internal model will be created. The ActualModel.Update will be called (updates all series data).
  83. /// </summary>
  84. /// <param name="updateData">if set to <c>true</c> , all data collections will be updated.</param>
  85. protected new void UpdateModel(bool updateData = true)
  86. {
  87. SynchronizeProperties();
  88. SynchronizeSeries();
  89. SynchronizeAxes();
  90. SynchronizeAnnotations();
  91. SynchronizeLegends();
  92. // TODO: does this achieve anything? we always call InvalidatePlot after UpdateModel
  93. base.UpdateModel(updateData);
  94. }
  95. /// <summary>
  96. /// Called when the visual appearance is changed.
  97. /// </summary>
  98. protected void OnAppearanceChanged()
  99. {
  100. UpdateModel(false);
  101. InvalidatePlot(false);
  102. }
  103. void IPlot.ElementAppearanceChanged(object element)
  104. {
  105. // TODO: determine type of element to perform a more fine-grained update
  106. this.UpdateModel(false);
  107. base.InvalidatePlot(false);
  108. }
  109. void IPlot.ElementDataChanged(object element)
  110. {
  111. // TODO: determine type of element to perform a more fine-grained update
  112. this.UpdateModel(true);
  113. base.InvalidatePlot(true);
  114. }
  115. /// <summary>
  116. /// Called when the visual appearance is changed.
  117. /// </summary>
  118. /// <param name="d">The d.</param>
  119. /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs" /> instance containing the event data.</param>
  120. private static void AppearanceChanged(global::Avalonia.AvaloniaObject d, global::Avalonia.AvaloniaPropertyChangedEventArgs e)
  121. {
  122. ((Plot)d).OnAppearanceChanged();
  123. }
  124. /// <summary>
  125. /// Called when annotations is changed.
  126. /// </summary>
  127. /// <param name="sender">The sender.</param>
  128. /// <param name="e">The <see cref="System.Collections.Specialized.NotifyCollectionChangedEventArgs" /> instance containing the event data.</param>
  129. private void OnAnnotationsChanged(object sender, NotifyCollectionChangedEventArgs e)
  130. {
  131. SyncLogicalTree(e);
  132. }
  133. /// <summary>
  134. /// Called when axes is changed.
  135. /// </summary>
  136. /// <param name="sender">The sender.</param>
  137. /// <param name="e">The <see cref="System.Collections.Specialized.NotifyCollectionChangedEventArgs" /> instance containing the event data.</param>
  138. private void OnAxesChanged(object sender, NotifyCollectionChangedEventArgs e)
  139. {
  140. SyncLogicalTree(e);
  141. }
  142. /// <summary>
  143. /// Called when series is changed.
  144. /// </summary>
  145. /// <param name="sender">The sender.</param>
  146. /// <param name="e">The <see cref="System.Collections.Specialized.NotifyCollectionChangedEventArgs" /> instance containing the event data.</param>
  147. private void OnSeriesChanged(object sender, NotifyCollectionChangedEventArgs e)
  148. {
  149. SyncLogicalTree(e);
  150. }
  151. /// <summary>
  152. /// Synchronizes the logical tree.
  153. /// </summary>
  154. /// <param name="e">The <see cref="System.Collections.Specialized.NotifyCollectionChangedEventArgs" /> instance containing the event data.</param>
  155. private void SyncLogicalTree(NotifyCollectionChangedEventArgs e)
  156. {
  157. // In order to get DataContext and binding to work with the series, axes and annotations
  158. // we add the items to the logical tree
  159. if (e.NewItems != null)
  160. {
  161. foreach (var item in e.NewItems.OfType<ISetLogicalParent>())
  162. {
  163. item.SetParent(this);
  164. }
  165. LogicalChildren.AddRange(e.NewItems.OfType<ILogical>());
  166. VisualChildren.AddRange(e.NewItems.OfType<Visual>());
  167. }
  168. if (e.OldItems != null)
  169. {
  170. foreach (var item in e.OldItems.OfType<ISetLogicalParent>())
  171. {
  172. item.SetParent(null);
  173. }
  174. foreach (var item in e.OldItems)
  175. {
  176. LogicalChildren.Remove((ILogical)item);
  177. VisualChildren.Remove((Visual)item);
  178. }
  179. }
  180. this.OnAppearanceChanged();
  181. }
  182. /// <summary>
  183. /// Synchronize properties in the internal Plot model
  184. /// </summary>
  185. private void SynchronizeProperties()
  186. {
  187. var m = internalModel;
  188. m.PlotType = PlotType;
  189. m.PlotMargins = PlotMargins.ToOxyThickness();
  190. m.Padding = Padding.ToOxyThickness();
  191. m.TitlePadding = TitlePadding;
  192. m.Culture = Culture;
  193. m.DefaultColors = DefaultColors.Select(c => c.ToOxyColor()).ToArray();
  194. m.DefaultFont = DefaultFont;
  195. m.DefaultFontSize = DefaultFontSize;
  196. m.Title = Title;
  197. m.TitleColor = TitleColor.ToOxyColor();
  198. m.TitleFont = TitleFont;
  199. m.TitleFontSize = TitleFontSize;
  200. m.TitleFontWeight = (int)TitleFontWeight;
  201. m.TitleToolTip = TitleToolTip;
  202. m.Subtitle = Subtitle;
  203. m.SubtitleColor = SubtitleColor.ToOxyColor();
  204. m.SubtitleFont = SubtitleFont;
  205. m.SubtitleFontSize = SubtitleFontSize;
  206. m.SubtitleFontWeight = (int)SubtitleFontWeight;
  207. m.TextColor = TextColor.ToOxyColor();
  208. m.SelectionColor = SelectionColor.ToOxyColor();
  209. m.RenderingDecorator = RenderingDecorator;
  210. m.AxisTierDistance = AxisTierDistance;
  211. m.IsLegendVisible = IsLegendVisible;
  212. m.PlotAreaBackground = PlotAreaBackground.ToOxyColor();
  213. m.PlotAreaBorderColor = PlotAreaBorderColor.ToOxyColor();
  214. m.PlotAreaBorderThickness = PlotAreaBorderThickness.ToOxyThickness();
  215. }
  216. /// <summary>
  217. /// Synchronizes the annotations in the internal model.
  218. /// </summary>
  219. private void SynchronizeAnnotations()
  220. {
  221. internalModel.Annotations.Clear();
  222. foreach (var a in Annotations)
  223. {
  224. internalModel.Annotations.Add(a.CreateModel());
  225. }
  226. }
  227. /// <summary>
  228. /// Synchronizes the axes in the internal model.
  229. /// </summary>
  230. private void SynchronizeAxes()
  231. {
  232. internalModel.Axes.Clear();
  233. foreach (var a in Axes)
  234. {
  235. internalModel.Axes.Add(a.CreateModel());
  236. }
  237. }
  238. /// <summary>
  239. /// Synchronizes the series in the internal model.
  240. /// </summary>
  241. private void SynchronizeSeries()
  242. {
  243. internalModel.Series.Clear();
  244. foreach (var s in Series)
  245. {
  246. internalModel.Series.Add(s.CreateModel());
  247. }
  248. }
  249. /// <summary>
  250. /// Synchronizes the legends in the internal model.
  251. /// </summary>
  252. private void SynchronizeLegends()
  253. {
  254. internalModel.Legends.Clear();
  255. foreach (var l in Legends)
  256. {
  257. internalModel.Legends.Add(l.CreateModel());
  258. }
  259. }
  260. }
  261. }