Unity3D開發之折線圖的製作(二)

    一年前寫過一篇折線圖的製作,當時顯示效果還可以,只不過因爲之前剛接觸寫博客,所以寫的內容不是很完善,加上比較忙,都是草率記錄的,代碼結構也不是很好。昨天我又把這個項目的代碼熟悉了一遍,然後把代碼更改精煉了下。應該比以前更容易讀懂了。

    代碼如下,上面都有註釋:

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

//折線圖
public class LineChart : MaskableGraphic,ICanvasRaycastFilter
{
    [SerializeField]//曲線個數
    private int lineCount = 1;

    [SerializeField]//顏色
    private List<Color> lineColors = new List<Color>() { };

    [SerializeField]
    private int xwidth = 20;//數據間隔

    private List<float> pointList = new List<float>();

    private Vector3 pos;//數據點的座標

    private RectTransform rectTransform;

    private Text numText;


    //兩個數據之間的間隔
    private float xLength;
    

    //最多顯示的數據數量
    private const int RemainCount = 50;


    public Vector3 Pos
    {
        get
        {
            return pos;
        }
    }
    protected override void Awake()
    {
        base.Awake();
        rectTransform = GetComponent<RectTransform>();
        xLength = transform.parent.parent.GetComponent<RectTransform>().sizeDelta.x;
        numText = transform.Find("NumText").GetComponent<Text>();
    }

    private bool IsReachLength = false;
    public void AddPoint(float point)
    {
        pointList.Add(point);
        int count = pointList.Count;
        
        if (count> lineCount)//如果只有一條曲線,則至少有兩個點纔可以開始繪製曲線
        {
            Vector2 size = rectTransform.sizeDelta;
            //此函數改變RectTransform的大小  可以觸發OnPopulateMesh調用
            rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, xwidth * (count)); //當數據量達到我們設定的顯示上限  數據個數保持不變  這個時候設置他的大小是不發生變化的 
            rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, xwidth * (count+1));//所以我們就先設置小一單位 在設置加一單位  保證大小變化 
            if (size.x> xLength)//顯示區域的大小
            {
                if (count > RemainCount)//當數據個數大於我們規定的顯示個數  就需要移除前面的數據 
                {
                    pointList.RemoveAt(0);
                    Vector3 pos = transform.localPosition;
                    transform.localPosition = pos + new Vector3(xwidth, 0, 0);//把顯示往前移動一個單位 然後做移動動畫
                }
                transform.DOLocalMoveX(transform.localPosition.x-xwidth,0.3f);
            }
        }
    }
    

    protected override void OnPopulateMesh(VertexHelper vh)
    {
        int _count = pointList.Count;

        //畫線
        if (_count > lineCount)
        {
            vh.Clear();
            for (int i = 0; i < _count - lineCount; i++)
            {
                //讓曲線寬度在各種斜率下寬度一致
                float k = (pointList[i + lineCount] - pointList[i]) / (xwidth);

                float _y = Mathf.Sqrt(Mathf.Pow(k, 2) + 4);
                _y = Mathf.Abs(_y);
                UIVertex[] verts = new UIVertex[4];

                verts[0].position = new Vector3(xwidth * (i / lineCount), pointList[i] - _y / 2);

                verts[1].position = new Vector3(xwidth * (i / lineCount), _y / 2 + pointList[i]);

                verts[2].position = new Vector3(xwidth * ((i + lineCount) / lineCount), pointList[i + lineCount] + _y / 2);

                verts[3].position = new Vector3(xwidth * ((i + lineCount) / lineCount), pointList[i + lineCount] - _y / 2);

                for(int j=0;j<4;j++)
                {
                    verts[j].color = lineColors[(i % lineCount)];
                    verts[j].uv0 = Vector2.zero;
                }
                vh.AddUIVertexQuad(verts);
            }
        }
        //draw quad  顯示數據大小的方塊點
        for (int i = 0; i < _count; i++)
        {
            UIVertex[] quadverts = new UIVertex[4];
            quadverts[0].position = new Vector3((i / lineCount) * xwidth - 1.5f, pointList[i] - 1.5f);
            quadverts[0].color = Color.white;
            quadverts[0].uv0 = Vector2.zero;

            quadverts[1].position = new Vector3((i / lineCount) * xwidth - 1.5f, pointList[i] + 1.5f);
            quadverts[1].color = Color.white;
            quadverts[1].uv0 = Vector2.zero;

            quadverts[2].position = new Vector3((i / lineCount) * xwidth + 1.5f, pointList[i] + 1.5f);
            quadverts[2].color = Color.white;
            quadverts[2].uv0 = Vector2.zero;

            quadverts[3].position = new Vector3((i / lineCount) * xwidth + 1.5f, pointList[i] - 1.5f);
            quadverts[3].color = Color.white;
            quadverts[3].uv0 = Vector2.zero;

            vh.AddUIVertexQuad(quadverts);
        }
    }



    //如果鼠標在數據點上 就會返回true
    public bool IsRaycastLocationValid(UnityEngine.Vector2 sp, UnityEngine.Camera eventCamera)
    {
        Vector2 local;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, sp, eventCamera, out local);
        Rect rect = GetPixelAdjustedRect();

        local.x += rectTransform.pivot.x * rect.width;
        local.y += rectTransform.pivot.y * rect.height;
        int _count = pointList.Count;
        for (int i=0;i< _count; i++)
        {
            if (local.x > (i / lineCount) * xwidth - 3f && local.x < ((i / lineCount) * xwidth + 3f) && local.y > (pointList[i] - 3f)
                && local.y < (pointList[i] + 3f))
            {
                pos = new Vector3((i / lineCount) * xwidth, pointList[i], 0);
                return true;
            }
        }
        return false;
    }

    void Update()
    {
        //鼠標是否放在白點處
        if(IsRaycastLocationValid(Input.mousePosition,null))
        {
            numText.gameObject.SetActive(true);
            numText.text = (pos.y).ToString();
            numText.transform.localPosition = pos;
        }
        else
        {
            numText.gameObject.SetActive(false);
        }
    }

}

    然後我們在面板上創建一個Scroll View更改名字爲LineChart(命名隨意),因爲我們不需要顯示滑動條,所以將Scroll View下的兩個滑動條都給刪除掉。然後將我們上面的腳本加到子目錄Content上。如下圖:


    因爲我們設置的以左下角爲原點,向右爲X軸,向上爲Y軸,所以我們設置Content的Anchors和Pivot都爲0,如下圖:


    設置已經完成,這時候我們只需在外部調用往裏添加數據就可以了。

public class Test : MonoBehaviour {
    public LineChart lineChart;
    // Use this for initialization
    IEnumerator Start ()
    {
        while(true)
        {
            lineChart.AddPoint(Random.Range(10.0f,50.0f));
            yield return new WaitForSeconds(2f);
        }
    }
}

    還有就是我們要實現鼠標移動到數據上顯示數據的值,這時候我們需要在Content下創建一個Text,命名爲NumText,設置他的Pivot爲(0.5,-0.2)。這樣可以讓文本顯示在數上0.2單位處。偏移量你可以自己設定。

    以上就是對摺線圖製作的更新。對於繪製曲線以及原理,可以觀看第一篇折線圖博客。點擊打開鏈接。希望本博客對你有幫助!


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