欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

WPF開(kāi)發(fā)之利用DrawingVisual繪制高性能曲線圖

 更新時(shí)間:2022年02月22日 11:06:31   作者:流浪g  
通過(guò)WPF實(shí)現(xiàn)大數(shù)據(jù)曲線圖時(shí),如果用最基礎(chǔ)的Canvas來(lái)實(shí)現(xiàn),性能堪憂。所以本文將利用DrawingVisual繪制高性能曲線圖,感興趣的可以了解一下

前言

項(xiàng)目中涉及到了心率檢測(cè),而且數(shù)據(jù)量達(dá)到了百萬(wàn)級(jí)別,通過(guò)WPF實(shí)現(xiàn)大數(shù)據(jù)曲線圖時(shí),嘗試過(guò)最基礎(chǔ)的Canvas來(lái)實(shí)現(xiàn),但是性能堪憂,而且全部畫(huà)出來(lái)也不實(shí)際。同時(shí)也嘗試過(guò)找第三方的開(kāi)源庫(kù),但是因?yàn)榍€圖涉及到很多細(xì)節(jié)功能,第三方的肯定也沒(méi)法滿足。沒(méi)辦法,只能自己實(shí)現(xiàn),上網(wǎng)查找后發(fā)現(xiàn)DrawingVisual這個(gè)玩意可以實(shí)現(xiàn)高性能畫(huà)圖,同時(shí)再搭配局部顯示,這樣就能實(shí)現(xiàn)自己想要的效果。話不多說(shuō),今天把大致的實(shí)現(xiàn)思路寫(xiě)一下,就不直接把項(xiàng)目的源碼貼出來(lái),寫(xiě)個(gè)簡(jiǎn)單的Demo就好了。

正文

1、首先新建個(gè)項(xiàng)目,然后創(chuàng)建個(gè)自定義控件,命名為CurveChartDrawingVisual,然后讓它繼承FrameworkElement。因?yàn)橐褂肈rawingVisual對(duì)象的話,需要為它創(chuàng)建一個(gè)主機(jī)容器。關(guān)于其他相關(guān)DrawingVisual的細(xì)節(jié)這里不做過(guò)多闡述,不明白的可以去微軟官網(wǎng)看。

2、實(shí)現(xiàn)的具體代碼如下,相關(guān)細(xì)節(jié)有備注標(biāo)注了。這里記得要重寫(xiě)一下VisualChildrenCount屬性和重寫(xiě)GetVisualChild()方法,不然圖畫(huà)不出來(lái)

public class CruveChartDrawingVisual : FrameworkElement
{
    private List<Visual> visuals = new List<Visual>();
    private DrawingVisual Layer;

    private double offset_x = 0;//滑動(dòng)條偏移值
    private double y_scale;//y軸放心縮放比例

    private List<int> list_points;//曲線數(shù)據(jù)

    private static int Top_Val_Max = 100;//y軸最大值
    private static int Top_Val_Min = 0;//y軸最小值
    private static int X_Sex = 20;//x軸分度值
    private static int Y_Sex = 20;//x軸分度值
    private static int Bottom = 30;//底部x軸坐標(biāo)顯示高度

    Pen pen = new Pen(Brushes.Green, 2);
    Pen primarygrid_pen = new Pen(Brushes.Black, 1);
    Pen secondgrid_pen = new Pen(Brushes.Gray, 1);

    public CruveChartDrawingVisual()
    {
        pen.Freeze();//凍結(jié)筆,提高性能關(guān)鍵所在
        primarygrid_pen.Freeze();
        secondgrid_pen.Freeze();

        Layer = new DrawingVisual();

        visuals.Add(Layer);
    }

    public void SetupData(List<int> points)
    {
        list_points = points;
        offset_x = 0;
        DrawContent();
    }

    public void OffsetX(double offset)
    {
        offset_x = offset;
        DrawContent();
        InvalidateVisual();
    }

