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

 第三方插件:無

            微信掃碼下載源代碼:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM