| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607 |
- using MuchInfo.Chart.Data.Interfaces;
- using MuchInfo.Chart.Infrastructure.Helpers;
- 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.Input;
- using System.Windows.Media;
- using System.Windows.Shapes;
- namespace MuchInfo.Chart.WPF.Primitives
- {
- /// <summary>
- /// 数据滑块类
- /// </summary>
- public class DateChartSlider : Canvas
- {
- #region Fields
- private Chart _chart;
- private IList<ILineDataPoint> _dataPoints;
- private int _dataPointsCount;
- private Point _oldPosition;
- private bool _isDarkBackground;
- /// <summary>
- /// 底部微型数据展示区域
- /// </summary>
- private Rect _miniAreaRect;
- private UIElement _miniTrendPath;
- /// <summary>
- /// 标志鼠标位于滑块状态
- /// </summary>
- private DateChartSlider.MouseLocationType _mouseLocation;
- private Rect _oldMiniAreaRect;
- private Rectangle _selectedArea;
- /// <summary>
- /// 滑块手柄区域
- /// </summary>
- private Rect _selectedAreaRec;
- /// <summary>
- /// 开始数据索引
- /// </summary>
- private int _startIndex;
- /// <summary>
- /// 滑块右边的x坐标-鼠标按下坐标
- /// </summary>
- private int _xRight;
- #endregion Fields
- #region Constructors
- public DateChartSlider(Chart aChart)
- {
- base.LostMouseCapture -= (new MouseEventHandler(this.DateChartSlider_LostMouseCapture));
- base.MouseLeftButtonDown -= (new MouseButtonEventHandler(this.DateChartSlider_MouseLeftButtonDown));
- base.MouseLeftButtonUp -= (new MouseButtonEventHandler(this.DateChartSlider_MouseLeftButtonUp));
- base.MouseMove -= (new MouseEventHandler(this.DateChartSlider_MouseMove));
- base.LostMouseCapture += (new MouseEventHandler(this.DateChartSlider_LostMouseCapture));
- base.MouseLeftButtonDown += (new MouseButtonEventHandler(this.DateChartSlider_MouseLeftButtonDown));
- base.MouseLeftButtonUp += (new MouseButtonEventHandler(this.DateChartSlider_MouseLeftButtonUp));
- base.MouseMove += (new MouseEventHandler(this.DateChartSlider_MouseMove));
- this._mouseLocation = DateChartSlider.MouseLocationType.Outer;
- this._isDarkBackground = true;
- this._chart = aChart;
- }
- #endregion Constructors
- #region Enumerations
- /// <summary>
- /// 标志鼠标位于滑块状态
- /// </summary>
- private enum MouseLocationType
- {
- /// <summary>
- /// 位于滑块手柄左边
- /// </summary>
- Left,
- /// <summary>
- /// 位于滑块手柄右边
- /// </summary>
- Right,
- /// <summary>
- /// 位于滑块手柄中间
- /// </summary>
- Center,
- /// <summary>
- /// 位于滑块手柄外面
- /// </summary>
- Outer
- }
- #endregion Enumerations
- #region Methods
- #region Internal Methods
- /// <summary>
- /// 构造微缩图例
- /// </summary>
- internal void BuildDateChartSlider()
- {
- float num = 0;
- if (this._chart != null)
- {
- this._isDarkBackground = this._chart.IsDarkBackground;
- num = (float)(this._chart.ActualHeight * 0.03);
- }
- num = num > 35f ? 35 : (num < 18f ? 18f : num);
- if (!this.ActualHeight.Equals(num)) this.Height = ((double)num);
- var list = new List<UIElement>();
- //var actualWidth = (float)(this.ActualWidth - 40.0) - (this._chart == null ? 0 : this._chart.RightBuffer);
- var actualWidth = this._chart == null ? 0 : this._chart.GetChartPaneWidth();
- actualWidth = (actualWidth < 0f) ? 0f : actualWidth;
- //绘制整个控件背景色矩形
- if (this._isDarkBackground)
- {
- this.BuildRectangle(0.0, 0.0, (double)actualWidth, this.ActualHeight, Color.FromArgb(255, 40, 40, 40), Colors.Transparent, list);
- }
- else
- {
- if (this._chart != null)
- {
- this.BuildRectangle(0.0, 0.0, (double)actualWidth, this.ActualHeight, this._chart.ChartBackgroundColor, Colors.Transparent, list);
- }
- this.BuildRectangle(-1.0, 0.0, (double)actualWidth, this.ActualHeight + 2.0, Colors.Transparent, Colors.Gray, list);
- }
- this._miniAreaRect = new Rect(0.0, 0.0, (double)actualWidth, this.ActualHeight);
- if (_chart != null && _chart.DateScaler != null)
- {
- var count = _chart.DateScaler.Count();
- if (count > 1)
- {
- //绘制两滑块中背景色矩形
- double startLeft = (double)checked((int)Math.Round((double)(unchecked(actualWidth * (float)_chart.DateScaler.StartDateIndex) / (float)(count - 1)))) + 0.5;
- double endLeft = (double)checked((int)Math.Round((double)(unchecked(actualWidth * (float)_chart.DateScaler.EndDateIndex) / (float)(count - 1)))) + 0.5;
- this._selectedArea = this.BuildRectangle(startLeft, 0.0, endLeft - startLeft, this.ActualHeight,
- this._isDarkBackground ? Colors.DimGray : Colors.SlateGray, Colors.Transparent, list);
- this._selectedAreaRec = new Rect(startLeft, 0.0, endLeft - startLeft, this.ActualHeight);
- //绘制背景走势矩形
- list.Add(this.BuildMiniTrendPath());
- //绘制滑块上下两根线
- this.BuildLine(startLeft, 0.0, startLeft, this.ActualHeight, this._isDarkBackground ? Colors.DarkGray : Colors.LightGray, list);
- this.BuildLine(endLeft, 0.0, endLeft, this.ActualHeight, this._isDarkBackground ? Colors.DarkGray : Colors.LightGray, list);
- //绘制起始滑块
- this.BuildSliderHandle(startLeft, this.ActualHeight / 2.0, list);
- //绘制结束滑块
- this.BuildSliderHandle(endLeft, this.ActualHeight / 2.0, list);
- }
- //控制时间滑块区域:TD1464
- var rectangleGeometry = new RectangleGeometry
- {
- Rect = new Rect(0.0, 0.0, this.ActualWidth, this.ActualHeight)
- };
- this.Clip = (rectangleGeometry);
- this.Children.Clear();
- foreach (var current in list)
- {
- this.Children.Add(current);
- }
- }
- }
- #endregion Internal Methods
- #region Private Methods
- /// <summary>
- /// 画线
- /// </summary>
- /// <param name="x1">The x1.</param>
- /// <param name="y1">The y1.</param>
- /// <param name="x2">The x2.</param>
- /// <param name="y2">The y2.</param>
- /// <param name="aColor">A color.</param>
- /// <param name="toAdd">To add.</param>
- private void BuildLine(double x1, double y1, double x2, double y2, Color aColor, List<UIElement> toAdd)
- {
- if (toAdd == null) return;
- toAdd.Add(new Line { X1 = (x1), X2 = (x2), Y1 = (y1), Y2 = (y2), Stroke = new SolidColorBrush(aColor) });
- }
- /// <summary>
- /// 数据微缩显示区块
- /// </summary>
- /// <returns></returns>
- private UIElement BuildMiniTrendPath()
- {
- if (this._miniAreaRect.Equals(this._oldMiniAreaRect) && this._miniTrendPath != null &&
- this._chart != null && this._chart.DataSet != null && this._chart.DataSet.DataPoints != null &&
- this._dataPoints == this._chart.DataSet.DataPoints && this._dataPointsCount == this._chart.DateScaler.Count())
- {
- return this._miniTrendPath;
- }
- this._oldMiniAreaRect = this._miniAreaRect;
- var num = (float)this._miniAreaRect.Width;
- var solidColorBrush = new SolidColorBrush
- {
- Color = this._isDarkBackground ? Colors.DarkGray : ColorHelper.SteelBlue,
- Opacity = (0.5)
- };
- var path = new Path
- {
- Stroke = solidColorBrush,
- StrokeThickness = (1.0),
- Fill = this._isDarkBackground
- ? new SolidColorBrush(Color.FromArgb(100, 100, 100, 100))
- : new SolidColorBrush(Color.FromArgb(100, 155, 155, 155))
- };
- if (this._chart == null || this._chart.DataSet == null || this._chart.DataSet.DataPoints == null || !this._chart.DataSet.DataPoints.Any())
- {
- return path;
- }
- IDateScaler dateScaler = this._chart.DateScaler;
- var list = new List<ILineDataPoint>();
- this._dataPoints = this._chart.DataSet.DataPoints;
- this._dataPointsCount = this._chart.DateScaler.Count();
- list.AddRange(this._dataPoints);
- var pathFigure = new PathFigure { StartPoint = new Point(0.0, this.ActualHeight) };
- var pathGeometry = new PathGeometry();
- pathGeometry.Figures.Add(pathFigure);
- path.Data = pathGeometry;
- var maxValue = list.Max(z => z.Value); //存储最大值
- var minValue = list.Where(z => z.Value > 0).Min(z => z.Value); //存储最小值
- var scalerLength = dateScaler.Count() - 1;
- scalerLength = scalerLength <= 0 ? 1 : scalerLength;
- LineSegment lineSegment;
- int index;
- float top;
- float left;
- checked
- {
- if (list.Count > 8)
- {
- int length = list.Count - 1;
- int i = 0;
- while (true)
- {
- int num6 = length;
- if (i > num6)
- {
- break;
- }
- lineSegment = new LineSegment();
- index = i;
- unchecked
- {
- //top = num * (float)index / (float)(dateScaler.Count());
- top = num * index / scalerLength;
- if (maxValue.Equals(minValue))
- {
- left = (float)(this.ActualHeight * 0.5);
- }
- else
- {
- left = (float)(this.ActualHeight * (double)(1f - (list[i].Value - minValue) / (maxValue - minValue)));
- }
- lineSegment.Point = new Point((double)top, (double)left);
- pathFigure.Segments.Add(lineSegment);
- }
- i += 5;
- }
- }
- lineSegment = new LineSegment();
- index = dateScaler.IndexFromDate(list[list.Count - 1].Date);
- }
- //top = num * (float)index / (float)(dateScaler.Count());
- top = num * index / scalerLength;
- if (maxValue.Equals(minValue))
- {
- left = (float)(this.ActualHeight * 0.5);
- }
- else
- {
- left = (float)(this.ActualHeight * (double)(1f - (list[checked(list.Count - 1)].Value - minValue) / (maxValue - minValue)));
- }
- lineSegment.Point = new Point((double)top, (double)left);
- pathFigure.Segments.Add(lineSegment);
- lineSegment = new LineSegment { Point = new Point((double)top, this.ActualHeight) };
- pathFigure.Segments.Add(lineSegment);
- lineSegment = new LineSegment { Point = new Point(0.0, this.ActualHeight) };
- pathFigure.Segments.Add(lineSegment);
- this._miniTrendPath = path;
- return path;
- }
- /// <summary>
- /// 构造一个矩形
- /// </summary>
- /// <param name="x"></param>
- /// <param name="y"></param>
- /// <param name="width"></param>
- /// <param name="height"></param>
- /// <param name="fill"></param>
- /// <param name="border"></param>
- /// <param name="toAdd"></param>
- /// <returns></returns>
- private Rectangle BuildRectangle(double x, double y, double width, double height, Color fill, Color border, List<UIElement> toAdd)
- {
- Rectangle result = null;
- if (width > 0.0 && height > 0.0)
- {
- var rectangle = new Rectangle()
- {
- Height = height,
- Width = width,
- };
- rectangle.SetValue(Canvas.LeftProperty, x);
- rectangle.SetValue(Canvas.TopProperty, y);
- if (!fill.Equals(Colors.Transparent))
- {
- rectangle.Fill = new SolidColorBrush(fill);
- }
- if (!border.Equals(Colors.Transparent))
- {
- rectangle.Stroke = new SolidColorBrush(border);
- }
- toAdd.Add(rectangle);
- result = rectangle;
- }
- return result;
- }
- /// <summary>
- /// 构造一个滑块手柄
- /// </summary>
- /// <param name="x"></param>
- /// <param name="y"></param>
- /// <param name="toAdd"></param>
- /// <returns></returns>
- private Rectangle BuildSliderHandle(double x, double y, List<UIElement> toAdd)
- {
- var rectangle = new Rectangle
- {
- Height = 16.0,
- Width = 10.0,
- Fill = this._isDarkBackground ? new SolidColorBrush(Colors.DarkGray) : new SolidColorBrush(Colors.LightGray),
- RadiusX = 4.0,
- RadiusY = 4.0,
- };
- rectangle.SetValue(Canvas.TopProperty, y - 8.0);
- rectangle.SetValue(Canvas.LeftProperty, x - 5.0);
- toAdd.Add(rectangle);
- int num = -2;
- do
- {
- var line = new Line
- {
- X1 = x + (double)num,
- X2 = x + (double)num,
- Y1 = y - 3.0,
- Y2 = y + 3.0,
- Stroke = new SolidColorBrush(Color.FromArgb(255, 130, 130, 130))
- };
- toAdd.Add(line);
- checked
- {
- num += 2;
- }
- }
- while (num <= 2);
- return rectangle;
- }
- private void DateChartSlider_LostMouseCapture(object sender, MouseEventArgs e)
- {
- this._mouseLocation = DateChartSlider.MouseLocationType.Outer;
- }
- private void DateChartSlider_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
- {
- e.Handled = true;
- Point position = e.GetPosition(this);
- _oldPosition = position;
- this._mouseLocation = this.GetMouseLocationType(position);
- checked
- {
- this._xRight = (int)Math.Round(unchecked(this._selectedAreaRec.Right - position.X));
- this._startIndex = this._chart.DateScaler.StartDateIndex;
- switch (this._mouseLocation)
- {
- case DateChartSlider.MouseLocationType.Left:
- case DateChartSlider.MouseLocationType.Right:
- this.Cursor = Cursors.SizeWE;
- this.CaptureMouse();
- break;
- case DateChartSlider.MouseLocationType.Center:
- this.Cursor = Cursors.Hand;
- this.CaptureMouse();
- break;
- case DateChartSlider.MouseLocationType.Outer:
- this.Cursor = Cursors.Arrow;
- break;
- }
- }
- }
- private void DateChartSlider_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
- {
- e.Handled = true;
- var position = e.GetPosition(this);
- if (this._mouseLocation != DateChartSlider.MouseLocationType.Outer)
- {
- this.DragSliderTo(position);
- this._mouseLocation = DateChartSlider.MouseLocationType.Outer;
- this.ReleaseMouseCapture();
- }
- }
- private void DateChartSlider_MouseMove(object sender, MouseEventArgs e)
- {
- var position = e.GetPosition(this);
- bool flag = this._mouseLocation != DateChartSlider.MouseLocationType.Outer;
- if (flag)
- {
- this.DragSliderTo(position);
- }
- else
- {
- switch (this.GetMouseLocationType(position))
- {
- case DateChartSlider.MouseLocationType.Left:
- case DateChartSlider.MouseLocationType.Right:
- this.Cursor = Cursors.SizeWE;
- break;
- case DateChartSlider.MouseLocationType.Center:
- this.Cursor = Cursors.Hand;
- break;
- case DateChartSlider.MouseLocationType.Outer:
- this.Cursor = Cursors.Arrow;
- break;
- }
- }
- _oldPosition = position;
- }
- /// <summary>
- /// 拖拉、移动滑块执行操作
- /// </summary>
- /// <param name="pos"></param>
- private void DragSliderTo(Point pos)
- {
- //避免在选择块中间单击移动
- if (this._mouseLocation == MouseLocationType.Center)
- {
- var x = pos.X - _oldPosition.X;
- if (Math.Abs(x) < 2) return;
- }
- bool flag = false;
- var scalerCount = this._chart.DateScaler.Count();
- double num = (pos.X - this._miniAreaRect.X) / this._miniAreaRect.Width;
- num = num * scalerCount - 1.0; //得出num=鼠标点击处位于数据展示区的数据个数
- if (double.IsInfinity(num) || double.IsNaN(num)) return;
- switch (this._mouseLocation)
- {
- case DateChartSlider.MouseLocationType.Left:
- {
- checked
- {
- var number = (int)Math.Round(num);
- number = number < 0 ? 0 : number;
- if (number > this._chart.DateScaler.EndDateIndex - 3)
- {
- number = this._chart.DateScaler.EndDateIndex - 3;
- }
- if (this._chart.DateScaler.NumBars != this._chart.DateScaler.EndDateIndex - number)
- {
- this._chart.DateScaler.NumBars = this._chart.DateScaler.EndDateIndex - number;
- flag = true;
- }
- break;
- }
- }
- case DateChartSlider.MouseLocationType.Right:
- {
- checked
- {
- var number = (int)Math.Round(num);
- number = number < this._startIndex + 3 ? this._startIndex + 3 : number;
- if (number >= scalerCount - 1)
- {
- if (DateTime.Compare(this._chart.DateScaler.DesiredEndDate, DateTime.MaxValue) != 0)
- {
- this._chart.DateScaler.DesiredEndDate = DateTime.MaxValue;
- flag = true;
- }
- number = scalerCount - 1;
- }
- else
- {
- if (DateTime.Compare(this._chart.DateScaler.DesiredEndDate, this._chart.DateScaler.DateValue(number)) != 0)
- {
- this._chart.DateScaler.DesiredEndDate = this._chart.DateScaler.DateValue(number);
- flag = true;
- }
- }
- var bars = number - this._startIndex;
- if (this._chart.DateScaler.NumBars != bars)
- {
- this._chart.DateScaler.NumBars = bars;
- flag = true;
- }
- break;
- }
- }
- case DateChartSlider.MouseLocationType.Center:
- {
- checked
- {
- var number = (int)Math.Round(num);
- number = number - this._chart.DateScaler.NumBars < 0 ? this._chart.DateScaler.NumBars : number;
- if (number >= scalerCount - 1)
- {
- if (DateTime.Compare(this._chart.DateScaler.DesiredEndDate, DateTime.MaxValue) != 0)
- {
- this._chart.DateScaler.DesiredEndDate = DateTime.MaxValue;
- flag = true;
- }
- number = scalerCount - 1;
- }
- else
- {
- if (DateTime.Compare(this._chart.DateScaler.DesiredEndDate, this._chart.DateScaler.DateValue(number)) != 0)
- {
- this._chart.DateScaler.DesiredEndDate = this._chart.DateScaler.DateValue(number);
- flag = true;
- }
- }
- break;
- }
- }
- }
- if (flag)
- {
- this._chart.Refresh();
- }
- }
- /// <summary>
- /// 返回指定点位于滑块的位置
- /// </summary>
- /// <param name="pos"></param>
- /// <returns></returns>
- private DateChartSlider.MouseLocationType GetMouseLocationType(Point pos)
- {
- if (pos.X > this._selectedAreaRec.Left - 3.0 && pos.X < this._selectedAreaRec.Left + 3.0)
- return DateChartSlider.MouseLocationType.Left;
- if (pos.X > this._selectedAreaRec.Right - 3.0 && pos.X < this._selectedAreaRec.Right + 3.0)
- return DateChartSlider.MouseLocationType.Right;
- if (this._selectedAreaRec.Contains(pos)) return DateChartSlider.MouseLocationType.Center;
- return DateChartSlider.MouseLocationType.Outer;
- }
- #endregion Private Methods
- #endregion Methods
- }
- }
|