ComparisonPlot.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. using Microsoft.VisualBasic.CompilerServices;
  2. using MuchInfo.Chart.Data.EnumTypes;
  3. using MuchInfo.Chart.Data.Interfaces;
  4. using MuchInfo.Chart.Data.Models;
  5. using MuchInfo.Chart.Infrastructure.Utilities;
  6. using MuchInfo.Chart.WPF.Helpers;
  7. using MuchInfo.Chart.WPF.Primitives.Interfaces;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Linq;
  11. using System.Runtime.CompilerServices;
  12. using System.Windows;
  13. using System.Windows.Media;
  14. namespace MuchInfo.Chart.WPF.Primitives
  15. {
  16. public class ComparisonPlot : LinePlot
  17. {
  18. #region Fields
  19. private GoodsInfo _currentGoods;
  20. private ChartDataSet _data;
  21. private bool _isActive;
  22. private TimeSpan _timeSpan;
  23. #endregion Fields
  24. #region Constructors
  25. /// <summary>
  26. /// Initializes a new instance of the <see cref="ComparisonPlot"/> class.
  27. /// </summary>
  28. public ComparisonPlot()
  29. {
  30. this._timeSpan = new TimeSpan(1, 0, 0, 0);
  31. this._isActive = false;
  32. this._data = new ChartDataSet();
  33. }
  34. /// <summary>
  35. ///
  36. /// </summary>
  37. /// <param name="indeicator"></param>
  38. /// <param name="chart"></param>
  39. /// <param name="goodsInfo"></param>
  40. public ComparisonPlot(IndicatorModel indeicator, Chart chart, GoodsInfo goodsInfo)
  41. : base(indeicator, chart)
  42. {
  43. this.mChart = chart;
  44. this.CurrentGoods = goodsInfo;
  45. this._timeSpan = new TimeSpan(1, 0, 0, 0);
  46. this._isActive = false;
  47. this._data = new ChartDataSet();
  48. //bool flag = calc is IComparisonCalculation;
  49. //if (flag)
  50. //{
  51. // bool flag2 = SymbolManager.Manager().AllSymbolsLoaded();
  52. // if (flag2)
  53. // {
  54. // this.Symbol = SymbolManager.Manager().SymbolFromSymbol(((IComparisonCalculation)calc).DefaultSymbol());
  55. // }
  56. // else
  57. // {
  58. // this.mSymSearch = SymbolManager.Manager().FetchSingleSymbolBySymbol(((IComparisonCalculation)calc).DefaultSymbol());
  59. // this.mSymSearch.GoGetIt();
  60. // }
  61. //}
  62. this.UpdateOutData();
  63. }
  64. #endregion Constructors
  65. #region Properties
  66. #region Public Properties
  67. /// <summary>
  68. /// Gets or sets the current goods.
  69. /// </summary>
  70. public GoodsInfo CurrentGoods
  71. {
  72. get
  73. {
  74. return this._currentGoods;
  75. }
  76. set
  77. {
  78. bool flag = false;
  79. bool flag2 = value == null && this._currentGoods != null;
  80. if (flag2)
  81. {
  82. flag = true;
  83. }
  84. else
  85. {
  86. flag2 = (value != null && this._currentGoods == null);
  87. if (flag2)
  88. {
  89. flag = true;
  90. }
  91. else
  92. {
  93. flag2 = (value != null && this._currentGoods != null && Operators.CompareString(this._currentGoods.Symbol, value.Symbol, false) != 0);
  94. if (flag2)
  95. {
  96. flag = true;
  97. }
  98. }
  99. }
  100. flag2 = flag;
  101. if (flag2)
  102. {
  103. this._currentGoods = value;
  104. this.UpdateData();
  105. }
  106. }
  107. }
  108. /// <summary>
  109. /// Gets or sets the m data.
  110. /// </summary>
  111. public virtual ChartDataSet Data
  112. {
  113. get
  114. {
  115. return this._data;
  116. }
  117. set
  118. {
  119. var obj = new LineDataSetDataChangedEventHandler(this.OnDataChanged);
  120. bool flag = this._data != null;
  121. if (flag)
  122. {
  123. this._data.DataChanged -= obj;
  124. }
  125. this._data = value;
  126. flag = (this._data != null);
  127. if (flag)
  128. {
  129. this._data.DataChanged += obj;
  130. }
  131. }
  132. }
  133. /// <summary>
  134. /// Gets or sets a value indicating whether this instance is active.
  135. /// </summary>
  136. public bool IsActive
  137. {
  138. get
  139. {
  140. return this._isActive;
  141. }
  142. set
  143. {
  144. bool flag = value != this._isActive;
  145. if (flag)
  146. {
  147. this._isActive = value;
  148. this.UpdateData();
  149. }
  150. }
  151. }
  152. /// <summary>
  153. /// Gets or sets the time frame.
  154. /// </summary>
  155. public TimeSpan TimeFrame
  156. {
  157. get
  158. {
  159. return this._timeSpan;
  160. }
  161. set
  162. {
  163. bool flag = !(value == this._timeSpan);
  164. if (flag)
  165. {
  166. this._timeSpan = value;
  167. this.UpdateData();
  168. }
  169. }
  170. }
  171. #endregion Public Properties
  172. #endregion Properties
  173. #region Methods
  174. #region Public Methods
  175. /// <summary>
  176. /// Sources the data change.
  177. /// </summary>
  178. /// <param name="change">The change.</param>
  179. public override void SourceDataChange(object change)
  180. {
  181. base.SourceDataChange(RuntimeHelpers.GetObjectValue(change));
  182. bool flag = this.mChart != null;
  183. if (flag)
  184. {
  185. this.mChart.Refresh(true);
  186. }
  187. }
  188. #endregion Public Methods
  189. #region Internal Methods
  190. /// <summary>
  191. /// 重写返回空:不添加LegendButton
  192. /// </summary>
  193. /// <returns>List{FrameworkElement}.</returns>
  194. internal List<FrameworkElement> AddLegendButton()
  195. {
  196. return new List<FrameworkElement>();
  197. }
  198. /// <summary>
  199. /// Builds the plot.
  200. /// </summary>
  201. /// <param name="owner">The owner.</param>
  202. /// <param name="aScale">A scale.</param>
  203. /// <param name="dateScale">The date scale.</param>
  204. /// <param name="valScale">The val scale.</param>
  205. /// <param name="aRect">A rect.</param>
  206. /// <returns>List{FrameworkElement}.</returns>
  207. internal override List<FrameworkElement> BuildPlot(Chart owner, ScaleLayer aScale, IDateScaler dateScale, IValueScaler valScale, Rect aRect)
  208. {
  209. // bool flag = this.PlotCalculation is ComparisonCalculation;
  210. bool flag = true;
  211. List<FrameworkElement> result;
  212. if (flag)
  213. {
  214. this.mChart = owner;
  215. this.mScale = aScale;
  216. flag = !this._isActive;
  217. if (flag)
  218. {
  219. result = new List<FrameworkElement>();
  220. }
  221. else
  222. {
  223. var painter = new PlotPainter(aRect, null, 1.2);
  224. switch (this.Indicator.LinePlotType)
  225. {
  226. case LinePlotType.Candlestick:
  227. this.BuildCandlestickPoints(painter, dateScale, valScale, aRect);
  228. break;
  229. case LinePlotType.Line: //分时图叠加
  230. this.BuildAreaLine(painter, dateScale, valScale, aRect);
  231. break;
  232. default:
  233. //叠加商品直线画虚线
  234. painter.DashStyle = new DoubleCollection { 3.0, 3.0 };
  235. this.BuildAreaLine(painter, dateScale, valScale, aRect);
  236. break;
  237. }
  238. var list = painter.GetGraph();
  239. if (list != null && list.Any())
  240. {
  241. foreach (var element in list)
  242. {
  243. element.IsHitTestVisible = false;
  244. }
  245. }
  246. result = list;
  247. }
  248. }
  249. else
  250. {
  251. result = base.BuildPlot(owner, aScale, dateScale, valScale, aRect);
  252. }
  253. return result;
  254. }
  255. /// <summary>
  256. /// 检测画图面板中的图例,并返回它们在aDate日期下的数据面板
  257. /// </summary>
  258. /// <param name="aDate">A date.</param>
  259. /// <param name="isDarkBackground">if set to <c>true</c> [is dark background].</param>
  260. /// <param name="isForex">if set to <c>true</c> [is forex].</param>
  261. /// <returns>List{ControlPair}.</returns>
  262. internal override List<ControlPair> GetControlPairs(DateTime aDate, bool isDarkBackground, bool isForex)
  263. {
  264. var digits = isForex ? 4 : 2;
  265. return GetControlPairs(aDate, isDarkBackground, digits);
  266. }
  267. /// <summary>
  268. /// Gets the control pairs.
  269. /// </summary>
  270. /// <param name="aDate">A date.</param>
  271. /// <param name="isDarkBackground">if set to <c>true</c> [is dark background].</param>
  272. /// <param name="digits">The digits.</param>
  273. /// <returns>List{ControlPair}.</returns>
  274. internal override List<ControlPair> GetControlPairs(DateTime aDate, bool isDarkBackground, int digits)
  275. {
  276. // bool flag = this.PlotCalculation is ComparisonCalculation;
  277. bool flag = true;
  278. checked
  279. {
  280. List<ControlPair> result;
  281. if (flag)
  282. {
  283. var list = new List<ControlPair>();
  284. flag = (this._isActive && this.OutputSource != null && this.OutputSource.CalculateDataPoints != null);
  285. if (flag)
  286. {
  287. var list2 = this.OutputSource.CalculateDataPoints;
  288. int num = list2.Count - 1;
  289. while (true)
  290. {
  291. int arg_E3_0 = num;
  292. int num2 = 0;
  293. if (arg_E3_0 < num2)
  294. {
  295. goto IL_E5;
  296. }
  297. flag = (DateTime.Compare(list2[num].Date, aDate) == 0);
  298. if (flag)
  299. {
  300. bool flag2 = this._currentGoods != null;
  301. if (flag2)
  302. {
  303. break;
  304. }
  305. }
  306. num += -1;
  307. }
  308. list.Add(this.GetPointerPair(this._currentGoods.Symbol, this.GetPlotColor(), list2[num].Value, false, digits, false));
  309. }
  310. IL_E5:
  311. result = list;
  312. }
  313. else
  314. {
  315. result = base.GetControlPairs(aDate, isDarkBackground, digits);
  316. }
  317. return result;
  318. }
  319. }
  320. /// <summary>
  321. /// Updates the out data.
  322. /// </summary>
  323. internal void UpdateOutData()
  324. {
  325. //bool flag = this.PlotCalculation == null;
  326. //if (!flag)
  327. //{
  328. // flag = (this.PlotCalculation is IComparisonCalculation);
  329. // if (flag)
  330. // {
  331. // this.mOutputData.OnDataSetDataChanged(((IComparisonCalculation)this.PlotCalculation).CalculateComparison(this.mSource, this.Data, this.CurrentPlotColor(), this._currentGoods));
  332. // }
  333. // else
  334. // {
  335. // this.mOutputData.OnDataSetDataChanged(((ILineCalculation)this.PlotCalculation).Calculate(this.mSource, this.CurrentPlotColor()));
  336. // }
  337. //}
  338. }
  339. #endregion Internal Methods
  340. #region Protected Methods
  341. /// <summary>
  342. /// Deletes the data.
  343. /// </summary>
  344. protected override void DeleteData()
  345. {
  346. base.DeleteData();
  347. this._currentGoods = null;
  348. this.UpdateData();
  349. if (_data != null)
  350. {
  351. this._data.OnDelete();
  352. this._data = null;
  353. }
  354. }
  355. protected Color UpBrush(IndicatorModel indicator)
  356. {
  357. return this.CurrentPlotColor();
  358. }
  359. #endregion Protected Methods
  360. #region Private Methods
  361. /// <summary>
  362. /// Builds the area line.
  363. /// </summary>
  364. /// <param name="painter">The painter.</param>
  365. /// <param name="dateScale">The date scale.</param>
  366. /// <param name="valScale">The val scale.</param>
  367. /// <param name="aRect">A rect.</param>
  368. private void BuildAreaLine(PlotPainter painter, IDateScaler dateScale, IValueScaler valScale, Rect aRect)
  369. {
  370. var destionation = GetComparisonList(dateScale);
  371. if (destionation == null || !destionation.Any()) return;
  372. //if (destionation.Count < 2) return;
  373. float num = 1;
  374. if (this.mChart != null && this.mChart.CycleType == CycleType.TimeSharing)
  375. {
  376. if (Math.Abs(CurrentGoods.PreClose) > 0)
  377. {
  378. num = ((ValueScalerArithmetic)valScale).GetPercentBaseline() / CurrentGoods.PreClose;
  379. }
  380. }
  381. else
  382. {
  383. num = ((ValueScalerArithmetic)valScale).GetPercentBaseline() / destionation[1].Value;
  384. }
  385. for (var i = 1; i < destionation.Count; i++)
  386. {
  387. var startIndex = dateScale.IndexFromDate(destionation[i - 1].Date);
  388. var endIndex = dateScale.IndexFromDate(destionation[i].Date);
  389. if (startIndex < 0 || endIndex < 0) continue;
  390. var start = dateScale.XforDate(destionation[i - 1].Date);
  391. var end = dateScale.XforDate(destionation[i].Date);
  392. if (start < 0 || end < 0 || start.Equals(end)) continue;
  393. var lineGeometry = new LineGeometry
  394. {
  395. //lineplot都加上了0.5buffer.
  396. StartPoint = new Point((double)start, 0.5 + (double)valScale.ScaledY(destionation[(i - 1)].Value * num, aRect)),
  397. EndPoint = new Point((double)end, 0.5 + (double)valScale.ScaledY(destionation[i].Value * num, aRect))
  398. };
  399. painter.AddLine(lineGeometry, this.CurrentPlotColor());
  400. }
  401. }
  402. /// <summary>
  403. /// Builds the candlestick points.
  404. /// </summary>
  405. /// <param name="painter">The painter.</param>
  406. /// <param name="dateScale">The date scale.</param>
  407. /// <param name="valScale">The val scale.</param>
  408. /// <param name="aRect">A rect.</param>
  409. private void BuildCandlestickPoints(PlotPainter painter, IDateScaler dateScale, IValueScaler valScale, Rect aRect)
  410. {
  411. var list = GetComparisonList(dateScale);
  412. if (list == null || !list.Any()) return;
  413. //初始化时出现101需修改
  414. //var index = list.Count > 2 ? 1 : 0;
  415. var index = 0;
  416. var percent = ((ValueScalerArithmetic)valScale).GetPercentBaseline() / list[index].Value;
  417. var num = (float)((int)Math.Round(unchecked(0.3 * (double)dateScale.DistanceBetweenDates())));
  418. var start = dateScale.FirstVisibleIndexFromData(list);
  419. var length = list.Count;
  420. for (var i = start; i < length; i++)
  421. {
  422. var current = list[i];
  423. var visible = dateScale.DateVisible(current.Date);
  424. if (!visible) continue;
  425. var ohlcDataPoint = current as IOHLCDataPoint;
  426. if (ohlcDataPoint == null) continue;
  427. var dateX = (float)((int)Math.Round((double)dateScale.XforDate(ohlcDataPoint.Date)));
  428. var color = this.CurrentPlotColor();
  429. var isRising = false;
  430. var isDeclining = false;
  431. if (ohlcDataPoint.Close > ohlcDataPoint.Open)
  432. {
  433. isRising = true;
  434. }
  435. else if (ohlcDataPoint.Close < ohlcDataPoint.Open)
  436. {
  437. isDeclining = true;
  438. }
  439. Rect rect;
  440. if (!isRising && !isDeclining)
  441. {
  442. //相等画直线
  443. rect = new Rect(dateX - num + 0.5, 0.5 + valScale.ScaledY(ohlcDataPoint.Open * percent, aRect), 2f * num, 0);
  444. painter.AddLine(new LineGeometry
  445. {
  446. StartPoint = new Point(rect.X - 0.5, rect.Y),
  447. EndPoint = new Point(rect.Right + 0.5, rect.Y)
  448. }, color);
  449. }
  450. else if (isRising)
  451. {
  452. rect = new Rect(dateX - num + 0.5,
  453. 0.5 + (double)valScale.ScaledY(ohlcDataPoint.Close * percent, aRect), 2f * num, 0);
  454. rect.Height = (0.5 + (double)valScale.ScaledY(ohlcDataPoint.Open * percent, aRect) - rect.Top);
  455. var rectangleGeometry = new RectangleGeometry { Rect = rect };
  456. if (mChart.FillComparisonCandle)
  457. {
  458. painter.AddShape(rectangleGeometry, color);
  459. }
  460. else
  461. {
  462. painter.AddLine(rectangleGeometry, color);
  463. }
  464. }
  465. else
  466. {
  467. rect = new Rect(dateX - num + 0.5, 0.5 + (double)valScale.ScaledY(ohlcDataPoint.Open * percent, aRect), 2f * num, 0);
  468. rect.Height = (0.5 + (double)valScale.ScaledY(ohlcDataPoint.Close * percent, aRect) - rect.Top);
  469. var rectangleGeometry = new RectangleGeometry { Rect = (rect) };
  470. if (mChart.FillComparisonCandle)
  471. {
  472. painter.AddShape(rectangleGeometry, color);
  473. }
  474. else
  475. {
  476. painter.AddLine(rectangleGeometry, color);
  477. }
  478. }
  479. painter.AddLine(new LineGeometry
  480. {
  481. StartPoint = new Point(dateX + 0.5, (double)valScale.ScaledY(ohlcDataPoint.High * percent, aRect)),
  482. EndPoint = new Point((double)dateX + 0.5, rect.Top)
  483. }, color);
  484. painter.AddLine(new LineGeometry
  485. {
  486. StartPoint = new Point(dateX + 0.5, (double)valScale.ScaledY(ohlcDataPoint.Low * percent, aRect)),
  487. EndPoint = new Point(dateX + 0.5, rect.Bottom)
  488. }, color);
  489. }
  490. }
  491. private List<ILineDataPoint> GetComparisonList(IDateScaler dateScale)
  492. {
  493. var list = this.OutputSource.CalculateDataPoints;
  494. if (list == null || !list.Any()) return null;
  495. var firstIndex = dateScale.FirstVisibleIndexFromData(list);
  496. var lastIndex = dateScale.LastVisibleIndexFromData(list);
  497. //只添加包含的时间
  498. var destionation = new List<ILineDataPoint>();
  499. for (var i = firstIndex; i <= lastIndex; i++)
  500. {
  501. var current = list[i].Date;
  502. if (dateScale.DateContains(current))
  503. {
  504. destionation.Add(list[i]);
  505. }
  506. else if (this.mChart.CycleType == CycleType.TimeSharing)
  507. {
  508. destionation.Add(list[i]);
  509. }
  510. }
  511. return destionation;
  512. }
  513. /// <summary>
  514. /// Called when [data changed].
  515. /// </summary>
  516. /// <param name="change">The change.</param>
  517. private void OnDataChanged(object change)
  518. {
  519. this.SourceDataChange(RuntimeHelpers.GetObjectValue(change));
  520. }
  521. /// <summary>
  522. /// Updates the data.
  523. /// </summary>
  524. private void UpdateData()
  525. {
  526. bool flag = this._currentGoods == null || !this._isActive;
  527. if (flag)
  528. {
  529. bool flag2 = this.Data != null;
  530. if (flag2)
  531. {
  532. this.Data.OnDelete();
  533. this.Data = null;
  534. }
  535. }
  536. else
  537. {
  538. bool flag2 = this.Data == null;
  539. if (flag2)
  540. {
  541. this.Data = new ChartDataSet();
  542. }
  543. if (mChart.ComparisionTimeShareDic.ContainsKey(CurrentGoods.GoodsCode) &&
  544. mChart.ComparisionDictionary.ContainsKey(this.CurrentGoods.Symbol))
  545. {
  546. var dataPoints = mChart.CycleType == CycleType.TimeSharing
  547. ? mChart.ComparisionTimeShareDic[CurrentGoods.GoodsCode]
  548. : mChart.ComparisionDictionary[this.CurrentGoods.Symbol];
  549. this.Data.DataPoints = dataPoints;
  550. }
  551. this.UpdateOutData();
  552. }
  553. }
  554. #endregion Private Methods
  555. #endregion Methods
  556. }
  557. }