開發一個類似於unity profile的數據可視化面板

內容非原創 是參考一個大佬的源碼改的。
大佬地址:https://blog.51cto.com/13638120/2103991
先上效果圖:
在這裏插入圖片描述
這裏數據是完全隨機的,當然如果有需要可以捕獲一些真數據。

先貼源碼,思路其實很簡單,想必大家看了都能懂。

using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;


public class DataClass
{
    public int[] data = new int[7];
}

public class Paint : EditorWindow
{
    [MenuItem("#############Paint##############/Paint")]
    public static void ShowWindow()
    {
        Rect wr = new Rect(0, 0, 1000, 500);
        Paint window = (Paint)GetWindowWithRect(typeof(Paint), wr, true, "Paint");
        window.wantsMouseMove = false;
        window.Show();
        window.Focus();
    }

    const int LAYERS = 7;

    private GUIStyle _headStyle;
    private Rect _axisRect = new Rect(170, 250 - 250, 800, 300);
    private Rect _graphRect = new Rect(170, 270 - 250, 760, 280);

    private Rect _graphContentRect = new Rect(170, 270 - 250, 760, 280);

    private Color[] _layerColor = new Color[LAYERS]
    {
            new Color(220f / 255f, 20f / 255f, 60f / 255f),
            new Color(255f / 255f, 165f / 255f, 0f / 255f),
            new Color(255f / 255f, 255f / 255f, 0f / 255f),
            new Color(124f / 255f, 252f / 255f, 0f / 255f),
            new Color(0f / 255f, 255f / 255f, 255f / 255f),
            new Color(0f / 255f, 0f / 255f, 255f / 255f),
            new Color(128f / 255f, 0f / 255f, 128f / 255f),
    };

    private Vector3[][] _points = new Vector3[LAYERS][];
    //當前鼠標指向的x軸座標
    private int _current;
    private bool _clickGraph;

    //採樣數據
    private int _sampleCount;
    private List<DataClass> _samples = new List<DataClass>();
    private void OnEnable()
    {
        //捕獲數據
        _samples = GenFackeData();
        //數據橫座標大小
        _sampleCount = _samples.Count;
    }

    private void OnGUI()
    {
        if (_headStyle == null)
        {
            _headStyle = new GUIStyle();
            _headStyle.fontSize = 15;
            _headStyle.alignment = TextAnchor.MiddleCenter;
            _headStyle.normal.textColor = new Color(0.8f, 0.8f, 0.8f);
        }
        if (EditorApplication.isPlaying)
        {
            DrawGraph();
            //鼠標交互
            HandleEvent();
        }
        if (GUI.Button(new Rect(50, 320, 120, 20), "生成隨機數據"))
        {
            //捕獲數據
            _samples = GenFackeData();
            //數據橫座標大小
            _sampleCount = _samples.Count;
        }
    }

    public void DrawGraph()
    {
        if (_points[0] == null || _points[0].Length != _sampleCount)
        {
            for (int layer = 0; layer < LAYERS; ++layer)
                _points[layer] = new Vector3[_sampleCount];
        }

        float maxValue = GetListMaxValue(_samples);
        float avgValue = GetListAverageValue(_samples);

        //劃線算法核心
        for (int i = 0; i < _samples.Count; ++i)
        {
            for (int layer = 0; layer < LAYERS; layer++)
            {
                _points[layer][i].x = (float)i / _sampleCount * _graphContentRect.width + _graphContentRect.xMin;
                _points[layer][i].y = _graphContentRect.yMax - _samples[i].data[layer] / maxValue * _graphContentRect.height;
            }
        }

        //填充顏色 
        //畫點連線
        for (int layer = 0; layer < LAYERS; ++layer)
        {

            GL.Begin(GL.TRIANGLE_STRIP);
            GL.Color(_layerColor[layer]);
            for (int i = 0; i < _samples.Count; ++i)
            {
                if (_graphRect.Contains(_points[layer][i]))
                {
                    //提交頂點
                    GL.Vertex(_points[layer][i]);
                    if (layer == LAYERS - 1)
                        GL.Vertex3(_points[layer][i].x, _graphContentRect.yMax, 0);
                    else
                        GL.Vertex(_points[layer + 1][i]);
                }
            }
            GL.End();
        }

        //鼠標定位線
        if (_graphRect.Contains(_points[0][_current]))
        {
            Handles.BeginGUI();
            Handles.color = Color.white;
            //縱向線
            Handles.DrawAAPolyLine(5, new Vector2(_points[0][_current].x, _points[0][_current].y), new Vector2(_points[0][_current].x, _axisRect.yMax));
            Handles.EndGUI();
            //橫向座標數據
            EditorGUI.LabelField(new Rect(_points[0][_current].x, _axisRect.yMin + 310, 50, 50), _current.ToString() + "/" + (_sampleCount - 1));
            //縱向座標數據
            for (int i = 0; i < LAYERS; i++)
            {
                EditorGUI.LabelField(new Rect(_points[i][_current].x, _points[i][_current].y, 20, 20), _samples[_current].data[i].ToString());
            }
            //EditorGUI.LabelField(new Rect(_points[0][_current].x, _points[0][_current].y, 20, 20), _samples[_current].data[0].ToString());
            //EditorGUI.LabelField(new Rect(_points[1][_current].x, _points[1][_current].y, 20, 20), _samples[_current].data[1].ToString());
            //EditorGUI.LabelField(new Rect(_points[2][_current].x, _points[2][_current].y, 20, 20), _samples[_current].data[2].ToString());
            //EditorGUI.LabelField(new Rect(_points[3][_current].x, _points[3][_current].y, 20, 20), _samples[_current].data[3].ToString());
        }

        //座標軸
        DrawArrow(new Vector2(_axisRect.xMin, _axisRect.yMax), new Vector2(_axisRect.xMin, _axisRect.yMin), Color.white);
        DrawArrow(new Vector2(_axisRect.xMin, _axisRect.yMax), new Vector2(_axisRect.xMax, _axisRect.yMax), Color.white);
    }

