using System; using System.Collections.Generic; using System.ComponentModel; using UnityEngine; using UnityEngine.Serialization; namespace XCharts { public enum SerieType { Line, Bar, Pie, Radar, Scatter, EffectScatter } public enum RoseType { None, Radius, Area } [System.Serializable] public class Serie : JsonDataSupport { [SerializeField] [DefaultValue("true")] private bool m_Show = true; [SerializeField] private SerieType m_Type; [SerializeField] private string m_Name; [SerializeField] private string m_Stack; [SerializeField] [Range(0, 1)] private int m_AxisIndex; [SerializeField] private SerieSymbol m_Symbol = new SerieSymbol(); #region PieChart [SerializeField] private bool m_ClickOffset = true; [SerializeField] private RoseType m_RoseType = RoseType.None; [SerializeField] private float m_Space; [SerializeField] private float[] m_Center = new float[2] { 0.5f, 0.5f }; [SerializeField] private float[] m_Radius = new float[2] { 0, 80 }; #endregion [SerializeField] private SerieLabel m_Label = new SerieLabel(); [SerializeField] private SerieLabel m_HighlightLabel = new SerieLabel(); [SerializeField] [Range(1, 6)] private int m_ShowDataDimension; [SerializeField] private bool m_ShowDataName; [FormerlySerializedAs("m_Data")] [SerializeField] private List m_YData = new List(); [SerializeField] private List m_XData = new List(); [SerializeField] private List m_Data = new List(); public bool show { get { return m_Show; } set { m_Show = value; } } public SerieType type { get { return m_Type; } set { m_Type = value; } } public string name { get { return m_Name; } set { m_Name = value; } } public string stack { get { return m_Stack; } set { m_Stack = value; } } public int axisIndex { get { return m_AxisIndex; } set { m_AxisIndex = value; } } public SerieSymbol symbol { get { return m_Symbol; } set { m_Symbol = value; } } public bool clickOffset { get { return m_ClickOffset; } set { m_ClickOffset = value; } } public RoseType roseType { get { return m_RoseType; } set { m_RoseType = value; } } public float space { get { return m_Space; } set { m_Space = value; } } public float[] center { get { return m_Center; } set { m_Center = value; } } public float[] radius { get { return m_Radius; } set { m_Radius = value; } } /// /// Text label of graphic element,to explain some data information about graphic item like value, name and so on. /// 图形上的文本标签,可用于说明图形的一些数据信息,比如值,名称等。 /// public SerieLabel label { get { return m_Label; } set { m_Label = value; } } public SerieLabel highlightLabel { get { return m_HighlightLabel; } set { m_HighlightLabel = value; } } public List yData { get { return m_YData; } } public List xData { get { return m_XData; } } public List data { get { return m_Data; } } /// /// The index of serie,start at 0. /// 系列的索引,从0开始。 /// public int index { get; set; } /// /// Whether the serie is highlighted. /// 该系列是否高亮,一般由图例悬停触发。 /// public bool highlighted { get; set; } public int dataCount { get { return m_Data.Count; } } public int filterStart { get; set; } public int filterEnd { get; set; } private List yFilterData { get; set; } private List xFilterData { get; set; } private List filterData { get; set; } public float yMax { get { float max = int.MinValue; foreach (var sdata in data) { if (sdata.show && sdata.data[1] > max) { max = sdata.data[1]; } } return max; } } public float xMax { get { float max = int.MinValue; foreach (var sdata in data) { if (sdata.show && sdata.data[0] > max) { max = sdata.data[0]; } } return max; } } public float yMin { get { float min = int.MaxValue; foreach (var sdata in data) { if (sdata.show && sdata.data[1] < min) { min = sdata.data[1]; } } return min; } } public float xMin { get { float min = int.MaxValue; foreach (var sdata in data) { if (sdata.show && sdata.data[0] < min) { min = sdata.data[0]; } } return min; } } public float yTotal { get { float total = 0; foreach (var sdata in data) { if (sdata.show) total += sdata.data[1]; } return total; } } public float xTotal { get { float total = 0; foreach (var sdata in data) { if (sdata.show) total += sdata.data[0]; } return total; } } public void ClearData() { m_XData.Clear(); m_YData.Clear(); m_Data.Clear(); } public void RemoveData(int index) { m_XData.RemoveAt(index); m_YData.RemoveAt(index); m_Data.RemoveAt(index); } public void AddYData(float value, string dataName = null, int maxDataNumber = 0) { if (maxDataNumber > 0) { while (m_XData.Count > maxDataNumber) m_XData.RemoveAt(0); while (m_YData.Count > maxDataNumber) m_YData.RemoveAt(0); while (m_Data.Count > maxDataNumber) m_Data.RemoveAt(0); } int xValue = m_XData.Count; m_XData.Add(xValue); m_YData.Add(value); m_Data.Add(new SerieData() { data = new List() { xValue, value }, name = dataName }); } public void AddXYData(float xValue, float yValue, string dataName = null, int maxDataNumber = 0) { if (maxDataNumber > 0) { while (m_XData.Count > maxDataNumber) m_XData.RemoveAt(0); while (m_YData.Count > maxDataNumber) m_YData.RemoveAt(0); while (m_Data.Count > maxDataNumber) m_Data.RemoveAt(0); } m_XData.Add(xValue); m_YData.Add(yValue); m_Data.Add(new SerieData() { data = new List() { xValue, yValue }, name = dataName }); } public void AddData(List valueList, string dataName = null, int maxDataNumber = 0) { if (valueList == null || valueList.Count == 0) return; if (valueList.Count == 1) { AddYData(valueList[0], dataName, maxDataNumber); } else if (valueList.Count == 2) { AddXYData(valueList[0], valueList[1], dataName, maxDataNumber); } else { if (maxDataNumber > 0) { while (m_XData.Count > maxDataNumber) m_XData.RemoveAt(0); while (m_YData.Count > maxDataNumber) m_YData.RemoveAt(0); while (m_Data.Count > maxDataNumber) m_Data.RemoveAt(0); } var serieData = new SerieData(); serieData.name = dataName; for (int i = 0; i < valueList.Count; i++) { if (i == 0) m_XData.Add(valueList[i]); else if (i == 1) m_YData.Add(valueList[i]); serieData.data.Add(valueList[0]); } m_Data.Add(serieData); } } public float GetYData(int index, DataZoom dataZoom = null) { if (index < 0) return 0; var serieData = GetDataList(dataZoom); if (index < serieData.Count) { return serieData[index].data[1]; } return 0; } public void GetYData(int index, out float yData, out string dataName, DataZoom dataZoom = null) { yData = 0; dataName = null; if (index < 0) return; var serieData = GetDataList(dataZoom); if (index < serieData.Count) { yData = serieData[index].data[1]; dataName = serieData[index].name; } } public SerieData GetSerieData(int index, DataZoom dataZoom = null) { var data = GetDataList(dataZoom); if (index >= 0 && index <= data.Count - 1) { return data[index]; } return null; } public void GetXYData(int index, DataZoom dataZoom, out float xValue, out float yVlaue) { xValue = 0; yVlaue = 0; if (index < 0) return; var showData = GetDataList(dataZoom); if (index < showData.Count) { var serieData = showData[index]; xValue = serieData.data[0]; yVlaue = serieData.data[1]; } } public List GetYDataList(DataZoom dataZoom) { if (dataZoom != null && dataZoom.show) { var startIndex = (int)((yData.Count - 1) * dataZoom.start / 100); var endIndex = (int)((yData.Count - 1) * dataZoom.end / 100); var count = endIndex == startIndex ? 1 : endIndex - startIndex + 1; if (yFilterData == null || yFilterData.Count != count) { UpdateFilterData(dataZoom); } return yFilterData; } else { return m_YData; } } public List GetXDataList(DataZoom dataZoom) { if (dataZoom != null && dataZoom.show) { var startIndex = (int)((xData.Count - 1) * dataZoom.start / 100); var endIndex = (int)((xData.Count - 1) * dataZoom.end / 100); var count = endIndex == startIndex ? 1 : endIndex - startIndex + 1; if (xFilterData == null || xFilterData.Count != count) { UpdateFilterData(dataZoom); } return xFilterData; } else { return m_XData; } } public List GetDataList(DataZoom dataZoom) { if (dataZoom != null && dataZoom.show) { var startIndex = (int)((m_Data.Count - 1) * dataZoom.start / 100); var endIndex = (int)((m_Data.Count - 1) * dataZoom.end / 100); var count = endIndex == startIndex ? 1 : endIndex - startIndex + 1; if (filterData == null || filterData.Count != count) { UpdateFilterData(dataZoom); } return filterData; } else { return m_Data; } } public void UpdateFilterData(DataZoom dataZoom) { if (dataZoom != null && dataZoom.show) { var startIndex = (int)((yData.Count - 1) * dataZoom.start / 100); var endIndex = (int)((yData.Count - 1) * dataZoom.end / 100); if (startIndex != filterStart || endIndex != filterEnd) { filterStart = startIndex; filterEnd = endIndex; var count = endIndex == startIndex ? 1 : endIndex - startIndex + 1; if (m_YData.Count > 0) { yFilterData = m_YData.GetRange(startIndex, count); } else { yFilterData = m_YData; } if (m_XData.Count > 0) { xFilterData = m_XData.GetRange(startIndex, count); } else { xFilterData = m_XData; } if (m_Data.Count > 0) { filterData = m_Data.GetRange(startIndex, count); } else { filterData = m_Data; } } else if (endIndex == 0) { yFilterData = new List(); xFilterData = new List(); filterData = new List(); } } } public void UpdateYData(int index, float value) { UpdateData(index, 2, value); } public void UpdateXYData(int index, float xValue, float yValue) { UpdateData(index, 1, xValue); UpdateData(index, 2, yValue); } public void UpdateData(int index, int dimension, float value) { if (index < 0) return; if (dimension == 1) { if (index < m_XData.Count) m_XData[index] = value; } else if (dimension == 2) { if (index < m_YData.Count) m_YData[index] = value; } if (index < m_Data.Count && dimension < m_Data[index].data.Count) { m_Data[index].data[dimension] = value; } } public void ClearHighlight() { highlighted = false; foreach (var sd in m_Data) { sd.highlighted = false; } } public void SetHighlight(int index) { if (index <= 0) return; for (int i = 0; i < m_Data.Count; i++) { m_Data[i].highlighted = index == i; } } public override void ParseJsonData(string jsonData) { if (string.IsNullOrEmpty(jsonData) || !m_DataFromJson) return; jsonData = jsonData.Replace("\r\n", ""); jsonData = jsonData.Replace(" ", ""); jsonData = jsonData.Replace("\n", ""); int startIndex = jsonData.IndexOf("["); int endIndex = jsonData.LastIndexOf("]"); if (startIndex == -1 || endIndex == -1) { Debug.LogError("json data need include in [ ]"); return; } ClearData(); string temp = jsonData.Substring(startIndex + 1, endIndex - startIndex - 1); if (temp.IndexOf("],") > -1 || temp.IndexOf("] ,") > -1) { string[] datas = temp.Split(new string[] { "],", "] ," }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < datas.Length; i++) { var data = datas[i].Split(new char[] { '[', ',' }, StringSplitOptions.RemoveEmptyEntries); var serieData = new SerieData(); for (int j = 0; j < data.Length; j++) { var txt = data[j].Trim().Replace("]", ""); float value; var flag = float.TryParse(txt, out value); if (flag) { serieData.data.Add(value); if (j == 0) m_XData.Add(value); else if (j == 1) m_YData.Add(value); } else serieData.name = txt.Replace("\"", "").Trim(); } m_Data.Add(serieData); } } else if (temp.IndexOf("value") > -1 && temp.IndexOf("name") > -1) { string[] datas = temp.Split(new string[] { "},", "} ,", "}" }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < datas.Length; i++) { var arr = datas[i].Replace("{", "").Split(','); var serieData = new SerieData(); foreach (var a in arr) { if (a.StartsWith("value:")) { float value = float.Parse(a.Substring(6, a.Length - 6)); serieData.data = new List() { i, value }; } else if (a.StartsWith("name:")) { string name = a.Substring(6, a.Length - 6 - 1); serieData.name = name; } else if (a.StartsWith("selected:")) { string selected = a.Substring(9, a.Length - 9); serieData.selected = bool.Parse(selected); } } m_Data.Add(serieData); } } else { string[] datas = temp.Split(','); for (int i = 0; i < datas.Length; i++) { float value; var flag = float.TryParse(datas[i].Trim(), out value); if (flag) { var serieData = new SerieData(); serieData.data = new List() { i, value }; m_Data.Add(serieData); } } } } } }