using MuchInfo.Chart.Data.Models; using MuchInfo.Chart.Infrastructure.Helpers; using MuchInfo.Chart.WPF.Controls.DateScaling; using MuchInfo.Chart.WPF.Primitives.Interfaces; using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; using System.Windows.Shapes; namespace MuchInfo.Chart.WPF.Primitives { /// /// 微型数据展示类 /// public class DateScaleDisplay : Canvas { #region Fields private Chart _chart; private List _dateScaleDisplayItems; private FutureDateSplit _futureDateSplit; private bool _isDark; private const int minTickWidth = 50; private const int minTick = 12; //显示分时图的实线 private List _timeSpanScaleDisplayItems; #endregion Fields #region Constructors public DateScaleDisplay(Chart chart) { this.ValuePaintMode = DateScaleDisplay.DateScalePaintType.AutoScale; this.TextColor = Colors.White; this.LineColor = Colors.LightGray; this._chart = chart; this._futureDateSplit = new FutureDateSplit(this, _chart) { VerticalAlignment = VerticalAlignment.Stretch }; this.Children.Add(this._futureDateSplit); this.MinHeight = 24; _isDrawGridLines = (this._chart != null && this._chart.GridOpacity > 0) ? true : false; } #endregion Constructors #region Enumerations public enum DateScalePaintType { AutoScale, LineCount, Daily, Weekly, Monthly, Quarterly, Yearly, FiveYear } #endregion Enumerations #region Properties #region Public Properties private readonly bool _isDrawGridLines; public Color LineColor { get; set; } public Color TextColor { get; set; } public DateScaleDisplay.DateScalePaintType ValuePaintMode { get; set; } #endregion Public Properties #region Private Properties private bool DarkBackground { get { return this._isDark; } set { bool flag = value != this._isDark; if (flag) { this._isDark = value; flag = this._isDark; if (flag) { this.TextColor = Colors.White; this.LineColor = Colors.LightGray; } else { this.LineColor = Colors.Black; this.TextColor = Colors.Black; } } } } #endregion Private Properties #endregion Properties #region Methods #region Internal Methods internal void BuildCanvas(IDateScaler dateScale, float left, int paneWidth, bool isForex) { if (this._chart != null) this.DarkBackground = this._chart.IsDarkBackground; this._dateScaleDisplayItems = null; var allDateScaler = dateScale as AllDateScaler; if (allDateScaler == null || allDateScaler.Count() == 0) { this.CleanupCanvas(); } else { this.CleanupCanvas(); BuildFutureDateSplit(allDateScaler, paneWidth, isForex); var items = this.BuildDisplayItems((float)allDateScaler.WidthWithBarBuffer(), allDateScaler); if (items != null && items.Count > 0) { //chart宽度 var width = paneWidth + _chart.RightBuffer * 2 + _chart.GetChartPanelOffset() * 2; foreach (var current in items) { //用日期计算位置更准确 //float textBlockLeft = (float)left + (float)allDateScaler.WidthWithBarBuffer() * current.Percent; var textBlockLeft = (float)((int)Math.Round((double)allDateScaler.XforDate(current.Date))); textBlockLeft = (float)(Math.Round(textBlockLeft) + 0.5) + (float)this._chart.GetChartPanelOffset(); double textBlockTop = 0d; if (current.IsTwoLines) { textBlockTop = 11d; } var textBlock = BuildTextBlock(current.Text, textBlockLeft, textBlockTop); var flag = (textBlockLeft + GetTextWidth(textBlock.Text)) < width; if (flag) { this.Children.Add(textBlock); } } } } } /// /// 创建分时图的横轴坐标 /// internal void BuildTimeShareCanvas(IDateScaler dateScale, float left, int paneWidth, bool isForex, List openTimes, Chart chart) { if (openTimes == null || !openTimes.Any()) return; var timeSpan = new TimeSpan(); timeSpan = openTimes.Aggregate(timeSpan, (current, openCloseTime) => current.Add(openCloseTime.CloseTime - openCloseTime.OpenTime)); int addMinutes = 0; int lineCount = (int)timeSpan.TotalMinutes / 30; //显示分钟线小于12 if (lineCount <= 12) { addMinutes = 30; } else if (lineCount > 12) { lineCount = (int)timeSpan.TotalHours;//一小时显示一网格 if (lineCount <= 12) { addMinutes = 60; } else { lineCount = (int)timeSpan.TotalHours / 2; addMinutes = 120; } } var openDateList = new List(); //显示开收盘时间线网格(实线) for (int i = 0; i < openTimes.Count; i++) { //openDateList.Add(openTimes[i].OpenTime); //if (i == openTimes.Count - 1) //{ // openDateList.Add(openTimes[i].CloseTime); //} if (i == 0) openDateList.Add(openTimes[i].OpenTime); openDateList.Add(openTimes[i].CloseTime); } if (openTimes.Count > 0 && openTimes[0].OpenTime == DateTime.MinValue) return; var avgDateList = new List(); //显示时间线平均网格(虚线) for (int j = 0; j < openTimes.Count; j++) { int indexTime = 0; var openTime = openTimes[j].OpenTime; //if (avgDateList.Any() && j > 0 && (avgDateList[avgDateList.Count - 1] == openTimes[j - 1].CloseTime)) //{ // avgDateList.RemoveAt(avgDateList.Count - 1); //删除上一个收盘价等于下一个开盘时间的 //} //avgDateList.Add(openTime); if (!((avgDateList.Any() && j > 0 && (avgDateList[avgDateList.Count - 1] == openTimes[j - 1].CloseTime)))) { avgDateList.Add(openTime); } var intTime = openTime.Date.AddHours(openTime.Hour).AddMinutes(addMinutes * indexTime); while (intTime <= openTimes[j].CloseTime) { if (intTime > openTime) { avgDateList.Add(intTime); } indexTime++; intTime = openTimes[j].OpenTime.Date.AddHours(openTimes[j].OpenTime.Hour).AddMinutes(addMinutes * indexTime); } } this._futureDateSplit.Visibility = Visibility.Collapsed; //不显示右下角时间 _dateScaleDisplayItems = BuildTimeShareList(paneWidth, dateScale, avgDateList); _timeSpanScaleDisplayItems = BuildTimeShareList(paneWidth, dateScale, openDateList); //分时图实线 this.CleanupCanvas(); var items = _dateScaleDisplayItems; if (items != null && items.Count > 0) { foreach (var current in items) { //用日期计算位置更准确 var textBlockLeft = (float)((int)Math.Round((double)dateScale.XforDate(current.Date))); textBlockLeft = (float)(Math.Round(textBlockLeft) + 0.5) + (float)this._chart.GetChartPanelOffset(); double textBlockTop = 0d; if (current.IsTwoLines) { textBlockTop = 11d; } //var length = GetTextWidth(current.Text); //textBlockLeft = textBlockLeft - length / 2; var textBlock = BuildTextBlock(current.Text, textBlockLeft, textBlockTop); textBlock.Foreground = chart.TimeSharingGridBrush; this.Children.Add(textBlock); } } } //创建线 internal List BuilTimeSpandPath(IDateScaler dateScale, Rect rect, Chart chart) { List shapes = new List(); var path = new Path { IsHitTestVisible = false }; var rectangleGeometry = new RectangleGeometry { Rect = rect }; path.Clip = (rectangleGeometry); bool flag = dateScale.Count() == 0; Path result; if (flag) { result = path; } else { path.UseLayoutRounding = true; var geometryGroup = new GeometryGroup(); // var solidColorBrush = new SolidColorBrush { Color = this.LineColor, Opacity = chart.GridOpacity }; path.Stroke = chart.TimeSharingGridBrush.Clone(); path.Stroke.Opacity = chart.GridOpacity; path.StrokeThickness = (2.0); var list = this.BuildDisplayItems((float)dateScale.WidthWithBarBuffer(), dateScale); var tempDic = new Dictionary(); if (list != null && list.Any()) { foreach (var current in list) { // 用日期计算位置更准确 // var num = (float)(rect.Left + (double)((float)dateScale.WidthWithBarBuffer() * current.Percent)); var num = (float)((int)Math.Round((double)dateScale.XforDate(current.Date))); // num += (dateScale.DistanceBetweenDates() / 2); num = (float)(Math.Round(num) + 0.5); // var num = (float)((int)Math.Round((double)dateScale.XforDate(current.Date))); // num = (float)(Math.Round(num) + 0.5); if (this._isDrawGridLines) { var line = new Line(); line.Stroke = chart.TimeSharingGridBrush.Clone(); line.Stroke.Opacity = chart.GridOpacity; line.X1 = (double)num; line.Y1 = rect.Top; line.X2 = (double)num; line.Y2 = rect.Bottom; line.StrokeThickness = (1.0); line.StrokeDashArray.Add(5); line.StrokeDashArray.Add(3); tempDic.Add(current.Date, line); } } if (_timeSpanScaleDisplayItems != null) //画实线 { foreach (var current in _timeSpanScaleDisplayItems) { // 用日期计算位置更准确 var num = (float)((int)Math.Round((double)dateScale.XforDate(current.Date))); if (tempDic.ContainsKey(current.Date)) { tempDic.Remove(current.Date); } // num += (dateScale.DistanceBetweenDates() / 2); num = (float)(Math.Round(num) + 0.5); // var num = (float)((int)Math.Round((double)dateScale.XforDate(current.Date))); // num = (float)(Math.Round(num) + 0.5); if (this._isDrawGridLines) { var lineGeometry = new LineGeometry(); geometryGroup.Children.Add(lineGeometry); lineGeometry.StartPoint = new Point((double)num, rect.Top); lineGeometry.EndPoint = new Point((double)num, rect.Bottom); } } } } path.Data = (geometryGroup); result = path; shapes.AddRange(tempDic.Values); shapes.Add(result); } return shapes; } internal Path BuildPath(IDateScaler dateScale, Rect rect, Chart chart) { var path = new Path { IsHitTestVisible = false }; var rectangleGeometry = new RectangleGeometry { Rect = rect }; path.Clip = (rectangleGeometry); bool flag = dateScale.Count() == 0; Path result; if (flag) { result = path; } else { path.UseLayoutRounding = (true); var geometryGroup = new GeometryGroup(); var solidColorBrush = new SolidColorBrush { Color = this.LineColor, Opacity = chart.GridOpacity }; path.Stroke = (solidColorBrush); path.StrokeThickness = (1.0); var list = this.BuildDisplayItems((float)dateScale.WidthWithBarBuffer(), dateScale); if (list != null && list.Any()) { foreach (var current in list) { //用日期计算位置更准确 //var num = (float)(rect.Left + (double)((float)dateScale.WidthWithBarBuffer() * current.Percent)); //num += (dateScale.DistanceBetweenDates() / 2); //num = (float)(Math.Round(num) + 0.5); var num = (float)((int)Math.Round((double)dateScale.XforDate(current.Date))); num = (float)(Math.Round(num) + 0.5); if (this._isDrawGridLines) { var lineGeometry = new LineGeometry(); geometryGroup.Children.Add(lineGeometry); lineGeometry.StartPoint = new Point((double)num, rect.Top); lineGeometry.EndPoint = new Point((double)num, rect.Bottom); } } } path.Data = (geometryGroup); result = path; } return result; } #endregion Internal Methods #region Private Methods /// /// 创建分时图的刻度 /// /// private List BuildTimeShareList(float width, IDateScaler dateScale, List timeTicks) { var list = new List(); int startDateIndex = dateScale.StartDateIndex; var aDate = dateScale.DateValue(startDateIndex); int num = -2147483648; // aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day, tempInterval * (aDate.Hour / tempInterval), 0, 0); //aDate = aDate.AddHours(1.0); bool flag = !dateScale.HasNonEODDates(); List result; bool flag3; for (int i = 0; i < timeTicks.Count; i++) { var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem { Percent = ((float)i) / (float)(timeTicks.Count - 1), Text = timeTicks[i].ToString("HH:mm"), Date = timeTicks[i], }; list.Add(dateScaleDisplay); } flag3 = (list.Count == 0); if (flag3) { return null; } result = list; return result; } private List BuildDailyList(float width, IDateScaler dateScale, bool failOnCollision, int interval) { var list = new List(); int startDateIndex = dateScale.StartDateIndex; DateTime aDate = dateScale.DateValue(startDateIndex); int num = -2147483648; aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day, 0, 0, 0); //aDate = aDate.AddDays(interval); List result; for (int i = dateScale.BinaryIndexSearch(aDate, startDateIndex); i >= 0; i = dateScale.BinaryIndexSearch(aDate, i)) { aDate = dateScale.DateValue(i); bool flag = i >= startDateIndex; if (aDate.Equals(default(DateTime))) break; if (flag) { var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem { Percent = dateScale.PercentFromIndex(i), Text = aDate.ToString("dd"), Date = aDate }; if (failOnCollision) { bool flag2 = width * dateScaleDisplay.Percent < (float)num; if (flag2) { result = null; return result; } num = checked((int)Math.Round((double)unchecked(this.GetTextWidth(dateScaleDisplay.Text) + width * dateScaleDisplay.Percent))); } list.Add(dateScaleDisplay); } // aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day, 0, 0, 0); aDate = aDate.AddDays(interval); } result = list; return result; } private List BuildDisplayItems(float width, IDateScaler dateScale) { bool flag = this._dateScaleDisplayItems != null; List result; if (flag) { result = this._dateScaleDisplayItems; } else { var list = new List(); //switch (this.ValuePaintMode) //{ // case DateScaleDisplay.DateScalePaintType.AutoScale: // list = this.BuildList(width, dateScale); // break; // case DateScaleDisplay.DateScalePaintType.LineCount: // list = this.BuildEmptyList(width, dateScale); // break; // case DateScaleDisplay.DateScalePaintType.Daily: // list = this.BuildDailyList(width, dateScale, false, 1); // break; // case DateScaleDisplay.DateScalePaintType.Weekly: // list = this.BuildWeeklyList(width, dateScale, false); // break; // case DateScaleDisplay.DateScalePaintType.Monthly: // list = this.BuildMonthlyList(width, dateScale, false, 1); // break; // case DateScaleDisplay.DateScalePaintType.Quarterly: // list = this.BuildQuarterlyList(width, dateScale, false); // break; // case DateScaleDisplay.DateScalePaintType.Yearly: // list = this.BuildYearlyList(width, dateScale, false, 1); // break; // case DateScaleDisplay.DateScalePaintType.FiveYear: // list = this.BuildYearlyList(width, dateScale, false, 5); // break; //} switch (this._chart.CycleType) { case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute: case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute3: case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute5: case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute10: case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute15: case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute30: case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute60: case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute90: case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute120: case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute180: case MuchInfo.Chart.Data.EnumTypes.CycleType.Minute240: case MuchInfo.Chart.Data.EnumTypes.CycleType.Hour: list = this.BuildList(width, dateScale); break; case MuchInfo.Chart.Data.EnumTypes.CycleType.Day: list = GetDailyDisplayItemsList(width, dateScale, 1); break; case MuchInfo.Chart.Data.EnumTypes.CycleType.Week: list = this.BuildWeeklyList(width, dateScale, true); break; case MuchInfo.Chart.Data.EnumTypes.CycleType.Month: list = this.BuildMonthlyList(width, dateScale, false, 1); break; case MuchInfo.Chart.Data.EnumTypes.CycleType.Quarter: list = this.BuildQuarterlyList(width, dateScale, false); break; case MuchInfo.Chart.Data.EnumTypes.CycleType.Year: list = this.BuildYearlyList(width, dateScale, false, 1); break; case MuchInfo.Chart.Data.EnumTypes.CycleType.Custom: list = this.BuildList(width, dateScale); break; default: list = this.BuildList(width, dateScale); break; } this._dateScaleDisplayItems = list; result = list; } return result; } private List BuildEmptyList(float width, IDateScaler dateScale) { return new List(); } private void BuildFutureDateSplit(AllDateScaler allDateScaler, int paneWidth, bool isForex) { this._futureDateSplit.BuildFutureDateSplit(allDateScaler, this.LineColor, (double)this.GetFontSize(), isForex); //int indexOfLastDataDate = allDateScaler.IndexOfLastDataDate; //if (indexOfLastDataDate <= allDateScaler.EndIndex) //{ // double num3 = (double)allDateScaler.XforDate(allDateScaler.DateValue(indexOfLastDataDate)); // num3 -= this._futureDateSplit.ActualWidth; // //num3 += 22.0; // this._futureDateSplit.SetValue(Canvas.LeftProperty, num3); // this._futureDateSplit.SetValue(Canvas.TopProperty, 11.0); //} //else //{ // this._futureDateSplit.SetValue(Canvas.LeftProperty, (double)paneWidth - (this._futureDateSplit.ActualWidth + 12.0)); // this._futureDateSplit.SetValue(Canvas.TopProperty, 11.0); //} var offset = this._chart.GetChartPanelOffset(); this._futureDateSplit.SetValue(Canvas.LeftProperty, (double)paneWidth + offset - this._futureDateSplit.ActualWidth); this._futureDateSplit.SetValue(Canvas.TopProperty, 11.0); this._futureDateSplit.Visibility = Visibility.Visible; } private List BuildHourlyList(float width, IDateScaler dateScale, bool failOnCollision, int interval) { var list = new List(); int startDateIndex = dateScale.StartDateIndex; var aDate = dateScale.DateValue(startDateIndex); int num = -2147483648; var tempInterval = interval == 0 ? 1 : interval; aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day, tempInterval * (aDate.Hour / tempInterval), 0, 0); //aDate = aDate.AddHours(1.0); bool flag = !dateScale.HasNonEODDates(); List result; if (flag) { result = null; } else { bool flag3; for (int i = dateScale.BinaryIndexSearch(aDate, startDateIndex); i >= 0; i = dateScale.BinaryIndexSearch(aDate, i)) { aDate = dateScale.DateValue(i); if (aDate.Equals(default(DateTime))) break; var dateTime2 = new DateTime(aDate.Year, aDate.Month, aDate.Day); flag = (DateTime.Compare(aDate, dateTime2) != 0 && i >= startDateIndex); if (flag) { var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem { Percent = dateScale.PercentFromIndex(i), Text = aDate.ToString("HH"), Date = aDate }; if (failOnCollision) { bool flag2 = width * dateScaleDisplay.Percent < (float)num; if (flag2) { return null; } list.Add(dateScaleDisplay); num = checked((int)Math.Round((double)unchecked(this.GetTextWidth(dateScaleDisplay.Text) + width * dateScaleDisplay.Percent))); } else { list.Add(dateScaleDisplay); } } aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day, tempInterval * (aDate.Hour / tempInterval), 0, 0); aDate = aDate.AddHours(tempInterval); } flag3 = (list.Count == 0); if (flag3) { return null; } result = list; } return result; } private List BuildList(float width, IDateScaler dateScale) { var result = GetMinutelyDisplayItemsList(width, dateScale, 1); if (result != null) return result; result = GetMinutelyDisplayItemsList(width, dateScale, 15); if (result != null) return result; result = GetMinutelyDisplayItemsList(width, dateScale, 30); if (result != null) return result; result = GetHourlyDisplayItemsList(width, dateScale, 1); if (result != null) return result; result = GetHourlyDisplayItemsList(width, dateScale, 4); if (result != null) return result; result = GetDailyDisplayItemsList(width, dateScale, 1); if (result != null) return result; result = GetDailyDisplayItemsList(width, dateScale, 3); if (result != null) return result; result = GetMonthlyDisplayItemsList(width, dateScale, 1); if (result != null) return result; result = GetMonthlyDisplayItemsList(width, dateScale, 3); if (result != null) return result; result = this.BuildYearlyList(width, dateScale, true, 1); if (result != null) return result; result = this.BuildYearlyList(width, dateScale, true, 5); if (result != null) return result; return result; } private List BuildMintelyList(float width, IDateScaler dateScale, bool failOnCollision, int interval) { var list = new List(); int startDateIndex = dateScale.StartDateIndex; var aDate = dateScale.DateValue(startDateIndex); int num = -2147483648; var intervalInt = interval == 0 ? 1 : interval; aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day, aDate.Hour, (int)(intervalInt * (aDate.Minute / intervalInt)), 0); //aDate = aDate.AddMinutes(intervalInt); bool flag = !dateScale.HasNonEODDates(); List result; if (flag) { result = null; } else { bool flag2; for (int i = dateScale.BinaryIndexSearch(aDate, startDateIndex); i >= 0; i = dateScale.BinaryIndexSearch(aDate, i)) { aDate = dateScale.DateValue(i); if (aDate.Equals(default(DateTime))) break; var newDateTime = new DateTime(aDate.Year, aDate.Month, aDate.Day); flag = (DateTime.Compare(aDate, newDateTime) != 0 && i >= startDateIndex); if (flag) { var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem { Percent = dateScale.PercentFromIndex(i), Text = aDate.ToString("HH:mm"), Date = aDate }; if (failOnCollision) { flag2 = (width * dateScaleDisplay.Percent < (float)num); if (flag2) { result = null; return result; } num = checked((int)Math.Round((double)unchecked(this.GetTextWidth(dateScaleDisplay.Text) + width * dateScaleDisplay.Percent))); } list.Add(dateScaleDisplay); } aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day, aDate.Hour, (int)(intervalInt * (aDate.Minute / intervalInt)), 0); aDate = aDate.AddMinutes(intervalInt); } result = list.Count == 0 ? null : list; } return result; } private List BuildMonthlyList(float width, IDateScaler dateScale, bool failOnCollision, int interval) { var list = new List(); int startDateIndex = dateScale.StartDateIndex; var aDate = dateScale.DateValue(startDateIndex); int num = -2147483648; var tempInterval = interval == 0 ? 1 : interval; aDate = new DateTime(aDate.Year, 1 + tempInterval * ((aDate.Month - 1) / tempInterval), 1); //aDate = aDate.AddMonths(tempInterval); List result; for (int i = dateScale.BinaryIndexSearch(aDate, startDateIndex); i >= 0; i = dateScale.BinaryIndexSearch(aDate, i)) { aDate = dateScale.DateValue(i); if (aDate.Equals(default(DateTime))) break; bool flag = i >= startDateIndex; if (flag) { var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem { Percent = dateScale.PercentFromIndex(i), Text = aDate.ToString("MM"), Date = aDate }; if (failOnCollision) { bool flag2 = width * dateScaleDisplay.Percent < (float)num; if (flag2) { result = null; return result; } num = checked((int)Math.Round((double)unchecked(this.GetTextWidth(dateScaleDisplay.Text) + width * dateScaleDisplay.Percent))); } list.Add(dateScaleDisplay); } aDate = new DateTime(aDate.Year, 1 + tempInterval * ((aDate.Month - 1) / tempInterval), 1); aDate = aDate.AddMonths(tempInterval); } result = list; return result; } private List BuildQuarterlyList(float width, IDateScaler dateScale, bool failOnCollision) { var list = new List(); int startDateIndex = dateScale.StartDateIndex; var aDate = dateScale.DateValue(startDateIndex); int num = -2147483648; checked { aDate = new DateTime(aDate.Year, 1 + 3 * ((aDate.Month - 1) / 3), 1); //aDate = aDate.AddMonths(3); List result; for (int i = dateScale.BinaryIndexSearch(aDate, startDateIndex); i >= 0; i = dateScale.BinaryIndexSearch(aDate, i)) { aDate = dateScale.DateValue(i); if (aDate.Equals(default(DateTime))) break; bool flag = i >= startDateIndex; if (flag) { var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem { Percent = dateScale.PercentFromIndex(i), Text = this.GetQuarterString(aDate), Date = aDate }; if (failOnCollision) { bool flag2 = unchecked(width * dateScaleDisplay.Percent) < (float)num; if (flag2) { result = null; return result; } num = (int)Math.Round((double)unchecked(this.GetTextWidth(dateScaleDisplay.Text) + width * dateScaleDisplay.Percent)); } list.Add(dateScaleDisplay); } aDate = new DateTime(aDate.Year, 1 + 3 * ((aDate.Month - 1) / 3), 1); aDate = aDate.AddMonths(3); } result = list; return result; } } private TextBlock BuildTextBlock(string text, double left, double top) { var textBlock = new TextBlock { Text = text, FontSize = (double)this.GetFontSize(), FontFamily = new FontFamily("Verdana"), Foreground = new SolidColorBrush(this.TextColor) }; textBlock.SetValue(Canvas.LeftProperty, left); textBlock.SetValue(Canvas.TopProperty, top); return textBlock; } private List BuildWeeklyList(float width, IDateScaler DateScale, bool failOnCollision) { var list = new List(); int startDateIndex = DateScale.StartDateIndex; var aDate = DateScale.DateValue(startDateIndex); int num = -2147483648; aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day); checked { aDate = aDate.AddDays((DayOfWeek)1 - aDate.DayOfWeek); //aDate = aDate.AddDays(7.0); List result; for (int i = DateScale.BinaryIndexSearch(aDate, startDateIndex); i >= 0; i = DateScale.BinaryIndexSearch(aDate, i)) { aDate = DateScale.DateValue(i); if (aDate.Equals(default(DateTime))) break; bool flag = i >= startDateIndex; if (flag) { var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem { Percent = DateScale.PercentFromIndex(i), Text = aDate.Day.ToString("d"), Date = aDate }; if (failOnCollision) { bool flag2 = unchecked(width * dateScaleDisplay.Percent) < (float)num; if (flag2) { result = null; return result; } num = (int)Math.Round((double)unchecked(this.GetTextWidth(dateScaleDisplay.Text)+5 + width * dateScaleDisplay.Percent)); //加5不显示靠近 } list.Add(dateScaleDisplay); } aDate = new DateTime(aDate.Year, aDate.Month, aDate.Day); aDate = aDate.AddDays((DayOfWeek)1 - aDate.DayOfWeek); aDate = aDate.AddDays(7.0); } result = list; return result; } } private List BuildYearlyList(float width, IDateScaler dateScale, bool failOnCollision, int interval) { var list = new List(); int startDateIndex = dateScale.StartDateIndex; var aDate = dateScale.DateValue(startDateIndex); int num = -2147483648; aDate = new DateTime(aDate.Year, 1, 1); //aDate = aDate.AddYears(1); List result; DateTime aDate2; for (int i = dateScale.BinaryIndexSearch(aDate, startDateIndex); i >= 0; i = dateScale.BinaryIndexSearch(aDate2, i)) { aDate = dateScale.DateValue(i); if (aDate.Equals(default(DateTime))) break; bool flag = i >= startDateIndex; if (flag) { var dateScaleDisplay = new DateScaleDisplay.DateScaleDisplayItem { Percent = dateScale.PercentFromIndex(i), Text = aDate.ToString("yyyy"), Date = aDate }; if (failOnCollision) { bool flag2 = unchecked(width * dateScaleDisplay.Percent) < (float)num; if (flag2) { result = null; return result; } num = (int)Math.Round((double)unchecked(this.GetTextWidth(dateScaleDisplay.Text) + width * dateScaleDisplay.Percent)); } list.Add(dateScaleDisplay); } aDate2 = new DateTime(aDate.Year + interval, 1, 1); } result = list; return result; } /// /// 移除所有非 FutureDateSplit 元素 /// private void CleanupCanvas() { if (this.Children == null || this.Children.Count == 0) return; var length = this.Children.Count - 1; for (int i = length; i >= 0; i--) { var current = this.Children[i] as UIElement; if (current != null && !(current is FutureDateSplit)) { this.Children.Remove(current); } } } private List GetDailyDisplayItemsList(float width, IDateScaler dateScale, int interval) { var list = this.BuildDailyList(width, dateScale, true, interval); if (list == null) return null; //不显示第二行数据 //var line2List = this.BuildLine2MonthList(width, dateScale, true); //if (line2List == null) return null; //list.AddRange(line2List); return list; } private double GetFontSize() { return 12d; //时间滑块的字体不用变 //bool flag = this._chart != null; //double result; //if (flag) //{ // result = this._chart.ChartFontSize - 1; //} //else //{ // result = 11f; //} //return result; } private List GetHourlyDisplayItemsList(float width, IDateScaler dateScale, int interval) { var list = this.BuildHourlyList(width, dateScale, true, interval); if (list == null) return null; //不显示第二行数据 //var line2List = this.BuildLine2DailyList(width, dateScale, true); //if (line2List == null) return null; //list.AddRange(line2List); return list; } private List GetMinutelyDisplayItemsList(float width, IDateScaler dateScale, int interval) { var list = this.BuildMintelyList(width, dateScale, true, interval); if (list == null) return null; //不显示第二行数据 //var line2List = this.BuildLine2DailyList(width, dateScale, true); //if (line2List == null) return null; //list.AddRange(line2List); return list; } private List GetMonthlyDisplayItemsList(float width, IDateScaler dateScale, int interval) { var list = this.BuildMonthlyList(width, dateScale, true, interval); if (list == null) return null; //不显示第二行数据 //var line2List = this.BuildLine2YearylyList(width, dateScale, true); //if (line2List == null) return null; //list.AddRange(line2List); return list; } private string GetQuarterString(DateTime aDate) { bool flag = aDate.Month >= 1 & aDate.Month <= 3; string result = "Q1"; if (flag) { result = "Q1"; } else { flag = (aDate.Month >= 4 & aDate.Month <= 6); if (flag) { result = "Q2"; } else { flag = (aDate.Month >= 7 & aDate.Month <= 9); if (flag) { result = "Q3"; } else { flag = (aDate.Month >= 10 & aDate.Month <= 12); if (flag) { result = "Q4"; } } } } return result; } private double GetTextWidth(string txt) { return TreeHelper.GetTextWidth(this.GetFontSize(), txt); //(float)((double)this.GetFontSize() * 0.8 * (double)txt.Length); } #endregion Private Methods #endregion Methods #region Nested Types private class DateScaleDisplayItem { #region Fields protected float _precent; //DateScaleDisplay_138_786; #endregion Fields #region Constructors public DateScaleDisplayItem() { this.IsEven = false; this.IsTwoLines = false; } #endregion Constructors #region Properties #region Public Properties public bool IsEven { get; set; } public bool IsTwoLines { get; set; } public float Percent { get { bool flag = this._precent > 0f; float result; if (flag) { result = this._precent; } else { result = 0f; } return result; } set { bool flag = value > 0f; if (flag) { this._precent = value; } } } public string Text { get; set; } public DateTime Date { get; set; } #endregion Public Properties #endregion Properties } #endregion Nested Types } }