    private void DrawContent()
    {
        var dc = Layer.RenderOpen();
        y_scale = (RenderSize.Height - Bottom) / (Top_Val_Max - Top_Val_Min);

        var mat = new Matrix();
        mat.ScaleAt(1, -1, 0, RenderSize.Height / 2);

        mat.OffsetX = -offset_x;
        dc.PushTransform(new MatrixTransform(mat));

        //橫線
        for (int y = 0; y <= Top_Val_Max - Top_Val_Min; y += 10)
        {
            Point point1 = new Point(offset_x, y * y_scale + Bottom);
            Point point2 = new Point(offset_x + RenderSize.Width, y * y_scale + Bottom);
            if (y % Y_Sex == 0)
            {
                dc.DrawLine(primarygrid_pen, point1, point2);
                continue;
            }
            dc.DrawLine(secondgrid_pen, point1, point2);
        }

        //豎線與文字
        for (int i = 0; i <= (offset_x + RenderSize.Width); i += X_Sex * 2)
        {
            if (i < offset_x)
            {
                continue;
            }
            var point1 = new Point(i, Bottom);
            var point2 = new Point(i, (Top_Val_Max - Top_Val_Min) * y_scale + Bottom);


            //y軸文字
            if (i % 100 == 0)
            {
                var text1 = new FormattedText(i + "", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Verdana"), 16, Brushes.Black);
                var mat3 = new Matrix();
                mat3.ScaleAt(1, -1, i - text1.Width / 2, 8 + text1.Height / 2);
                dc.PushTransform(new MatrixTransform(mat3));
                dc.DrawText(text1, new Point(i - text1.Width / 2, 8));
                dc.Pop();
            }

            //表格刻度文字
            if (i % 100 == 0)
            {
                for (int y = Top_Val_Min; y <= Top_Val_Max; y += 10)
                {
                    if (y % Y_Sex == 0)
                    {
                        var text1 = new FormattedText(y + "", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Verdana"), 12, Brushes.Black);
                        var mat3 = new Matrix();
                        mat3.ScaleAt(1, -1, i + 1, (y - Top_Val_Min) * y_scale + Bottom + text1.Height / 2);
                        dc.PushTransform(new MatrixTransform(mat3));
                        dc.DrawText(text1, new Point(i + 1, (y - Top_Val_Min) * y_scale + Bottom));
                        dc.Pop();
                    }
                }
                //深色豎線
                dc.DrawLine(primarygrid_pen, point1, point2);
                continue;
            }
            //淺色豎線
            dc.DrawLine(secondgrid_pen, point1, point2);
        }

        if (list_points != null)
        {
            for (int i = (int)offset_x; i < list_points.Count - 1; i++)
            {
                if (i > offset_x + RenderSize.Width)
                {
                    break;
                }
                dc.DrawLine(pen, new Point(i, list_points[i] * y_scale + Bottom), new Point(i + 1, list_points[i + 1] * y_scale + Bottom));
            }
        }

        dc.Pop();
        dc.Close();
    }

    protected override int VisualChildrenCount => visuals.Count;
    protected override Visual GetVisualChild(int index)
    {
        return visuals[index];
    }

    protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
    {
        DrawContent();
        base.OnRenderSizeChanged(sizeInfo);
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        drawingContext.DrawRectangle(Brushes.White, null, new Rect(0, 0, RenderSize.Width, RenderSize.Height));
        base.OnRender(drawingContext);
    }
}

3、接著測(cè)試一下,打開(kāi)MainWindow,添加我們的自定義控件,這里局部顯示需要搭配一個(gè)ScrollViewer來(lái)實(shí)現(xiàn),記得這里沒(méi)有將我們的自定義控件嵌入ScrollViewer,而是放一個(gè)Canvas來(lái)填充,代碼如下

<Grid>
    <local:CruveChartDrawingVisual x:Name="curve" Margin="0,15,0,20" />
    <ScrollViewer
        Name="scroll"
        HorizontalScrollBarVisibility="Auto"
        ScrollChanged="ScrollViewer_ScrollChanged"
        VerticalScrollBarVisibility="Disabled">
        <Canvas x:Name="canvas" Height="1" />
    </ScrollViewer>
</Grid>

4、接著就是后臺(tái)代碼,比較簡(jiǎn)單,就是自動(dòng)生成一個(gè)List,然后傳給自定義控件,Canvas的寬度直接設(shè)置為L(zhǎng)ist的長(zhǎng)度,因?yàn)檫@里是水平方向一個(gè)像素點(diǎn)畫(huà)一個(gè)點(diǎn),然后滑動(dòng)條滑動(dòng)時(shí)再將對(duì)應(yīng)的偏移值傳遞到控件,再通過(guò)偏移值更新視圖

public partial class MainWindow : Window
{
    private bool isAdd = true;

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        List<int> lists = new List<int>();
        int temp = 20;
        for (int i = 0; i < 60 * 60; i++)
        {
            if (isAdd)
            {
                lists.Add(temp);
                temp ++;
            }
            else
            {
                lists.Add(temp);
                temp --;
            }

            if (temp == 90) isAdd = false;
            if (temp == 10) isAdd = true;
        }

        canvas.Width = lists.Count;

        curve.SetupData(lists);
    }

    private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        curve.OffsetX(scroll.HorizontalOffset);
    }
}

5、運(yùn)行效果如下,滑動(dòng)條拖到哪里就顯示哪里,這樣就算數(shù)據(jù)量再大也沒(méi)問(wèn)題,這種曲線圖跟常規(guī)的曲線圖有點(diǎn)差別,這里更多的是提供一種思路

以上就是WPF開(kāi)發(fā)之利用DrawingVisual繪制高性能曲線圖的詳細(xì)內(nèi)容,更多關(guān)于WPF DrawingVisual繪制曲線圖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論