    public void HandleEvent()
    {
        var point = Event.current.mousePosition;
        switch (Event.current.type)
        {
            //滑動鼠標
            case EventType.MouseDrag:

                if (Event.current.button == 0 && _clickGraph)
                {
                    UpdateCurrentSample();
                    Repaint();
                }

                if (Event.current.button == 2 && _clickGraph)
                {
                    _graphContentRect.x += Event.current.delta.x;
                    if (_graphContentRect.x > _graphRect.x)
                        _graphContentRect.x = _graphRect.x;
                    if (_graphContentRect.xMax < _graphRect.xMax)
                        _graphContentRect.x = _graphRect.xMax - _graphContentRect.width;
                    Repaint();
                }
                break;

            //單擊鼠標左鍵
            case EventType.MouseDown:
                //如果集合內獲取過點 就肯定按下了鼠標
                _clickGraph = _graphRect.Contains(point);

                if (_clickGraph)
                    //EditorGUI.FocusTextInControl(null);

                    if (Event.current.button == 0 && _clickGraph)
                    {
                        UpdateCurrentSample();
                        Repaint();
                    }
                if (Event.current.button == 1)
                {
                    //DrawFloatMenu();
                    Repaint();
                }
                break;

            //鍵盤左右鍵
            case EventType.KeyDown:

                if (Event.current.keyCode == KeyCode.LeftArrow)
                    SetCurrentIndex(_current - 1);
                if (Event.current.keyCode == KeyCode.RightArrow)
                    SetCurrentIndex(_current + 1);
                Repaint();
                break;
        }
    }

    private void UpdateCurrentSample()
    {
        float x = Event.current.mousePosition.x;
        float distance = float.MaxValue;
        int index = 0;
        for (int i = 0; i < _points[0].Length; ++i)
        {
            //找最近距離的點
            if (_graphRect.Contains(_points[0][i]) && Mathf.Abs(x - _points[0][i].x) < distance)
            {
                distance = Mathf.Abs(x - _points[0][i].x);
                index = i;
            }
        }
        //設置當前點
        SetCurrentIndex(index);
    }

    private void SetCurrentIndex(int i)
    {
        _current = Mathf.Clamp(i, 0, _samples.Count - 1);
    }

    //Color轉string
    private string Color2String(Color color)
    {
        string c = "#";
        //ToString("X2")轉換爲大寫16進制
        c += ((int)(color.r * 255)).ToString("X2");
        c += ((int)(color.g * 255)).ToString("X2");
        c += ((int)(color.b * 255)).ToString("X2");
        return c;
    }

    //畫座標軸
    private void DrawArrow(Vector2 from, Vector2 to, Color color)
    {
        Handles.BeginGUI();
        Handles.color = color;
        Handles.DrawAAPolyLine(3, from, to);
        Vector2 v0 = from - to;
        v0 *= 10 / v0.magnitude;
        Vector2 v1 = new Vector2(v0.x * 0.866f - v0.y * 0.5f, v0.x * 0.5f + v0.y * 0.866f);
        Vector2 v2 = new Vector2(v0.x * 0.866f + v0.y * 0.5f, v0.x * -0.5f + v0.y * 0.866f); ;
        Handles.DrawAAPolyLine(3, to + v1, to, to + v2);
        Handles.EndGUI();
    }

    private int GetListMaxValue(List<DataClass> list)
    {
        List<int> newList = new List<int>();
        for (int i = 0; i < list.Count; i++)
        {
            for (int j = 0; j < LAYERS; j++)
            {
                newList.Add(list[i].data[j]);
            }
        }
        return newList.Max();
    }

    private float GetListAverageValue(List<DataClass> list)
    {
        List<int> newList = new List<int>();
        for (int i = 0; i < list.Count; i++)
        {
            for (int j = 0; j < LAYERS; j++)
            {
                newList.Add(list[i].data[j]);
            }
        }
        return (float)newList.Average();
    }

    //捕獲數據
    private List<DataClass> GenFackeData()
    {
        List<DataClass> list = new List<DataClass>();
        DataClass data = null;
        for (int i = 0; i < 100; i++)
        {
            data = new DataClass();
            data.data[0] = Random.Range(90, 100);
            data.data[1] = Random.Range(80, 90);
            data.data[2] = Random.Range(70, 80);
            data.data[3] = Random.Range(55, 70);
            data.data[4] = Random.Range(40, 45);
            data.data[5] = Random.Range(20, 30);
            data.data[6] = Random.Range(0, 15);

            list.Add(data);
        }
        return list;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章