WPF数据可视化-瀑布图

实现方式一:

       将数据(Point[])根据索引沿X轴使用虚拟画布进行绘制,每个数据绘制大小为1px * 1px;最终绘制出的宽度等于数据的总长度。标记并存储当前绘制的图为PreviousBitmap; 继续置顶绘制第二组数据,第二组数据绘制完后,将标记的PreviousBitmap作为Image在Y轴距离顶部距离为1px的地方用DrawingContext.DrawImage()方式绘制,以此类推。核心代码如下:

private void DoAddDataArray(Point[] arrPoints)
{
    this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
    {
        double dPixelWidth = Pixel;
        double dContainerWidth = this.VbxContainer.ActualWidth;
        double dContainerHeight = this.VbxContainer.ActualHeight;
        double dPixelHeight = Pixel/2d;
        double dCellHeight = 1;
        double dCellWidth = 1;

        DrawingVisual drawingVisual = new DrawingVisual();
        DrawingContext drawingContext = drawingVisual.RenderOpen();
        drawingContext.DrawRectangle(new SolidColorBrush(Colors.Blue),
                new Pen(), new Rect(0, 0, dPixelWidth, dCellHeight));

        // 绘制新数据
                  
        for (int i = 0; i < arrPoints.Length; i++)
        {
            double dCellX = Math.Round(((arrPoints[i].X - MinAxisX) / (MaxAxisX - MinAxisX)) * Pixel);
            double dY = arrPoints[i].Y;
            Color oColor = this.GetColor(dY);
            //drawingContext.DrawRectangle(new SolidColorBrush(oColor),
            //    new Pen(), new Rect(dCellX, 0, dCellWidth, dCellHeight));
            LinearGradientBrush lineBrush = new LinearGradientBrush();
            lineBrush.GradientStops.Add(new GradientStop(Colors.Transparent, 0));
            lineBrush.GradientStops.Add(new GradientStop(oColor, 0.25));
            lineBrush.GradientStops.Add(new GradientStop(oColor, 0.5));
            lineBrush.GradientStops.Add(new GradientStop(oColor, 0.75));
            lineBrush.GradientStops.Add(new GradientStop(Colors.Transparent, 1));
            drawingContext.DrawRectangle(lineBrush, new Pen(), new Rect(dCellX-1, 0, dCellWidth + 2, dCellHeight));
        }    

        // 绘制历史数据
        if (this.PreviousBitmap != null)
            drawingContext.DrawImage(this.PreviousBitmap, new Rect(0, dCellHeight, dPixelWidth, dPixelHeight));
        drawingContext.Close();

        // 生成图像处理
        RenderTargetBitmap rtbCurrent = new RenderTargetBitmap((int)dPixelWidth,
            (int)dPixelHeight, 96, 96, PixelFormats.Pbgra32);
        rtbCurrent.Render(drawingVisual);

        this.PreviousBitmap = rtbCurrent; // 当前绘制的存为历史,下次绘制时直接调用
        this.ImgMain.Source = rtbCurrent; // 显示绘制的图像
    }));
}

运行效果

 

实现方式二:

        将数据(Point[])根据索引沿X轴使用虚拟画布进行绘制,每个数据绘制大小为1px * 1px;最终绘制出的宽度等于数据的总长度。创建一个Rectangle,将绘制的图赋值给Rectangle.Fill属性,将绘制过程中不断创建的Rectangle插入控件Stackpanel的首位。核心代码如下:

private void DoAddDataArray(Point[] arrPoints)
{
    this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => 
    {
        double dPixelWidth = Pixel;
        double dContainerWidth = this.VbxContainer.ActualWidth;
        double dContainerHeight = this.VbxContainer.ActualHeight;
        double dPixelHeight = Pixel / 2d;

        DrawingVisual drawingVisual = new DrawingVisual();
        DrawingContext drawingContext = drawingVisual.RenderOpen();
        drawingContext.DrawRectangle(new SolidColorBrush(Colors.Blue),
                new Pen(), new Rect(0, 0, dPixelWidth, 1));

        // 绘制新数据
        double dCellHeight = 1;
        double dCellWidth = 1;
        for (int i = 0; i < arrPoints.Length; i++)
        {
            double dCellX = Math.Round(((arrPoints[i].X - MinAxisX) / (MaxAxisX - MinAxisX)) * Pixel);
            double dY = arrPoints[i].Y;
            Color oColor = this.GetColor(dY);
            //drawingContext.DrawRectangle(new SolidColorBrush(oColor),
            //    new Pen(), new Rect(dCellX, 0, dCellWidth, dCellHeight));
            LinearGradientBrush lineBrush = new LinearGradientBrush();
            lineBrush.GradientStops.Add(new GradientStop(Colors.Transparent, 0));
            lineBrush.GradientStops.Add(new GradientStop(oColor, 0.25));
            lineBrush.GradientStops.Add(new GradientStop(oColor, 0.5));
            lineBrush.GradientStops.Add(new GradientStop(oColor, 0.75));
            lineBrush.GradientStops.Add(new GradientStop(Colors.Transparent, 1));
            drawingContext.DrawRectangle(lineBrush, new Pen(), new Rect(dCellX - 0.5, 0, dCellWidth + 1, dCellHeight));
        }
        drawingContext.Close();

        // 生成图像处理
        RenderTargetBitmap rtbCurrent = new RenderTargetBitmap((int)dPixelWidth, (int)1, 96, 96, PixelFormats.Pbgra32);
        rtbCurrent.Render(drawingVisual);

        Rectangle rect = new Rectangle();
        rect.Width = Pixel;
        rect.Height = 1;
        rect.Fill = new ImageBrush(rtbCurrent);
        // SpContainers  ---- Stackpanel
        this.SpContainers.Children.Insert(0, rect);
        if (this.SpContainers.Children.Count > 500)
            this.SpContainers.Children.RemoveAt(500);
    }));
}

 运行效果:

相对而言,方式二由于不断插入新的Rectangle。下移效果为控件位置变化所呈现,不像方式一是一张完整图,故画质欠缺。 

性能和测试: 

       采用Timer生成随机数据进行测试。10毫秒1组,每组1000个数据点。 相当于每秒绘制10万个点。

测试时在Release模式下,开启多个子模块,性能勉强能接受。 

环境:

 语言: C#

 工程:WPF

 工具:Visual Studio 2017

 系统:Windows

 第三方插件:无

            微信扫码下载源代码:

posted @ 2019-10-18 00:42  DuelCode  阅读(2639)  评论(1编辑  收藏  举报