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
{
///
/// 数据滑块类
///
public class DateChartSlider : Canvas
{
#region Fields
private Chart _chart;
private IList _dataPoints;
private int _dataPointsCount;
private Point _oldPosition;
private bool _isDarkBackground;
///
/// 底部微型数据展示区域
///
private Rect _miniAreaRect;
private UIElement _miniTrendPath;
///
/// 标志鼠标位于滑块状态
///
private DateChartSlider.MouseLocationType _mouseLocation;
private Rect _oldMiniAreaRect;
private Rectangle _selectedArea;
///
/// 滑块手柄区域
///
private Rect _selectedAreaRec;
///
/// 开始数据索引
///
private int _startIndex;
///
/// 滑块右边的x坐标-鼠标按下坐标
///
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
///
/// 标志鼠标位于滑块状态
///
private enum MouseLocationType
{
///
/// 位于滑块手柄左边
///
Left,
///
/// 位于滑块手柄右边
///
Right,
///
/// 位于滑块手柄中间
///
Center,
///
/// 位于滑块手柄外面
///
Outer
}
#endregion Enumerations
#region Methods
#region Internal Methods
///
/// 构造微缩图例
///
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();
//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
///
/// 画线
///
/// The x1.
/// The y1.
/// The x2.
/// The y2.
/// A color.
/// To add.
private void BuildLine(double x1, double y1, double x2, double y2, Color aColor, List toAdd)
{
if (toAdd == null) return;
toAdd.Add(new Line { X1 = (x1), X2 = (x2), Y1 = (y1), Y2 = (y2), Stroke = new SolidColorBrush(aColor) });
}
///
/// 数据微缩显示区块
///
///
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();
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;
}
///
/// 构造一个矩形
///
///
///
///
///
///
///
///
///
private Rectangle BuildRectangle(double x, double y, double width, double height, Color fill, Color border, List 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;
}
///
/// 构造一个滑块手柄
///
///
///
///
///
private Rectangle BuildSliderHandle(double x, double y, List 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;
}
///
/// 拖拉、移动滑块执行操作
///
///
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();
}
}
///
/// 返回指定点位于滑块的位置
///
///
///
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
}
}