mirror of
https://github.com/XCharts-Team/XCharts.git
synced 2026-05-19 06:50:18 +00:00
增加代码API注释文档,整理代码
This commit is contained in:
721
Scripts/UI/Component/Axis.cs
Normal file
721
Scripts/UI/Component/Axis.cs
Normal file
@@ -0,0 +1,721 @@
|
||||
using System.Net.Mime;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace XCharts
|
||||
{
|
||||
/// <summary>
|
||||
/// The axis in rectangular coordinate.
|
||||
/// 直角坐标系的坐标轴组件。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Axis : JsonDataSupport, IEquatable<Axis>
|
||||
{
|
||||
/// <summary>
|
||||
/// the type of axis.
|
||||
/// 坐标轴类型。
|
||||
/// </summary>
|
||||
public enum AxisType
|
||||
{
|
||||
/// <summary>
|
||||
/// Numerical axis, suitable for continuous data.
|
||||
/// 数值轴,适用于连续数据。
|
||||
/// </summary>
|
||||
Value,
|
||||
/// <summary>
|
||||
/// Category axis, suitable for discrete category data. Data should only be set via data for this type.
|
||||
/// 类目轴,适用于离散的类目数据,为该类型时必须通过 data 设置类目数据。
|
||||
/// </summary>
|
||||
Category
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// the type of axis min and max value.
|
||||
/// 坐标轴最大最小刻度显示类型。
|
||||
/// </summary>
|
||||
public enum AxisMinMaxType
|
||||
{
|
||||
/// <summary>
|
||||
/// 0 - maximum.
|
||||
/// 0-最大值。
|
||||
/// </summary>
|
||||
Default,
|
||||
/// <summary>
|
||||
/// minimum - maximum.
|
||||
/// 最小值-最大值。
|
||||
/// </summary>
|
||||
MinMax,
|
||||
/// <summary>
|
||||
/// Customize the minimum and maximum.
|
||||
/// 自定义最小值最大值。
|
||||
/// </summary>
|
||||
Custom
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// the type of split line.
|
||||
/// 分割线类型
|
||||
/// </summary>
|
||||
public enum SplitLineType
|
||||
{
|
||||
/// <summary>
|
||||
/// 不显示分割线
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// 实线
|
||||
/// </summary>
|
||||
Solid,
|
||||
/// <summary>
|
||||
/// 破折线
|
||||
/// </summary>
|
||||
Dashed,
|
||||
/// <summary>
|
||||
/// 虚线
|
||||
/// </summary>
|
||||
Dotted
|
||||
}
|
||||
|
||||
[SerializeField] protected bool m_Show = true;
|
||||
[SerializeField] protected AxisType m_Type;
|
||||
[SerializeField] protected AxisMinMaxType m_MinMaxType;
|
||||
[SerializeField] protected int m_Min;
|
||||
[SerializeField] protected int m_Max;
|
||||
[SerializeField] protected int m_SplitNumber = 5;
|
||||
[SerializeField] protected bool m_ShowSplitLine = false;
|
||||
[SerializeField] protected SplitLineType m_SplitLineType = SplitLineType.Dashed;
|
||||
[SerializeField] protected bool m_BoundaryGap = true;
|
||||
[SerializeField] protected List<string> m_Data = new List<string>();
|
||||
[SerializeField] protected AxisLine m_AxisLine = AxisLine.defaultAxisLine;
|
||||
[SerializeField] protected AxisName m_AxisName = AxisName.defaultAxisName;
|
||||
[SerializeField] protected AxisTick m_AxisTick = AxisTick.defaultTick;
|
||||
[SerializeField] protected AxisLabel m_AxisLabel = AxisLabel.defaultAxisLabel;
|
||||
[SerializeField] protected AxisSplitArea m_SplitArea = AxisSplitArea.defaultSplitArea;
|
||||
|
||||
/// <summary>
|
||||
/// Set this to false to prevent the axis from showing.
|
||||
/// 是否显示坐标轴。
|
||||
/// </summary>
|
||||
public bool show { get { return m_Show; } set { m_Show = value; } }
|
||||
/// <summary>
|
||||
/// the type of axis.
|
||||
/// 坐标轴类型。
|
||||
/// </summary>
|
||||
public AxisType type { get { return m_Type; } set { m_Type = value; } }
|
||||
/// <summary>
|
||||
/// the type of axis minmax.
|
||||
/// 坐标轴刻度最大最小值显示类型。
|
||||
/// </summary>
|
||||
public AxisMinMaxType minMaxType { get { return m_MinMaxType; } set { m_MinMaxType = value; } }
|
||||
/// <summary>
|
||||
/// The minimun value of axis.
|
||||
/// 设定的坐标轴刻度最小值,当minMaxType为Custom时有效。
|
||||
/// </summary>
|
||||
public int min { get { return m_Min; } set { m_Min = value; } }
|
||||
/// <summary>
|
||||
/// The maximum value of axis.
|
||||
/// 设定的坐标轴刻度最大值,当minMaxType为Custom时有效。
|
||||
/// </summary>
|
||||
public int max { get { return m_Max; } set { m_Max = value; } }
|
||||
/// <summary>
|
||||
/// Number of segments that the axis is split into.
|
||||
/// 坐标轴的分割段数。
|
||||
/// </summary>
|
||||
public int splitNumber { get { return m_SplitNumber; } set { m_SplitNumber = value; } }
|
||||
/// <summary>
|
||||
/// showSplitLineSet this to false to prevent the splitLine from showing. value type axes are shown by default, while category type axes are hidden.
|
||||
/// 是否显示分隔线。默认数值轴显示,类目轴不显示。
|
||||
/// </summary>
|
||||
public bool showSplitLine { get { return m_ShowSplitLine; } set { m_ShowSplitLine = value; } }
|
||||
/// <summary>
|
||||
/// the type of split line.
|
||||
/// 分割线类型。
|
||||
/// </summary>
|
||||
public SplitLineType splitLineType { get { return m_SplitLineType; } set { m_SplitLineType = value; } }
|
||||
/// <summary>
|
||||
/// The boundary gap on both sides of a coordinate axis.
|
||||
/// 坐标轴两边是否留白。
|
||||
/// </summary>
|
||||
public bool boundaryGap { get { return m_BoundaryGap; } set { m_BoundaryGap = value; } }
|
||||
/// <summary>
|
||||
/// Category data, available in type: 'Category' axis.
|
||||
/// 类目数据,在类目轴(type: 'category')中有效。
|
||||
/// </summary>
|
||||
public List<string> data { get { return m_Data; } }
|
||||
/// <summary>
|
||||
/// axis Line.
|
||||
/// 坐标轴轴线。
|
||||
/// </summary>
|
||||
public AxisLine axisLine { get { return m_AxisLine; } set { m_AxisLine = value; } }
|
||||
/// <summary>
|
||||
/// axis name.
|
||||
/// 坐标轴名称。
|
||||
/// </summary>
|
||||
public AxisName axisName { get { return m_AxisName; } set { m_AxisName = value; } }
|
||||
/// <summary>
|
||||
/// axis tick.
|
||||
/// 坐标轴刻度。
|
||||
/// </summary>
|
||||
public AxisTick axisTick { get { return m_AxisTick; } set { m_AxisTick = value; } }
|
||||
/// <summary>
|
||||
/// axis label.
|
||||
/// 坐标轴刻度标签。
|
||||
/// </summary>
|
||||
public AxisLabel axisLabel { get { return m_AxisLabel; } set { m_AxisLabel = value; } }
|
||||
/// <summary>
|
||||
/// axis split area.
|
||||
/// 坐标轴分割区域。
|
||||
/// </summary>
|
||||
public AxisSplitArea splitArea { get { return m_SplitArea; } set { m_SplitArea = value; } }
|
||||
/// <summary>
|
||||
/// the axis label text list.
|
||||
/// 坐标轴刻度标签的Text列表。
|
||||
/// </summary>
|
||||
public List<Text> axisLabelTextList { get { return m_AxisLabelTextList; } set { m_AxisLabelTextList = value; } }
|
||||
/// <summary>
|
||||
/// the current minimun value.
|
||||
/// 当前最小值。
|
||||
/// </summary>
|
||||
public float minValue { get; set; }
|
||||
/// <summary>
|
||||
/// the current maximum value.
|
||||
/// 当前最大值。
|
||||
/// </summary>
|
||||
public float maxValue { get; set; }
|
||||
/// <summary>
|
||||
/// the x offset of zero position.
|
||||
/// 坐标轴原点在X轴的偏移。
|
||||
/// </summary>
|
||||
public float zeroXOffset { get; set; }
|
||||
/// <summary>
|
||||
/// the y offset of zero position.
|
||||
/// 坐标轴原点在Y轴的偏移。
|
||||
/// </summary>
|
||||
public float zeroYOffset { get; set; }
|
||||
|
||||
private int filterStart;
|
||||
private int filterEnd;
|
||||
private List<string> filterData;
|
||||
private List<Text> m_AxisLabelTextList = new List<Text>();
|
||||
private GameObject m_TooltipLabel;
|
||||
private Text m_TooltipLabelText;
|
||||
private RectTransform m_TooltipLabelRect;
|
||||
|
||||
public void Copy(Axis other)
|
||||
{
|
||||
m_Show = other.show;
|
||||
m_Type = other.type;
|
||||
m_Min = other.min;
|
||||
m_Max = other.max;
|
||||
m_SplitNumber = other.splitNumber;
|
||||
|
||||
m_ShowSplitLine = other.showSplitLine;
|
||||
m_SplitLineType = other.splitLineType;
|
||||
m_BoundaryGap = other.boundaryGap;
|
||||
m_AxisName.Copy(other.axisName);
|
||||
m_AxisLabel.Copy(other.axisLabel);
|
||||
m_Data.Clear();
|
||||
foreach (var d in other.data) m_Data.Add(d);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空类目数据
|
||||
/// </summary>
|
||||
public void ClearData()
|
||||
{
|
||||
m_Data.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前坐标轴是否时类目轴
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsCategory()
|
||||
{
|
||||
return type == AxisType.Category;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前坐标轴是否时数值轴
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsValue()
|
||||
{
|
||||
return type == AxisType.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个类目到类目数据列表
|
||||
/// </summary>
|
||||
/// <param name="category"></param>
|
||||
/// <param name="maxDataNumber"></param>
|
||||
public void AddData(string category, int maxDataNumber)
|
||||
{
|
||||
if (maxDataNumber > 0)
|
||||
{
|
||||
while (m_Data.Count > maxDataNumber) m_Data.RemoveAt(0);
|
||||
}
|
||||
m_Data.Add(category);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得在dataZoom范围内指定索引的类目数据
|
||||
/// </summary>
|
||||
/// <param name="index">类目数据索引</param>
|
||||
/// <param name="dataZoom">区域缩放</param>
|
||||
/// <returns></returns>
|
||||
public string GetData(int index, DataZoom dataZoom)
|
||||
{
|
||||
var showData = GetDataList(dataZoom);
|
||||
if (index >= 0 && index < showData.Count)
|
||||
return showData[index];
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得指定区域缩放的类目数据列表
|
||||
/// </summary>
|
||||
/// <param name="dataZoom">区域缩放</param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetDataList(DataZoom dataZoom)
|
||||
{
|
||||
if (dataZoom != null && dataZoom.show)
|
||||
{
|
||||
var startIndex = (int)((data.Count - 1) * dataZoom.start / 100);
|
||||
var endIndex = (int)((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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新dataZoom对应的类目数据列表
|
||||
/// </summary>
|
||||
/// <param name="dataZoom"></param>
|
||||
public void UpdateFilterData(DataZoom dataZoom)
|
||||
{
|
||||
if (dataZoom != null && dataZoom.show)
|
||||
{
|
||||
var startIndex = (int)((data.Count - 1) * dataZoom.start / 100);
|
||||
var endIndex = (int)((data.Count - 1) * dataZoom.end / 100);
|
||||
if (startIndex != filterStart || endIndex != filterEnd)
|
||||
{
|
||||
filterStart = startIndex;
|
||||
filterEnd = endIndex;
|
||||
if (m_Data.Count > 0)
|
||||
{
|
||||
var count = endIndex == startIndex ? 1 : endIndex - startIndex + 1;
|
||||
filterData = m_Data.GetRange(startIndex, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
filterData = m_Data;
|
||||
}
|
||||
}
|
||||
else if (endIndex == 0)
|
||||
{
|
||||
filterData = new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得分割段数
|
||||
/// </summary>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <returns></returns>
|
||||
public int GetSplitNumber(DataZoom dataZoom)
|
||||
{
|
||||
if (type == AxisType.Value) return m_SplitNumber;
|
||||
int dataCount = GetDataList(dataZoom).Count;
|
||||
if (dataCount > 2 * m_SplitNumber || dataCount <= 0)
|
||||
return m_SplitNumber;
|
||||
else
|
||||
return dataCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得分割段的宽度
|
||||
/// </summary>
|
||||
/// <param name="coordinateWidth"></param>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <returns></returns>
|
||||
public float GetSplitWidth(float coordinateWidth, DataZoom dataZoom)
|
||||
{
|
||||
return coordinateWidth / (m_BoundaryGap ? GetSplitNumber(dataZoom) : GetSplitNumber(dataZoom) - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得类目数据个数
|
||||
/// </summary>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <returns></returns>
|
||||
public int GetDataNumber(DataZoom dataZoom)
|
||||
{
|
||||
return GetDataList(dataZoom).Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得一个类目数据在坐标系中代表的宽度
|
||||
/// </summary>
|
||||
/// <param name="coordinateWidth"></param>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <returns></returns>
|
||||
public float GetDataWidth(float coordinateWidth, DataZoom dataZoom)
|
||||
{
|
||||
var dataCount = GetDataNumber(dataZoom);
|
||||
return coordinateWidth / (m_BoundaryGap ? dataCount : dataCount - 1);
|
||||
}
|
||||
|
||||
private Dictionary<float, string> _cacheValue2str = new Dictionary<float, string>();
|
||||
/// <summary>
|
||||
/// 获得标签显示的名称
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="minValue"></param>
|
||||
/// <param name="maxValue"></param>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <returns></returns>
|
||||
public string GetLabelName(int index, float minValue, float maxValue, DataZoom dataZoom)
|
||||
{
|
||||
if (m_Type == AxisType.Value)
|
||||
{
|
||||
float value = (minValue + (maxValue - minValue) * index / (GetSplitNumber(dataZoom) - 1));
|
||||
if (_cacheValue2str.ContainsKey(value)) return _cacheValue2str[value];
|
||||
else
|
||||
{
|
||||
if (value - (int)value == 0)
|
||||
_cacheValue2str[value] = (value).ToString();
|
||||
else
|
||||
_cacheValue2str[value] = (value).ToString("f1");
|
||||
return _cacheValue2str[value];
|
||||
}
|
||||
}
|
||||
var showData = GetDataList(dataZoom);
|
||||
int dataCount = showData.Count;
|
||||
if (dataCount <= 0) return "";
|
||||
|
||||
if (index == GetSplitNumber(dataZoom) - 1 && !m_BoundaryGap)
|
||||
{
|
||||
return showData[dataCount - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
float rate = dataCount / GetSplitNumber(dataZoom);
|
||||
if (rate < 1) rate = 1;
|
||||
int offset = m_BoundaryGap ? (int)(rate / 2) : 0;
|
||||
int newIndex = (int)(index * rate >= dataCount - 1 ?
|
||||
dataCount - 1 : offset + index * rate);
|
||||
return showData[newIndex];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得分割线条数
|
||||
/// </summary>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <returns></returns>
|
||||
public int GetScaleNumber(DataZoom dataZoom)
|
||||
{
|
||||
if (type == AxisType.Value)
|
||||
{
|
||||
return m_BoundaryGap ? m_SplitNumber + 1 : m_SplitNumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
var showData = GetDataList(dataZoom);
|
||||
int dataCount = showData.Count;
|
||||
if (dataCount > 2 * splitNumber || dataCount <= 0)
|
||||
return m_BoundaryGap ? m_SplitNumber + 1 : m_SplitNumber;
|
||||
else
|
||||
return m_BoundaryGap ? dataCount + 1 : dataCount;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得分割段宽度
|
||||
/// </summary>
|
||||
/// <param name="coordinateWidth"></param>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <returns></returns>
|
||||
public float GetScaleWidth(float coordinateWidth, DataZoom dataZoom)
|
||||
{
|
||||
int num = GetScaleNumber(dataZoom) - 1;
|
||||
if (num <= 0) num = 1;
|
||||
return coordinateWidth / num;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新刻度标签文字
|
||||
/// </summary>
|
||||
/// <param name="dataZoom"></param>
|
||||
public void UpdateLabelText(DataZoom dataZoom)
|
||||
{
|
||||
for (int i = 0; i < axisLabelTextList.Count; i++)
|
||||
{
|
||||
if (axisLabelTextList[i] != null)
|
||||
{
|
||||
axisLabelTextList[i].text = GetLabelName(i, minValue, maxValue, dataZoom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTooltipLabel(GameObject label)
|
||||
{
|
||||
m_TooltipLabel = label;
|
||||
m_TooltipLabelRect = label.GetComponent<RectTransform>();
|
||||
m_TooltipLabelText = label.GetComponentInChildren<Text>();
|
||||
m_TooltipLabel.SetActive(true);
|
||||
}
|
||||
|
||||
public void SetTooltipLabelColor(Color bgColor, Color textColor)
|
||||
{
|
||||
m_TooltipLabel.GetComponent<Image>().color = bgColor;
|
||||
m_TooltipLabelText.color = textColor;
|
||||
}
|
||||
|
||||
public void SetTooltipLabelActive(bool flag)
|
||||
{
|
||||
if (m_TooltipLabel && m_TooltipLabel.activeInHierarchy != flag)
|
||||
{
|
||||
m_TooltipLabel.SetActive(flag);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTooptipLabelText(string text)
|
||||
{
|
||||
if (m_TooltipLabelText)
|
||||
{
|
||||
m_TooltipLabelText.text = text;
|
||||
m_TooltipLabelRect.sizeDelta = new Vector2(m_TooltipLabelText.preferredWidth + 8,
|
||||
m_TooltipLabelText.preferredHeight + 8);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTooltipLabelPos(Vector2 pos)
|
||||
{
|
||||
if (m_TooltipLabel)
|
||||
{
|
||||
m_TooltipLabel.transform.localPosition = pos;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调整最大最小值
|
||||
/// </summary>
|
||||
/// <param name="minValue"></param>
|
||||
/// <param name="maxValue"></param>
|
||||
public void AdjustMinMaxValue(ref int minValue, ref int maxValue)
|
||||
{
|
||||
if (minMaxType == Axis.AxisMinMaxType.Custom)
|
||||
{
|
||||
if (min != 0 || max != 0)
|
||||
{
|
||||
minValue = min;
|
||||
maxValue = max;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (minMaxType)
|
||||
{
|
||||
case Axis.AxisMinMaxType.Default:
|
||||
if (minValue > 0 && maxValue > 0)
|
||||
{
|
||||
minValue = 0;
|
||||
maxValue = ChartHelper.GetMaxDivisibleValue(maxValue);
|
||||
}
|
||||
else if (minValue < 0 && maxValue < 0)
|
||||
{
|
||||
minValue = ChartHelper.GetMinDivisibleValue(minValue);
|
||||
maxValue = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
minValue = ChartHelper.GetMinDivisibleValue(minValue);
|
||||
maxValue = ChartHelper.GetMaxDivisibleValue(maxValue);
|
||||
}
|
||||
break;
|
||||
case Axis.AxisMinMaxType.MinMax:
|
||||
minValue = ChartHelper.GetMinDivisibleValue(minValue);
|
||||
maxValue = ChartHelper.GetMaxDivisibleValue(maxValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (obj is Axis)
|
||||
{
|
||||
return Equals((Axis)obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(Axis other)
|
||||
{
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return show == other.show &&
|
||||
type == other.type &&
|
||||
min == other.min &&
|
||||
max == other.max &&
|
||||
splitNumber == other.splitNumber &&
|
||||
showSplitLine == other.showSplitLine &&
|
||||
m_AxisLabel.Equals(other.axisLabel) &&
|
||||
splitLineType == other.splitLineType &&
|
||||
boundaryGap == other.boundaryGap &&
|
||||
axisName.Equals(other.axisName) &&
|
||||
ChartHelper.IsValueEqualsList<string>(m_Data, other.data);
|
||||
}
|
||||
|
||||
public static bool operator ==(Axis left, Axis right)
|
||||
{
|
||||
if (ReferenceEquals(left, null) && ReferenceEquals(right, null))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Axis left, Axis right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
|
||||
public override void ParseJsonData(string jsonData)
|
||||
{
|
||||
if (string.IsNullOrEmpty(jsonData) || !m_DataFromJson) return;
|
||||
m_Data = ChartHelper.ParseStringFromString(jsonData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The x axis in cartesian(rectangular) coordinate. a grid component can place at most 2 x axis,
|
||||
/// one on the bottom and another on the top.
|
||||
/// <para>直角坐标系 grid 中的 x 轴,单个 grid 组件最多只能放上下两个 x 轴。</para>
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class XAxis : Axis
|
||||
{
|
||||
public XAxis Clone()
|
||||
{
|
||||
var axis = new XAxis();
|
||||
axis.show = show;
|
||||
axis.type = type;
|
||||
axis.min = min;
|
||||
axis.max = max;
|
||||
axis.splitNumber = splitNumber;
|
||||
|
||||
axis.showSplitLine = showSplitLine;
|
||||
axis.splitLineType = splitLineType;
|
||||
axis.boundaryGap = boundaryGap;
|
||||
axis.axisName.Copy(axisName);
|
||||
axis.axisLabel.Copy(axisLabel);
|
||||
axis.data.Clear();
|
||||
foreach (var d in data) axis.data.Add(d);
|
||||
return axis;
|
||||
}
|
||||
|
||||
public static XAxis defaultXAxis
|
||||
{
|
||||
get
|
||||
{
|
||||
var axis = new XAxis
|
||||
{
|
||||
m_Show = true,
|
||||
m_Type = AxisType.Category,
|
||||
m_Min = 0,
|
||||
m_Max = 0,
|
||||
m_SplitNumber = 5,
|
||||
m_ShowSplitLine = false,
|
||||
m_SplitLineType = SplitLineType.Dashed,
|
||||
m_BoundaryGap = true,
|
||||
m_Data = new List<string>()
|
||||
{
|
||||
"x1","x2","x3","x4","x5"
|
||||
}
|
||||
};
|
||||
return axis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The x axis in cartesian(rectangular) coordinate. a grid component can place at most 2 x axis,
|
||||
/// one on the bottom and another on the top.
|
||||
/// <para>直角坐标系 grid 中的 y 轴,单个 grid 组件最多只能放左右两个 y 轴</para>
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class YAxis : Axis
|
||||
{
|
||||
public YAxis Clone()
|
||||
{
|
||||
var axis = new YAxis();
|
||||
axis.show = show;
|
||||
axis.type = type;
|
||||
axis.min = min;
|
||||
axis.max = max;
|
||||
axis.splitNumber = splitNumber;
|
||||
|
||||
axis.showSplitLine = showSplitLine;
|
||||
axis.splitLineType = splitLineType;
|
||||
axis.boundaryGap = boundaryGap;
|
||||
axis.axisName.Copy(axisName);
|
||||
axis.axisLabel.Copy(axisLabel);
|
||||
axis.data.Clear();
|
||||
foreach (var d in data) axis.data.Add(d);
|
||||
return axis;
|
||||
}
|
||||
|
||||
public static YAxis defaultYAxis
|
||||
{
|
||||
get
|
||||
{
|
||||
var axis = new YAxis
|
||||
{
|
||||
m_Show = true,
|
||||
m_Type = AxisType.Value,
|
||||
m_Min = 0,
|
||||
m_Max = 0,
|
||||
m_SplitNumber = 5,
|
||||
m_ShowSplitLine = true,
|
||||
m_SplitLineType = SplitLineType.Dashed,
|
||||
m_BoundaryGap = false,
|
||||
m_Data = new List<string>(5),
|
||||
};
|
||||
return axis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/UI/Component/Axis.cs.meta
Normal file
11
Scripts/UI/Component/Axis.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 42232255fb44747ba8d680aa7d76c2ee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
45
Scripts/UI/Component/Bar.cs
Normal file
45
Scripts/UI/Component/Bar.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace XCharts
|
||||
{
|
||||
/// <summary>
|
||||
/// bar component.global setting for bar chart.
|
||||
/// 柱状图的全局配置组件。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Bar
|
||||
{
|
||||
[SerializeField] private bool m_InSameBar = false;
|
||||
[SerializeField] private float m_BarWidth = 0.7f;
|
||||
[SerializeField] private float m_Space = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to draw all bar in the same bar,but not stacked.
|
||||
/// 非堆叠同柱。多序列绘制在同一bar上,但不堆叠,而是覆盖绘制。
|
||||
/// </summary>
|
||||
public bool inSameBar { get { return m_InSameBar; } set { m_InSameBar = value; } }
|
||||
/// <summary>
|
||||
/// the width of bar.
|
||||
/// 状态的宽度。
|
||||
/// </summary>
|
||||
public float barWidth { get { return m_BarWidth; } set { m_BarWidth = value; } }
|
||||
/// <summary>
|
||||
/// the space of bars.
|
||||
/// 多柱状间的间距。
|
||||
/// </summary>
|
||||
public float space { get { return m_Space; } set { m_Space = value; } }
|
||||
|
||||
public static Bar defaultBar
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Bar()
|
||||
{
|
||||
m_InSameBar = false,
|
||||
m_BarWidth = 0.6f,
|
||||
m_Space = 10
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/UI/Component/Bar.cs.meta
Normal file
11
Scripts/UI/Component/Bar.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4f4f93f97ce4c4274a4153986a3e5752
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
324
Scripts/UI/Component/DataZoom.cs
Normal file
324
Scripts/UI/Component/DataZoom.cs
Normal file
@@ -0,0 +1,324 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace XCharts
|
||||
{
|
||||
/// <summary>
|
||||
/// DataZoom component is used for zooming a specific area,
|
||||
/// which enables user to investigate data in detail,
|
||||
/// or get an overview of the data, or get rid of outlier points.
|
||||
/// <para>DataZoom 组件 用于区域缩放,从而能自由关注细节的数据信息,或者概览数据整体,或者去除离群点的影响。</para>
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class DataZoom
|
||||
{
|
||||
public enum DataZoomType
|
||||
{
|
||||
/// <summary>
|
||||
/// DataZoom functionalities is embeded inside coordinate systems, enable user to
|
||||
/// zoom or roam coordinate system by mouse dragging, mouse move or finger touch (in touch screen).
|
||||
/// 内置于坐标系中,使用户可以在坐标系上通过鼠标拖拽、鼠标滚轮、手指滑动(触屏上)来缩放或漫游坐标系。
|
||||
/// </summary>
|
||||
Inside,
|
||||
/// <summary>
|
||||
/// A special slider bar is provided, on which coordinate systems can be zoomed or
|
||||
/// roamed by mouse dragging or finger touch (in touch screen).
|
||||
/// 有单独的滑动条,用户在滑动条上进行缩放或漫游。
|
||||
/// </summary>
|
||||
Slider
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generally dataZoom component zoom or roam coordinate system through data filtering
|
||||
/// and set the windows of axes internally.
|
||||
/// Its behaviours vary according to filtering mode settings.
|
||||
/// dataZoom 的运行原理是通过 数据过滤 来达到 数据窗口缩放 的效果。数据过滤模式的设置不同,效果也不同。
|
||||
/// </summary>
|
||||
public enum FilterMode
|
||||
{
|
||||
/// <summary>
|
||||
/// data that outside the window will be filtered, which may lead to some changes of windows of other axes.
|
||||
/// For each data item, it will be filtered if one of the relevant dimensions is out of the window.
|
||||
/// 当前数据窗口外的数据,被 过滤掉。即 会 影响其他轴的数据范围。每个数据项,只要有一个维度在数据窗口外,整个数据项就会被过滤掉。
|
||||
/// </summary>
|
||||
Filter,
|
||||
/// <summary>
|
||||
/// data that outside the window will be filtered, which may lead to some changes of windows of other axes.
|
||||
/// For each data item, it will be filtered only if all of the relevant dimensions are out of the same side of the window.
|
||||
/// 当前数据窗口外的数据,被 过滤掉。即 会 影响其他轴的数据范围。每个数据项,只有当全部维度都在数据窗口同侧外部,整个数据项才会被过滤掉。
|
||||
/// </summary>
|
||||
WeakFilter,
|
||||
/// <summary>
|
||||
/// data that outside the window will be set to NaN, which will not lead to changes of windows of other axes.
|
||||
/// 当前数据窗口外的数据,被 设置为空。即 不会 影响其他轴的数据范围。
|
||||
/// </summary>
|
||||
Empty,
|
||||
/// <summary>
|
||||
/// Do not filter data.
|
||||
/// 不过滤数据,只改变数轴范围。
|
||||
/// </summary>
|
||||
None
|
||||
}
|
||||
/// <summary>
|
||||
/// The value type of start and end.取值类型
|
||||
/// </summary>
|
||||
public enum RangeMode
|
||||
{
|
||||
//Value,
|
||||
/// <summary>
|
||||
/// percent value. 百分比
|
||||
/// </summary>
|
||||
Percent
|
||||
}
|
||||
[SerializeField] private bool m_Show;
|
||||
[SerializeField] private DataZoomType m_Type;
|
||||
[SerializeField] private FilterMode m_FilterMode;
|
||||
[SerializeField] private Orient m_Orient;
|
||||
[SerializeField] private int m_XAxisIndex;
|
||||
[SerializeField] private int m_YAxisIndex;
|
||||
[SerializeField] private bool m_ShowDataShadow;
|
||||
[SerializeField] private bool m_ShowDetail;
|
||||
[SerializeField] private bool m_ZoomLock;
|
||||
[SerializeField] private bool m_Realtime;
|
||||
[SerializeField] private Color m_BackgroundColor;
|
||||
[SerializeField] private float m_Height;
|
||||
[SerializeField] private float m_Bottom;
|
||||
[SerializeField] private RangeMode m_RangeMode;
|
||||
[SerializeField] private float m_Start;
|
||||
[SerializeField] private float m_End;
|
||||
[SerializeField] private float m_StartValue;
|
||||
[SerializeField] private float m_EndValue;
|
||||
[Range(1f, 20f)]
|
||||
[SerializeField] private float m_ScrollSensitivity;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to show dataZoom.
|
||||
/// 是否显示缩放区域。
|
||||
/// </summary>
|
||||
public bool show { get { return m_Show; } set { m_Show = value; } }
|
||||
/// <summary>
|
||||
/// The type of dataZoom.
|
||||
/// 缩放区域的类型。
|
||||
/// </summary>
|
||||
public DataZoomType type { get { return m_Type; } set { m_Type = value; } }
|
||||
/// <summary>
|
||||
/// The mode of data filter.
|
||||
/// 数据过滤类型。
|
||||
/// </summary>
|
||||
public FilterMode filterMode { get { return m_FilterMode; } set { m_FilterMode = value; } }
|
||||
/// <summary>
|
||||
/// Specify whether the layout of dataZoom component is horizontal or vertical.
|
||||
/// 水平还是垂直显示。
|
||||
/// </summary>
|
||||
public Orient orient { get { return m_Orient; } set { m_Orient = value; } }
|
||||
/// <summary>
|
||||
/// Specify which xAxis is controlled by the dataZoom.
|
||||
/// 控制哪个一 x 轴。
|
||||
/// </summary>
|
||||
public int xAxisIndex { get { return m_XAxisIndex; } set { m_XAxisIndex = value; } }
|
||||
/// <summary>
|
||||
/// Specify which yAxis is controlled by the dataZoom.
|
||||
/// 控制哪一个 y 轴。
|
||||
/// </summary>
|
||||
public int yAxisIndex { get { return m_YAxisIndex; } set { m_YAxisIndex = value; } }
|
||||
/// <summary>
|
||||
/// Whether to show data shadow, to indicate the data tendency in brief.
|
||||
/// default:true
|
||||
/// 是否显示数据阴影。数据阴影可以简单地反应数据走势。
|
||||
/// </summary>
|
||||
public bool showDataShadow { get { return m_ShowDataShadow; } set { m_ShowDataShadow = value; } }
|
||||
/// <summary>
|
||||
/// Whether to show detail, that is, show the detailed data information when dragging.
|
||||
/// 是否显示detail,即拖拽时候显示详细数值信息。
|
||||
/// </summary>
|
||||
public bool showDetail { get { return m_ShowDetail; } set { m_ShowDetail = value; } }
|
||||
/// <summary>
|
||||
/// Specify whether to lock the size of window (selected area).
|
||||
/// default:false
|
||||
/// 是否锁定选择区域(或叫做数据窗口)的大小。
|
||||
/// 如果设置为 true 则锁定选择区域的大小,也就是说,只能平移,不能缩放。
|
||||
/// </summary>
|
||||
public bool zoomLock { get { return m_ZoomLock; } set { m_ZoomLock = value; } }
|
||||
/// <summary>
|
||||
/// Whether to show data shadow in dataZoom-silder component, to indicate the data tendency in brief.
|
||||
/// default:true
|
||||
/// 如果设置为 true 则锁定选择区域的大小,也就是说,只能平移,不能缩放。
|
||||
/// </summary>
|
||||
public bool realtime { get { return m_Realtime; } set { m_Realtime = value; } }
|
||||
/// <summary>
|
||||
/// The background color of the component.
|
||||
/// 组件的背景颜色。
|
||||
/// </summary>
|
||||
public Color backgroundColor { get { return m_BackgroundColor; } set { m_BackgroundColor = value; } }
|
||||
/// <summary>
|
||||
/// Distance between dataZoom component and the bottom side of the container.
|
||||
/// bottom value is a instant pixel value like 10.
|
||||
/// default:10
|
||||
/// 组件离容器下侧的距离。
|
||||
/// </summary>
|
||||
public float bottom { get { return m_Bottom; } set { m_Bottom = value; } }
|
||||
/// <summary>
|
||||
/// The height of dataZoom component.
|
||||
/// height value is a instant pixel value like 10.
|
||||
/// default:50
|
||||
/// 组件高度。
|
||||
/// </summary>
|
||||
public float height { get { return m_Height; } set { m_Height = value; } }
|
||||
/// <summary>
|
||||
/// Use absolute value or percent value in DataZoom.start and DataZoom.end.
|
||||
/// default:RangeMode.Percent.
|
||||
/// 取绝对值还是百分比。
|
||||
/// </summary>
|
||||
public RangeMode rangeMode { get { return m_RangeMode; } set { m_RangeMode = value; } }
|
||||
/// <summary>
|
||||
/// The start percentage of the window out of the data extent, in the range of 0 ~ 100.
|
||||
/// default:30
|
||||
/// 数据窗口范围的起始百分比。范围是:0 ~ 100。
|
||||
/// </summary>
|
||||
public float start { get { return m_Start; } set { m_Start = value; } }
|
||||
/// <summary>
|
||||
/// The end percentage of the window out of the data extent, in the range of 0 ~ 100.
|
||||
/// default:70
|
||||
/// 数据窗口范围的结束百分比。范围是:0 ~ 100。
|
||||
/// </summary>
|
||||
public float end { get { return m_End; } set { m_End = value; } }
|
||||
/// <summary>
|
||||
/// The sensitivity of dataZoom scroll.
|
||||
/// The larger the number, the more sensitive it is.
|
||||
/// default:10
|
||||
/// 缩放区域组件的敏感度。值越高每次缩放所代表的数据越多。
|
||||
/// </summary>
|
||||
public float scrollSensitivity { get { return m_ScrollSensitivity; } set { m_ScrollSensitivity = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// DataZoom is in draging.
|
||||
/// 正在拖拽组件。
|
||||
/// </summary>
|
||||
public bool isDraging { get; set; }
|
||||
/// <summary>
|
||||
/// The start label.
|
||||
/// 组件的开始信息文本。
|
||||
/// </summary>
|
||||
public Text startLabel { get; set; }
|
||||
/// <summary>
|
||||
/// The end label.
|
||||
/// 组件的结束信息文本。
|
||||
/// </summary>
|
||||
public Text endLabel { get; set; }
|
||||
|
||||
public static DataZoom defaultDataZoom
|
||||
{
|
||||
get
|
||||
{
|
||||
return new DataZoom()
|
||||
{
|
||||
m_Type = DataZoomType.Slider,
|
||||
filterMode = FilterMode.None,
|
||||
orient = Orient.Horizonal,
|
||||
xAxisIndex = 0,
|
||||
yAxisIndex = 0,
|
||||
showDataShadow = true,
|
||||
showDetail = false,
|
||||
zoomLock = false,
|
||||
realtime = true,
|
||||
m_Height = 50,
|
||||
m_Bottom = 10,
|
||||
rangeMode = RangeMode.Percent,
|
||||
start = 30,
|
||||
end = 70,
|
||||
m_ScrollSensitivity = 10,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 给定的坐标是否在缩放区域内
|
||||
/// </summary>
|
||||
/// <param name="pos"></param>
|
||||
/// <param name="startX"></param>
|
||||
/// <param name="width"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsInZoom(Vector2 pos, float startX, float width)
|
||||
{
|
||||
Rect rect = Rect.MinMaxRect(startX, m_Bottom, startX + width, m_Bottom + m_Height);
|
||||
return rect.Contains(pos);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 给定的坐标是否在选中区域内
|
||||
/// </summary>
|
||||
/// <param name="pos"></param>
|
||||
/// <param name="startX"></param>
|
||||
/// <param name="width"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsInSelectedZoom(Vector2 pos, float startX, float width)
|
||||
{
|
||||
var start = startX + width * m_Start / 100;
|
||||
var end = startX + width * m_End / 100;
|
||||
Rect rect = Rect.MinMaxRect(start, m_Bottom, end, m_Bottom + m_Height);
|
||||
return rect.Contains(pos);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 给定的坐标是否在开始活动条触发区域内
|
||||
/// </summary>
|
||||
/// <param name="pos"></param>
|
||||
/// <param name="startX"></param>
|
||||
/// <param name="width"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsInStartZoom(Vector2 pos, float startX, float width)
|
||||
{
|
||||
var start = startX + width * m_Start / 100;
|
||||
Rect rect = Rect.MinMaxRect(start - 10, m_Bottom, start + 10, m_Bottom + m_Height);
|
||||
return rect.Contains(pos);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 给定的坐标是否在结束活动条触发区域内
|
||||
/// </summary>
|
||||
/// <param name="pos"></param>
|
||||
/// <param name="startX"></param>
|
||||
/// <param name="width"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsInEndZoom(Vector2 pos, float startX, float width)
|
||||
{
|
||||
var end = startX + width * m_End / 100;
|
||||
Rect rect = Rect.MinMaxRect(end - 10, m_Bottom, end + 10, m_Bottom + m_Height);
|
||||
return rect.Contains(pos);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示文本
|
||||
/// </summary>
|
||||
/// <param name="flag"></param>
|
||||
public void SetLabelActive(bool flag)
|
||||
{
|
||||
if (startLabel && startLabel.gameObject.activeInHierarchy != flag)
|
||||
{
|
||||
startLabel.gameObject.SetActive(flag);
|
||||
}
|
||||
if (endLabel && endLabel.gameObject.activeInHierarchy != flag)
|
||||
{
|
||||
endLabel.gameObject.SetActive(flag);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置开始文本内容
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public void SetStartLabelText(string text)
|
||||
{
|
||||
if (startLabel) startLabel.text = text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置结束文本内容
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public void SetEndLabelText(string text)
|
||||
{
|
||||
if (endLabel) endLabel.text = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/UI/Component/DataZoom.cs.meta
Normal file
11
Scripts/UI/Component/DataZoom.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46383c1c58e1f4c1a891ab60c86446eb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
136
Scripts/UI/Component/Grid.cs
Normal file
136
Scripts/UI/Component/Grid.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace XCharts
|
||||
{
|
||||
/// <summary>
|
||||
/// Grid component.
|
||||
/// Drawing grid in rectangular coordinate. In a single grid, at most two X and Y axes each is allowed.
|
||||
/// Line chart, bar chart, and scatter chart can be drawn in grid.
|
||||
/// There is only one single grid component at most in a single echarts instance.
|
||||
/// <para>
|
||||
/// 网格组件。
|
||||
/// 直角坐标系内绘图网格,单个 grid 内最多可以放置上下两个 X 轴,左右两个 Y 轴。可以在网格上绘制折线图,柱状图,散点图。
|
||||
/// 单个xcharts实例中只能存在一个grid组件。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Grid : IEquatable<Grid>
|
||||
{
|
||||
[SerializeField] private bool m_Show;
|
||||
[SerializeField] private float m_Left;
|
||||
[SerializeField] private float m_Right;
|
||||
[SerializeField] private float m_Top;
|
||||
[SerializeField] private float m_Bottom;
|
||||
[SerializeField] private Color m_BackgroundColor;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to show the grid in rectangular coordinate.
|
||||
/// 是否显示直角坐标系网格。
|
||||
/// </summary>
|
||||
public bool show { get { return m_Show; } set { m_Show = value; } }
|
||||
/// <summary>
|
||||
/// Distance between grid component and the left side of the container.
|
||||
/// grid 组件离容器左侧的距离。
|
||||
/// </summary>
|
||||
public float left { get { return m_Left; } set { m_Left = value; } }
|
||||
/// <summary>
|
||||
/// Distance between grid component and the right side of the container.
|
||||
/// grid 组件离容器右侧的距离。
|
||||
/// </summary>
|
||||
public float right { get { return m_Right; } set { m_Right = value; } }
|
||||
/// <summary>
|
||||
/// Distance between grid component and the top side of the container.
|
||||
/// grid 组件离容器上侧的距离。
|
||||
/// </summary>
|
||||
public float top { get { return m_Top; } set { m_Top = value; } }
|
||||
/// <summary>
|
||||
/// Distance between grid component and the bottom side of the container.
|
||||
/// grid 组件离容器下侧的距离。
|
||||
/// </summary>
|
||||
public float bottom { get { return m_Bottom; } set { m_Bottom = value; } }
|
||||
/// <summary>
|
||||
/// Background color of grid, which is transparent by default.
|
||||
/// 网格背景色,默认透明。
|
||||
/// </summary>
|
||||
public Color backgroundColor { get { return m_BackgroundColor; } set { m_BackgroundColor = value; } }
|
||||
|
||||
public static Grid defaultGrid
|
||||
{
|
||||
get
|
||||
{
|
||||
var coordinate = new Grid
|
||||
{
|
||||
m_Show = false,
|
||||
m_Left = 50,
|
||||
m_Right = 30,
|
||||
m_Top = 50,
|
||||
m_Bottom = 30
|
||||
};
|
||||
return coordinate;
|
||||
}
|
||||
}
|
||||
public void Copy(Grid other)
|
||||
{
|
||||
m_Show = other.show;
|
||||
m_Left = other.left;
|
||||
m_Right = other.right;
|
||||
m_Top = other.top;
|
||||
m_Bottom = other.bottom;
|
||||
m_BackgroundColor = other.backgroundColor;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (obj is Grid)
|
||||
{
|
||||
return Equals((Grid)obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(Grid other)
|
||||
{
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return m_Show == other.show &&
|
||||
m_Left == other.left &&
|
||||
m_Right == other.right &&
|
||||
m_Top == other.top &&
|
||||
m_Bottom == other.bottom &&
|
||||
ChartHelper.IsValueEqualsColor(m_BackgroundColor, other.backgroundColor);
|
||||
}
|
||||
|
||||
public static bool operator ==(Grid left, Grid right)
|
||||
{
|
||||
if (ReferenceEquals(left, null) && ReferenceEquals(right, null))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Grid left, Grid right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/UI/Component/Grid.cs.meta
Normal file
11
Scripts/UI/Component/Grid.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15d97f34ea6674855859ef7d7941e2e0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
335
Scripts/UI/Component/Legend.cs
Normal file
335
Scripts/UI/Component/Legend.cs
Normal file
@@ -0,0 +1,335 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace XCharts
|
||||
{
|
||||
/// <summary>
|
||||
/// 图例组件。
|
||||
/// 图例组件展现了不同系列的标记,颜色和名字。可以通过点击图例控制哪些系列不显示。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Legend : JsonDataSupport, IPropertyChanged, IEquatable<Legend>
|
||||
{
|
||||
[SerializeField] private bool m_Show = true;
|
||||
[SerializeField] private Orient m_Orient = Orient.Horizonal;
|
||||
[SerializeField] private Location m_Location = Location.defaultRight;
|
||||
[SerializeField] private float m_ItemWidth = 50.0f;
|
||||
[SerializeField] private float m_ItemHeight = 20.0f;
|
||||
[SerializeField] private float m_ItemGap = 5;
|
||||
[SerializeField] private int m_ItemFontSize = 18;
|
||||
[SerializeField] private List<string> m_Data = new List<string>();
|
||||
|
||||
private Dictionary<string, Button> m_DataBtnList = new Dictionary<string, Button>();
|
||||
|
||||
/// <summary>
|
||||
/// Whether to show legend component.
|
||||
/// 是否显示图例组件。
|
||||
/// </summary>
|
||||
public bool show { get { return m_Show; } set { m_Show = value; } }
|
||||
/// <summary>
|
||||
/// Specify whether the layout of legend component is horizontal or vertical.
|
||||
/// 布局方式是横还是竖。
|
||||
/// </summary>
|
||||
public Orient orient { get { return m_Orient; } set { m_Orient = value; } }
|
||||
/// <summary>
|
||||
/// The location of legend.
|
||||
/// 图例显示的位置。
|
||||
/// </summary>
|
||||
public Location location { get { return m_Location; } set { m_Location = value; } }
|
||||
/// <summary>
|
||||
/// the width of legend item.
|
||||
/// 每个图例项的宽度。
|
||||
/// </summary>
|
||||
public float itemWidth { get { return m_ItemWidth; } set { m_ItemWidth = value; } }
|
||||
/// <summary>
|
||||
/// the height of legend item.
|
||||
/// 每个图例项的高度。
|
||||
/// </summary>
|
||||
public float itemHeight { get { return m_ItemHeight; } set { m_ItemHeight = value; } }
|
||||
/// <summary>
|
||||
/// The distance between each legend, horizontal distance in horizontal layout, and vertical distance in vertical layout.
|
||||
/// 图例每项之间的间隔。横向布局时为水平间隔,纵向布局时为纵向间隔。
|
||||
/// </summary>
|
||||
public float itemGap { get { return m_ItemGap; } set { m_ItemGap = value; } }
|
||||
/// <summary>
|
||||
/// font size of item text.
|
||||
/// 图例项的字体大小。
|
||||
/// </summary>
|
||||
public int itemFontSize { get { return m_ItemFontSize; } set { m_ItemFontSize = value; } }
|
||||
/// <summary>
|
||||
/// Data array of legend. An array item is usually a name representing string. (If it is a pie chart,
|
||||
/// it could also be the name of a single data in the pie chart) of a series.
|
||||
/// If data is not specified, it will be auto collected from series.
|
||||
/// 图例的数据数组。数组项通常为一个字符串,每一项代表一个系列的 name(如果是饼图,也可以是饼图单个数据的 name)。
|
||||
/// 如果 data 没有被指定,会自动从当前系列中获取。指定data时里面的数据项和serie匹配时才会生效。
|
||||
/// </summary>
|
||||
public List<string> data { get { return m_Data; } }
|
||||
|
||||
/// <summary>
|
||||
/// 一个在顶部居中显示的默认图例。
|
||||
/// </summary>
|
||||
public static Legend defaultLegend
|
||||
{
|
||||
get
|
||||
{
|
||||
var legend = new Legend
|
||||
{
|
||||
m_Show = false,
|
||||
m_Orient = Orient.Horizonal,
|
||||
m_Location = Location.defaultTop,
|
||||
m_ItemWidth = 60.0f,
|
||||
m_ItemHeight = 20.0f,
|
||||
m_ItemGap = 5,
|
||||
m_ItemFontSize = 16
|
||||
};
|
||||
legend.location.top = 30;
|
||||
return legend;
|
||||
}
|
||||
}
|
||||
public void Copy(Legend legend)
|
||||
{
|
||||
m_Show = legend.show;
|
||||
m_Orient = legend.orient;
|
||||
m_Location.Copy(legend.location);
|
||||
m_ItemWidth = legend.itemWidth;
|
||||
m_ItemHeight = legend.itemHeight;
|
||||
m_ItemGap = legend.itemGap;
|
||||
m_ItemFontSize = legend.itemFontSize;
|
||||
m_Data.Clear();
|
||||
foreach (var d in legend.data) m_Data.Add(d);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (obj is Legend)
|
||||
{
|
||||
return Equals((Legend)obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(Legend other)
|
||||
{
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return show == other.show &&
|
||||
orient == other.orient &&
|
||||
location == other.location &&
|
||||
itemWidth == other.itemWidth &&
|
||||
itemHeight == other.itemHeight &&
|
||||
itemGap == other.itemGap &&
|
||||
itemFontSize == other.itemFontSize &&
|
||||
ChartHelper.IsValueEqualsList<string>(m_Data, other.data);
|
||||
}
|
||||
|
||||
public static bool operator ==(Legend left, Legend right)
|
||||
{
|
||||
if (ReferenceEquals(left, null) && ReferenceEquals(right, null))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Legend left, Legend right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空
|
||||
/// </summary>
|
||||
public void ClearData()
|
||||
{
|
||||
m_Data.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否包括由指定名字的图例
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public bool ContainsData(string name)
|
||||
{
|
||||
return m_Data.Contains(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除指定名字的图例
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
public void RemoveData(string name)
|
||||
{
|
||||
if (m_Data.Contains(name))
|
||||
{
|
||||
m_Data.Remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加图例项
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
public void AddData(string name)
|
||||
{
|
||||
if (!m_Data.Contains(name) && !string.IsNullOrEmpty(name))
|
||||
{
|
||||
m_Data.Add(name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得指定索引的图例
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public string GetData(int index)
|
||||
{
|
||||
if (index >= 0 && index < m_Data.Count)
|
||||
{
|
||||
return m_Data[index];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得指定图例的索引
|
||||
/// </summary>
|
||||
/// <param name="legendName"></param>
|
||||
/// <returns></returns>
|
||||
public int GetIndex(string legendName)
|
||||
{
|
||||
return m_Data.IndexOf(legendName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除所有图例按钮
|
||||
/// </summary>
|
||||
public void RemoveButton()
|
||||
{
|
||||
m_DataBtnList.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 给图例绑定按钮
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="btn"></param>
|
||||
/// <param name="total"></param>
|
||||
public void SetButton(string name, Button btn, int total)
|
||||
{
|
||||
int index = m_DataBtnList.Values.Count;
|
||||
btn.transform.localPosition = GetButtonLocationPosition(total, index);
|
||||
m_DataBtnList[name] = btn;
|
||||
btn.gameObject.SetActive(show);
|
||||
btn.GetComponentInChildren<Text>().text = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新图例按钮颜色
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="color"></param>
|
||||
public void UpdateButtonColor(string name, Color color)
|
||||
{
|
||||
if (m_DataBtnList.ContainsKey(name))
|
||||
{
|
||||
m_DataBtnList[name].GetComponent<Image>().color = color;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 参数变更时的回调处理
|
||||
/// </summary>
|
||||
public void OnChanged()
|
||||
{
|
||||
m_Location.OnChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据图例的布局和位置类型获得具体位置
|
||||
/// </summary>
|
||||
/// <param name="size"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
private Vector2 GetButtonLocationPosition(int size, int index)
|
||||
{
|
||||
switch (m_Orient)
|
||||
{
|
||||
case Orient.Vertical:
|
||||
switch (m_Location.align)
|
||||
{
|
||||
case Location.Align.TopCenter:
|
||||
case Location.Align.TopLeft:
|
||||
case Location.Align.TopRight:
|
||||
return new Vector2(0, -index * (itemHeight + itemGap));
|
||||
|
||||
case Location.Align.Center:
|
||||
case Location.Align.CenterLeft:
|
||||
case Location.Align.CenterRight:
|
||||
float totalHeight = size * itemHeight + (size - 1) * itemGap;
|
||||
float startY = totalHeight / 2;
|
||||
return new Vector2(0, startY - index * (itemHeight + itemGap));
|
||||
|
||||
case Location.Align.BottomCenter:
|
||||
case Location.Align.BottomLeft:
|
||||
case Location.Align.BottomRight:
|
||||
return new Vector2(0, (size - index - 1) * (itemHeight + itemGap));
|
||||
}
|
||||
return Vector2.zero;
|
||||
|
||||
case Orient.Horizonal:
|
||||
switch (m_Location.align)
|
||||
{
|
||||
case Location.Align.TopLeft:
|
||||
case Location.Align.CenterLeft:
|
||||
case Location.Align.BottomLeft:
|
||||
return new Vector2(index * (itemWidth + itemGap), 0);
|
||||
|
||||
case Location.Align.TopCenter:
|
||||
case Location.Align.Center:
|
||||
case Location.Align.BottomCenter:
|
||||
float totalWidth = size * itemWidth + (size - 1) * itemGap;
|
||||
float startX = totalWidth / 2;
|
||||
return new Vector2(-startX + itemWidth / 2 + index * (itemWidth + itemGap), 0);
|
||||
case Location.Align.TopRight:
|
||||
case Location.Align.CenterRight:
|
||||
case Location.Align.BottomRight:
|
||||
return new Vector2(-(size - index - 1) * (itemWidth + itemGap), 0);
|
||||
}
|
||||
return Vector2.zero;
|
||||
}
|
||||
return Vector2.zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从json字符串解析数据,json格式如:['邮件营销','联盟广告','视频广告','直接访问','搜索引擎']
|
||||
/// </summary>
|
||||
/// <param name="jsonData"></param>
|
||||
public override void ParseJsonData(string jsonData)
|
||||
{
|
||||
if (string.IsNullOrEmpty(jsonData) || !m_DataFromJson) return;
|
||||
m_Data = ChartHelper.ParseStringFromString(jsonData);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/UI/Component/Legend.cs.meta
Normal file
11
Scripts/UI/Component/Legend.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7a925c1e6149497098620272a65057f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
86
Scripts/UI/Component/Line.cs
Normal file
86
Scripts/UI/Component/Line.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace XCharts
|
||||
{
|
||||
/// <summary>
|
||||
/// The global settings of line chart.
|
||||
/// LineChart的全局配置。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Line
|
||||
{
|
||||
/// <summary>
|
||||
/// the type fo step line.
|
||||
/// 阶梯线图类型。
|
||||
/// </summary>
|
||||
public enum StepType
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前点。
|
||||
/// </summary>
|
||||
Start,
|
||||
/// <summary>
|
||||
/// 当前点和下一个点的中间。
|
||||
/// </summary>
|
||||
Middle,
|
||||
/// <summary>
|
||||
/// 下一个拐点
|
||||
/// </summary>
|
||||
End
|
||||
}
|
||||
[SerializeField] private float m_Tickness;
|
||||
[SerializeField] private bool m_Smooth;
|
||||
[SerializeField] [Range(1f, 10f)] private float m_SmoothStyle;
|
||||
[SerializeField] private bool m_Area;
|
||||
[SerializeField] private bool m_Step;
|
||||
[SerializeField] private StepType m_StepType;
|
||||
|
||||
/// <summary>
|
||||
/// the tickness of lines.
|
||||
/// 线条粗细。
|
||||
/// </summary>
|
||||
public float tickness { get { return m_Tickness; } set { m_Tickness = value; } }
|
||||
/// <summary>
|
||||
/// smoothness.
|
||||
/// 平滑风格。
|
||||
/// </summary>
|
||||
public float smoothStyle { get { return m_SmoothStyle; } set { m_SmoothStyle = value; } }
|
||||
/// <summary>
|
||||
/// Whether the lines are displayed smoothly.
|
||||
/// 是否平滑显示。
|
||||
/// </summary>
|
||||
public bool smooth { get { return m_Smooth; } set { m_Smooth = value; } }
|
||||
/// <summary>
|
||||
/// Whether to show area.
|
||||
/// 是否显示区域填充颜色。
|
||||
/// </summary>
|
||||
public bool area { get { return m_Area; } set { m_Area = value; } }
|
||||
/// <summary>
|
||||
/// Whether to show as a step line.
|
||||
/// 是否是阶梯线图。
|
||||
/// </summary>
|
||||
public bool step { get { return m_Step; } set { m_Step = value; } }
|
||||
/// <summary>
|
||||
/// the type of step line.
|
||||
/// 阶梯线图类型。
|
||||
/// </summary>
|
||||
public StepType stepTpe { get { return m_StepType; } set { m_StepType = value; } }
|
||||
|
||||
public static Line defaultLine
|
||||
{
|
||||
get
|
||||
{
|
||||
var line = new Line
|
||||
{
|
||||
m_Tickness = 0.8f,
|
||||
m_Smooth = false,
|
||||
m_SmoothStyle = 2f,
|
||||
m_Area = false,
|
||||
m_Step = false,
|
||||
m_StepType = StepType.Middle
|
||||
};
|
||||
return line;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/UI/Component/Line.cs.meta
Normal file
11
Scripts/UI/Component/Line.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a4ce8176d040474db7238ccc962c79f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
38
Scripts/UI/Component/Pie.cs
Normal file
38
Scripts/UI/Component/Pie.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace XCharts
|
||||
{
|
||||
/// <summary>
|
||||
/// the global setting of pie chart.
|
||||
/// 饼图的全局设置。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Pie
|
||||
{
|
||||
[SerializeField] private float m_TooltipExtraRadius;
|
||||
[SerializeField] private float m_SelectedOffset;
|
||||
/// <summary>
|
||||
/// the extra dadius of pie chart when the tooltip indicatored pie.
|
||||
/// 提示框指示时的额外半径。
|
||||
/// </summary>
|
||||
public float tooltipExtraRadius { get { return m_TooltipExtraRadius; } set { m_TooltipExtraRadius = value; } }
|
||||
/// <summary>
|
||||
/// the offset of pie when the pie item is selected.
|
||||
/// 饼图项被选中时的偏移。
|
||||
/// </summary>
|
||||
public float selectedOffset { get { return m_SelectedOffset; } set { m_SelectedOffset = value; } }
|
||||
|
||||
public static Pie defaultPie
|
||||
{
|
||||
get
|
||||
{
|
||||
var pie = new Pie
|
||||
{
|
||||
m_TooltipExtraRadius = 10f,
|
||||
m_SelectedOffset = 10f,
|
||||
};
|
||||
return pie;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/UI/Component/Pie.cs.meta
Normal file
11
Scripts/UI/Component/Pie.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a657ed0fd5aeb4312801338fb5308811
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
317
Scripts/UI/Component/Radar.cs
Normal file
317
Scripts/UI/Component/Radar.cs
Normal file
@@ -0,0 +1,317 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace XCharts
|
||||
{
|
||||
/// <summary>
|
||||
/// Coordinate for radar charts.
|
||||
/// 雷达图坐标系组件,只适用于雷达图。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Radar : JsonDataSupport, IEquatable<Radar>
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicator of radar chart, which is used to assign multiple variables(dimensions) in radar chart.
|
||||
/// 雷达图的指示器,用来指定雷达图中的多个变量(维度)。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Indicator : IEquatable<Indicator>
|
||||
{
|
||||
[SerializeField] private string m_Name;
|
||||
[SerializeField] private float m_Max;
|
||||
[SerializeField] private float m_Min;
|
||||
[SerializeField] private Color m_Color;
|
||||
/// <summary>
|
||||
/// 指示器名称。
|
||||
/// </summary>
|
||||
public string name { get { return m_Name; } set { m_Name = value; } }
|
||||
/// <summary>
|
||||
/// The maximum value of indicator, with default value of 0, but we recommend to set it manually.
|
||||
/// 指示器的最大值,默认为 0 无限制。
|
||||
/// </summary>
|
||||
public float max { get { return m_Max; } set { m_Max = value; } }
|
||||
/// <summary>
|
||||
/// The minimum value of indicator, with default value of 0.
|
||||
/// 指示器的最小值,默认为 0 无限制。
|
||||
/// </summary>
|
||||
public float min { get { return m_Min; } set { m_Min = value; } }
|
||||
/// <summary>
|
||||
/// Specfy a color the the indicator.
|
||||
/// 标签特定的颜色。
|
||||
/// </summary>
|
||||
public Color color { get { return m_Color; } set { m_Color = value; } }
|
||||
|
||||
public Indicator Clone()
|
||||
{
|
||||
return new Indicator()
|
||||
{
|
||||
m_Name = name,
|
||||
m_Max = max,
|
||||
m_Min = min,
|
||||
m_Color = color
|
||||
};
|
||||
}
|
||||
|
||||
public bool Equals(Indicator other)
|
||||
{
|
||||
return name.Equals(other.name);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private bool m_Cricle;
|
||||
[SerializeField] private bool m_Area;
|
||||
|
||||
[SerializeField] private float m_Radius = 100;
|
||||
[SerializeField] private int m_SplitNumber = 5;
|
||||
|
||||
[SerializeField] private float m_Left;
|
||||
[SerializeField] private float m_Right;
|
||||
[SerializeField] private float m_Top;
|
||||
[SerializeField] private float m_Bottom;
|
||||
|
||||
[SerializeField] private float m_LineTickness = 1f;
|
||||
[SerializeField] private float m_LinePointSize = 5f;
|
||||
[SerializeField] private Color m_LineColor = Color.grey;
|
||||
[Range(0, 255)]
|
||||
[SerializeField] private int m_AreaAlpha;
|
||||
|
||||
[SerializeField] private List<Color> m_BackgroundColorList = new List<Color>();
|
||||
[SerializeField] private bool m_Indicator = true;
|
||||
[SerializeField] private List<Indicator> m_IndicatorList = new List<Indicator>();
|
||||
|
||||
/// <summary>
|
||||
/// True is render radar as cricle,otherwise render as polygon.
|
||||
///雷达图是否绘制成圆形,true为圆形,false为多边形。
|
||||
/// </summary>
|
||||
public bool cricle { get { return m_Cricle; } set { m_Cricle = value; } }
|
||||
/// <summary>
|
||||
/// Whether to fill color in area.
|
||||
/// 是否区域填充颜色
|
||||
/// </summary>
|
||||
public bool area { get { return m_Area; } set { m_Area = value; } }
|
||||
/// <summary>
|
||||
/// the radius of radar.
|
||||
/// 雷达图的半径。
|
||||
/// </summary>
|
||||
public float radius { get { return m_Radius; } set { m_Radius = value; } }
|
||||
/// <summary>
|
||||
/// Segments of indicator axis.
|
||||
/// 指示器轴的分割段数。
|
||||
/// </summary>
|
||||
public int splitNumber { get { return m_SplitNumber; } set { m_SplitNumber = value; } }
|
||||
/// <summary>
|
||||
/// Distance between radar component and the left side of the container.
|
||||
/// 雷达图离容器左侧的距离。
|
||||
/// </summary>
|
||||
public float left { get { return m_Left; } set { m_Left = value; } }
|
||||
/// <summary>
|
||||
/// Distance between radar component and the right side of the container.
|
||||
/// 雷达图离容器右侧的距离。
|
||||
/// </summary>
|
||||
public float right { get { return m_Right; } set { m_Right = value; } }
|
||||
/// <summary>
|
||||
/// Distance between radar component and the top side of the container.
|
||||
/// 雷达图离容器上侧的距离。
|
||||
/// </summary>
|
||||
public float top { get { return m_Top; } set { m_Top = value; } }
|
||||
/// <summary>
|
||||
/// Distance between radar component and the bottom side of the container.
|
||||
/// 雷达图离容器下侧的距离。
|
||||
/// </summary>
|
||||
public float bottom { get { return m_Bottom; } set { m_Bottom = value; } }
|
||||
/// <summary>
|
||||
/// the tickness of line.
|
||||
/// 线的粗细。
|
||||
/// </summary>
|
||||
public float lineTickness { get { return m_LineTickness; } set { m_LineTickness = value; } }
|
||||
/// <summary>
|
||||
/// the size of point.
|
||||
/// 圆点大小。
|
||||
/// </summary>
|
||||
public float linePointSize { get { return m_LinePointSize; } set { m_LinePointSize = value; } }
|
||||
/// <summary>
|
||||
/// the color of line.
|
||||
/// 线的颜色。
|
||||
/// </summary>
|
||||
public Color lineColor { get { return m_LineColor; } set { m_LineColor = value; } }
|
||||
/// <summary>
|
||||
/// the alpha of area color.
|
||||
/// 区域填充时的颜色alpha值
|
||||
/// </summary>
|
||||
public int areaAlpha { get { return m_AreaAlpha; } set { m_AreaAlpha = value; } }
|
||||
/// <summary>
|
||||
/// the color list of split area.
|
||||
/// 分割区域颜色列表。
|
||||
/// </summary>
|
||||
public List<Color> backgroundColorList { get { return m_BackgroundColorList; } }
|
||||
/// <summary>
|
||||
/// Whether to show indicator.
|
||||
/// 是否显示指示器。
|
||||
/// </summary>
|
||||
public bool indicator { get { return m_Indicator; } set { m_Indicator = value; } }
|
||||
/// <summary>
|
||||
/// the indicator list.
|
||||
/// 指示器列表。
|
||||
/// </summary>
|
||||
public List<Indicator> indicatorList { get { return m_IndicatorList; } }
|
||||
|
||||
public static Radar defaultRadar
|
||||
{
|
||||
get
|
||||
{
|
||||
var radar = new Radar
|
||||
{
|
||||
m_Cricle = false,
|
||||
m_Area = false,
|
||||
m_Radius = 100,
|
||||
m_SplitNumber = 5,
|
||||
m_Left = 0,
|
||||
m_Right = 0,
|
||||
m_Top = 0,
|
||||
m_Bottom = 0,
|
||||
m_LineTickness = 1f,
|
||||
m_LinePointSize = 5f,
|
||||
m_AreaAlpha = 150,
|
||||
m_LineColor = Color.grey,
|
||||
m_Indicator = true,
|
||||
m_BackgroundColorList = new List<Color> {
|
||||
new Color32(246, 246, 246, 255),
|
||||
new Color32(231, 231, 231, 255)
|
||||
},
|
||||
m_IndicatorList = new List<Indicator>(5){
|
||||
new Indicator(){name="radar1",max = 100},
|
||||
new Indicator(){name="radar2",max = 100},
|
||||
new Indicator(){name="radar3",max = 100},
|
||||
new Indicator(){name="radar4",max = 100},
|
||||
new Indicator(){name="radar5",max = 100},
|
||||
}
|
||||
};
|
||||
return radar;
|
||||
}
|
||||
}
|
||||
|
||||
public void Copy(Radar other)
|
||||
{
|
||||
m_Radius = other.radius;
|
||||
m_SplitNumber = other.splitNumber;
|
||||
m_Left = other.left;
|
||||
m_Right = other.right;
|
||||
m_Top = other.top;
|
||||
m_Bottom = other.bottom;
|
||||
m_Indicator = other.indicator;
|
||||
m_AreaAlpha = other.areaAlpha;
|
||||
indicatorList.Clear();
|
||||
foreach (var d in other.indicatorList) indicatorList.Add(d.Clone());
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (obj is Radar)
|
||||
{
|
||||
return Equals((Radar)obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(Radar other)
|
||||
{
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return radius == other.radius &&
|
||||
splitNumber == other.splitNumber &&
|
||||
left == other.left &&
|
||||
right == other.right &&
|
||||
top == other.top &&
|
||||
bottom == other.bottom &&
|
||||
indicator == other.indicator &&
|
||||
IsEqualsIndicatorList(indicatorList, other.indicatorList);
|
||||
}
|
||||
|
||||
private bool IsEqualsIndicatorList(List<Indicator> indicators1, List<Indicator> indicators2)
|
||||
{
|
||||
if (indicators1.Count != indicators2.Count) return false;
|
||||
for (int i = 0; i < indicators1.Count; i++)
|
||||
{
|
||||
var indicator1 = indicators1[i];
|
||||
var indicator2 = indicators2[i];
|
||||
if (!indicator1.Equals(indicator2)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool operator ==(Radar left, Radar right)
|
||||
{
|
||||
if (ReferenceEquals(left, null) && ReferenceEquals(right, null))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Radar left, Radar right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
|
||||
public override void ParseJsonData(string jsonData)
|
||||
{
|
||||
if (string.IsNullOrEmpty(jsonData) || !m_DataFromJson) return;
|
||||
string pattern = "[\"|'](.*?)[\"|']";
|
||||
if (Regex.IsMatch(jsonData, pattern))
|
||||
{
|
||||
m_IndicatorList.Clear();
|
||||
MatchCollection m = Regex.Matches(jsonData, pattern);
|
||||
foreach (Match match in m)
|
||||
{
|
||||
m_IndicatorList.Add(new Indicator()
|
||||
{
|
||||
name = match.Groups[1].Value
|
||||
});
|
||||
}
|
||||
}
|
||||
pattern = "(\\d+)";
|
||||
if (Regex.IsMatch(jsonData, pattern))
|
||||
{
|
||||
MatchCollection m = Regex.Matches(jsonData, pattern);
|
||||
int index = 0;
|
||||
foreach (Match match in m)
|
||||
{
|
||||
if (m_IndicatorList[index] != null)
|
||||
{
|
||||
m_IndicatorList[index].max = int.Parse(match.Groups[1].Value);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float GetIndicatorMax(int index)
|
||||
{
|
||||
if (index >= 0 && index < m_IndicatorList.Count)
|
||||
{
|
||||
return m_IndicatorList[index].max;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/UI/Component/Radar.cs.meta
Normal file
11
Scripts/UI/Component/Radar.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0edd44f3a0d104bcbb1371b511d15550
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
754
Scripts/UI/Component/Serie.cs
Normal file
754
Scripts/UI/Component/Serie.cs
Normal file
@@ -0,0 +1,754 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace XCharts
|
||||
{
|
||||
/// <summary>
|
||||
/// the type of serie.
|
||||
/// 系列类型。
|
||||
/// </summary>
|
||||
public enum SerieType
|
||||
{
|
||||
/// <summary>
|
||||
/// 折线图。折线图是用折线将各个数据点标志连接起来的图表,用于展现数据的变化趋势。可用于直角坐标系和极坐标系上。
|
||||
/// </summary>
|
||||
Line,
|
||||
/// <summary>
|
||||
/// 柱状图。柱状/条形图 通过 柱形的高度/条形的宽度 来表现数据的大小,用于有至少一个类目轴或时间轴的直角坐标系上。
|
||||
/// </summary>
|
||||
Bar,
|
||||
/// <summary>
|
||||
/// 饼图。饼图主要用于表现不同类目的数据在总和中的占比。每个的弧度表示数据数量的比例。
|
||||
/// 饼图更适合表现数据相对于总数的百分比等关系。
|
||||
/// </summary>
|
||||
Pie,
|
||||
/// <summary>
|
||||
/// 雷达图。雷达图主要用于表现多变量的数据,例如球员的各个属性分析。依赖 radar 组件。
|
||||
/// </summary>
|
||||
Radar,
|
||||
/// <summary>
|
||||
/// 散点图。直角坐标系上的散点图可以用来展现数据的 x,y 之间的关系,如果数据项有多个维度,
|
||||
/// 其它维度的值可以通过不同大小的 symbol 展现成气泡图,也可以用颜色来表现。
|
||||
/// </summary>
|
||||
Scatter,
|
||||
/// <summary>
|
||||
/// 带有涟漪特效动画的散点图。利用动画特效可以将某些想要突出的数据进行视觉突出。
|
||||
/// </summary>
|
||||
EffectScatter
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether to show as Nightingale chart, which distinguishs data through radius.
|
||||
/// 是否展示成南丁格尔图,通过半径区分数据大小。
|
||||
/// </summary>
|
||||
public enum RoseType
|
||||
{
|
||||
/// <summary>
|
||||
/// Don't show as Nightingale chart.不展示成南丁格尔玫瑰图
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// Use central angle to show the percentage of data, radius to show data size.
|
||||
/// 扇区圆心角展现数据的百分比,半径展现数据的大小。
|
||||
/// </summary>
|
||||
Radius,
|
||||
/// <summary>
|
||||
/// All the sectors will share the same central angle, the data size is shown only through radiuses.
|
||||
/// 所有扇区圆心角相同,仅通过半径展现数据大小。
|
||||
/// </summary>
|
||||
Area
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 系列。每个系列通过 type 决定自己的图表类型。
|
||||
/// </summary>
|
||||
[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 field
|
||||
[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<float> m_YData = new List<float>();
|
||||
[SerializeField] private List<float> m_XData = new List<float>();
|
||||
[SerializeField] private List<SerieData> m_Data = new List<SerieData>();
|
||||
|
||||
/// <summary>
|
||||
/// Whether to show serie in chart.
|
||||
/// 系列是否显示在图表上。
|
||||
/// </summary>
|
||||
public bool show { get { return m_Show; } set { m_Show = value; } }
|
||||
/// <summary>
|
||||
/// the chart type of serie.
|
||||
/// 系列的图表类型。
|
||||
/// </summary>
|
||||
public SerieType type { get { return m_Type; } set { m_Type = value; } }
|
||||
/// <summary>
|
||||
/// Series name used for displaying in tooltip and filtering with legend.
|
||||
/// 系列名称,用于 tooltip 的显示,legend 的图例筛选。
|
||||
/// </summary>
|
||||
public string name { get { return m_Name; } set { m_Name = value; } }
|
||||
/// <summary>
|
||||
/// If stack the value. On the same category axis, the series with the same stack name would be put on top of each other.
|
||||
/// 数据堆叠,同个类目轴上系列配置相同的stack值后,后一个系列的值会在前一个系列的值上相加。
|
||||
/// </summary>
|
||||
public string stack { get { return m_Stack; } set { m_Stack = value; } }
|
||||
/// <summary>
|
||||
/// Index of axis to combine with, which is useful for multiple x axes in one chart.
|
||||
/// 使用的坐标轴轴的 index,在单个图表实例中存在多个坐标轴轴的时候有用。
|
||||
/// </summary>
|
||||
public int axisIndex { get { return m_AxisIndex; } set { m_AxisIndex = value; } }
|
||||
/// <summary>
|
||||
/// the symbol of serie data item.
|
||||
/// 标记的图形。
|
||||
/// </summary>
|
||||
public SerieSymbol symbol { get { return m_Symbol; } set { m_Symbol = value; } }
|
||||
/// <summary>
|
||||
/// Whether offset when mouse click pie chart item.
|
||||
/// 鼠标点击时是否开启偏移,一般用在PieChart图表中。
|
||||
/// </summary>
|
||||
public bool clickOffset { get { return m_ClickOffset; } set { m_ClickOffset = value; } }
|
||||
/// <summary>
|
||||
/// Whether to show as Nightingale chart.
|
||||
/// 是否展示成南丁格尔图,通过半径区分数据大小。
|
||||
/// </summary>
|
||||
public RoseType roseType { get { return m_RoseType; } set { m_RoseType = value; } }
|
||||
/// <summary>
|
||||
/// the space of pie chart item.
|
||||
/// 饼图项间的空隙留白。
|
||||
/// </summary>
|
||||
public float space { get { return m_Space; } set { m_Space = value; } }
|
||||
/// <summary>
|
||||
/// the center of pie chart.
|
||||
/// 饼图的中心点。
|
||||
/// </summary>
|
||||
public float[] center { get { return m_Center; } set { m_Center = value; } }
|
||||
/// <summary>
|
||||
/// the radius of pie chart.
|
||||
/// 饼图的半径。radius[0]表示内径,radius[1]表示外径。
|
||||
/// </summary>
|
||||
public float[] radius { get { return m_Radius; } set { m_Radius = value; } }
|
||||
/// <summary>
|
||||
/// Text label of graphic element,to explain some data information about graphic item like value, name and so on.
|
||||
/// 图形上的文本标签,可用于说明图形的一些数据信息,比如值,名称等。
|
||||
/// </summary>
|
||||
public SerieLabel label { get { return m_Label; } set { m_Label = value; } }
|
||||
/// <summary>
|
||||
/// Text label of highlight graphic element.
|
||||
/// 高亮时的文本标签配置。
|
||||
/// </summary>
|
||||
public SerieLabel highlightLabel { get { return m_HighlightLabel; } set { m_HighlightLabel = value; } }
|
||||
/// <summary>
|
||||
/// 维度Y的数据列表。默认对应yAxis。
|
||||
/// </summary>
|
||||
public List<float> yData { get { return m_YData; } }
|
||||
/// <summary>
|
||||
/// 维度X的数据列表。默认对应xAxis。
|
||||
/// </summary>
|
||||
public List<float> xData { get { return m_XData; } }
|
||||
/// <summary>
|
||||
/// 系列中的数据内容数组。SerieData可以设置1到n维数据。
|
||||
/// </summary>
|
||||
public List<SerieData> data { get { return m_Data; } }
|
||||
|
||||
/// <summary>
|
||||
/// The index of serie,start at 0.
|
||||
/// 系列的索引,从0开始。
|
||||
/// </summary>
|
||||
public int index { get; set; }
|
||||
/// <summary>
|
||||
/// Whether the serie is highlighted.
|
||||
/// 该系列是否高亮,一般由图例悬停触发。
|
||||
/// </summary>
|
||||
public bool highlighted { get; set; }
|
||||
/// <summary>
|
||||
/// the count of data list.
|
||||
/// 数据项个数。
|
||||
/// </summary>
|
||||
public int dataCount { get { return m_Data.Count; } }
|
||||
|
||||
private int filterStart { get; set; }
|
||||
private int filterEnd { get; set; }
|
||||
private List<float> yFilterData { get; set; }
|
||||
private List<float> xFilterData { get; set; }
|
||||
private List<SerieData> filterData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 维度Y对应数据中最大值。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 维度X对应数据中的最大值。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 维度Y对应数据的最小值。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 维度X对应数据的最小值。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 维度Y数据的总和。
|
||||
/// </summary>
|
||||
public float yTotal
|
||||
{
|
||||
get
|
||||
{
|
||||
float total = 0;
|
||||
foreach (var sdata in data)
|
||||
{
|
||||
if (sdata.show)
|
||||
total += sdata.data[1];
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 维度X数据的总和。
|
||||
/// </summary>
|
||||
public float xTotal
|
||||
{
|
||||
get
|
||||
{
|
||||
float total = 0;
|
||||
foreach (var sdata in data)
|
||||
{
|
||||
if (sdata.show)
|
||||
total += sdata.data[0];
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空所有数据
|
||||
/// </summary>
|
||||
public void ClearData()
|
||||
{
|
||||
m_XData.Clear();
|
||||
m_YData.Clear();
|
||||
m_Data.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除指定索引的数据
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
public void RemoveData(int index)
|
||||
{
|
||||
m_XData.RemoveAt(index);
|
||||
m_YData.RemoveAt(index);
|
||||
m_Data.RemoveAt(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个数据到维度Y(此时维度X对应的数据是索引)
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="dataName"></param>
|
||||
/// <param name="maxDataNumber"></param>
|
||||
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<float>() { xValue, value }, name = dataName });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加(x,y)数据到维度X和维度Y
|
||||
/// </summary>
|
||||
/// <param name="xValue"></param>
|
||||
/// <param name="yValue"></param>
|
||||
/// <param name="dataName"></param>
|
||||
/// <param name="maxDataNumber"></param>
|
||||
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<float>() { xValue, yValue }, name = dataName });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将一组数据添加到系列中。
|
||||
/// 如果数据只有一个,默认添加到维度Y中。
|
||||
/// </summary>
|
||||
/// <param name="valueList"></param>
|
||||
/// <param name="dataName"></param>
|
||||
/// <param name="maxDataNumber"></param>
|
||||
public void AddData(List<float> 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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得维度Y索引对应的数据
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得维度Y索引对应的数据和数据名
|
||||
/// </summary>
|
||||
/// <param name="index">索引</param>
|
||||
/// <param name="yData">对应的数据值</param>
|
||||
/// <param name="dataName">对应的数据名</param>
|
||||
/// <param name="dataZoom">区域缩放</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得指定索引的数据项
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <returns></returns>
|
||||
public SerieData GetSerieData(int index, DataZoom dataZoom = null)
|
||||
{
|
||||
var data = GetDataList(dataZoom);
|
||||
if (index >= 0 && index <= data.Count - 1)
|
||||
{
|
||||
return data[index];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得指定索引的维度X和维度Y的数据
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <param name="xValue"></param>
|
||||
/// <param name="yVlaue"></param>
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得维度Y的数据列表
|
||||
/// </summary>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <returns></returns>
|
||||
public List<float> 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得维度X的数据列表
|
||||
/// </summary>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <returns></returns>
|
||||
public List<float> 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得系列的数据列表
|
||||
/// </summary>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <returns></returns>
|
||||
public List<SerieData> 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据dataZoom更新数据列表缓存
|
||||
/// </summary>
|
||||
/// <param name="dataZoom"></param>
|
||||
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<float>();
|
||||
xFilterData = new List<float>();
|
||||
filterData = new List<SerieData>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新指定索引的维度Y数据
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="value"></param>
|
||||
public void UpdateYData(int index, float value)
|
||||
{
|
||||
UpdateData(index, 2, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新指定索引的维度X和维度Y的数据
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="xValue"></param>
|
||||
/// <param name="yValue"></param>
|
||||
public void UpdateXYData(int index, float xValue, float yValue)
|
||||
{
|
||||
UpdateData(index, 1, xValue);
|
||||
UpdateData(index, 2, yValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新指定索引指定维数的数据
|
||||
/// </summary>
|
||||
/// <param name="index">要更新数据的索引</param>
|
||||
/// <param name="dimension">要更新数据的维数</param>
|
||||
/// <param name="value">新的数据值</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除所有数据的高亮标志
|
||||
/// </summary>
|
||||
public void ClearHighlight()
|
||||
{
|
||||
highlighted = false;
|
||||
foreach (var sd in m_Data)
|
||||
{
|
||||
sd.highlighted = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置指定索引的数据为高亮状态
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
public void SetHighlight(int index)
|
||||
{
|
||||
if (index <= 0) return;
|
||||
for (int i = 0; i < m_Data.Count; i++)
|
||||
{
|
||||
m_Data[i].highlighted = index == i;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从json中导入数据
|
||||
/// </summary>
|
||||
/// <param name="jsonData"></param>
|
||||
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<float>() { 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<float>() { i, value };
|
||||
m_Data.Add(serieData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/UI/Component/Serie.cs.meta
Normal file
11
Scripts/UI/Component/Serie.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e8779db31fe5441ba4491407ee03cd1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
776
Scripts/UI/Component/Series.cs
Normal file
776
Scripts/UI/Component/Series.cs
Normal file
@@ -0,0 +1,776 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace XCharts
|
||||
{
|
||||
/// <summary>
|
||||
/// the list of series.
|
||||
/// 系列列表。每个系列通过 type 决定自己的图表类型。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Series : JsonDataSupport
|
||||
{
|
||||
[SerializeField] protected List<Serie> m_Series;
|
||||
|
||||
/// <summary>
|
||||
/// the list of serie
|
||||
/// 系列列表。
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public List<Serie> series { get { return m_Series; } }
|
||||
/// <summary>
|
||||
/// the size of serie list.
|
||||
/// 系列个数。
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public int Count { get { return m_Series.Count; } }
|
||||
|
||||
public static Series defaultSeries
|
||||
{
|
||||
get
|
||||
{
|
||||
var series = new Series
|
||||
{
|
||||
m_Series = new List<Serie>(){new Serie(){
|
||||
show = true,
|
||||
name = "serie1",
|
||||
index = 0
|
||||
}}
|
||||
};
|
||||
return series;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空所有系列的数据
|
||||
/// </summary>
|
||||
public void ClearData()
|
||||
{
|
||||
foreach (var serie in m_Series)
|
||||
{
|
||||
serie.ClearData();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得指定序列指定索引的数据值
|
||||
/// </summary>
|
||||
/// <param name="serieIndex"></param>
|
||||
/// <param name="dataIndex"></param>
|
||||
/// <returns></returns>
|
||||
public float GetData(int serieIndex, int dataIndex)
|
||||
{
|
||||
if (serieIndex >= 0 && serieIndex < Count)
|
||||
{
|
||||
return m_Series[serieIndex].GetYData(dataIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得指定系列名的第一个系列
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public Serie GetSerie(string name)
|
||||
{
|
||||
for (int i = 0; i < m_Series.Count; i++)
|
||||
{
|
||||
if (name.Equals(m_Series[i].name))
|
||||
{
|
||||
m_Series[i].index = i;
|
||||
return m_Series[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得指定系列名的所有系列
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public List<Serie> GetSeries(string name)
|
||||
{
|
||||
var list = new List<Serie>();
|
||||
if (name == null) return list;
|
||||
foreach (var serie in m_Series)
|
||||
{
|
||||
if (name.Equals(serie.name)) list.Add(serie);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得指定索引的系列
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public Serie GetSerie(int index)
|
||||
{
|
||||
if (index >= 0 && index < m_Series.Count)
|
||||
{
|
||||
return m_Series[index];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含指定名字的系列
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(string name)
|
||||
{
|
||||
for (int i = 0; i < m_Series.Count; i++)
|
||||
{
|
||||
if (name.Equals(m_Series[i].name))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove serie from series.
|
||||
/// 移除指定名字的系列。
|
||||
/// </summary>
|
||||
/// <param name="serieName">the name of serie</param>
|
||||
public void Remove(string serieName)
|
||||
{
|
||||
var serie = GetSerie(serieName);
|
||||
if (serie != null)
|
||||
{
|
||||
m_Series.Remove(serie);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all serie from series.
|
||||
/// 移除所有系列。
|
||||
/// </summary>
|
||||
public void RemoveAll()
|
||||
{
|
||||
m_Series.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个系列到列表中。
|
||||
/// </summary>
|
||||
/// <param name="serieName"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="show"></param>
|
||||
/// <returns></returns>
|
||||
public Serie AddSerie(string serieName, SerieType type, bool show = true)
|
||||
{
|
||||
var serie = GetSerie(serieName);
|
||||
if (serie == null)
|
||||
{
|
||||
serie = new Serie();
|
||||
serie.type = type;
|
||||
serie.show = show;
|
||||
serie.name = serieName;
|
||||
serie.index = m_Series.Count;
|
||||
|
||||
if (type == SerieType.Scatter)
|
||||
{
|
||||
serie.symbol.type = SerieSymbolType.Circle;
|
||||
serie.symbol.size = 20f;
|
||||
serie.symbol.selectedSize = 30f;
|
||||
}
|
||||
else if (type == SerieType.Line)
|
||||
{
|
||||
serie.symbol.type = SerieSymbolType.EmptyCircle;
|
||||
serie.symbol.size = 2.5f;
|
||||
serie.symbol.selectedSize = 5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
serie.symbol.type = SerieSymbolType.None;
|
||||
}
|
||||
m_Series.Add(serie);
|
||||
}
|
||||
else
|
||||
{
|
||||
serie.show = show;
|
||||
}
|
||||
return serie;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个数据到指定系列的维度Y数据中
|
||||
/// </summary>
|
||||
/// <param name="serieName"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="dataName"></param>
|
||||
/// <param name="maxDataNumber"></param>
|
||||
/// <returns></returns>
|
||||
public bool AddData(string serieName, float value, string dataName = null, int maxDataNumber = 0)
|
||||
{
|
||||
var serie = GetSerie(serieName);
|
||||
if (serie != null)
|
||||
{
|
||||
serie.AddYData(value, dataName, maxDataNumber);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个数据到指定系列的维度Y中
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="dataName"></param>
|
||||
/// <param name="maxDataNumber"></param>
|
||||
/// <returns></returns>
|
||||
public bool AddData(int index, float value, string dataName = null, int maxDataNumber = 0)
|
||||
{
|
||||
var serie = GetSerie(index);
|
||||
if (serie != null)
|
||||
{
|
||||
serie.AddYData(value, dataName, maxDataNumber);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一组数据到指定的系列中
|
||||
/// </summary>
|
||||
/// <param name="serieName"></param>
|
||||
/// <param name="multidimensionalData"></param>
|
||||
/// <param name="dataName"></param>
|
||||
/// <param name="maxDataNumber"></param>
|
||||
/// <returns></returns>
|
||||
public bool AddData(string serieName, List<float> multidimensionalData, string dataName = null, int maxDataNumber = 0)
|
||||
{
|
||||
var serie = GetSerie(serieName);
|
||||
if (serie != null)
|
||||
{
|
||||
serie.AddData(multidimensionalData, dataName, maxDataNumber);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一组数据到指定的系列中
|
||||
/// </summary>
|
||||
/// <param name="serieIndex"></param>
|
||||
/// <param name="multidimensionalData"></param>
|
||||
/// <param name="dataName"></param>
|
||||
/// <param name="maxDataNumber"></param>
|
||||
/// <returns></returns>
|
||||
public bool AddData(int serieIndex, List<float> multidimensionalData, string dataName = null, int maxDataNumber = 0)
|
||||
{
|
||||
var serie = GetSerie(serieIndex);
|
||||
if (serie != null)
|
||||
{
|
||||
serie.AddData(multidimensionalData, dataName, maxDataNumber);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加(x,y)数据到指定的系列中
|
||||
/// </summary>
|
||||
/// <param name="serieName"></param>
|
||||
/// <param name="xValue"></param>
|
||||
/// <param name="yValue"></param>
|
||||
/// <param name="dataName"></param>
|
||||
/// <param name="maxDataNumber"></param>
|
||||
/// <returns></returns>
|
||||
public bool AddXYData(string serieName, float xValue, float yValue, string dataName = null, int maxDataNumber = 0)
|
||||
{
|
||||
var serie = GetSerie(serieName);
|
||||
if (serie != null)
|
||||
{
|
||||
serie.AddXYData(xValue, yValue, dataName, maxDataNumber);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加(x,y)数据到指定的系列中
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="xValue"></param>
|
||||
/// <param name="yValue"></param>
|
||||
/// <param name="dataName"></param>
|
||||
/// <param name="maxDataNumber"></param>
|
||||
/// <returns></returns>
|
||||
public bool AddXYData(int index, float xValue, float yValue, string dataName = null, int maxDataNumber = 0)
|
||||
{
|
||||
var serie = GetSerie(index);
|
||||
if (serie != null)
|
||||
{
|
||||
serie.AddXYData(xValue, yValue, dataName, maxDataNumber);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新指定系列的维度Y数据
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="dataIndex"></param>
|
||||
public void UpdateData(string name, float value, int dataIndex = 0)
|
||||
{
|
||||
var serie = GetSerie(name);
|
||||
if (serie != null)
|
||||
{
|
||||
serie.UpdateYData(dataIndex, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新指定系列的维度Y数据
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="dataIndex"></param>
|
||||
public void UpdateData(int index, float value, int dataIndex = 0)
|
||||
{
|
||||
var serie = GetSerie(index);
|
||||
if (serie != null)
|
||||
{
|
||||
serie.UpdateYData(dataIndex, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 更新指定系列的维度X和维度Y数据
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="xValue"></param>
|
||||
/// <param name="yValue"></param>
|
||||
/// <param name="dataIndex"></param>
|
||||
public void UpdateXYData(string name, float xValue, float yValue, int dataIndex = 0)
|
||||
{
|
||||
var serie = GetSerie(name);
|
||||
if (serie != null)
|
||||
{
|
||||
serie.UpdateXYData(dataIndex, xValue, yValue);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新指定系列的维度X和维度Y数据
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="xValue"></param>
|
||||
/// <param name="yValue"></param>
|
||||
/// <param name="dataIndex"></param>
|
||||
public void UpdateXYData(int index, float xValue, float yValue, int dataIndex = 0)
|
||||
{
|
||||
var serie = GetSerie(index);
|
||||
if (serie != null)
|
||||
{
|
||||
serie.UpdateXYData(dataIndex, xValue, yValue);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// dataZoom由变化是更新系列的缓存数据
|
||||
/// </summary>
|
||||
/// <param name="dataZoom"></param>
|
||||
public void UpdateFilterData(DataZoom dataZoom)
|
||||
{
|
||||
if (dataZoom != null && dataZoom.show)
|
||||
{
|
||||
for (int i = 0; i < m_Series.Count; i++)
|
||||
{
|
||||
m_Series[i].UpdateFilterData(dataZoom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指定系列是否显示
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsActive(string name)
|
||||
{
|
||||
var serie = GetSerie(name);
|
||||
return serie == null ? false : serie.show;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指定系列是否显示
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsActive(int index)
|
||||
{
|
||||
var serie = GetSerie(index);
|
||||
return serie == null ? false : serie.show;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置指定系列是否显示
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="active"></param>
|
||||
public void SetActive(string name, bool active)
|
||||
{
|
||||
var serie = GetSerie(name);
|
||||
if (serie != null)
|
||||
{
|
||||
serie.show = active;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置指定系列是否显示
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="active"></param>
|
||||
public void SetActive(int index, bool active)
|
||||
{
|
||||
var serie = GetSerie(index);
|
||||
if (serie != null)
|
||||
{
|
||||
serie.show = active;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否由系列在用指定索引的axis
|
||||
/// </summary>
|
||||
/// <param name="axisIndex"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsUsedAxisIndex(int axisIndex)
|
||||
{
|
||||
foreach (var serie in series)
|
||||
{
|
||||
if (serie.axisIndex == axisIndex) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指定系列是否处于高亮选中状态
|
||||
/// </summary>
|
||||
/// <param name="serieIndex"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsHighlight(int serieIndex)
|
||||
{
|
||||
var serie = GetSerie(serieIndex);
|
||||
if (serie != null) return serie.highlighted;
|
||||
else return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得维度X的最大最小值
|
||||
/// </summary>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <param name="axisIndex"></param>
|
||||
/// <param name="minVaule"></param>
|
||||
/// <param name="maxValue"></param>
|
||||
public void GetXMinMaxValue(DataZoom dataZoom, int axisIndex, out int minVaule, out int maxValue)
|
||||
{
|
||||
GetMinMaxValue(dataZoom, axisIndex, false, out minVaule, out maxValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得维度Y的最大最小值
|
||||
/// </summary>
|
||||
/// <param name="dataZoom"></param>
|
||||
/// <param name="axisIndex"></param>
|
||||
/// <param name="minVaule"></param>
|
||||
/// <param name="maxValue"></param>
|
||||
public void GetYMinMaxValue(DataZoom dataZoom, int axisIndex, out int minVaule, out int maxValue)
|
||||
{
|
||||
GetMinMaxValue(dataZoom, axisIndex, true, out minVaule, out maxValue);
|
||||
}
|
||||
|
||||
private Dictionary<int, List<Serie>> _stackSeriesForMinMax = new Dictionary<int, List<Serie>>();
|
||||
private Dictionary<int, float> _serieTotalValueForMinMax = new Dictionary<int, float>();
|
||||
public void GetMinMaxValue(DataZoom dataZoom, int axisIndex, bool yValue, out int minVaule, out int maxValue)
|
||||
{
|
||||
float min = int.MaxValue;
|
||||
float max = int.MinValue;
|
||||
if (IsStack())
|
||||
{
|
||||
GetStackSeries(ref _stackSeriesForMinMax);
|
||||
foreach (var ss in _stackSeriesForMinMax)
|
||||
{
|
||||
_serieTotalValueForMinMax.Clear();
|
||||
for (int i = 0; i < ss.Value.Count; i++)
|
||||
{
|
||||
var serie = ss.Value[i];
|
||||
if (serie.axisIndex != axisIndex) continue;
|
||||
var showData = yValue ? serie.GetYDataList(dataZoom) : serie.GetXDataList(dataZoom);
|
||||
for (int j = 0; j < showData.Count; j++)
|
||||
{
|
||||
if (!_serieTotalValueForMinMax.ContainsKey(j))
|
||||
_serieTotalValueForMinMax[j] = 0;
|
||||
_serieTotalValueForMinMax[j] = _serieTotalValueForMinMax[j] + showData[j];
|
||||
}
|
||||
}
|
||||
float tmax = int.MinValue;
|
||||
float tmin = int.MaxValue;
|
||||
foreach (var tt in _serieTotalValueForMinMax)
|
||||
{
|
||||
if (tt.Value > tmax) tmax = tt.Value;
|
||||
if (tt.Value < tmin) tmin = tt.Value;
|
||||
}
|
||||
if (tmax > max) max = tmax;
|
||||
if (tmin < min) min = tmin;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < m_Series.Count; i++)
|
||||
{
|
||||
if (m_Series[i].axisIndex != axisIndex) continue;
|
||||
if (IsActive(i))
|
||||
{
|
||||
var showData = yValue ? m_Series[i].GetYDataList(dataZoom) : m_Series[i].GetXDataList(dataZoom);
|
||||
foreach (var data in showData)
|
||||
{
|
||||
if (data > max) max = data;
|
||||
if (data < min) min = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (max == int.MinValue && min == int.MaxValue)
|
||||
{
|
||||
minVaule = 0;
|
||||
maxValue = 90;
|
||||
}
|
||||
else
|
||||
{
|
||||
minVaule = Mathf.FloorToInt(min);
|
||||
maxValue = Mathf.CeilToInt(max);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得指定系列的最大值
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public float GetMaxValue(int index)
|
||||
{
|
||||
float max = int.MinValue;
|
||||
float min = int.MaxValue;
|
||||
for (int i = 0; i < m_Series.Count; i++)
|
||||
{
|
||||
var showData = m_Series[i].yData;
|
||||
if (showData[index] > max)
|
||||
{
|
||||
max = Mathf.Ceil(showData[index]);
|
||||
}
|
||||
if (showData[index] < min)
|
||||
{
|
||||
min = Mathf.Ceil(showData[index]);
|
||||
}
|
||||
}
|
||||
if (max < 1 && max > -1) return max;
|
||||
if (max < 0 && min < 0) max = min;
|
||||
return ChartHelper.GetMaxDivisibleValue(max);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得指定系列的最小值
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public float GetMinValue(int index)
|
||||
{
|
||||
float max = int.MinValue;
|
||||
float min = int.MaxValue;
|
||||
for (int i = 0; i < m_Series.Count; i++)
|
||||
{
|
||||
var showData = m_Series[i].yData;
|
||||
if (showData[index] > max)
|
||||
{
|
||||
max = Mathf.Ceil(showData[index]);
|
||||
}
|
||||
if (showData[index] < min)
|
||||
{
|
||||
min = Mathf.Ceil(showData[index]);
|
||||
}
|
||||
}
|
||||
if (min < 1 && min > -1) return min;
|
||||
if (min < 0 && max < 0) min = max;
|
||||
return ChartHelper.GetMinDivisibleValue(min);
|
||||
}
|
||||
|
||||
private HashSet<string> _setForStack = new HashSet<string>();
|
||||
/// <summary>
|
||||
/// 是否由数据堆叠
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsStack()
|
||||
{
|
||||
_setForStack.Clear();
|
||||
foreach (var serie in m_Series)
|
||||
{
|
||||
if (string.IsNullOrEmpty(serie.stack)) continue;
|
||||
if (_setForStack.Contains(serie.stack)) return true;
|
||||
else
|
||||
{
|
||||
_setForStack.Add(serie.stack);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得堆叠系列列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Dictionary<int, List<Serie>> GetStackSeries()
|
||||
{
|
||||
int count = 0;
|
||||
Dictionary<string, int> sets = new Dictionary<string, int>();
|
||||
Dictionary<int, List<Serie>> stackSeries = new Dictionary<int, List<Serie>>();
|
||||
for (int i = 0; i < m_Series.Count; i++)
|
||||
{
|
||||
var serie = m_Series[i];
|
||||
serie.index = i;
|
||||
if (string.IsNullOrEmpty(serie.stack))
|
||||
{
|
||||
stackSeries[count] = new List<Serie>();
|
||||
stackSeries[count].Add(serie);
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sets.ContainsKey(serie.stack))
|
||||
{
|
||||
sets.Add(serie.stack, count);
|
||||
stackSeries[count] = new List<Serie>();
|
||||
stackSeries[count].Add(serie);
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
int stackIndex = sets[serie.stack];
|
||||
stackSeries[stackIndex].Add(serie);
|
||||
}
|
||||
}
|
||||
}
|
||||
return stackSeries;
|
||||
}
|
||||
|
||||
private Dictionary<string, int> sets = new Dictionary<string, int>();
|
||||
/// <summary>
|
||||
/// 获得堆叠系列列表
|
||||
/// </summary>
|
||||
/// <param name="Dictionary<int"></param>
|
||||
/// <param name="stackSeries"></param>
|
||||
public void GetStackSeries(ref Dictionary<int, List<Serie>> stackSeries)
|
||||
{
|
||||
int count = 0;
|
||||
sets.Clear();
|
||||
if (stackSeries == null)
|
||||
{
|
||||
stackSeries = new Dictionary<int, List<Serie>>(m_Series.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var kv in stackSeries)
|
||||
{
|
||||
kv.Value.Clear();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < m_Series.Count; i++)
|
||||
{
|
||||
var serie = m_Series[i];
|
||||
serie.index = i;
|
||||
if (string.IsNullOrEmpty(serie.stack))
|
||||
{
|
||||
if (!stackSeries.ContainsKey(count))
|
||||
stackSeries[count] = new List<Serie>(m_Series.Count);
|
||||
stackSeries[count].Add(serie);
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sets.ContainsKey(serie.stack))
|
||||
{
|
||||
sets.Add(serie.stack, count);
|
||||
if (!stackSeries.ContainsKey(count))
|
||||
stackSeries[count] = new List<Serie>(m_Series.Count);
|
||||
stackSeries[count].Add(serie);
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
int stackIndex = sets[serie.stack];
|
||||
stackSeries[stackIndex].Add(serie);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> serieNameList = new List<string>();
|
||||
/// <summary>
|
||||
/// 获得所有系列名,不包含空名字。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<string> GetSerieNameList()
|
||||
{
|
||||
serieNameList.Clear();
|
||||
foreach (var serie in m_Series)
|
||||
{
|
||||
if (serie.type == SerieType.Pie)
|
||||
{
|
||||
foreach (var data in serie.data)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(data.name) && !serieNameList.Contains(data.name))
|
||||
{
|
||||
serieNameList.Add(data.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(serie.name) && !serieNameList.Contains(serie.name))
|
||||
{
|
||||
serieNameList.Add(serie.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return serieNameList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置获得标志图形大小的回调
|
||||
/// </summary>
|
||||
/// <param name="size"></param>
|
||||
/// <param name="selectedSize"></param>
|
||||
public void SetSerieSymbolSizeCallback(SymbolSizeCallback size, SymbolSizeCallback selectedSize)
|
||||
{
|
||||
foreach (var serie in m_Series)
|
||||
{
|
||||
serie.symbol.sizeCallback = size;
|
||||
serie.symbol.selectedSizeCallback = selectedSize;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从json中解析数据
|
||||
/// </summary>
|
||||
/// <param name="jsonData"></param>
|
||||
public override void ParseJsonData(string jsonData)
|
||||
{
|
||||
//TODO:
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/UI/Component/Series.cs.meta
Normal file
11
Scripts/UI/Component/Series.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96ea96c66cf5d47c481d8d692a35ed93
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
603
Scripts/UI/Component/Theme.cs
Normal file
603
Scripts/UI/Component/Theme.cs
Normal file
@@ -0,0 +1,603 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace XCharts
|
||||
{
|
||||
/// <summary>
|
||||
/// 主题
|
||||
/// </summary>
|
||||
public enum Theme
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认主题。
|
||||
/// </summary>
|
||||
Default,
|
||||
/// <summary>
|
||||
/// 亮主题。
|
||||
/// </summary>
|
||||
Light,
|
||||
/// <summary>
|
||||
/// 暗主题。
|
||||
/// </summary>
|
||||
Dark
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
/// <summary>
|
||||
/// Theme.
|
||||
/// 主题相关配置。
|
||||
/// </summary>
|
||||
public class ThemeInfo : IEquatable<ThemeInfo>
|
||||
{
|
||||
[SerializeField] private Theme m_Theme = Theme.Default;
|
||||
[SerializeField] private Font m_Font;
|
||||
[SerializeField] private Color32 m_BackgroundColor;
|
||||
[FormerlySerializedAs("m_TextColor")]
|
||||
[SerializeField] private Color32 m_TitleTextColor;
|
||||
[SerializeField] private Color32 m_TitleSubTextColor;
|
||||
[SerializeField] private Color32 m_LegendTextColor;
|
||||
[SerializeField] private Color32 m_LegendUnableColor;
|
||||
[SerializeField] private Color32 m_AxisTextColor;
|
||||
[SerializeField] private Color32 m_AxisLineColor;
|
||||
[SerializeField] private Color32 m_AxisSplitLineColor;
|
||||
[SerializeField] private Color32 m_TooltipBackgroundColor;
|
||||
[SerializeField] private Color32 m_TooltipFlagAreaColor;
|
||||
[SerializeField] private Color32 m_TooltipTextColor;
|
||||
[SerializeField] private Color32 m_TooltipLabelColor;
|
||||
[SerializeField] private Color32 m_TooltipLineColor;
|
||||
[SerializeField] private Color32 m_DataZoomTextColor;
|
||||
[SerializeField] private Color32 m_DataZoomLineColor;
|
||||
[SerializeField] private Color32 m_DataZoomSelectedColor;
|
||||
[SerializeField] private Color32[] m_ColorPalette;
|
||||
|
||||
[SerializeField] private Font m_CustomFont;
|
||||
[SerializeField] private Color32 m_CustomBackgroundColor;
|
||||
[FormerlySerializedAs("m_CustomTextColor")]
|
||||
[SerializeField] private Color32 m_CustomTitleTextColor;
|
||||
[SerializeField] private Color32 m_CustomTitleSubTextColor;
|
||||
[SerializeField] private Color32 m_CustomLegendTextColor;
|
||||
[SerializeField] private Color32 m_CustomLegendUnableColor;
|
||||
[SerializeField] private Color32 m_CustomAxisTextColor;
|
||||
[SerializeField] private Color32 m_CustomAxisLineColor;
|
||||
[SerializeField] private Color32 m_CustomAxisSplitLineColor;
|
||||
[SerializeField] private Color32 m_CustomTooltipBackgroundColor;
|
||||
[SerializeField] private Color32 m_CustomTooltipFlagAreaColor;
|
||||
[SerializeField] private Color32 m_CustomTooltipTextColor;
|
||||
[SerializeField] private Color32 m_CustomTooltipLabelColor;
|
||||
[SerializeField] private Color32 m_CustomTooltipLineColor;
|
||||
[SerializeField] private Color32 m_CustomDataZoomTextColor;
|
||||
[SerializeField] private Color32 m_CustomDataZoomLineColor;
|
||||
[SerializeField] private Color32 m_CustomDataZoomSelectedColor;
|
||||
[SerializeField] private List<Color32> m_CustomColorPalette = new List<Color32>(13);
|
||||
/// <summary>
|
||||
/// the theme of chart.
|
||||
/// 主题类型。
|
||||
/// </summary>
|
||||
public Theme theme { get { return m_Theme; } set { m_Theme = value; } }
|
||||
/// <summary>
|
||||
/// the font of chart text。
|
||||
/// 字体。
|
||||
/// </summary>
|
||||
public Font font
|
||||
{
|
||||
get { return m_CustomFont != null ? m_CustomFont : m_Font; }
|
||||
set { m_CustomFont = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the background color of chart.
|
||||
/// 背景颜色。
|
||||
/// </summary>
|
||||
public Color32 backgroundColor
|
||||
{
|
||||
get { return m_CustomBackgroundColor != Color.clear ? m_CustomBackgroundColor : m_BackgroundColor; }
|
||||
set { m_CustomBackgroundColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the main title text color.
|
||||
/// 主标题颜色。
|
||||
/// </summary>
|
||||
public Color32 titleTextColor
|
||||
{
|
||||
get { return m_CustomTitleTextColor != Color.clear ? m_CustomTitleTextColor : m_TitleTextColor; }
|
||||
set { m_CustomTitleTextColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the subtitie text color.
|
||||
/// 副标题颜色。
|
||||
/// </summary>
|
||||
public Color32 titleSubTextColor
|
||||
{
|
||||
get { return m_CustomTitleSubTextColor != Color.clear ? m_CustomTitleSubTextColor : m_TitleSubTextColor; }
|
||||
set { m_CustomTitleSubTextColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the legend text color.
|
||||
/// 图例文字的颜色。
|
||||
/// </summary>
|
||||
public Color32 legendTextColor
|
||||
{
|
||||
get { return m_CustomLegendTextColor != Color.clear ? m_CustomLegendTextColor : m_LegendTextColor; }
|
||||
set { m_CustomLegendTextColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the legend unable text color.
|
||||
/// 图例变为不可用时的按钮颜色。
|
||||
/// </summary>
|
||||
public Color32 legendUnableColor
|
||||
{
|
||||
get { return m_CustomLegendUnableColor != Color.clear ? m_CustomLegendUnableColor : m_LegendUnableColor; }
|
||||
set { m_CustomLegendUnableColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the axis text color.
|
||||
/// 坐标轴上标签的颜色。
|
||||
/// </summary>
|
||||
public Color32 axisTextColor
|
||||
{
|
||||
get { return m_CustomAxisTextColor != Color.clear ? m_CustomAxisTextColor : m_AxisTextColor; }
|
||||
set { m_CustomAxisTextColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the color of axis line.
|
||||
/// 坐标轴轴线的颜色。
|
||||
/// </summary>
|
||||
public Color32 axisLineColor
|
||||
{
|
||||
get { return m_CustomAxisLineColor != Color.clear ? m_CustomAxisLineColor : m_AxisLineColor; }
|
||||
set { m_CustomAxisLineColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the color of axis split line.
|
||||
/// 分割线的颜色,默认和坐标轴轴线颜色一致。
|
||||
/// </summary>
|
||||
public Color32 axisSplitLineColor
|
||||
{
|
||||
get { return m_CustomAxisSplitLineColor != Color.clear ? m_CustomAxisSplitLineColor : m_AxisSplitLineColor; }
|
||||
set { m_CustomAxisSplitLineColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the tooltip background color.
|
||||
/// 提示框背景颜色。
|
||||
/// </summary>
|
||||
public Color32 tooltipBackgroundColor
|
||||
{
|
||||
get { return m_CustomTooltipBackgroundColor != Color.clear ? m_CustomTooltipBackgroundColor : m_TooltipBackgroundColor; }
|
||||
set { m_CustomTooltipBackgroundColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the color of tooltip shadow crosshair indicator.
|
||||
/// 提示框阴影指示器的颜色。
|
||||
/// </summary>
|
||||
public Color32 tooltipFlagAreaColor
|
||||
{
|
||||
get { return m_CustomTooltipFlagAreaColor != Color.clear ? m_CustomTooltipFlagAreaColor : m_TooltipFlagAreaColor; }
|
||||
set { m_CustomTooltipFlagAreaColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the color of tooltip text.
|
||||
/// 提示框文字颜色。
|
||||
/// </summary>
|
||||
public Color32 tooltipTextColor
|
||||
{
|
||||
get { return m_CustomTooltipTextColor != Color.clear ? m_CustomTooltipTextColor : m_TooltipTextColor; }
|
||||
set { m_CustomTooltipTextColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the background color of tooltip cross indicator's axis label.
|
||||
/// 提示框的十字指示器坐标轴标签的背景颜色。
|
||||
/// </summary>
|
||||
public Color32 tooltipLabelColor
|
||||
{
|
||||
get { return m_CustomTooltipLabelColor != Color.clear ? m_CustomTooltipLabelColor : m_TooltipLabelColor; }
|
||||
set { m_CustomTooltipLabelColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the color tooltip indicator line.
|
||||
/// 提示框的指示线的颜色。
|
||||
/// </summary>
|
||||
public Color32 tooltipLineColor
|
||||
{
|
||||
get { return m_CustomTooltipLineColor != Color.clear ? m_CustomTooltipLineColor : m_TooltipLineColor; }
|
||||
set { m_CustomTooltipLineColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the color of datazoom text.
|
||||
/// 区域缩放的文字颜色。
|
||||
/// </summary>
|
||||
public Color32 dataZoomTextColor
|
||||
{
|
||||
get { return m_CustomDataZoomTextColor != Color.clear ? m_CustomDataZoomTextColor : m_DataZoomTextColor; }
|
||||
set { m_CustomDataZoomTextColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the color of datazoom line.
|
||||
/// 区域缩放的线条颜色。
|
||||
/// </summary>
|
||||
public Color32 dataZoomLineColor
|
||||
{
|
||||
get { return m_CustomDataZoomLineColor != Color.clear ? m_CustomDataZoomLineColor : m_DataZoomLineColor; }
|
||||
set { m_CustomDataZoomLineColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// the color of datazoom selected area.
|
||||
/// 区域缩放的选中区域颜色。
|
||||
/// </summary>
|
||||
public Color32 dataZoomSelectedColor
|
||||
{
|
||||
get { return m_CustomDataZoomSelectedColor != Color.clear ? m_CustomDataZoomSelectedColor : m_DataZoomSelectedColor; }
|
||||
set { m_CustomDataZoomSelectedColor = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The color list of palette. If no color is set in series, the colors would be adopted sequentially and circularly from this list as the colors of series.
|
||||
/// 调色盘颜色列表。如果系列没有设置颜色,则会依次循环从该列表中取颜色作为系列颜色。
|
||||
/// </summary>
|
||||
public List<Color32> colorPalette { set { m_CustomColorPalette = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the color of the specified index from the palette.
|
||||
/// 获得调色盘对应系列索引的颜色值。
|
||||
/// </summary>
|
||||
/// <param name="index">编号索引</param>
|
||||
/// <returns>the color,or Color.clear when failed.颜色值,失败时返回Color.clear</returns>
|
||||
public Color32 GetColor(int index)
|
||||
{
|
||||
if (index < 0) index = 0;
|
||||
var customIndex = index >= m_CustomColorPalette.Count ? index : index % m_CustomColorPalette.Count;
|
||||
if (customIndex < m_CustomColorPalette.Count && m_CustomColorPalette[customIndex] != Color.clear)
|
||||
{
|
||||
return m_CustomColorPalette[customIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
var newIndex = index >= m_ColorPalette.Length ? index : index % m_ColorPalette.Length;
|
||||
if (newIndex < m_ColorPalette.Length)
|
||||
return m_ColorPalette[newIndex];
|
||||
else return Color.clear;
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<int, string> _colorDic = new Dictionary<int, string>();
|
||||
/// <summary>
|
||||
/// Gets the hexadecimal color string of the specified index from the palette.
|
||||
/// 获得指定索引的十六进制颜色值字符串。
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public string GetColorStr(int index)
|
||||
{
|
||||
if (index < 0)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
index = index % m_ColorPalette.Length;
|
||||
if (_colorDic.ContainsKey(index)) return _colorDic[index];
|
||||
else
|
||||
{
|
||||
_colorDic[index] = ColorUtility.ToHtmlStringRGBA(GetColor(index));
|
||||
return _colorDic[index];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// copy all configurations from theme.
|
||||
/// 复制主题的所有配置。
|
||||
/// </summary>
|
||||
/// <param name="theme"></param>
|
||||
public void Copy(ThemeInfo theme)
|
||||
{
|
||||
m_Theme = theme.theme;
|
||||
m_Font = theme.m_Font;
|
||||
m_BackgroundColor = theme.m_BackgroundColor;
|
||||
m_LegendUnableColor = theme.m_LegendUnableColor;
|
||||
m_TitleTextColor = theme.m_TitleTextColor;
|
||||
m_TitleSubTextColor = theme.m_TitleSubTextColor;
|
||||
m_LegendTextColor = theme.m_LegendTextColor;
|
||||
m_AxisTextColor = theme.m_AxisTextColor;
|
||||
m_AxisLineColor = theme.m_AxisLineColor;
|
||||
m_AxisSplitLineColor = theme.m_AxisSplitLineColor;
|
||||
m_TooltipBackgroundColor = theme.m_TooltipBackgroundColor;
|
||||
m_TooltipTextColor = theme.m_TooltipTextColor;
|
||||
m_TooltipLabelColor = theme.m_TooltipLabelColor;
|
||||
m_TooltipLineColor = theme.m_TooltipLineColor;
|
||||
m_DataZoomLineColor = theme.m_DataZoomLineColor;
|
||||
m_DataZoomSelectedColor = theme.m_DataZoomSelectedColor;
|
||||
m_DataZoomTextColor = theme.m_DataZoomTextColor;
|
||||
m_ColorPalette = new Color32[theme.m_ColorPalette.Length];
|
||||
for (int i = 0; i < theme.m_ColorPalette.Length; i++)
|
||||
{
|
||||
m_ColorPalette[i] = theme.m_ColorPalette[i];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all custom configurations.
|
||||
/// 重置,清除所有自定义配置。
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
m_Theme = Theme.Default;
|
||||
m_Font = null;
|
||||
m_BackgroundColor = Color.clear;
|
||||
m_LegendUnableColor = Color.clear;
|
||||
m_TitleTextColor = Color.clear;
|
||||
m_TitleSubTextColor = Color.clear;
|
||||
m_LegendTextColor = Color.clear;
|
||||
m_AxisTextColor = Color.clear;
|
||||
m_AxisLineColor = Color.clear;
|
||||
m_AxisSplitLineColor = Color.clear;
|
||||
m_TooltipBackgroundColor = Color.clear;
|
||||
m_TooltipTextColor = Color.clear;
|
||||
m_TooltipLabelColor = Color.clear;
|
||||
m_TooltipLineColor = Color.clear;
|
||||
m_DataZoomLineColor = Color.clear;
|
||||
m_DataZoomSelectedColor = Color.clear;
|
||||
m_DataZoomTextColor = Color.clear;
|
||||
for (int i = 0; i < m_CustomColorPalette.Count; i++)
|
||||
{
|
||||
m_CustomColorPalette[i] = Color.clear;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// default theme.
|
||||
/// 默认主题。
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public static ThemeInfo Default
|
||||
{
|
||||
get
|
||||
{
|
||||
return new ThemeInfo()
|
||||
{
|
||||
m_Theme = Theme.Default,
|
||||
m_Font = Resources.GetBuiltinResource<Font>("Arial.ttf"),
|
||||
m_BackgroundColor = new Color32(255, 255, 255, 255),
|
||||
m_LegendUnableColor = GetColor("#cccccc"),
|
||||
m_TitleTextColor = GetColor("#514D4D"),
|
||||
m_TitleSubTextColor = GetColor("#514D4D"),
|
||||
m_LegendTextColor = GetColor("#eee"),
|
||||
m_AxisTextColor = GetColor("#514D4D"),
|
||||
m_AxisLineColor = GetColor("#514D4D"),
|
||||
m_AxisSplitLineColor = GetColor("#51515120"),
|
||||
m_TooltipBackgroundColor = GetColor("#515151C8"),
|
||||
m_TooltipTextColor = GetColor("#FFFFFFFF"),
|
||||
m_TooltipFlagAreaColor = GetColor("#51515120"),
|
||||
m_TooltipLabelColor = GetColor("#292929FF"),
|
||||
m_TooltipLineColor = GetColor("#29292964"),
|
||||
m_DataZoomLineColor = GetColor("#51515120"),
|
||||
m_DataZoomSelectedColor = GetColor("#51515120"),
|
||||
m_DataZoomTextColor = GetColor("#514D4D"),
|
||||
m_ColorPalette = new Color32[]
|
||||
{
|
||||
new Color32(194, 53, 49, 255),
|
||||
new Color32(47, 69, 84, 255),
|
||||
new Color32(97, 160, 168, 255),
|
||||
new Color32(212, 130, 101, 255),
|
||||
new Color32(145, 199, 174, 255),
|
||||
new Color32(116, 159, 131, 255),
|
||||
new Color32(202, 134, 34, 255),
|
||||
new Color32(189, 162, 154, 255),
|
||||
new Color32(110, 112, 116, 255),
|
||||
new Color32(84, 101, 112, 255),
|
||||
new Color32(196, 204, 211, 255)
|
||||
},
|
||||
m_CustomColorPalette = new List<Color32>{
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// light theme.
|
||||
/// 亮主题。
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public static ThemeInfo Light
|
||||
{
|
||||
get
|
||||
{
|
||||
return new ThemeInfo()
|
||||
{
|
||||
m_Theme = Theme.Light,
|
||||
m_Font = Resources.GetBuiltinResource<Font>("Arial.ttf"),
|
||||
m_BackgroundColor = new Color32(255, 255, 255, 255),
|
||||
m_LegendUnableColor = GetColor("#cccccc"),
|
||||
m_TitleTextColor = GetColor("#514D4D"),
|
||||
m_TitleSubTextColor = GetColor("#514D4D"),
|
||||
m_LegendTextColor = GetColor("#514D4D"),
|
||||
m_AxisTextColor = GetColor("#514D4D"),
|
||||
m_AxisLineColor = GetColor("#514D4D"),
|
||||
m_AxisSplitLineColor = GetColor("#51515120"),
|
||||
m_TooltipBackgroundColor = GetColor("#515151C8"),
|
||||
m_TooltipTextColor = GetColor("#FFFFFFFF"),
|
||||
m_TooltipFlagAreaColor = GetColor("#51515120"),
|
||||
m_TooltipLabelColor = GetColor("#292929FF"),
|
||||
m_TooltipLineColor = GetColor("#29292964"),
|
||||
m_DataZoomLineColor = GetColor("#51515120"),
|
||||
m_DataZoomSelectedColor = GetColor("#51515120"),
|
||||
m_DataZoomTextColor = GetColor("#514D4D"),
|
||||
m_ColorPalette = new Color32[]
|
||||
{
|
||||
new Color32(55, 162, 218, 255),
|
||||
new Color32(255, 159, 127, 255),
|
||||
new Color32(50, 197, 233, 255),
|
||||
new Color32(251, 114, 147, 255),
|
||||
new Color32(103, 224, 227, 255),
|
||||
new Color32(224, 98, 174, 255),
|
||||
new Color32(159, 230, 184, 255),
|
||||
new Color32(230, 144, 209, 255),
|
||||
new Color32(255, 219, 92, 255),
|
||||
new Color32(230, 188, 243, 255),
|
||||
new Color32(157, 150, 245, 255),
|
||||
new Color32(131, 120, 234, 255),
|
||||
new Color32(150, 191, 255, 255)
|
||||
},
|
||||
m_CustomColorPalette = new List<Color32>{
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// dark theme.
|
||||
/// 暗主题。
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public static ThemeInfo Dark
|
||||
{
|
||||
get
|
||||
{
|
||||
return new ThemeInfo()
|
||||
{
|
||||
m_Theme = Theme.Dark,
|
||||
m_Font = Resources.GetBuiltinResource<Font>("Arial.ttf"),
|
||||
m_LegendUnableColor = GetColor("#cccccc"),
|
||||
m_BackgroundColor = new Color32(34, 34, 34, 255),
|
||||
m_TitleTextColor = GetColor("#eee"),
|
||||
m_TitleSubTextColor = GetColor("#eee"),
|
||||
m_LegendTextColor = GetColor("#eee"),
|
||||
m_AxisTextColor = GetColor("#eee"),
|
||||
m_AxisLineColor = GetColor("#eee"),
|
||||
m_AxisSplitLineColor = GetColor("#aaa"),
|
||||
m_TooltipBackgroundColor = GetColor("#515151C8"),
|
||||
m_TooltipTextColor = GetColor("#FFFFFFFF"),
|
||||
m_TooltipFlagAreaColor = GetColor("#51515120"),
|
||||
m_TooltipLabelColor = GetColor("#A7A7A7FF"),
|
||||
m_TooltipLineColor = GetColor("#eee"),
|
||||
m_DataZoomLineColor = GetColor("#FFFFFF45"),
|
||||
m_DataZoomSelectedColor = GetColor("#D0D0D03D"),
|
||||
m_DataZoomTextColor = GetColor("#FFFFFFFF"),
|
||||
m_ColorPalette = new Color32[]
|
||||
{
|
||||
new Color32(221, 107, 102, 255),
|
||||
new Color32(117, 154, 160, 255),
|
||||
new Color32(230, 157, 135, 255),
|
||||
new Color32(141, 193, 169, 255),
|
||||
new Color32(234, 126, 83, 255),
|
||||
new Color32(238, 221, 120, 255),
|
||||
new Color32(115, 163, 115, 255),
|
||||
new Color32(115, 185, 188, 255),
|
||||
new Color32(114, 137, 171, 255),
|
||||
new Color32(145, 202, 140, 255),
|
||||
new Color32(244, 159, 66, 255)
|
||||
},
|
||||
m_CustomColorPalette = new List<Color32>{
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear,
|
||||
Color.clear
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert the html string to color.
|
||||
/// 将字符串颜色值转成Color。
|
||||
/// </summary>
|
||||
/// <param name="hexColorStr"></param>
|
||||
/// <returns></returns>
|
||||
public static Color32 GetColor(string hexColorStr)
|
||||
{
|
||||
Color color;
|
||||
ColorUtility.TryParseHtmlString(hexColorStr, out color);
|
||||
return (Color32)color;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (obj is ThemeInfo)
|
||||
{
|
||||
return Equals((ThemeInfo)obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(ThemeInfo other)
|
||||
{
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return m_Font == other.m_Font &&
|
||||
ChartHelper.IsValueEqualsColor(m_LegendUnableColor, other.m_LegendUnableColor) &&
|
||||
ChartHelper.IsValueEqualsColor(m_BackgroundColor, other.m_BackgroundColor) &&
|
||||
ChartHelper.IsValueEqualsColor(m_TitleTextColor, other.m_TitleTextColor) &&
|
||||
ChartHelper.IsValueEqualsColor(m_TitleSubTextColor, other.m_TitleSubTextColor) &&
|
||||
ChartHelper.IsValueEqualsColor(m_AxisTextColor, other.m_AxisTextColor) &&
|
||||
ChartHelper.IsValueEqualsColor(m_AxisLineColor, other.m_AxisLineColor) &&
|
||||
ChartHelper.IsValueEqualsColor(m_AxisSplitLineColor, other.m_AxisSplitLineColor) &&
|
||||
ChartHelper.IsValueEqualsColor(m_TooltipBackgroundColor, other.m_TooltipBackgroundColor) &&
|
||||
ChartHelper.IsValueEqualsColor(m_AxisSplitLineColor, other.m_AxisSplitLineColor) &&
|
||||
ChartHelper.IsValueEqualsColor(m_TooltipTextColor, other.m_TooltipTextColor) &&
|
||||
ChartHelper.IsValueEqualsColor(m_TooltipFlagAreaColor, other.m_TooltipFlagAreaColor) &&
|
||||
ChartHelper.IsValueEqualsColor(m_DataZoomLineColor, other.m_DataZoomLineColor) &&
|
||||
ChartHelper.IsValueEqualsColor(m_DataZoomSelectedColor, other.m_DataZoomSelectedColor) &&
|
||||
ChartHelper.IsValueEqualsColor(m_DataZoomTextColor, other.m_DataZoomTextColor) &&
|
||||
m_ColorPalette.Length == other.m_ColorPalette.Length;
|
||||
}
|
||||
|
||||
public static bool operator ==(ThemeInfo left, ThemeInfo right)
|
||||
{
|
||||
if (ReferenceEquals(left, null) && ReferenceEquals(right, null))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(ThemeInfo left, ThemeInfo right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/UI/Component/Theme.cs.meta
Normal file
11
Scripts/UI/Component/Theme.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: abf18feda656241b0be785d95b57aab9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
148
Scripts/UI/Component/Title.cs
Normal file
148
Scripts/UI/Component/Title.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
|
||||
namespace XCharts
|
||||
{
|
||||
/// <summary>
|
||||
/// Title component, including main title and subtitle.
|
||||
/// 标题组件,包含主标题和副标题。
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Title : IPropertyChanged, IEquatable<Title>
|
||||
{
|
||||
[SerializeField] private bool m_Show = true;
|
||||
[SerializeField] private string m_Text;
|
||||
[SerializeField] private int m_TextFontSize;
|
||||
[SerializeField] private string m_SubText;
|
||||
[SerializeField] private int m_SubTextFontSize;
|
||||
[SerializeField] private float m_ItemGap;
|
||||
[SerializeField] private Location m_Location;
|
||||
|
||||
/// <summary>
|
||||
/// [default:true]
|
||||
/// Set this to false to prevent the title from showing.
|
||||
/// 是否显示标题组件。
|
||||
/// </summary>
|
||||
public bool show { get { return m_Show; } set { m_Show = value; } }
|
||||
/// <summary>
|
||||
/// The main title text, supporting for \n for newlines.
|
||||
/// 主标题文本,支持使用 \n 换行。
|
||||
/// </summary>
|
||||
public string text { get { return m_Text; } set { m_Text = value; } }
|
||||
/// <summary>
|
||||
/// [default:16]
|
||||
/// main title font size.
|
||||
/// 主标题文字的字体大小。
|
||||
/// </summary>
|
||||
public int textFontSize { get { return m_TextFontSize; } set { m_TextFontSize = value; } }
|
||||
/// <summary>
|
||||
/// Subtitle text, supporting for \n for newlines.
|
||||
/// 副标题文本,支持使用 \n 换行。
|
||||
/// </summary>
|
||||
public string subText { get { return m_SubText; } set { m_Text = value; } }
|
||||
/// <summary>
|
||||
/// [default:14]
|
||||
/// subtitle font size.
|
||||
/// 副标题文字的字体大小。
|
||||
/// </summary>
|
||||
public int subTextFontSize { get { return m_SubTextFontSize; } set { m_SubTextFontSize = value; } }
|
||||
/// <summary>
|
||||
/// [default:14]
|
||||
/// The gap between the main title and subtitle.
|
||||
/// 主副标题之间的间距。
|
||||
/// </summary>
|
||||
public float itemGap { get { return m_ItemGap; } set { m_ItemGap = value; } }
|
||||
/// <summary>
|
||||
/// The location of title component.
|
||||
/// 标题显示位置。
|
||||
/// </summary>
|
||||
public Location location { get { return m_Location; } set { m_Location = value; } }
|
||||
|
||||
public static Title defaultTitle
|
||||
{
|
||||
get
|
||||
{
|
||||
var title = new Title
|
||||
{
|
||||
m_Show = true,
|
||||
m_Text = "Chart Title",
|
||||
m_TextFontSize = 16,
|
||||
m_SubText = "",
|
||||
m_SubTextFontSize = 14,
|
||||
m_ItemGap = 14,
|
||||
m_Location = Location.defaultTop
|
||||
};
|
||||
return title;
|
||||
}
|
||||
}
|
||||
public void Copy(Title title)
|
||||
{
|
||||
m_Show = title.show;
|
||||
m_Text = title.text;
|
||||
m_TextFontSize = title.textFontSize;
|
||||
m_SubText = title.subText;
|
||||
m_SubTextFontSize = title.subTextFontSize;
|
||||
m_ItemGap = title.itemGap;
|
||||
m_Location.Copy(title.location);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (obj is Title)
|
||||
{
|
||||
return Equals((Title)obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(Title other)
|
||||
{
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return m_Show == other.show &&
|
||||
m_Text.Equals(other.text) &&
|
||||
m_TextFontSize == other.textFontSize &&
|
||||
m_SubText.Equals(other.subText) &&
|
||||
m_SubTextFontSize == other.subTextFontSize &&
|
||||
m_ItemGap == other.itemGap &&
|
||||
m_Location.Equals(other.location);
|
||||
}
|
||||
|
||||
public static bool operator ==(Title left, Title right)
|
||||
{
|
||||
if (ReferenceEquals(left, null) && ReferenceEquals(right, null))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Title left, Title right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
|
||||
public void OnChanged()
|
||||
{
|
||||
m_Location.OnChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/UI/Component/Title.cs.meta
Normal file
11
Scripts/UI/Component/Title.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d24bcb046d3e74a898fc64f02a2a5985
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
278
Scripts/UI/Component/Tooltip.cs
Normal file
278
Scripts/UI/Component/Tooltip.cs
Normal file
@@ -0,0 +1,278 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace XCharts
|
||||
{
|
||||
/// <summary>
|
||||
/// Tooltip component.
|
||||
/// 提示框组件
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Tooltip
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicator type.
|
||||
/// 阴影指示器。
|
||||
/// </summary>
|
||||
public enum Type
|
||||
{
|
||||
/// <summary>
|
||||
/// line indicator.
|
||||
/// 直线指示器
|
||||
/// </summary>
|
||||
Line,
|
||||
/// <summary>
|
||||
/// shadow crosshair indicator.
|
||||
/// 阴影指示器
|
||||
/// </summary>
|
||||
Shadow,
|
||||
/// <summary>
|
||||
/// no indicator displayed.
|
||||
/// 无指示器
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// crosshair indicator, which is actually the shortcut of enable two axisPointers of two orthometric axes.
|
||||
/// 十字准星指示器。坐标轴显示Label和交叉线。
|
||||
/// </summary>
|
||||
Corss
|
||||
}
|
||||
|
||||
[SerializeField] private bool m_Show;
|
||||
[SerializeField] private Type m_Type;
|
||||
|
||||
private GameObject m_GameObject;
|
||||
private GameObject m_Content;
|
||||
private Text m_ContentText;
|
||||
private RectTransform m_ContentRect;
|
||||
private List<int> lastDataIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to show the tooltip component.
|
||||
/// 是否显示提示框组件。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool show { get { return m_Show; } set { m_Show = value; SetActive(value); } }
|
||||
/// <summary>
|
||||
/// Indicator type.
|
||||
/// 提示框指示器类型。
|
||||
/// </summary>
|
||||
public Type type { get { return m_Type; } set { m_Type = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// The data index currently indicated by Tooltip.
|
||||
/// 当前提示框所指示的数据项索引。
|
||||
/// </summary>
|
||||
public List<int> dataIndex { get; set; }
|
||||
/// <summary>
|
||||
/// the value for x indicator label.
|
||||
/// 指示器X轴上要显示的值。
|
||||
/// </summary>
|
||||
public float[] xValues { get; set; }
|
||||
/// <summary>
|
||||
/// the value for y indicator label.
|
||||
/// 指示器Y轴上要显示的值。
|
||||
/// </summary>
|
||||
public float[] yValues { get; set; }
|
||||
/// <summary>
|
||||
/// the current pointer position.
|
||||
/// 当前鼠标位置。
|
||||
/// </summary>
|
||||
public Vector2 pointerPos { get; set; }
|
||||
/// <summary>
|
||||
/// the width of tooltip.
|
||||
/// 提示框宽。
|
||||
/// </summary>
|
||||
public float width { get { return m_ContentRect.sizeDelta.x; } }
|
||||
/// <summary>
|
||||
/// the height of tooltip.
|
||||
/// 提示框高。
|
||||
/// </summary>
|
||||
public float height { get { return m_ContentRect.sizeDelta.y; } }
|
||||
/// <summary>
|
||||
/// Whether the tooltip has been initialized.
|
||||
/// 提示框是否已初始化。
|
||||
/// </summary>
|
||||
public bool inited { get { return m_GameObject != null; } }
|
||||
/// <summary>
|
||||
/// the gameObject of tooltip.
|
||||
/// 提示框的gameObject。
|
||||
/// </summary>
|
||||
public GameObject gameObject { get { return m_GameObject; } }
|
||||
|
||||
public static Tooltip defaultTooltip
|
||||
{
|
||||
get
|
||||
{
|
||||
var tooltip = new Tooltip
|
||||
{
|
||||
m_Show = true,
|
||||
xValues = new float[2],
|
||||
yValues = new float[2],
|
||||
dataIndex = new List<int>() { -1, -1 },
|
||||
lastDataIndex = new List<int>() { -1, -1 }
|
||||
};
|
||||
return tooltip;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绑定提示框gameObject
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
public void SetObj(GameObject obj)
|
||||
{
|
||||
m_GameObject = obj;
|
||||
m_GameObject.SetActive(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绑定提示框的文本框gameObject
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
public void SetContentObj(GameObject content)
|
||||
{
|
||||
m_Content = content;
|
||||
m_ContentRect = m_Content.GetComponent<RectTransform>();
|
||||
m_ContentText = m_Content.GetComponentInChildren<Text>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Keep Tooltiop displayed at the top.
|
||||
/// 保持Tooltiop显示在最顶上
|
||||
/// </summary>
|
||||
public void UpdateToTop()
|
||||
{
|
||||
int count = m_GameObject.transform.parent.childCount;
|
||||
m_GameObject.GetComponent<RectTransform>().SetSiblingIndex(count - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置提示框文本背景色
|
||||
/// </summary>
|
||||
/// <param name="color"></param>
|
||||
public void SetContentBackgroundColor(Color color)
|
||||
{
|
||||
m_Content.GetComponent<Image>().color = color;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置提示框文本字体颜色
|
||||
/// </summary>
|
||||
/// <param name="color"></param>
|
||||
public void SetContentTextColor(Color color)
|
||||
{
|
||||
if (m_ContentText)
|
||||
{
|
||||
m_ContentText.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置提示框文本内容
|
||||
/// </summary>
|
||||
/// <param name="txt"></param>
|
||||
public void UpdateContentText(string txt)
|
||||
{
|
||||
if (m_ContentText)
|
||||
{
|
||||
m_ContentText.text = txt;
|
||||
m_ContentRect.sizeDelta = new Vector2(m_ContentText.preferredWidth + 8,
|
||||
m_ContentText.preferredHeight + 8);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除提示框指示数据
|
||||
/// </summary>
|
||||
public void ClearValue()
|
||||
{
|
||||
dataIndex[0] = dataIndex[1] = -1;
|
||||
xValues[0] = xValues[1] = -1;
|
||||
yValues[0] = yValues[1] = -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提示框是否显示
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsActive()
|
||||
{
|
||||
return m_GameObject != null && m_GameObject.activeInHierarchy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置提示框是否显示
|
||||
/// </summary>
|
||||
/// <param name="flag"></param>
|
||||
public void SetActive(bool flag)
|
||||
{
|
||||
lastDataIndex[0] = lastDataIndex[1] = -1;
|
||||
if (m_GameObject && m_GameObject.activeInHierarchy != flag)
|
||||
m_GameObject.SetActive(flag);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新文本框位置
|
||||
/// </summary>
|
||||
/// <param name="pos"></param>
|
||||
public void UpdateContentPos(Vector2 pos)
|
||||
{
|
||||
if (m_Content)
|
||||
m_Content.transform.localPosition = pos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得当前提示框的位置
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Vector3 GetContentPos()
|
||||
{
|
||||
if (m_Content)
|
||||
return m_Content.transform.localPosition;
|
||||
else
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the data item indicated by tooltip has changed.
|
||||
/// 提示框所指示的数据项是否发生变化。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsDataIndexChanged()
|
||||
{
|
||||
return dataIndex[0] != lastDataIndex[0] ||
|
||||
dataIndex[1] != lastDataIndex[1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前索引缓存
|
||||
/// </summary>
|
||||
public void UpdateLastDataIndex()
|
||||
{
|
||||
lastDataIndex[0] = dataIndex[0];
|
||||
lastDataIndex[1] = dataIndex[1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前提示框是否选中数据项
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsSelected()
|
||||
{
|
||||
return dataIndex[0] >= 0 || dataIndex[1] >= 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指定索引的数据项是否被提示框选中
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsSelected(int index)
|
||||
{
|
||||
return dataIndex[0] == index || dataIndex[1] == index;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/UI/Component/Tooltip.cs.meta
Normal file
11
Scripts/UI/Component/Tooltip.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ffc80b624e394046a373c94978bbb04
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user