DateScaleDisplay.cs 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163
  1. using MuchInfo.Chart.Data.Models;
  2. using MuchInfo.Chart.Infrastructure.Helpers;
  3. using MuchInfo.Chart.WPF.Controls.DateScaling;
  4. using MuchInfo.Chart.WPF.Primitives.Interfaces;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Windows;
  9. using System.Windows.Controls;
  10. using System.Windows.Documents;
  11. using System.Windows.Media;
  12. using System.Windows.Shapes;
  13. namespace MuchInfo.Chart.WPF.Primitives
  14. {
  15. /// <summary>
  16. /// 微型数据展示类
  17. /// </summary>
  18. public class DateScaleDisplay : Canvas
  19. {
  20. #region Fields
  21. private Chart _chart;
  22. private List<DateScaleDisplay.DateScaleDisplayItem> _dateScaleDisplayItems;
  23. private FutureDateSplit _futureDateSplit;
  24. private bool _isDark;
  25. private const int minTickWidth = 50;
  26. private const int minTick = 12;
  27. //显示分时图的实线
  28. private List<DateScaleDisplay.DateScaleDisplayItem> _timeSpanScaleDisplayItems;
  29. #endregion Fields
  30. #region Constructors
  31. public DateScaleDisplay(Chart chart)
  32. {
  33. this.ValuePaintMode = DateScaleDisplay.DateScalePaintType.AutoScale;
  34. this.TextColor = Colors.White;
  35. this.LineColor = Colors.LightGray;
  36. this._chart = chart;
  37. this._futureDateSplit = new FutureDateSplit(this, _chart) { VerticalAlignment = VerticalAlignment.Stretch };
  38. this.Children.Add(this._futureDateSplit);
  39. this.MinHeight = 24;
  40. _isDrawGridLines = (this._chart != null && this._chart.GridOpacity > 0) ? true : false;
  41. }
  42. #endregion Constructors
  43. #region Enumerations
  44. public enum DateScalePaintType
  45. {
  46. AutoScale,
  47. LineCount,
  48. Daily,
  49. Weekly,
  50. Monthly,
  51. Quarterly,
  52. Yearly,
  53. FiveYear
  54. }
  55. #endregion Enumerations
  56. #region Properties
  57. #region Public Properties
  58. private readonly bool _isDrawGridLines;
  59. public Color LineColor
  60. {
  61. get;
  62. set;
  63. }
  64. public Color TextColor
  65. {
  66. get;
  67. set;
  68. }
  69. public DateScaleDisplay.DateScalePaintType ValuePaintMode
  70. {
  71. get;
  72. set;
  73. }
  74. #endregion Public Properties
  75. #region Private Properties
  76. private bool DarkBackground
  77. {
  78. get
  79. {
  80. return this._isDark;
  81. }
  82. set
  83. {
  84. bool flag = value != this._isDark;
  85. if (flag)
  86. {
  87. this._isDark = value;
  88. flag = this._isDark;
  89. if (flag)
  90. {
  91. this.TextColor = Colors.White;
  92. this.LineColor = Colors.LightGray;
  93. }
  94. else
  95. {
  96. this.LineColor = Colors.Black;
  97. this.TextColor = Colors.Black;
  98. }
  99. }
  100. }
  101. }
  102. #endregion Private Properties
  103. #endregion Properties
  104. #region Methods
  105. #region Internal Methods
  106. internal void BuildCanvas(IDateScaler dateScale, float left, int paneWidth, bool isForex)
  107. {
  108. if (this._chart != null) this.DarkBackground = this._chart.IsDarkBackground;
  109. this._dateScaleDisplayItems = null;
  110. var allDateScaler = dateScale as AllDateScaler;
  111. if (allDateScaler == null || allDateScaler.Count() == 0)
  112. {
  113. this.CleanupCanvas();
  114. }
  115. else
  116. {
  117. this.CleanupCanvas();
  118. BuildFutureDateSplit(allDateScaler, paneWidth, isForex);
  119. var items = this.BuildDisplayItems((float)allDateScaler.WidthWithBarBuffer(), allDateScaler);
  120. if (items != null && items.Count > 0)
  121. {
  122. //chart宽度
  123. var width = paneWidth + _chart.RightBuffer * 2 + _chart.GetChartPanelOffset() * 2;
  124. foreach (var current in items)
  125. {
  126. //用日期计算位置更准确
  127. //float textBlockLeft = (float)left + (float)allDateScaler.WidthWithBarBuffer() * current.Percent;
  128. var textBlockLeft = (float)((int)Math.Round((double)allDateScaler.XforDate(current.Date)));
  129. textBlockLeft = (float)(Math.Round(textBlockLeft) + 0.5) + (float)this._chart.GetChartPanelOffset();
  130. double textBlockTop = 0d;
  131. if (current.IsTwoLines)
  132. {
  133. textBlockTop = 11d;
  134. }
  135. var textBlock = BuildTextBlock(current.Text, textBlockLeft, textBlockTop);
  136. var flag = (textBlockLeft + GetTextWidth(textBlock.Text)) < width;
  137. if (flag)
  138. {
  139. this.Children.Add(textBlock);
  140. }
  141. }
  142. }
  143. }
  144. }
  145. /// <summary>
  146. /// 创建分时图的横轴坐标
  147. /// </summary>
  148. internal void BuildTimeShareCanvas(IDateScaler dateScale, float left, int paneWidth, bool isForex,
  149. List<OpenCloseTime> openTimes, Chart chart)
  150. {
  151. if (openTimes == null || !openTimes.Any()) return;
  152. var timeSpan = new TimeSpan();
  153. timeSpan = openTimes.Aggregate(timeSpan,
  154. (current, openCloseTime) => current.Add(openCloseTime.CloseTime - openCloseTime.OpenTime));
  155. int addMinutes = 0;
  156. int lineCount = (int)timeSpan.TotalMinutes / 30; //显示分钟线小于12
  157. if (lineCount <= 12)
  158. {
  159. addMinutes = 30;
  160. }
  161. else if (lineCount > 12)
  162. {
  163. lineCount = (int)timeSpan.TotalHours;//一小时显示一网格
  164. if (lineCount <= 12)
  165. {
  166. addMinutes = 60;
  167. }
  168. else
  169. {
  170. lineCount = (int)timeSpan.TotalHours / 2;
  171. addMinutes = 120;
  172. }
  173. }
  174. var openDateList = new List<DateTime>(); //显示开收盘时间线网格(实线)
  175. for (int i = 0; i < openTimes.Count; i++)
  176. {
  177. //openDateList.Add(openTimes[i].OpenTime);
  178. //if (i == openTimes.Count - 1)
  179. //{
  180. // openDateList.Add(openTimes[i].CloseTime);
  181. //}
  182. if (i == 0) openDateList.Add(openTimes[i].OpenTime);
  183. openDateList.Add(openTimes[i].CloseTime);
  184. }
  185. if (openTimes.Count > 0 && openTimes[0].OpenTime == DateTime.MinValue) return;
  186. var avgDateList = new List<DateTime>(); //显示时间线平均网格(虚线)
  187. for (int j = 0; j < openTimes.Count; j++)
  188. {
  189. int indexTime = 0;
  190. var openTime = openTimes[j].OpenTime;
  191. //if (avgDateList.Any() && j > 0 && (avgDateList[avgDateList.Count - 1] == openTimes[j - 1].CloseTime))
  192. //{
  193. // avgDateList.RemoveAt(avgDateList.Count - 1); //删除上一个收盘价等于下一个开盘时间的
  194. //}
  195. //avgDateList.Add(openTime);
  196. if (!((avgDateList.Any() && j > 0 && (avgDateList[avgDateList.Count - 1] == openTimes[j - 1].CloseTime))))
  197. {
  198. avgDateList.Add(openTime);
  199. }
  200. var intTime = openTime.Date.AddHours(openTime.Hour).AddMinutes(addMinutes * indexTime);
  201. while (intTime <= openTimes[j].CloseTime)
  202. {
  203. if (intTime > openTime)
  204. {
  205. avgDateList.Add(intTime);
  206. }
  207. indexTime++;
  208. intTime = openTimes[j].OpenTime.Date.AddHours(openTimes[j].OpenTime.Hour).AddMinutes(addMinutes * indexTime);
  209. }
  210. }
  211. this._futureDateSplit.Visibility = Visibility.Collapsed; //不显示右下角时间
  212. _dateScaleDisplayItems = BuildTimeShareList(paneWidth, dateScale, avgDateList);
  213. _timeSpanScaleDisplayItems = BuildTimeShareList(paneWidth, dateScale, openDateList); //分时图实线
  214. this.CleanupCanvas();
  215. var items = _dateScaleDisplayItems;
  216. if (items != null && items.Count > 0)
  217. {
  218. foreach (var current in items)
  219. {
  220. //用日期计算位置更准确
  221. var textBlockLeft = (float)((int)Math.Round((double)dateScale.XforDate(current.Date)));
  222. textBlockLeft = (float)(Math.Round(textBlockLeft) + 0.5) + (float)this._chart.GetChartPanelOffset();
  223. double textBlockTop = 0d;
  224. if (current.IsTwoLines)
  225. {
  226. textBlockTop = 11d;
  227. }
  228. //var length = GetTextWidth(current.Text);
  229. //textBlockLeft = textBlockLeft - length / 2;
  230. var textBlock = BuildTextBlock(current.Text, textBlockLeft, textBlockTop);
  231. textBlock.Foreground = chart.TimeSharingGridBrush;
  232. this.Children.Add(textBlock);
  233. }
  234. }
  235. }
  236. //创建线
  237. internal List<Shape> BuilTimeSpandPath(IDateScaler dateScale, Rect rect, Chart chart)
  238. {
  239. List<Shape> shapes = new List<Shape>();
  240. var path = new Path { IsHitTestVisible = false };
  241. var rectangleGeometry = new RectangleGeometry { Rect = rect };
  242. path.Clip = (rectangleGeometry);
  243. bool flag = dateScale.Count() == 0;
  244. Path result;
  245. if (flag)
  246. {
  247. result = path;
  248. }
  249. else
  250. {
  251. path.UseLayoutRounding = true;
  252. var geometryGroup = new GeometryGroup();
  253. // var solidColorBrush = new SolidColorBrush { Color = this.LineColor, Opacity = chart.GridOpacity };
  254. path.Stroke = chart.TimeSharingGridBrush.Clone();
  255. path.Stroke.Opacity = chart.GridOpacity;
  256. path.StrokeThickness = (2.0);
  257. var list = this.BuildDisplayItems((float)dateScale.WidthWithBarBuffer(), dateScale);
  258. var tempDic = new Dictionary<DateTime, Shape>();
  259. if (list != null && list.Any())
  260. {
  261. foreach (var current in list)
  262. {
  263. // 用日期计算位置更准确
  264. // var num = (float)(rect.Left + (double)((float)dateScale.WidthWithBarBuffer() * current.Percent));
  265. var num = (float)((int)Math.Round((double)dateScale.XforDate(current.Date)));
  266. // num += (dateScale.DistanceBetweenDates() / 2);
  267. num = (float)(Math.Round(num) + 0.5);
  268. // var num = (float)((int)Math.Round((double)dateScale.XforDate(current.Date)));
  269. // num = (float)(Math.Round(num) + 0.5);
  270. if (this._isDrawGridLines)
  271. {
  272. var line = new Line();
  273. line.Stroke = chart.TimeSharingGridBrush.Clone();
  274. line.Stroke.Opacity = chart.GridOpacity;
  275. line.X1 = (double)num;
  276. line.Y1 = rect.Top;
  277. line.X2 = (double)num;
  278. line.Y2 = rect.Bottom;
  279. line.StrokeThickness = (1.0);
  280. line.StrokeDashArray.Add(5);
  281. line.StrokeDashArray.Add(3);
  282. tempDic.Add(current.Date, line);
  283. }
  284. }
  285. if (_timeSpanScaleDisplayItems != null) //画实线
  286. {
  287. foreach (var current in _timeSpanScaleDisplayItems)
  288. {
  289. // 用日期计算位置更准确
  290. var num = (float)((int)Math.Round((double)dateScale.XforDate(current.Date)));
  291. if (tempDic.ContainsKey(current.Date))
  292. {
  293. tempDic.Remove(current.Date);
  294. }
  295. // num += (dateScale.DistanceBetweenDates() / 2);
  296. num = (float)(Math.Round(num) + 0.5);
  297. // var num = (float)((int)Math.Round((double)dateScale.XforDate(current.Date)));
  298. // num = (float)(Math.Round(num) + 0.5);
  299. if (this._isDrawGridLines)
  300. {
  301. var lineGeometry = new LineGeometry();
  302. geometryGroup.Children.Add(lineGeometry);
  303. lineGeometry.StartPoint = new Point((double)num, rect.Top);
  304. lineGeometry.EndPoint = new Point((double)num, rect.Bottom);
  305. }
  306. }
  307. }
  308. }
  309. path.Data = (geometryGroup);
  310. result = path;
  311. shapes.AddRange(tempDic.Values);
  312. shapes.Add(result);
  313. }
  314. return shapes;
  315. }
  316. internal Path BuildPath(IDateScaler dateScale, Rect rect, Chart chart)
  317. {
  318. var path = new Path { IsHitTestVisible = false };
  319. var rectangleGeometry = new RectangleGeometry { Rect = rect };
  320. path.Clip = (rectangleGeometry);
  321. bool flag = dateScale.Count() == 0;
  322. Path result;
  323. if (flag)
  324. {
  325. result = path;
  326. }
  327. else
  328. {
  329. path.UseLayoutRounding = (true);
  330. var geometryGroup = new GeometryGroup();
  331. var solidColorBrush = new SolidColorBrush { Color = this.LineColor, Opacity = chart.GridOpacity };
  332. path.Stroke = (solidColorBrush);
  333. path.StrokeThickness = (1.0);
  334. var list = this.BuildDisplayItems((float)dateScale.WidthWithBarBuffer(), dateScale);
  335. if (list != null && list.Any())
  336. {
  337. foreach (var current in list)
  338. {
  339. //用日期计算位置更准确
  340. //var num = (float)(rect.Left + (double)((float)dateScale.WidthWithBarBuffer() * current.Percent));
  341. //num += (dateScale.DistanceBetweenDates() / 2);
  342. //num = (float)(Math.Round(num) + 0.5);
  343. var num = (float)((int)Math.Round((double)dateScale.XforDate(current.Date)));
  344. num = (float)(Math.Round(num) + 0.5);
  345. if (this._isDrawGridLines)
  346. {
  347. var lineGeometry = new LineGeometry();
  348. geometryGroup.Children.Add(lineGeometry);
  349. lineGeometry.StartPoint = new Point((double)num, rect.Top);
  350. lineGeometry.EndPoint = new Point((double)num, rect.Bottom);
  351. }
  352. }
  353. }
  354. path.Data = (geometryGroup);
  355. result = path;
  356. }
  357. return result;
  358. }
  359. #endregion Internal Methods
  360. #region Private Methods
  361. /// <summary>
  362. /// 创建分时图的刻度
  363. /// </summary>
  364. /// <returns></returns>
  365. private List<DateScaleDisplay.DateScaleDisplayItem> BuildTimeShareList(float width, IDateScaler dateScale, List<DateTime> timeTicks)
  366. {
  367. var list = new List<DateScaleDisplay.DateScaleDisplayItem>();
  368. int startDateIndex = dateScale.StartDateIndex;
  369. var aDate = dateScale.DateValue(startDateIndex);
  370. int num = -2147483648;
  371. // aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day, tempInterval * (aDate.Hour / tempInterval), 0, 0);
  372. //aDate = aDate.AddHours(1.0);
  373. bool flag = !dateScale.HasNonEODDates();
  374. List<DateScaleDisplay.DateScaleDisplayItem> result;
  375. bool flag3;
  376. for (int i = 0; i < timeTicks.Count; i++)
  377. {
  378. var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem
  379. {
  380. Percent = ((float)i) / (float)(timeTicks.Count - 1),
  381. Text = timeTicks[i].ToString("HH:mm"),
  382. Date = timeTicks[i],
  383. };
  384. list.Add(dateScaleDisplay);
  385. }
  386. flag3 = (list.Count == 0);
  387. if (flag3)
  388. {
  389. return null;
  390. }
  391. result = list;
  392. return result;
  393. }
  394. private List<DateScaleDisplay.DateScaleDisplayItem> BuildDailyList(float width, IDateScaler dateScale, bool failOnCollision, int interval)
  395. {
  396. var list = new List<DateScaleDisplay.DateScaleDisplayItem>();
  397. int startDateIndex = dateScale.StartDateIndex;
  398. DateTime aDate = dateScale.DateValue(startDateIndex);
  399. int num = -2147483648;
  400. aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day, 0, 0, 0);
  401. //aDate = aDate.AddDays(interval);
  402. List<DateScaleDisplay.DateScaleDisplayItem> result;
  403. for (int i = dateScale.BinaryIndexSearch(aDate, startDateIndex); i >= 0; i = dateScale.BinaryIndexSearch(aDate, i))
  404. {
  405. aDate = dateScale.DateValue(i);
  406. bool flag = i >= startDateIndex;
  407. if (aDate.Equals(default(DateTime))) break;
  408. if (flag)
  409. {
  410. var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem
  411. {
  412. Percent = dateScale.PercentFromIndex(i),
  413. Text = aDate.ToString("dd"),
  414. Date = aDate
  415. };
  416. if (failOnCollision)
  417. {
  418. bool flag2 = width * dateScaleDisplay.Percent < (float)num;
  419. if (flag2)
  420. {
  421. result = null;
  422. return result;
  423. }
  424. num = checked((int)Math.Round((double)unchecked(this.GetTextWidth(dateScaleDisplay.Text) + width * dateScaleDisplay.Percent)));
  425. }
  426. list.Add(dateScaleDisplay);
  427. }
  428. // aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day, 0, 0, 0);
  429. aDate = aDate.AddDays(interval);
  430. }
  431. result = list;
  432. return result;
  433. }
  434. private List<DateScaleDisplay.DateScaleDisplayItem> BuildDisplayItems(float width, IDateScaler dateScale)
  435. {
  436. bool flag = this._dateScaleDisplayItems != null;
  437. List<DateScaleDisplay.DateScaleDisplayItem> result;
  438. if (flag)
  439. {
  440. result = this._dateScaleDisplayItems;
  441. }
  442. else
  443. {
  444. var list = new List<DateScaleDisplay.DateScaleDisplayItem>();
  445. //switch (this.ValuePaintMode)
  446. //{
  447. // case DateScaleDisplay.DateScalePaintType.AutoScale:
  448. // list = this.BuildList(width, dateScale);
  449. // break;
  450. // case DateScaleDisplay.DateScalePaintType.LineCount:
  451. // list = this.BuildEmptyList(width, dateScale);
  452. // break;
  453. // case DateScaleDisplay.DateScalePaintType.Daily:
  454. // list = this.BuildDailyList(width, dateScale, false, 1);
  455. // break;
  456. // case DateScaleDisplay.DateScalePaintType.Weekly:
  457. // list = this.BuildWeeklyList(width, dateScale, false);
  458. // break;
  459. // case DateScaleDisplay.DateScalePaintType.Monthly:
  460. // list = this.BuildMonthlyList(width, dateScale, false, 1);
  461. // break;
  462. // case DateScaleDisplay.DateScalePaintType.Quarterly:
  463. // list = this.BuildQuarterlyList(width, dateScale, false);
  464. // break;
  465. // case DateScaleDisplay.DateScalePaintType.Yearly:
  466. // list = this.BuildYearlyList(width, dateScale, false, 1);
  467. // break;
  468. // case DateScaleDisplay.DateScalePaintType.FiveYear:
  469. // list = this.BuildYearlyList(width, dateScale, false, 5);
  470. // break;
  471. //}
  472. switch (this._chart.CycleType)
  473. {
  474. case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute:
  475. case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute3:
  476. case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute5:
  477. case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute10:
  478. case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute15:
  479. case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute30:
  480. case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute60:
  481. case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute90:
  482. case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute120:
  483. case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute180:
  484. case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute240:
  485. case MuchInfo.Chart.Data.EnumTypes.CycleType.Hour:
  486. list = this.BuildList(width, dateScale);
  487. break;
  488. case MuchInfo.Chart.Data.EnumTypes.CycleType.Day:
  489. list = GetDailyDisplayItemsList(width, dateScale, 1);
  490. break;
  491. case MuchInfo.Chart.Data.EnumTypes.CycleType.Week:
  492. list = this.BuildWeeklyList(width, dateScale, true);
  493. break;
  494. case MuchInfo.Chart.Data.EnumTypes.CycleType.Month:
  495. list = this.BuildMonthlyList(width, dateScale, false, 1);
  496. break;
  497. case MuchInfo.Chart.Data.EnumTypes.CycleType.Quarter:
  498. list = this.BuildQuarterlyList(width, dateScale, false);
  499. break;
  500. case MuchInfo.Chart.Data.EnumTypes.CycleType.Year:
  501. list = this.BuildYearlyList(width, dateScale, false, 1);
  502. break;
  503. case MuchInfo.Chart.Data.EnumTypes.CycleType.Custom:
  504. list = this.BuildList(width, dateScale);
  505. break;
  506. default:
  507. list = this.BuildList(width, dateScale);
  508. break;
  509. }
  510. this._dateScaleDisplayItems = list;
  511. result = list;
  512. }
  513. return result;
  514. }
  515. private List<DateScaleDisplay.DateScaleDisplayItem> BuildEmptyList(float width, IDateScaler dateScale)
  516. {
  517. return new List<DateScaleDisplay.DateScaleDisplayItem>();
  518. }
  519. private void BuildFutureDateSplit(AllDateScaler allDateScaler, int paneWidth, bool isForex)
  520. {
  521. this._futureDateSplit.BuildFutureDateSplit(allDateScaler, this.LineColor, (double)this.GetFontSize(), isForex);
  522. //int indexOfLastDataDate = allDateScaler.IndexOfLastDataDate;
  523. //if (indexOfLastDataDate <= allDateScaler.EndIndex)
  524. //{
  525. // double num3 = (double)allDateScaler.XforDate(allDateScaler.DateValue(indexOfLastDataDate));
  526. // num3 -= this._futureDateSplit.ActualWidth;
  527. // //num3 += 22.0;
  528. // this._futureDateSplit.SetValue(Canvas.LeftProperty, num3);
  529. // this._futureDateSplit.SetValue(Canvas.TopProperty, 11.0);
  530. //}
  531. //else
  532. //{
  533. // this._futureDateSplit.SetValue(Canvas.LeftProperty, (double)paneWidth - (this._futureDateSplit.ActualWidth + 12.0));
  534. // this._futureDateSplit.SetValue(Canvas.TopProperty, 11.0);
  535. //}
  536. var offset = this._chart.GetChartPanelOffset();
  537. this._futureDateSplit.SetValue(Canvas.LeftProperty, (double)paneWidth + offset - this._futureDateSplit.ActualWidth);
  538. this._futureDateSplit.SetValue(Canvas.TopProperty, 11.0);
  539. this._futureDateSplit.Visibility = Visibility.Visible;
  540. }
  541. private List<DateScaleDisplay.DateScaleDisplayItem> BuildHourlyList(float width, IDateScaler dateScale, bool failOnCollision, int interval)
  542. {
  543. var list = new List<DateScaleDisplay.DateScaleDisplayItem>();
  544. int startDateIndex = dateScale.StartDateIndex;
  545. var aDate = dateScale.DateValue(startDateIndex);
  546. int num = -2147483648;
  547. var tempInterval = interval == 0 ? 1 : interval;
  548. aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day, tempInterval * (aDate.Hour / tempInterval), 0, 0);
  549. //aDate = aDate.AddHours(1.0);
  550. bool flag = !dateScale.HasNonEODDates();
  551. List<DateScaleDisplay.DateScaleDisplayItem> result;
  552. if (flag)
  553. {
  554. result = null;
  555. }
  556. else
  557. {
  558. bool flag3;
  559. for (int i = dateScale.BinaryIndexSearch(aDate, startDateIndex); i >= 0; i = dateScale.BinaryIndexSearch(aDate, i))
  560. {
  561. aDate = dateScale.DateValue(i);
  562. if (aDate.Equals(default(DateTime))) break;
  563. var dateTime2 = new DateTime(aDate.Year, aDate.Month, aDate.Day);
  564. flag = (DateTime.Compare(aDate, dateTime2) != 0 && i >= startDateIndex);
  565. if (flag)
  566. {
  567. var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem
  568. {
  569. Percent = dateScale.PercentFromIndex(i),
  570. Text = aDate.ToString("HH"),
  571. Date = aDate
  572. };
  573. if (failOnCollision)
  574. {
  575. bool flag2 = width * dateScaleDisplay.Percent < (float)num;
  576. if (flag2)
  577. {
  578. return null;
  579. }
  580. list.Add(dateScaleDisplay);
  581. num = checked((int)Math.Round((double)unchecked(this.GetTextWidth(dateScaleDisplay.Text) + width * dateScaleDisplay.Percent)));
  582. }
  583. else
  584. {
  585. list.Add(dateScaleDisplay);
  586. }
  587. }
  588. aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day, tempInterval * (aDate.Hour / tempInterval), 0, 0);
  589. aDate = aDate.AddHours(tempInterval);
  590. }
  591. flag3 = (list.Count == 0);
  592. if (flag3)
  593. {
  594. return null;
  595. }
  596. result = list;
  597. }
  598. return result;
  599. }
  600. private List<DateScaleDisplay.DateScaleDisplayItem> BuildList(float width, IDateScaler dateScale)
  601. {
  602. var result = GetMinutelyDisplayItemsList(width, dateScale, 1);
  603. if (result != null) return result;
  604. result = GetMinutelyDisplayItemsList(width, dateScale, 15);
  605. if (result != null) return result;
  606. result = GetMinutelyDisplayItemsList(width, dateScale, 30);
  607. if (result != null) return result;
  608. result = GetHourlyDisplayItemsList(width, dateScale, 1);
  609. if (result != null) return result;
  610. result = GetHourlyDisplayItemsList(width, dateScale, 4);
  611. if (result != null) return result;
  612. result = GetDailyDisplayItemsList(width, dateScale, 1);
  613. if (result != null) return result;
  614. result = GetDailyDisplayItemsList(width, dateScale, 3);
  615. if (result != null) return result;
  616. result = GetMonthlyDisplayItemsList(width, dateScale, 1);
  617. if (result != null) return result;
  618. result = GetMonthlyDisplayItemsList(width, dateScale, 3);
  619. if (result != null) return result;
  620. result = this.BuildYearlyList(width, dateScale, true, 1);
  621. if (result != null) return result;
  622. result = this.BuildYearlyList(width, dateScale, true, 5);
  623. if (result != null) return result;
  624. return result;
  625. }
  626. private List<DateScaleDisplay.DateScaleDisplayItem> BuildMintelyList(float width, IDateScaler dateScale, bool failOnCollision, int interval)
  627. {
  628. var list = new List<DateScaleDisplay.DateScaleDisplayItem>();
  629. int startDateIndex = dateScale.StartDateIndex;
  630. var aDate = dateScale.DateValue(startDateIndex);
  631. int num = -2147483648;
  632. var intervalInt = interval == 0 ? 1 : interval;
  633. aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day, aDate.Hour, (int)(intervalInt * (aDate.Minute / intervalInt)), 0);
  634. //aDate = aDate.AddMinutes(intervalInt);
  635. bool flag = !dateScale.HasNonEODDates();
  636. List<DateScaleDisplay.DateScaleDisplayItem> result;
  637. if (flag)
  638. {
  639. result = null;
  640. }
  641. else
  642. {
  643. bool flag2;
  644. for (int i = dateScale.BinaryIndexSearch(aDate, startDateIndex); i >= 0; i = dateScale.BinaryIndexSearch(aDate, i))
  645. {
  646. aDate = dateScale.DateValue(i);
  647. if (aDate.Equals(default(DateTime))) break;
  648. var newDateTime = new DateTime(aDate.Year, aDate.Month, aDate.Day);
  649. flag = (DateTime.Compare(aDate, newDateTime) != 0 && i >= startDateIndex);
  650. if (flag)
  651. {
  652. var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem
  653. {
  654. Percent = dateScale.PercentFromIndex(i),
  655. Text = aDate.ToString("HH:mm"),
  656. Date = aDate
  657. };
  658. if (failOnCollision)
  659. {
  660. flag2 = (width * dateScaleDisplay.Percent < (float)num);
  661. if (flag2)
  662. {
  663. result = null;
  664. return result;
  665. }
  666. num = checked((int)Math.Round((double)unchecked(this.GetTextWidth(dateScaleDisplay.Text) + width * dateScaleDisplay.Percent)));
  667. }
  668. list.Add(dateScaleDisplay);
  669. }
  670. aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day, aDate.Hour, (int)(intervalInt * (aDate.Minute / intervalInt)), 0);
  671. aDate = aDate.AddMinutes(intervalInt);
  672. }
  673. result = list.Count == 0 ? null : list;
  674. }
  675. return result;
  676. }
  677. private List<DateScaleDisplay.DateScaleDisplayItem> BuildMonthlyList(float width, IDateScaler dateScale, bool failOnCollision, int interval)
  678. {
  679. var list = new List<DateScaleDisplay.DateScaleDisplayItem>();
  680. int startDateIndex = dateScale.StartDateIndex;
  681. var aDate = dateScale.DateValue(startDateIndex);
  682. int num = -2147483648;
  683. var tempInterval = interval == 0 ? 1 : interval;
  684. aDate = new DateTime(aDate.Year, 1 + tempInterval * ((aDate.Month - 1) / tempInterval), 1);
  685. //aDate = aDate.AddMonths(tempInterval);
  686. List<DateScaleDisplay.DateScaleDisplayItem> result;
  687. for (int i = dateScale.BinaryIndexSearch(aDate, startDateIndex); i >= 0; i = dateScale.BinaryIndexSearch(aDate, i))
  688. {
  689. aDate = dateScale.DateValue(i);
  690. if (aDate.Equals(default(DateTime))) break;
  691. bool flag = i >= startDateIndex;
  692. if (flag)
  693. {
  694. var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem
  695. {
  696. Percent = dateScale.PercentFromIndex(i),
  697. Text = aDate.ToString("MM"),
  698. Date = aDate
  699. };
  700. if (failOnCollision)
  701. {
  702. bool flag2 = width * dateScaleDisplay.Percent < (float)num;
  703. if (flag2)
  704. {
  705. result = null;
  706. return result;
  707. }
  708. num = checked((int)Math.Round((double)unchecked(this.GetTextWidth(dateScaleDisplay.Text) + width * dateScaleDisplay.Percent)));
  709. }
  710. list.Add(dateScaleDisplay);
  711. }
  712. aDate = new DateTime(aDate.Year, 1 + tempInterval * ((aDate.Month - 1) / tempInterval), 1);
  713. aDate = aDate.AddMonths(tempInterval);
  714. }
  715. result = list;
  716. return result;
  717. }
  718. private List<DateScaleDisplay.DateScaleDisplayItem> BuildQuarterlyList(float width, IDateScaler dateScale, bool failOnCollision)
  719. {
  720. var list = new List<DateScaleDisplay.DateScaleDisplayItem>();
  721. int startDateIndex = dateScale.StartDateIndex;
  722. var aDate = dateScale.DateValue(startDateIndex);
  723. int num = -2147483648;
  724. checked
  725. {
  726. aDate = new DateTime(aDate.Year, 1 + 3 * ((aDate.Month - 1) / 3), 1);
  727. //aDate = aDate.AddMonths(3);
  728. List<DateScaleDisplay.DateScaleDisplayItem> result;
  729. for (int i = dateScale.BinaryIndexSearch(aDate, startDateIndex); i >= 0; i = dateScale.BinaryIndexSearch(aDate, i))
  730. {
  731. aDate = dateScale.DateValue(i);
  732. if (aDate.Equals(default(DateTime))) break;
  733. bool flag = i >= startDateIndex;
  734. if (flag)
  735. {
  736. var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem
  737. {
  738. Percent = dateScale.PercentFromIndex(i),
  739. Text = this.GetQuarterString(aDate),
  740. Date = aDate
  741. };
  742. if (failOnCollision)
  743. {
  744. bool flag2 = unchecked(width * dateScaleDisplay.Percent) < (float)num;
  745. if (flag2)
  746. {
  747. result = null;
  748. return result;
  749. }
  750. num = (int)Math.Round((double)unchecked(this.GetTextWidth(dateScaleDisplay.Text) + width * dateScaleDisplay.Percent));
  751. }
  752. list.Add(dateScaleDisplay);
  753. }
  754. aDate = new DateTime(aDate.Year, 1 + 3 * ((aDate.Month - 1) / 3), 1);
  755. aDate = aDate.AddMonths(3);
  756. }
  757. result = list;
  758. return result;
  759. }
  760. }
  761. private TextBlock BuildTextBlock(string text, double left, double top)
  762. {
  763. var textBlock = new TextBlock
  764. {
  765. Text = text,
  766. FontSize = (double)this.GetFontSize(),
  767. FontFamily = new FontFamily("Verdana"),
  768. Foreground = new SolidColorBrush(this.TextColor)
  769. };
  770. textBlock.SetValue(Canvas.LeftProperty, left);
  771. textBlock.SetValue(Canvas.TopProperty, top);
  772. return textBlock;
  773. }
  774. private List<DateScaleDisplay.DateScaleDisplayItem> BuildWeeklyList(float width, IDateScaler DateScale, bool failOnCollision)
  775. {
  776. var list = new List<DateScaleDisplay.DateScaleDisplayItem>();
  777. int startDateIndex = DateScale.StartDateIndex;
  778. var aDate = DateScale.DateValue(startDateIndex);
  779. int num = -2147483648;
  780. aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day);
  781. checked
  782. {
  783. aDate = aDate.AddDays((DayOfWeek)1 - aDate.DayOfWeek);
  784. //aDate = aDate.AddDays(7.0);
  785. List<DateScaleDisplay.DateScaleDisplayItem> result;
  786. for (int i = DateScale.BinaryIndexSearch(aDate, startDateIndex); i >= 0; i = DateScale.BinaryIndexSearch(aDate, i))
  787. {
  788. aDate = DateScale.DateValue(i);
  789. if (aDate.Equals(default(DateTime))) break;
  790. bool flag = i >= startDateIndex;
  791. if (flag)
  792. {
  793. var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem
  794. {
  795. Percent = DateScale.PercentFromIndex(i),
  796. Text = aDate.Day.ToString("d"),
  797. Date = aDate
  798. };
  799. if (failOnCollision)
  800. {
  801. bool flag2 = unchecked(width * dateScaleDisplay.Percent) < (float)num;
  802. if (flag2)
  803. {
  804. result = null;
  805. return result;
  806. }
  807. num = (int)Math.Round((double)unchecked(this.GetTextWidth(dateScaleDisplay.Text)+5 + width * dateScaleDisplay.Percent)); //加5不显示靠近
  808. }
  809. list.Add(dateScaleDisplay);
  810. }
  811. aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day);
  812. aDate = aDate.AddDays((DayOfWeek)1 - aDate.DayOfWeek);
  813. aDate = aDate.AddDays(7.0);
  814. }
  815. result = list;
  816. return result;
  817. }
  818. }
  819. private List<DateScaleDisplay.DateScaleDisplayItem> BuildYearlyList(float width, IDateScaler dateScale, bool failOnCollision, int interval)
  820. {
  821. var list = new List<DateScaleDisplay.DateScaleDisplayItem>();
  822. int startDateIndex = dateScale.StartDateIndex;
  823. var aDate = dateScale.DateValue(startDateIndex);
  824. int num = -2147483648;
  825. aDate = new DateTime(aDate.Year, 1, 1);
  826. //aDate = aDate.AddYears(1);
  827. List<DateScaleDisplay.DateScaleDisplayItem> result;
  828. DateTime aDate2;
  829. for (int i = dateScale.BinaryIndexSearch(aDate, startDateIndex); i >= 0; i = dateScale.BinaryIndexSearch(aDate2, i))
  830. {
  831. aDate = dateScale.DateValue(i);
  832. if (aDate.Equals(default(DateTime))) break;
  833. bool flag = i >= startDateIndex;
  834. if (flag)
  835. {
  836. var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem
  837. {
  838. Percent = dateScale.PercentFromIndex(i),
  839. Text = aDate.ToString("yyyy"),
  840. Date = aDate
  841. };
  842. if (failOnCollision)
  843. {
  844. bool flag2 = unchecked(width * dateScaleDisplay.Percent) < (float)num;
  845. if (flag2)
  846. {
  847. result = null;
  848. return result;
  849. }
  850. num = (int)Math.Round((double)unchecked(this.GetTextWidth(dateScaleDisplay.Text) + width * dateScaleDisplay.Percent));
  851. }
  852. list.Add(dateScaleDisplay);
  853. }
  854. aDate2 = new DateTime(aDate.Year + interval, 1, 1);
  855. }
  856. result = list;
  857. return result;
  858. }
  859. /// <summary>
  860. /// 移除所有非 FutureDateSplit 元素
  861. /// </summary>
  862. private void CleanupCanvas()
  863. {
  864. if (this.Children == null || this.Children.Count == 0) return;
  865. var length = this.Children.Count - 1;
  866. for (int i = length; i >= 0; i--)
  867. {
  868. var current = this.Children[i] as UIElement;
  869. if (current != null && !(current is FutureDateSplit))
  870. {
  871. this.Children.Remove(current);
  872. }
  873. }
  874. }
  875. private List<DateScaleDisplay.DateScaleDisplayItem> GetDailyDisplayItemsList(float width, IDateScaler dateScale, int interval)
  876. {
  877. var list = this.BuildDailyList(width, dateScale, true, interval);
  878. if (list == null) return null;
  879. //不显示第二行数据
  880. //var line2List = this.BuildLine2MonthList(width, dateScale, true);
  881. //if (line2List == null) return null;
  882. //list.AddRange(line2List);
  883. return list;
  884. }
  885. private double GetFontSize()
  886. {
  887. return 12d;
  888. //时间滑块的字体不用变
  889. //bool flag = this._chart != null;
  890. //double result;
  891. //if (flag)
  892. //{
  893. // result = this._chart.ChartFontSize - 1;
  894. //}
  895. //else
  896. //{
  897. // result = 11f;
  898. //}
  899. //return result;
  900. }
  901. private List<DateScaleDisplay.DateScaleDisplayItem> GetHourlyDisplayItemsList(float width, IDateScaler dateScale, int interval)
  902. {
  903. var list = this.BuildHourlyList(width, dateScale, true, interval);
  904. if (list == null) return null;
  905. //不显示第二行数据
  906. //var line2List = this.BuildLine2DailyList(width, dateScale, true);
  907. //if (line2List == null) return null;
  908. //list.AddRange(line2List);
  909. return list;
  910. }
  911. private List<DateScaleDisplay.DateScaleDisplayItem> GetMinutelyDisplayItemsList(float width, IDateScaler dateScale, int interval)
  912. {
  913. var list = this.BuildMintelyList(width, dateScale, true, interval);
  914. if (list == null) return null;
  915. //不显示第二行数据
  916. //var line2List = this.BuildLine2DailyList(width, dateScale, true);
  917. //if (line2List == null) return null;
  918. //list.AddRange(line2List);
  919. return list;
  920. }
  921. private List<DateScaleDisplay.DateScaleDisplayItem> GetMonthlyDisplayItemsList(float width, IDateScaler dateScale, int interval)
  922. {
  923. var list = this.BuildMonthlyList(width, dateScale, true, interval);
  924. if (list == null) return null;
  925. //不显示第二行数据
  926. //var line2List = this.BuildLine2YearylyList(width, dateScale, true);
  927. //if (line2List == null) return null;
  928. //list.AddRange(line2List);
  929. return list;
  930. }
  931. private string GetQuarterString(DateTime aDate)
  932. {
  933. bool flag = aDate.Month >= 1 & aDate.Month <= 3;
  934. string result = "Q1";
  935. if (flag)
  936. {
  937. result = "Q1";
  938. }
  939. else
  940. {
  941. flag = (aDate.Month >= 4 & aDate.Month <= 6);
  942. if (flag)
  943. {
  944. result = "Q2";
  945. }
  946. else
  947. {
  948. flag = (aDate.Month >= 7 & aDate.Month <= 9);
  949. if (flag)
  950. {
  951. result = "Q3";
  952. }
  953. else
  954. {
  955. flag = (aDate.Month >= 10 & aDate.Month <= 12);
  956. if (flag)
  957. {
  958. result = "Q4";
  959. }
  960. }
  961. }
  962. }
  963. return result;
  964. }
  965. private double GetTextWidth(string txt)
  966. {
  967. return TreeHelper.GetTextWidth(this.GetFontSize(), txt); //(float)((double)this.GetFontSize() * 0.8 * (double)txt.Length);
  968. }
  969. #endregion Private Methods
  970. #endregion Methods
  971. #region Nested Types
  972. private class DateScaleDisplayItem
  973. {
  974. #region Fields
  975. protected float _precent; //DateScaleDisplay_138_786;
  976. #endregion Fields
  977. #region Constructors
  978. public DateScaleDisplayItem()
  979. {
  980. this.IsEven = false;
  981. this.IsTwoLines = false;
  982. }
  983. #endregion Constructors
  984. #region Properties
  985. #region Public Properties
  986. public bool IsEven
  987. {
  988. get;
  989. set;
  990. }
  991. public bool IsTwoLines
  992. {
  993. get;
  994. set;
  995. }
  996. public float Percent
  997. {
  998. get
  999. {
  1000. bool flag = this._precent > 0f;
  1001. float result;
  1002. if (flag)
  1003. {
  1004. result = this._precent;
  1005. }
  1006. else
  1007. {
  1008. result = 0f;
  1009. }
  1010. return result;
  1011. }
  1012. set
  1013. {
  1014. bool flag = value > 0f;
  1015. if (flag)
  1016. {
  1017. this._precent = value;
  1018. }
  1019. }
  1020. }
  1021. public string Text
  1022. {
  1023. get;
  1024. set;
  1025. }
  1026. public DateTime Date { get; set; }
  1027. #endregion Public Properties
  1028. #endregion Properties
  1029. }
  1030. #endregion Nested Types
  1031. }
  1032. }