wpf折线图可以放缩移动(第一版)

ChartDate.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace WpfApp5
{
    /// <summary>
    /// 画图的基本数据项
    /// </summary>
    public class ChartDate
    {
        private double yMarginTop;//顶部留空
        private double yMarginLeft;//Y轴左侧,用来显示刻度文字的空白间距
        private double xMarginBottom;//X轴下侧,用来显示刻度文字的空白间距

        private int yNumInt;//刻度个数
        private double yInterval;//Y轴刻度间隔量

        private int xNumInt;//x轴的刻度个数
        private double xInterval;//x轴间隔量
        private double xIntervalLineHeight;//X轴刻度线的高度

        private double minY;//Y轴最小值
        private double maxY;//Y轴最大值

        private DateTime minX;//X轴最小值
        private DateTime maxX;//X轴最大值

        private double xMove;//x位移量
        private double yMove;//y位移量

        public ChartDate(double yMarginTop, double yMarginLeft, double xMarginBottom, int yNumInt, double yInterval, int xNumInt, double xIntervalLineHeight, double minY, double maxY, DateTime minX, DateTime maxX, double xInterval, double xMove = 0, double yMove = 0)
        {
            this.yMarginTop = yMarginTop;
            this.yMarginLeft = yMarginLeft;
            this.xMarginBottom = xMarginBottom;
            this.yNumInt = yNumInt;
            this.yInterval = yInterval;
            this.xNumInt = xNumInt;
            this.xIntervalLineHeight = xIntervalLineHeight;
            this.minY = minY;
            this.maxY = maxY;
            this.minX = minX;
            this.maxX = maxX;
            this.XInterval = xInterval;
            this.xMove = xMove;
            this.yMove = yMove;
        }

        public double YMarginLeft { get => yMarginLeft; set => yMarginLeft = value; }
        public double XMarginBottom { get => xMarginBottom; set => xMarginBottom = value; }
        public int YNumInt { get => yNumInt; set => yNumInt = value; }
        public double YInterval { get => yInterval; set => yInterval = value; }
        public int XNumInt { get => xNumInt; set => xNumInt = value; }
        public double XIntervalLineHeight { get => xIntervalLineHeight; set => xIntervalLineHeight = value; }
        public double MinY { get => minY; set => minY = value; }
        public double MaxY { get => maxY; set => maxY = value; }
        public DateTime MinX { get => minX; set => minX = value; }
        public DateTime MaxX { get => maxX; set => maxX = value; }
        public double YMarginTop { get => yMarginTop; set => yMarginTop = value; }
        public double XInterval { get => xInterval; set => xInterval = value; }
        public double XMove { get => xMove; set => xMove = value; }
        public double YMove { get => yMove; set => yMove = value; }

        /// <summary>
        /// X轴线
        /// </summary>
        public Rectangle Xaxis()
        {
            //x轴线
            Rectangle rx = new Rectangle();//矩形
            rx.Height = 1;
            rx.Stroke = new SolidColorBrush(Color.FromRgb(128, 128, 142));//Stroke 边框
            rx.HorizontalAlignment = HorizontalAlignment.Stretch;//拉伸填充
            rx.VerticalAlignment = VerticalAlignment.Bottom;
            return rx;
        }

        /// <summary>
        /// Y轴线
        /// </summary>
        public Rectangle Yaxis()
        {
            Rectangle ry = new Rectangle();
            ry.Width = 1;
            ry.Stroke = new SolidColorBrush(Color.FromRgb(128, 128, 142));
            ry.HorizontalAlignment = HorizontalAlignment.Left;
            ry.VerticalAlignment = VerticalAlignment.Stretch;
            return ry;
        }

        /// <summary>
        ///  Y轴虚线
        /// </summary>
        public Line YImaginaryLine(double ActualHeight, double ActualWidth, int i)
        {
            //y轴虚线
            Line line = new Line();
            line.X1 = 0;
            line.Y1 = (ActualHeight - YMarginTop) / YInterval * i + YMarginTop;
            //Debug.WriteLine($"Data3 :{line.Y1.ToString()+"虚"+ ActualHeight+"高"+ YMarginTop+"顶"+ Convert.ToDouble(XNumInt)+"最后"+ YMove}");
            //MessageBox.Show($"Data3 :{line.Y1.ToString() + "Y轴位置"+ YInterval +"间距"+ ActualHeight + "高" + YMarginTop + "顶" + Convert.ToDouble(XNumInt) + "个数" + YMove+"移动量"}");
            line.X2 = ActualWidth;
            line.Y2 = line.Y1;
            line.Stroke = new SolidColorBrush(Color.FromRgb(73, 73, 91));
            line.StrokeThickness = 1;
            line.StrokeDashArray = new DoubleCollection() { 10, 15 };//虚线,实线的长度和间距
            return line;
        }


        /// <summary>
        ///Y轴图标
        /// </summary>
        public TextBlock YIco(double ActualHeight, int i)
        {
            //Y轴 
            //y轴图标
            TextBlock tb = new TextBlock();
            tb.FontSize = 12;
            tb.Foreground = new SolidColorBrush(Color.FromRgb(128, 128, 142));
            tb.Text = (maxY - (maxY - minY) / yInterval * i).ToString();
            tb.VerticalAlignment = VerticalAlignment.Top;
            tb.HorizontalAlignment = HorizontalAlignment.Left;
            tb.Margin = new Thickness(YMarginLeft-10, (ActualHeight - YMarginTop) / YInterval * i + YMarginTop - (GetFontSizeByTextBlock(tb).Height / 2D), 0, 0);//GetFontSizeByTextBlock 文体尺寸
          //  MessageBox.Show($"Data4 :{ "Y轴位置" + YInterval + "间距" + ActualHeight + "高" + YMarginTop + "顶" + Convert.ToDouble(XNumInt) + "个数" + YMove + "移动量"}");
            return tb;

        }

        /// <summary>
        /// //X轴刻度线
        /// </summary>
        public Line XImaginaryLine(double ActualHeight, double ActualWidth, int i)
        {
            //x刻度线
            Line line = new Line();//小短线
            //xInterval = (maxX.ToOADate() - minX.ToOADate())/Convert.ToDouble(xNumInt);
           // Debug.WriteLine("间距:"+xInterval.ToString());
            line.X1 =xInterval * i+xMove;
            line.Y1 = 0;//顶部
            line.X2 = line.X1;
            line.Y2 = -XIntervalLineHeight;
            if (i % 2 == 0)
            {
                line.Y2 -= 5D;
            }
            line.Stroke = new SolidColorBrush(Color.FromRgb(128, 128, 142));
            line.StrokeThickness = 1;
            return line;
        }

        //x轴图标
        public TextBlock XIco(double ActualWidth, int i)
        {
            //x轴图标
            //两个刻度显示一次文字,并且图标加长

            //Min
            Debug.WriteLine("_+_++++++++++++++++++++++++++++++++++++" + minX.ToString());
            string strMin = minX.ToString();
            string[] strArrayMin = strMin.Split(new char[] { '/', ' ', ':' });
            //foreach (string s in strArrayMin)
            //{
            //    Debug.WriteLine("_+_:" + s);
           

            int[] dataNumMin = new int[6];
            int countMin = 0;
            foreach (string j in strArrayMin)
            {
                dataNumMin[countMin++] = Convert.ToInt32(j);
             //   Debug.WriteLine("====:" + dataNumMin[countMin - 1]);
            }

            
            string strMax = maxX.ToString();
            string[] strArrayMax = strMax.Split(new char[] { '/', ' ', ':' });
            int[] dataNumMax = new int[6];
            int countMax = 0;
            foreach (string j in strArrayMin)
            {
                dataNumMax[countMax++] = Convert.ToInt32(j);
            //    Debug.WriteLine("====:" + dataNumMax[countMax - 1]);
            }

            //坐标轴位置输出
            TextBlock tb = new TextBlock();

            tb.FontSize = 12;
            tb.Foreground = new SolidColorBrush(Color.FromRgb(128, 128, 142));
            //i++;
          //  dataNumMin[1] += i;
          //  Debug.WriteLine("临时点:++:" + dataNumMin[1]);

            //if (dataNumMin[1] > 12)
            //{
            //    dataNumMin[1] = i % 12;
            //    dataNumMin[0]++;
            //}
            //if (dataNumMin[1] < 1)
            //{
            //    dataNumMin[1] = 12 + dataNumMin[1] % 12;
            //    dataNumMin[0]--;
            //}
            //for (int j = 0; j < 3; j++)
            //{
            //    tb.Text += dataNumMin[j].ToString();
            //    if (j < 2)
            //        tb.Text += "/";
            //}
            //tb.Text += "\n";
            //for (int j = 3; j < 6; j++)
            //{
            //    tb.Text += dataNumMin[j].ToString();
            //    if (j < 5)
            //        tb.Text += ":";
            //}

            //算出第一个坐标大个格子
            double data = (maxX.ToOADate() - minX.ToOADate()) /ActualWidth;
            double iData = minX.ToOADate()+data * i * (ActualWidth/xNumInt);
            DateTime iDataTime = DateTime.FromOADate(iData);
            Debug.WriteLine(" iDataTime  转换检测:======================" + iDataTime+"     "+i);
            tb.Text = iDataTime.ToString();

            tb.VerticalAlignment = VerticalAlignment.Bottom;
            tb.HorizontalAlignment = HorizontalAlignment.Left;
            tb.Margin = new Thickness(xInterval * i - (GetFontSizeByTextBlock(tb).Width / 2D) + xMove, 0, 0, XMarginBottom);
            return tb;


            //TextBlock tb = new TextBlock();
            //tb.FontSize = 12;
            //tb.Foreground = new SolidColorBrush(Color.FromRgb(128, 128, 142));
            //if (i < 10)//个位数补零
            //{
            //    tb.Text = "0" + i.ToString() + ":00";
            //}
            //else
            //{
            //    tb.Text = i.ToString() + ":00";
            //}
            //tb.VerticalAlignment = VerticalAlignment.Bottom;
            //tb.HorizontalAlignment = HorizontalAlignment.Left;
            //tb.Margin = new Thickness(xInterval * i  + (GetFontSizeByTextBlock(tb).Width / 2D)-xInterval/2D +xMove, 0, 0, XMarginBottom);
            //return tb;
        }

        //画折线图
        public Polyline DrawChart(SortedDictionary<DateTime, int> source, double actualWidth,double actualHeight)
        {
            //第二条数据折线
            Polyline plPeople = new Polyline();
            plPeople.Stroke = new SolidColorBrush(Color.FromRgb(27, 221, 58));
            plPeople.StrokeThickness = 1;
            plPeople.StrokeLineJoin = PenLineJoin.Round;
            plPeople.IsHitTestVisible = false;
            plPeople.Fill= new SolidColorBrush(Color.FromRgb(27, 221, 58));
            plPeople.Fill.Opacity = 0.1;

            //SortedDictionary<DateTime, int> temp = new SortedDictionary<DateTime, int>();


            //将第一个值为初始值
            DateTime preMinX= Convert.ToDateTime("2021-01-01 00:00:00");//最小值的前一个节点
            foreach (var t in source) 
            {
                preMinX= t.Key;//最小值的前一个节点
                break;
            }
                

            DateTime dateMaxX=Convert.ToDateTime("2021-01-01 00:00:00");//最后一个节点
            bool bPreMinx = false;//用于判断是否需要输出preMinx
            foreach (var t in source)
            {
              

                //在minX 和max之外的不显示
                DateTime k = t.Key;

                dateMaxX = k;
                

                //多显示图像的前一个和后一个保证图形的连续性

                if (k.ToOADate() <minX.ToOADate() )
                {
                    //Debug.WriteLine("全显示:key:" + k.ToString() + "  value:" + source[k]);
                    //Debug.WriteLine("minx:key:" + minX.ToString());
                    //Debug.WriteLine("max:key:" + maxX.ToString());
                    //Debug.WriteLine("k的double:" + k.ToOADate() + " min的double" + minX.ToOADate() + " max的double" + maxX.ToOADate());
                    preMinX = k;
                    continue;
                }

                //输入前一个
                if (!bPreMinx) 
                {
                    //连接0点
                    Point pStart1 = new Point();
                    pStart1.X = (actualWidth / xNumInt * ((preMinX.ToOADate() - minX.ToOADate()) / ((maxX.ToOADate() - minX.ToOADate()) / xNumInt))) + xMove;
                    pStart1.Y = actualHeight;
                    plPeople.Points.Add(pStart1);

                    Point p1 = new Point();
                    p1.X = (actualWidth / xNumInt * ((preMinX.ToOADate() - minX.ToOADate()) / ((maxX.ToOADate() - minX.ToOADate()) / xNumInt))) + xMove;
                    p1.Y = ((actualHeight - yMarginTop) / (maxY - minY) * (maxY - source[preMinX])) + yMarginTop;
                    plPeople.Points.Add(p1);
                    bPreMinx = true;
                }

                Point p = new Point();
                p.X = (actualWidth / xNumInt * ((k.ToOADate() - minX.ToOADate()) / ((maxX.ToOADate() - minX.ToOADate()) / xNumInt))) + xMove;

                //超出y的界限怎么计算?????????

                p.Y = ((actualHeight - yMarginTop) / (maxY - minY) * (maxY - source[k])) + yMarginTop;
                plPeople.Points.Add(p);

                //最后一个值的后一个
                //这值要是存在就输出,不存在就将最后一个值连接0点
                if (k.ToOADate() > maxX.ToOADate()) 
                {
                    Point pEnd1 = new Point();
                    pEnd1.X = (actualWidth / xNumInt * ((dateMaxX.ToOADate() - minX.ToOADate()) / ((maxX.ToOADate() - minX.ToOADate()) / xNumInt))) + xMove;
                    pEnd1.Y = actualHeight;
                    plPeople.Points.Add(pEnd1);

                    return plPeople;
                }
                   

                //Ellipse ep = new Ellipse();
                //ep.Width = 10;
                //ep.Height = 10;
                //ep.Stroke = new SolidColorBrush(Color.FromRgb(230, 230, 236));
                //ep.StrokeThickness = 0;
                //ep.Fill = new SolidColorBrush(Color.FromRgb(27, 221, 58));
                //ep.HorizontalAlignment = HorizontalAlignment.Left;
                //ep.VerticalAlignment = VerticalAlignment.Top;
                //ep.Margin = new Thickness(p.X - 5, p.Y - 5, 0, -5);//底部设置-5(圆球宽高的一半),当Y等于0的时候,可以让圆球全部显示

            }

            //当容器第一个数据出现,第一个最底边
            Point pStart = new Point();
            pStart.X = (actualWidth / xNumInt * ((preMinX.ToOADate() - minX.ToOADate()) / ((maxX.ToOADate() - minX.ToOADate()) / xNumInt))) + xMove;
            //Debug.WriteLine("二号折线图数据:"+ "MAX-MIN:"+((cd.MaxX.ToOADate() - cd.MinX.ToOADate()) / cd.YNumInt)+ "K-MIN"+ (k.ToOADate() - cd.MinX.ToOADate()));
            pStart.Y = actualHeight;
            plPeople.Points.Add(pStart);

            //当容器最后一个数据出现时,连接最后一个最底边
            Point pEnd = new Point();
            pEnd.X = (actualWidth / xNumInt * ((dateMaxX.ToOADate() - minX.ToOADate()) / ((maxX.ToOADate() - minX.ToOADate()) / xNumInt))) + xMove;
            //Debug.WriteLine("二号折线图数据:"+ "MAX-MIN:"+((cd.MaxX.ToOADate() - cd.MinX.ToOADate()) / cd.YNumInt)+ "K-MIN"+ (k.ToOADate() - cd.MinX.ToOADate()));
            pEnd.Y = actualHeight;
            plPeople.Points.Add(pEnd);

            return plPeople;
        }


        //测量文本框的尺寸
        public Size GetFontSizeByTextBlock(TextBlock tb)
        {
            var formattedText = new FormattedText(
               tb.Text,
               CultureInfo.CurrentUICulture,
               FlowDirection.LeftToRight,
               new Typeface(tb.FontFamily, tb.FontStyle, tb.FontWeight, tb.FontStretch),
               tb.FontSize,
               tb.Foreground
               );
            Size size = new Size(formattedText.Width, formattedText.Height);
            return size;
        }
    }

}

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace WpfApp5
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// //Y轴上方的空白间距
        /// </summary>
        //double maxYMarginTop = 20;//Y轴上方的空白间距
        //double yMarginLeft = 30D;//Y轴左侧,用来显示刻度文字的空白间距

        //double yNum = 10D;//Y轴的刻度个数
        //int yNumInt = 10;

        //double minY = 10D;//Y轴最小值
        //double maxY = 110D;//Y轴最大值
        //double yInterval = 10D;//Y轴刻度

        //double xMarginBottom = 20D;//X轴下侧,用来显示刻度文字的空白间距

        //double xNum = 100D;//x轴的刻度个数
        //int xNumInt = 100;//x轴的刻度个数
        //double xIntervalLineHeight = 10D;//X轴刻度线的高度
        //DateTime minX = Convert.ToDateTime("2022-06-27 00:00:00");//X轴最小值
        //DateTime maxX = Convert.ToDateTime("2022-06-27 00:00:00");//X轴最大值

        //提前计算最小最大,坐标刻度间隔度
        ChartDate cd;
        SortedDictionary<DateTime, int> bsource;

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            cd = new ChartDate(20D, 30D, 20D, 10, 10D, 12, 10D, 0D, 100D, Convert.ToDateTime("2021-01-01 00:00:00"), Convert.ToDateTime("2022-02-01 00:00:00"), Bgrid.ActualWidth / 12D);
            try
            {
                Stopwatch watch = new Stopwatch();

                Agrid.Children.Clear();//清除全部

                //double timeInterval = (maxX.ToOADate() - minX.ToOADate()) / (xNum - 1);
                watch.Start();
                //折线1数据
                SortedDictionary<DateTime, int> csource = new SortedDictionary<DateTime, int>();
                Random random = new Random(DateTime.Now.Millisecond);
                for (int i = 0; i < 50; i++)
                {
                    DateTime time = DateTime.Now.AddHours(random.Next(-2400, 0));
                    int x = random.Next(1, 100);

                    if (csource.Count == 0 || csource.Keys.ToList().FindIndex(cur => $"{cur:yyyy-MM-dd HH:mm:ss}" == $"{time:yyyy-MM-dd HH:mm:ss}") == -1)
                    {
                        csource.Add(time, x);
                    //    Debug.WriteLine("数据1 :" + time.ToString() + "   " + x.ToString());

                    }

                }


                watch.Stop();
                Console.WriteLine($"Data1 : {watch.ElapsedMilliseconds}ms");

                watch.Restart();

                ///折线2数据
                bsource = new SortedDictionary<DateTime, int>();

                for (int i = 0; i < 10000; i++)
                {
                    var time = DateTime.Now.AddDays(random.Next(-24000, 24000));
                    int x = random.Next(1, 100);

                    bool bl = true;
                    foreach (DateTime dt in bsource.Keys)
                    {
                        if (dt.ToOADate() == time.ToOADate())
                        {
                            bl = false;
                            break;
                        }

                    }

                    if (!bl)
                        continue;
                    bsource.Add(time, x);

                }
                foreach (var t in bsource)
                {
               //     Debug.WriteLine("数据2 :" + t.ToString());
                }

                    watch.Stop();
                Debug.WriteLine($"Data2 : {watch.ElapsedMilliseconds}ms");

                watch.Restart();

                //x轴线
                Bgrid.Children.Add(cd.Xaxis());

                //y轴线
                Bgrid.Children.Add(cd.Yaxis());

                //y图标
                Ychart();

                //x轴
                Xchart();


                //第一条数据折线
                Polyline plView = new Polyline();//互连直线
                plView.Stroke = new SolidColorBrush(Color.FromRgb(66, 120, 255));
                plView.StrokeThickness = 1;
                plView.StrokeLineJoin = PenLineJoin.Round;//联接形状
                plView.IsHitTestVisible = true;
                foreach (DateTime k in csource.Keys)
                {
                    Point p = new Point();
                    //  p.X = (Agrid.ActualWidth / Convert.ToDouble(cd.XNumInt) * ((k.ToOADate() - cd.MaxX.ToOADate()) / cd.)) + ((Agrid.ActualWidth / xNum) / 2D);
                    //p.Y = ((Agrid.ActualHeight - maxYMarginTop) / (maxY - minY) * (maxY - csource[k])) + maxYMarginTop;
                    plView.Points.Add(p);


                    Ellipse ep = new Ellipse();//椭圆形
                    ep.Width = 10;
                    ep.Height = 10;
                    //在点击节点时候出现
                    ep.Stroke = new SolidColorBrush(Color.FromRgb(230, 230, 236));//透明色,边框

                    ep.StrokeThickness = 0;
                    ep.Fill = new SolidColorBrush(Color.FromRgb(66, 120, 255));//内部上色
                    ep.HorizontalAlignment = HorizontalAlignment.Left;
                    ep.VerticalAlignment = VerticalAlignment.Top;
                    ep.Margin = new Thickness(p.X - 5, p.Y - 5, 0, -5);//底部设置-5(圆球宽高的一半),当Y等于0的时候,可以让圆球全部显示
                }
                Agrid.Children.Add(plView);



                //第二条数据折线
                Draw(bsource);
                watch.Stop();
                Console.WriteLine($"Drawing : {watch.ElapsedMilliseconds}ms");
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }

        }

        //X轴
        public void Xchart()
        {
            if (cd.XMove <= 0)
            {
                int countX = cd.XNumInt;
                //x轴
                for (int i = 0; i <= countX; i++)
                {
                    Debug.WriteLine("dad+:" + (cd.XInterval * i + cd.XMove));
                    if (cd.XInterval * i + cd.XMove < 0) 
                        countX++;
                    else
                    {
                        //虚线
                        a4.Children.Add(cd.XImaginaryLine(Bgrid.ActualWidth, Bgrid.ActualHeight, i));
                        //图标
                        if (i % 2 == 0)
                            a4.Children.Add(cd.XIco(Bgrid.ActualWidth, i));
                        //超出界限的不算数
                        Debug.WriteLine("判断x轴移动的越界情况:间隔量" + cd.XInterval + "  移动量:" + cd.XMove);

                    }
                }
            }
            else if (cd.XMove > 0)
            {
                int countX = 0;
                //x轴
                for (int i = cd.XNumInt; i >countX; i--)
                {
                    if (cd.XInterval * i + cd.XMove > Bgrid.ActualWidth)
                        countX--;
                    else 
                    {
                        //虚线
                        a4.Children.Add(cd.XImaginaryLine(Bgrid.ActualWidth, Bgrid.ActualHeight, i));
                        //图标
                        if (i % 2 == 0)
                            a4.Children.Add(cd.XIco(Bgrid.ActualWidth, i));
                        //超出界限的不算数
                        Debug.WriteLine("判断x轴移动的越界情况:间隔量" + cd.XInterval + "  移动量:" + cd.XMove);
                    }

                }
            }
        }

        //Y轴
        public void Ychart()
        {
            //Y轴
            //for (int i = 0; i < cd.YNumInt; i++)
            //{
            //    //虚线
            //    Agrid.Children.Add(cd.YImaginaryLine(Agrid.ActualHeight, Agrid.ActualWidth, i));
            //    //图标
            //    a1.Children.Add(cd.YIco(Agrid.ActualHeight, i));

            //    Debug.WriteLine("YY." + Agrid.ActualHeight.ToString() + " " + i);

            //}

            if (cd.YMove <= 0)
            {
                int countY = cd.YNumInt;
                //x轴
                for (int i = 0; i <= countY; i++)
                {
                    Debug.WriteLine("dad+:" + (cd.XInterval * i + cd.XMove));
                    if (cd.YInterval * i + cd.YMove < 0)
                        countY++;
                    else
                    {
                        //虚线
                        Agrid.Children.Add(cd.YImaginaryLine(Agrid.ActualHeight, Agrid.ActualWidth, i));
                        //图标
                        a1.Children.Add(cd.YIco(Agrid.ActualHeight, i));
                        //超出界限的不算数
                        Debug.WriteLine("判断x轴移动的越界情况:间隔量" + cd.YInterval + "  移动量:" + cd.YMove);

                    }
                }
            }
            else if (cd.YMove > 0)
            {
                int countY = 0;
                //x轴
                for (int i = cd.YNumInt; i >= countY; i--)
                {
                    if (cd.XInterval * i + cd.XMove > Bgrid.ActualWidth)
                        countY--;
                    else
                    {
                        //虚线
                        Agrid.Children.Add(cd.YImaginaryLine(Agrid.ActualHeight, Agrid.ActualWidth, i));
                        //图标
                        a1.Children.Add(cd.YIco(Agrid.ActualHeight, i));
                        //超出界限的不算数
                        Debug.WriteLine("判断x轴移动的越界情况:间隔量" + cd.YInterval + "  移动量:" + cd.YMove);
                    }

                }
            }
        }

        //画图
        public void Draw(SortedDictionary<DateTime, int> source) 
        {
            Polyline plPeople = new Polyline();
            plPeople = cd.DrawChart(source, Bgrid.ActualWidth, Bgrid.ActualHeight);

            Agrid.Children.Add(plPeople);
        }


        private bool mouseDown;
        private Point mouseXY;


        //sender
        //事件处理程序附加到的对象
        //事件数据
        //鼠标按下时的事件,启用捕获鼠标位置并把坐标赋值给mouseXY
        private void ContentControl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var img = sender as ContentControl;
            if (img == null)
            {
                return;
            }
            img.CaptureMouse(); //强制获得鼠标元素
            mouseDown = true;  //点击左键,赋值ture
            mouseXY = e.GetPosition(img);  //返回指针坐标
        }
        //鼠标松开时的事件,停止捕获鼠标位置
        private void ContentControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            var img = sender as ContentControl;
            if (img == null)
            {
                return;
            }
            img.ReleaseMouseCapture();//释放
            mouseDown = false;

        }

        //鼠标移动时的事件
        //当鼠标按下并移动时发生Domousemove(img, e);函数
        private void ContentControl_MouseMove(object sender, MouseEventArgs e)
        {
            var img = sender as ContentControl;
            if (img == null)
            {
                return;
            }
            if (mouseDown)
            {
                Domousemove(img, e);
            }
        }

        //它根据X.Y的值来移动。并把当前鼠标位置赋值给mouseXY
        //group.Children中的第二个是移动的函数
        //改:鼠标移动周不变
        private void Domousemove(ContentControl img, MouseEventArgs e)
        {
            if (e.LeftButton != MouseButtonState.Pressed)//LeftButton 获得鼠标的状态 判断左键是不是被按下 
            {
                return;
            }
            var group = View.FindResource("Trans") as TransformGroup;
            //var transform = group.Children[1] as TranslateTransform; //平移
            var position = e.GetPosition(img);
            // transform.X -= mouseXY.X - position.X;
            // transform.Y -= mouseXY.Y - position.Y;

            //这一块有问题??????解决了!!!
            // cd.XMove = transform.X*100;

            //x移动量
            cd.XMove = (mouseXY.X - position.X) * -1/10;

            //根据移动获取x最大最小值:
            double totalDateX = cd.MaxX.ToOADate() - cd.MinX.ToOADate();
            double wideDays = totalDateX / Agrid.ActualWidth;
            double rightDataX = cd.XMove * wideDays + cd.MinX.ToOADate();
            DateTime rightMinX = DateTime.FromOADate(rightDataX);
            double leftDataX = cd.XMove * wideDays + cd.MaxX.ToOADate();
            DateTime leftMaxX = DateTime.FromOADate(leftDataX);
            Debug.WriteLine("  左边 转换检测:" + rightMinX + "   右边 转换检测:" + leftMaxX);

            //传值
            cd.MinX = rightMinX;
            cd.MaxX = leftMaxX;

            //y移动量
            cd.YMove = (mouseXY.Y - position.Y) * -1/10;

            //根据移动获取y最大最小值
            double totalDateY = cd.MaxY - cd.MinY;
            double heighDays = totalDateY / (Agrid.ActualHeight-cd.YMarginTop);
            double topDataY = cd.YMove * heighDays + cd.MaxY;
            double botDataY = cd.YMove * heighDays + cd.MinY;
            Debug.WriteLine("  左边 转换检测:" + topDataY + "   右边 转换检测:" + botDataY + "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");

            //传值
            cd.MinY = botDataY;
            cd.MaxY = topDataY;

            a1.Children.Clear();
            a4.Children.Clear();
            Agrid.Children.Clear();

           
            //cd.YMove = -transform.Y;
         
            Xchart();
            Ychart();
            Draw(bsource);


            // mouseXY = position;


            //移动的坐标横坐标计算有问题????????????????

        }

        //鼠标滑轮事件,得到坐标,放缩函数和滑轮指数,由于滑轮值变化较大所以*0.001.
        private void ContentControl_MouseWheel(object sender, MouseWheelEventArgs e)
        {

            var img = sender as ContentControl;
            if (img == null)
            {
                return;
            }
            var point = e.GetPosition(Agrid);
            var group = View.FindResource("Trans") as TransformGroup;
            var delta = e.Delta * 0.001;
            DowheelZoom(group, point, delta,e);

        }

        // Group.Children中的第一个是放缩函数。
        //如果ScaleX+滑轮指数小于0.1时就返回。
        //var pointToContent = group.Inverse.Transform(point);
        // 获取此变换的逆变换的值
        //使图片放缩后,放缩原点也随之变化。
        private void DowheelZoom(TransformGroup group, Point point, double delta, MouseWheelEventArgs e)
        {

            var pointToContent = group.Inverse.Transform(point);
            var transform = group.Children[0] as ScaleTransform;
            if (transform.ScaleX + delta < 1) return;
            //实现放缩
            transform.ScaleX += delta;
            transform.ScaleY += delta;

            //找到放缩基点
            TranslateTransform translateTransform = group.Children[1] as TranslateTransform;
            Debug.WriteLine("原来的x:" + e.GetPosition(Agrid));
            translateTransform.X -= point.X * delta;
            translateTransform.Y -= point.Y * delta;
            Debug.WriteLine("旋转的x"+transform.ScaleX.ToString());
            Debug.WriteLine("移动的x:" + translateTransform.X+"  原来位置点 "+point.X+"  放缩倍数点 "+delta);

            a4.Children.Clear();
            Agrid.Children.Clear();
            a1.Children.Clear();


            // cd.XInterval *= transform.ScaleX + delta;

            // Debug.WriteLine("改变的间距:" + cd.XInterval);
            //  cd.MinX.AddHours(1);
            //  cd.MaxX.AddHours(-1);
            //cd.XMove = point.X-point.X/(1-delta);
            //Debug.WriteLine("移动的轴:" + cd.XMove);


            //这里改变最小最大值吧???先只算x的,y先不动
            DateTime k = Convert.ToDateTime("2022-02-01 01:00:00");

            //宽800  鼠标点击点的时间
            double width = Agrid.ActualWidth;
            double height = Agrid.Height;

            //鼠标点x的位置
            double preDoubleX = point.X * ((cd.MaxX.ToOADate() - cd.MinX.ToOADate()) / width) + cd.MinX.ToOADate();
         //   DateTime PointX = DateTime.FromOADate(preDoubleX);
          //  Debug.WriteLine("鼠标点位x:" + PointX);

            double totalDateX;//x轴最小最大距
            double totalDateY;//y轴最小最大距

            if (delta > 0)
            {
                //transNum++;
                //在放大
                totalDateX = (cd.MaxX.ToOADate() - cd.MinX.ToOADate()) / 2;
                totalDateY = (cd.MaxY - cd.MinY) / 2;
            }
            else 
            {
                totalDateX = (cd.MaxX.ToOADate() - cd.MinX.ToOADate()) * 2;
                totalDateY = (cd.MaxY - cd.MinY) * 2;
            }
                


            //根据鼠标点击x轴点求最大值和最小值

            double wideDays = totalDateX / width;
            double rightDataX = preDoubleX-point.X * wideDays;
            DateTime rightMinX = DateTime.FromOADate(rightDataX);
            double leftDataX = preDoubleX+(width - point.X) * wideDays;
            DateTime leftMaxX = DateTime.FromOADate(leftDataX);
            Debug.WriteLine( "  左边 转换检测:" + rightMinX+"   右边 转换检测:"+leftMaxX);

            //根据鼠标点击y轴点求最大值和最小值

            double heightDays = totalDateY / (height - cd.YMarginTop);
            double topDataY =cd.MaxY - (point.Y-cd.YMarginTop) * heightDays;
            double botDataY = cd.MinY + (height-point.Y) * heightDays;
            
            Debug.WriteLine("  上边 转换检测:" + topDataY + "   下边 转换检测:" + botDataY + "********************************************");

            //传值
            cd.MinX = rightMinX;
            cd.MaxX = leftMaxX;
            cd.MinY = botDataY;
            cd.MaxY = topDataY;

            Xchart();
            Ychart();

            //画图
            Draw(bsource);

            //DateTime l1 = Convert.ToDateTime("2022-06-02 00:00:00");
            //double kkk = l1.ToOADate();
            //Debug.WriteLine("测测试数据1:" + kkk);
            //DateTime dateMinX = DateTime.FromOADate(kkk);
            //Debug.WriteLine("原数据:"+l1.ToString()+"   转换检测:"+ dateMinX);


            根据点位计算x的变化后的min和max
            指定的点代表那一天
            //double cha=cd.MaxX.ToOADate() - cd.MinX.ToOADate();
            //double ge= cha/ Agrid.ActualWidth;
            坐标位置:
            //double data1 = ge * point.X;
            宽是700
            //Debug.WriteLine("X坐标:" + point.X+" max: "+ cd.MaxX.ToOADate() + " minx: "+ cd.MinX.ToOADate() + " ge: "+ cha / Agrid.ActualWidth + " data1: "+ ge * point.X);

            //cd.MinX=Convert.ToDateTime("2022-06-01 00:00:00");
            //cd.MaxX = Convert.ToDateTime("2022-06-10 00:00:00");
            //Draw(bsource);


            //DateTime l1 = Convert.ToDateTime("2022-06-02 00:00:00") ;
            //DateTime l2 = Convert.ToDateTime("2022-06-01 00:00:00"); 
            //Debug.WriteLine("测测试数据1:" + (l1.ToOADate() - l2.ToOADate()));
            //DateTime l3 = Convert.ToDateTime("2021-08-01 00:00:00"); 
            //DateTime l4 = Convert.ToDateTime("2022-08-01 00:00:00");
            //Debug.WriteLine("测测试数据2:" + (l3.ToOADate() - l4.ToOADate()));


        }


    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值