zoukankan      html  css  js  c++  java
  • wpf 高性能自定义chart

    上周五,公司要求我们用wpf做一个上波形图数据的控件,试了n个不收费的三方chart控件,功能是真好,但是性能不能,好一点的最多一次能加载几千个点,最后决定自己画。在QA论坛上问了一下,人家推荐用WriteableBitmap画,最后写完发现性能真的还行,10几万个点还算比较流畅,代码记录一下。

    
    
    using System;
    using System.Collections.Generic;
    using System.Drawing.Drawing2D;
    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;
    
    namespace _3.测试自定义控件
    {
        /// <summary>
        /// CustomerChart.xaml 的交互逻辑
        /// </summary>
        public partial class CustomerChart : UserControl
        {
        
            /// <summary>
            /// 垂直(纵向)边距(画图区域距离左右两边长度)
            /// </summary>
          public  double VerticalMargin { get; set; }
            /// <summary>
            /// 平行(横向)边距(画图区域距离左右两边长度)
            /// </summary>
          public  double HorizontalMargin { get; set; }
            /// <summary>
            /// 水平刻度间距像素
            /// </summary>
           public double horizontalBetween { get; set; }
            /// <summary>
            /// 垂直刻度间距像素
            /// </summary>
           public   double verticalBetween { get; set; }
    
            /// <summary>
            ///     x轴最大值
            /// </summary>
            public double MaxX { get; set; }
    
            /// <summary>
            ///     y轴最大值
            /// </summary>
            public double MaxY { get; set; }
    
            /// <summary>
            ///     x轴最小值
            /// </summary>
            public double MinX { get; set; }
    
            /// <summary>
            ///     y轴最小值
            /// </summary>
            public double MinY { get; set; }
    
            ///// 画图区域起点
            ///// </summary>
          public  Point StartPostion { get; set; }
            /// <summary>
            /// 画图区域终点
            /// </summary>
          public  Point EndPostion { get; set; }
    
    /// <summary>
    /// 点的集合
    /// </summary>
           public  System.Drawing.PointF[] points { get; set; }
            /// <summary>
            /// 缩放值
            /// </summary>
            public int Scale;
            public CustomerChart()
            {
                InitializeComponent();
                HorizontalMargin = 40;
                VerticalMargin = 40;
                StartPostion = new Point(HorizontalMargin, VerticalMargin);
                points = new System.Drawing.PointF[0];
            }
            public void Refresh()
            {
                InitCanvas();
    
                //获取y最大值
                if (MaxY < 0.0001)
                {
                    if (points.Length < 2) return;
                    MaxY = points.Max(m => m.Y);
                }
    
                if (MaxX < 0.0001)
                {
                    if (points.Length < 2) return;
                    MaxX = points.Max(m => m.X);
                }
    
                DrawXAxisTicks();
                DrawYAxisTicks();
                DrawAxis();
    
                DrawPolyline();
            }
    
            private void InitCanvas()
            {
                MainCanvas.Children.Clear();
                EndPostion = new Point(MainCanvas.ActualWidth - HorizontalMargin, MainCanvas.ActualHeight - VerticalMargin);
            }
    
            private void DrawPolyline()
            {
                WriteableBitmap _plotBitmap = new WriteableBitmap((int)(MainCanvas.ActualWidth - HorizontalMargin), (int)(MainCanvas.ActualHeight - VerticalMargin), 96, 96, PixelFormats.Rgb24, null);        
                Image image = new Image();
                image.MouseWheel += Image_MouseWheel;
                _plotBitmap.Lock();
    
                var b = new System.Drawing.Bitmap(_plotBitmap.PixelWidth,
                                   _plotBitmap.PixelHeight,
                                   _plotBitmap.BackBufferStride,
                                   System.Drawing.Imaging.PixelFormat.Format24bppRgb,
                                   _plotBitmap.BackBuffer);
    
                using (var bitmapGraphics = System.Drawing.Graphics.FromImage(b))
                {
    
                    bitmapGraphics.SmoothingMode = SmoothingMode.HighSpeed;
                    bitmapGraphics.InterpolationMode = InterpolationMode.NearestNeighbor;
                    bitmapGraphics.CompositingMode = CompositingMode.SourceCopy;
                    bitmapGraphics.CompositingQuality = CompositingQuality.HighSpeed;
                    System.Drawing.Pen myPen = new System.Drawing.Pen(System.Drawing.Color.Green);
    
                    for (int t = 0; t < points.Length; t++)
                    {
    
                        points[t].X = _plotBitmap.PixelWidth * (t * 1.0f / points.Length);
                        points[t].Y = _plotBitmap.PixelHeight *(((float)MaxY - points[t].Y)/(float)MaxY);
                    }
                    bitmapGraphics.DrawLines(myPen, points);
                }
                _plotBitmap.AddDirtyRect(new Int32Rect(0, 0, _plotBitmap.PixelWidth, _plotBitmap.PixelHeight));
                _plotBitmap.Unlock();
                image.Source = _plotBitmap;            
                MainCanvas.Children.Add(image);
                Canvas.SetBottom(image, VerticalMargin);
                Canvas.SetLeft(image, HorizontalMargin);
            }
    
            private void Image_MouseWheel(object sender, MouseWheelEventArgs e)
            {
                double x = e.GetPosition(sender as Image).X;
                
            }
    
            private void DrawYAxisTicks()
            {
                if (MinY >= MaxY)
                {
                    return;
                }
                if (verticalBetween < 0.0001)
                {
                    verticalBetween = (MaxY - MinY) / 10;
                }
                for (var i = MinY; i <= MaxY + 0.01; i += verticalBetween)
                {
                    var y = EndPostion.Y - i * (MainCanvas.ActualHeight - VerticalMargin) / (MaxY - MinY);
                    var marker = new Line
                    {
                        X1 = StartPostion.X - 5,
                        Y1 = y,
                        X2 = StartPostion.X,
                        Y2 = y,
                        Stroke = Brushes.Red
                    };
                    MainCanvas.Children.Add(marker);
    
                    var gridLine = new Line
                    {
                        X1 = StartPostion.X,
                        Y1 = y,
                        X2 = EndPostion.X,
                        Y2 = y,
                        StrokeThickness = 1,
                        Stroke = new SolidColorBrush(Colors.AliceBlue)
                    };
                    MainCanvas.Children.Add(gridLine);
    
                    //画y轴字符
                    var markText = new TextBlock
                    {
                        Text = i.ToString(CultureInfo.InvariantCulture),
                        Width = 30,
                        Foreground = Brushes.Black,
                        FontSize = 10,
                        HorizontalAlignment = HorizontalAlignment.Right,
                        TextAlignment = TextAlignment.Right
                    };
                    MainCanvas.Children.Add(markText);
                    Canvas.SetTop(markText, y -3);
                    Canvas.SetLeft(markText, 00);
                }
            }
    
            /// <summary>
            /// 画x轴标签
            /// </summary>
            private void DrawXAxisTicks()
            {
                if (MinX >= MaxX)
                {
                    return;
                }
                if (horizontalBetween < 0.0001)
                {
                    horizontalBetween = (MaxX - MinX) / 10;
                }
                for (var i = MinX; i <= MaxX + 0.01; i += horizontalBetween)
                {
                    var x = StartPostion.X + i * (MainCanvas.ActualWidth - HorizontalMargin) / (MaxX - MinX) ;
                    var marker = new Line
                    {
                        X1 = x,
                        Y1 = EndPostion.Y,
                        X2 = x,
                        Y2 = EndPostion.Y + 4,
                        Stroke = Brushes.Red
                    };
                    MainCanvas.Children.Add(marker);
    
                    var gridLine = new Line
                    {
                        X1 = x,
                        Y1 = StartPostion.Y,
                        X2 = x,
                        Y2 = EndPostion.Y,
                        StrokeThickness = 1,
                        Stroke = new SolidColorBrush(Colors.AliceBlue)
                    };
                    MainCanvas.Children.Add(gridLine);
    
                    //画x轴字符
                    var text =Convert.ToInt32(i).ToString(CultureInfo.InvariantCulture);
                    var markText = new TextBlock
                    {
                        Text = text,
                        Width = 130,
                        Foreground = Brushes.Black,
                        VerticalAlignment = VerticalAlignment.Top,
                        HorizontalAlignment = HorizontalAlignment.Stretch,
                        TextAlignment = TextAlignment.Left,
                        FontSize = 10
                    };
    
                    //Transform st = new SkewTransform(0, 0);
                    //markText.RenderTransform = st;
                    MainCanvas.Children.Add(markText);
                    Canvas.SetTop(markText, EndPostion.Y + 5);
                    Canvas.SetLeft(markText, x-15);
                }
    
    
            }
    
            /// <summary>
            /// X轴Y轴
            /// </summary>
            private void DrawAxis()
            {
                var xaxis = new Line
                {
                    X1 = StartPostion.X,
                    Y1 = EndPostion.Y,
                    X2 = EndPostion.X+HorizontalMargin,
                    Y2 = EndPostion.Y,
                    Stroke = new SolidColorBrush(Colors.Black)
                };
                MainCanvas.Children.Add(xaxis);
    
                var yaxis = new Line
                {
                    X1 = StartPostion.X,
                    Y1 = StartPostion.Y-VerticalMargin,
                    X2 = StartPostion.X,
                    Y2 = EndPostion.Y,
    
                    Stroke = new SolidColorBrush(Colors.Black)
                };
                MainCanvas.Children.Add(yaxis);
            }
    
            private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
            {
                Refresh();
            }
    
    
        }
    }
  • 相关阅读:
    优质Android小部件:索尼滚动相册
    Linux常用命令:文件与目录
    Android高效计算——RenderScript(二)
    Android高效计算——RenderScript(一)
    实用控件分享:自定义逼真相机光圈View
    Binder中的asInterface解析
    Android Adapter的几个方法
    Android中各种Drawable总结
    win10配置CUDA+Tensorflow2.0的一些经验
    关于Flash Helper Service的问题
  • 原文地址:https://www.cnblogs.com/dangnianxiaoqingxin/p/14135616.html
Copyright © 2011-2022 走看看