海拔图和小地图

This commit is contained in:
lishuo committed 2021-03-28 18:17:15 +08:00
1 parent 45801dff22
commit c5bd9daba2
521 files changed
+1985033 -439

No files matched your search

@@ -0,0 +1,978 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
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 : MainComponent
{
/// <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>
/// Log axis, suitable for log data.
/// 对数轴。适用于对数数据。
/// </summary>
Log,
/// <summary>
/// Time axis, suitable for continuous time series data.
/// 时间轴。适用于连续的时序数据。
/// </summary>
Time
}
/// <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 position of axis in grid.
/// 坐标轴在Grid中的位置
/// </summary>
public enum AxisPosition
{
Left,
Right,
Bottom,
Top
}
[SerializeField] protected bool m_Show = true;
[SerializeField] protected AxisType m_Type;
[SerializeField] protected AxisMinMaxType m_MinMaxType;
[SerializeField] protected int m_GridIndex;
[SerializeField] protected int m_PolarIndex;
[SerializeField] protected AxisPosition m_Position;
[SerializeField] protected float m_Offset;
[SerializeField] protected float m_Min;
[SerializeField] protected float m_Max;
[SerializeField] protected int m_SplitNumber = 5;
[SerializeField] protected float m_Interval = 0;
[SerializeField] protected bool m_BoundaryGap = true;
[SerializeField] protected int m_MaxCache = 0;
[SerializeField] protected float m_LogBase = 10;
[SerializeField] protected bool m_LogBaseE = false;
[SerializeField] protected int m_CeilRate = 0;
[SerializeField] protected bool m_Inverse = false;
[SerializeField] private bool m_Clockwise = 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 AxisSplitLine m_SplitLine = AxisSplitLine.defaultSplitLine;
[SerializeField] protected AxisSplitArea m_SplitArea = AxisSplitArea.defaultSplitArea;
[NonSerialized] private float m_MinMaxValueRange;
[NonSerialized] private bool m_NeedUpdateFilterData;
/// <summary>
/// Whether to show axis.
/// 是否显示坐标轴。
/// </summary>
public bool show
{
get { return m_Show; }
set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetAllDirty(); }
}
/// <summary>
/// the type of axis.
/// 坐标轴类型。
/// </summary>
public AxisType type
{
get { return m_Type; }
set { if (PropertyUtil.SetStruct(ref m_Type, value)) SetAllDirty(); }
}
/// <summary>
/// the type of axis minmax.
/// 坐标轴刻度最大最小值显示类型。
/// </summary>
public AxisMinMaxType minMaxType
{
get { return m_MinMaxType; }
set { if (PropertyUtil.SetStruct(ref m_MinMaxType, value)) SetAllDirty(); }
}
/// <summary>
/// The index of the grid on which the axis are located, by default, is in the first grid.
/// 坐标轴所在的 grid 的索引,默认位于第一个 grid。
/// </summary>
public int gridIndex
{
get { return m_GridIndex; }
set { if (PropertyUtil.SetStruct(ref m_GridIndex, value)) SetAllDirty(); }
}
/// <summary>
/// The index of the polar on which the axis are located, by default, is in the first polar.
/// 坐标轴所在的 ploar 的索引,默认位于第一个 polar。
/// </summary>
public int polarIndex
{
get { return m_PolarIndex; }
set { if (PropertyUtil.SetStruct(ref m_PolarIndex, value)) SetAllDirty(); }
}
/// <summary>
/// the position of axis in grid.
/// 坐标轴在Grid中的位置。
/// </summary>
public AxisPosition position
{
get { return m_Position; }
set { if (PropertyUtil.SetStruct(ref m_Position, value)) SetAllDirty(); }
}
/// <summary>
/// the offset of axis from the default position. Useful when the same position has multiple axes.
/// 坐标轴相对默认位置的偏移。在相同position有多个坐标轴时有用。
/// </summary>
public float offset
{
get { return m_Offset; }
set { if (PropertyUtil.SetStruct(ref m_Offset, value)) SetAllDirty(); }
}
/// <summary>
/// The minimun value of axis.Valid when `minMaxType` is `Custom`
/// 设定的坐标轴刻度最小值,当minMaxType为Custom时有效。
/// </summary>
public float min
{
get { return m_Min; }
set { if (PropertyUtil.SetStruct(ref m_Min, value)) SetAllDirty(); }
}
/// <summary>
/// The maximum value of axis.Valid when `minMaxType` is `Custom`
/// 设定的坐标轴刻度最大值,当minMaxType为Custom时有效。
/// </summary>
public float max
{
get { return m_Max; }
set { if (PropertyUtil.SetStruct(ref m_Max, value)) SetAllDirty(); }
}
/// <summary>
/// Number of segments that the axis is split into.
/// 坐标轴的分割段数。
/// </summary>
public int splitNumber
{
get { return m_SplitNumber; }
set { if (PropertyUtil.SetStruct(ref m_SplitNumber, value)) SetAllDirty(); }
}
/// <summary>
/// Compulsively set segmentation interval for axis.This is unavailable for category axis.
/// 强制设置坐标轴分割间隔。无法在类目轴中使用。
/// </summary>
public float interval
{
get { return m_Interval; }
set { if (PropertyUtil.SetStruct(ref m_Interval, value)) SetAllDirty(); }
}
/// <summary>
/// The boundary gap on both sides of a coordinate axis, which is valid only for category axis with type: 'Category'.
/// 坐标轴两边是否留白。只对类目轴有效。
/// </summary>
public bool boundaryGap
{
get { return IsCategory() ? m_BoundaryGap : false; }
set { if (PropertyUtil.SetStruct(ref m_BoundaryGap, value)) SetAllDirty(); }
}
/// <summary>
/// Base of logarithm, which is valid only for numeric axes with type: 'Log'.
/// 对数轴的底数,只在对数轴(type:'Log')中有效。
/// </summary>
public float logBase
{
get { return m_LogBase; }
set
{
if (value <= 0 || value == 1) value = 10;
if (PropertyUtil.SetStruct(ref m_LogBase, value)) SetAllDirty();
}
}
/// <summary>
/// On the log axis, if base e is the natural number, and is true, logBase fails.
/// 对数轴是否以自然数 e 为底数,为 true 时 logBase 失效。
/// </summary>
public bool logBaseE
{
get { return m_LogBaseE; }
set { if (PropertyUtil.SetStruct(ref m_LogBaseE, value)) SetAllDirty(); }
}
/// <summary>
/// The max number of axis data cache.
/// The first data will be remove when the size of axis data is larger then maxCache.
/// 可缓存的最大数据量。默认为0没有限制,大于0时超过指定值会移除旧数据再插入新数据。
/// </summary>
public int maxCache
{
get { return m_MaxCache; }
set { if (PropertyUtil.SetStruct(ref m_MaxCache, value < 0 ? 0 : value)) SetAllDirty(); }
}
/// <summary>
/// The ratio of maximum and minimum values rounded upward. The default is 0, which is automatically calculated.
/// 最大最小值向上取整的倍率。默认为0时自动计算。
/// </summary>
public int ceilRate
{
get { return m_CeilRate; }
set { if (PropertyUtil.SetStruct(ref m_CeilRate, value < 0 ? 0 : value)) SetAllDirty(); }
}
/// <summary>
/// Whether the axis are reversed or not. Invalid in `Category` axis.
/// 是否反向坐标轴。在类目轴中无效。
/// </summary>
public bool inverse
{
get { return m_Inverse; }
set { if (m_Type == AxisType.Value && PropertyUtil.SetStruct(ref m_Inverse, value)) SetAllDirty(); }
}
/// <summary>
/// Whether the positive position of axis is in clockwise. True for clockwise by default.
/// 刻度增长是否按顺时针,默认顺时针。
/// </summary>
public bool clockwise
{
get { return m_Clockwise; }
set { if (PropertyUtil.SetStruct(ref m_Clockwise, value)) SetAllDirty(); }
}
/// <summary>
/// Category data, available in type: 'Category' axis.
/// 类目数据,在类目轴(type: 'category')中有效。
/// </summary>
public List<string> data
{
get { return m_Data; }
set { if (value != null) { m_Data = value; SetAllDirty(); } }
}
/// <summary>
/// axis Line.
/// 坐标轴轴线。
/// /// </summary>
public AxisLine axisLine
{
get { return m_AxisLine; }
set { if (value != null) { m_AxisLine = value; SetVerticesDirty(); } }
}
/// <summary>
/// axis name.
/// 坐标轴名称。
/// </summary>
public AxisName axisName
{
get { return m_AxisName; }
set { if (value != null) { m_AxisName = value; SetComponentDirty(); } }
}
/// <summary>
/// axis tick.
/// 坐标轴刻度。
/// </summary>
public AxisTick axisTick
{
get { return m_AxisTick; }
set { if (value != null) { m_AxisTick = value; SetVerticesDirty(); } }
}
/// <summary>
/// axis label.
/// 坐标轴刻度标签。
/// </summary>
public AxisLabel axisLabel
{
get { return m_AxisLabel; }
set { if (value != null) { m_AxisLabel = value; SetComponentDirty(); } }
}
/// <summary>
/// axis split line.
/// 坐标轴分割线。
/// </summary>
public AxisSplitLine splitLine
{
get { return m_SplitLine; }
set { if (value != null) { m_SplitLine = value; SetVerticesDirty(); } }
}
/// <summary>
/// axis split area.
/// 坐标轴分割区域。
/// </summary>
public AxisSplitArea splitArea
{
get { return m_SplitArea; }
set { if (value != null) { m_SplitArea = value; SetVerticesDirty(); } }
}
public override bool vertsDirty
{
get { return m_VertsDirty || axisLine.anyDirty || axisTick.anyDirty || splitLine.anyDirty || splitArea.anyDirty; }
}
public override bool componentDirty
{
get { return m_ComponentDirty || axisName.anyDirty || axisLabel.anyDirty; }
}
internal override void ClearComponentDirty()
{
base.ClearComponentDirty();
axisName.ClearComponentDirty();
axisLabel.ClearComponentDirty();
}
internal override void ClearVerticesDirty()
{
base.ClearVerticesDirty();
axisLine.ClearVerticesDirty();
axisTick.ClearVerticesDirty();
splitLine.ClearVerticesDirty();
splitArea.ClearVerticesDirty();
}
public int index { get; internal set; }
/// <summary>
/// the axis label text list.
/// 坐标轴刻度标签的Text列表。
/// </summary>
public List<ChartText> axisLabelTextList { get { return m_AxisLabelTextList; } set { m_AxisLabelTextList = value; } }
/// <summary>
/// the current minimun value.
/// 当前最小值。
/// </summary>
public float runtimeMinValue
{
get { return m_RuntimeMinValue; }
internal set
{
m_RuntimeMinValue = value;
m_RuntimeLastMinValue = value;
m_RuntimeMinValueUpdateTime = Time.time;
m_RuntimeMinValueChanged = true;
}
}
/// <summary>
/// the current maximum value.
/// 当前最大值。
/// </summary>
public float runtimeMaxValue
{
get { return m_RuntimeMaxValue; }
internal set
{
m_RuntimeMaxValue = value;
m_RuntimeLastMaxValue = value;
m_RuntimeMaxValueUpdateTime = Time.time;
m_RuntimeMaxValueChanged = false;
}
}
/// <summary>
/// the x offset of zero position.
/// 坐标轴原点在X轴的偏移。
/// </summary>
public float runtimeZeroXOffset { get; internal set; }
/// <summary>
/// the y offset of zero position.
/// 坐标轴原点在Y轴的偏移。
/// </summary>
public float runtimeZeroYOffset { get; internal set; }
public int runtimeMinLogIndex { get { return logBaseE ? (int)Mathf.Log(runtimeMinValue) : (int)Mathf.Log(runtimeMinValue, logBase); } }
public int runtimeMaxLogIndex { get { return logBaseE ? (int)Mathf.Log(runtimeMaxValue) : (int)Mathf.Log(runtimeMaxValue, logBase); } }
internal bool runtimeLastCheckInverse { get; set; }
internal float runtimeMinMaxRange { get { return m_MinMaxValueRange; } set { m_MinMaxValueRange = value; } }
internal List<string> runtimeData { get { return m_RuntimeData; } }
private int filterStart;
private int filterEnd;
private int filterMinShow;
private List<string> filterData;
private List<ChartText> m_AxisLabelTextList = new List<ChartText>();
private GameObject m_TooltipLabel;
private ChartText m_TooltipLabelText;
private RectTransform m_TooltipLabelRect;
private float m_RuntimeMinValue;
private float m_RuntimeLastMinValue;
private bool m_RuntimeMinValueChanged;
private float m_RuntimeMinValueUpdateTime;
private float m_RuntimeMaxValue;
private float m_RuntimeLastMaxValue;
private bool m_RuntimeMaxValueChanged;
private float m_RuntimeMaxValueUpdateTime;
private bool m_RuntimeMinValueFirstChanged = true;
private bool m_RuntimeMaxValueFirstChanged = true;
protected List<string> m_RuntimeData = new List<string>();
public Axis Clone()
{
var axis = new Axis();
axis.show = show;
axis.type = type;
axis.gridIndex = 0;
axis.minMaxType = minMaxType;
axis.min = min;
axis.max = max;
axis.splitNumber = splitNumber;
axis.interval = interval;
axis.boundaryGap = boundaryGap;
axis.maxCache = maxCache;
axis.logBase = logBase;
axis.logBaseE = logBaseE;
axis.ceilRate = ceilRate;
axis.axisLine = axisLine.Clone();
axis.axisName = axisName.Clone();
axis.axisTick = axisTick.Clone();
axis.axisLabel = axisLabel.Clone();
axis.splitLine = splitLine.Clone();
axis.splitArea = splitArea.Clone();
axis.data = new List<string>();
ChartHelper.CopyList(axis.data, data);
return axis;
}
public void Copy(Axis axis)
{
show = axis.show;
type = axis.type;
minMaxType = axis.minMaxType;
gridIndex = axis.gridIndex;
min = axis.min;
max = axis.max;
splitNumber = axis.splitNumber;
interval = axis.interval;
boundaryGap = axis.boundaryGap;
maxCache = axis.maxCache;
logBase = axis.logBase;
logBaseE = axis.logBaseE;
ceilRate = axis.ceilRate;
axisLine.Copy(axis.axisLine);
axisName.Copy(axis.axisName);
axisTick.Copy(axis.axisTick);
axisLabel.Copy(axis.axisLabel);
splitLine.Copy(axis.splitLine);
splitArea.Copy(axis.splitArea);
ChartHelper.CopyList(data, axis.data);
}
/// <summary>
/// 清空类目数据
/// </summary>
public void ClearData()
{
m_Data.Clear();
m_RuntimeData.Clear();
SetAllDirty();
}
/// <summary>
/// 是否为类目轴。
/// </summary>
/// <returns></returns>
public bool IsCategory()
{
return type == AxisType.Category;
}
/// <summary>
/// 是否为数值轴。
/// </summary>
/// <returns></returns>
public bool IsValue()
{
return type == AxisType.Value;
}
/// <summary>
/// 是否为对数轴。
/// </summary>
/// <returns></returns>
public bool IsLog()
{
return type == AxisType.Log;
}
/// <summary>
/// 添加一个类目到类目数据列表
/// </summary>
/// <param name="category"></param>
public void AddData(string category)
{
if (maxCache > 0)
{
while (m_Data.Count > maxCache)
{
m_NeedUpdateFilterData = true;
m_Data.RemoveAt(0);
}
}
m_Data.Add(category);
SetAllDirty();
}
/// <summary>
/// 获得指定索引的类目数据
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public string GetData(int index)
{
if (index >= 0 && index < m_Data.Count)
return m_Data[index];
else
return null;
}
/// <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>
internal List<string> GetDataList(DataZoom dataZoom)
{
if (dataZoom != null && dataZoom.enable && dataZoom.IsContainsAxisIndex(index))
{
UpdateFilterData(dataZoom);
return filterData;
}
else
{
return m_Data.Count > 0 ? m_Data : m_RuntimeData;
}
}
internal List<string> GetDataList(){
return m_Data.Count > 0 ? m_Data : m_RuntimeData;
}
private List<string> emptyFliter = new List<string>();
/// <summary>
/// 更新dataZoom对应的类目数据列表
/// </summary>
/// <param name="dataZoom"></param>
internal void UpdateFilterData(DataZoom dataZoom)
{
if (dataZoom != null && dataZoom.enable && dataZoom.IsContainsAxisIndex(index))
{
var startIndex = (int)((data.Count - 1) * dataZoom.start / 100);
var endIndex = (int)((data.Count - 1) * dataZoom.end / 100);
if (endIndex < startIndex) endIndex = startIndex;
if (startIndex != filterStart || endIndex != filterEnd || dataZoom.minShowNum != filterMinShow || m_NeedUpdateFilterData)
{
filterStart = startIndex;
filterEnd = endIndex;
filterMinShow = dataZoom.minShowNum;
m_NeedUpdateFilterData = false;
var data = GetDataList();
if (data.Count > 0)
{
var count = endIndex == startIndex ? 1 : endIndex - startIndex + 1;
if (count < dataZoom.minShowNum)
{
if (dataZoom.minShowNum > data.Count) count = data.Count;
else count = dataZoom.minShowNum;
}
if (startIndex + count > data.Count)
{
int start = endIndex - count;
filterData = data.GetRange(start < 0 ? 0 : start, count);
}
else filterData = data.GetRange(startIndex, count);
}
else
{
filterData = data;
}
}
else if (endIndex == 0)
{
filterData = emptyFliter;
}
}
}
/// <summary>
/// 获得类目数据个数
/// </summary>
/// <param name="dataZoom"></param>
/// <returns></returns>
internal int GetDataNumber(DataZoom dataZoom)
{
return GetDataList(dataZoom).Count;
}
/// <summary>
/// 更新刻度标签文字
/// </summary>
/// <param name="dataZoom"></param>
internal void UpdateLabelText(float coordinateWidth, DataZoom dataZoom, bool forcePercent, float duration)
{
var minValue = GetCurrMinValue(duration);
var maxValue = GetCurrMaxValue(duration);
for (int i = 0; i < axisLabelTextList.Count; i++)
{
if (axisLabelTextList[i] != null)
{
var text = AxisHelper.GetLabelName(this, coordinateWidth, i, minValue, maxValue, dataZoom, forcePercent);
axisLabelTextList[i].SetText(text);
}
}
}
internal void SetTooltipLabel(GameObject label)
{
m_TooltipLabel = label;
m_TooltipLabelRect = label.GetComponent<RectTransform>();
m_TooltipLabelText = new ChartText(label);
ChartHelper.SetActive(m_TooltipLabel, true);
}
internal void SetTooltipLabelColor(Color bgColor, Color textColor)
{
m_TooltipLabel.GetComponent<Image>().color = bgColor;
m_TooltipLabelText.SetColor(textColor);
}
internal void SetTooltipLabelActive(bool flag)
{
ChartHelper.SetActive(m_TooltipLabel, flag);
}
internal void UpdateTooptipLabelText(string text)
{
if (m_TooltipLabelText != null)
{
m_TooltipLabelText.SetText(text);
m_TooltipLabelRect.sizeDelta = new Vector2(m_TooltipLabelText.GetPreferredWidth() + 8,
m_TooltipLabelText.GetPreferredHeight() + 8);
}
}
internal void UpdateTooltipLabelPos(Vector2 pos)
{
if (m_TooltipLabel)
{
m_TooltipLabel.transform.localPosition = pos;
}
}
internal void UpdateMinValue(float value, bool check)
{
if (value != m_RuntimeMaxValue)
{
if (check && Application.isPlaying)
{
if (m_RuntimeMinValueFirstChanged)
{
m_RuntimeMinValueFirstChanged = false;
}
else
{
m_RuntimeLastMinValue = m_RuntimeMinValue;
m_RuntimeMinValueChanged = true;
m_RuntimeMinValueUpdateTime = Time.time;
}
m_RuntimeMinValue = value;
}
else
{
m_RuntimeMinValue = value;
m_RuntimeLastMinValue = value;
m_RuntimeMinValueUpdateTime = Time.time;
m_RuntimeMinValueChanged = true;
}
}
}
internal void UpdateMaxValue(float value, bool check)
{
if (value != m_RuntimeMaxValue)
{
if (check && Application.isPlaying)
{
if (m_RuntimeMaxValueFirstChanged)
{
m_RuntimeMaxValueFirstChanged = false;
}
else
{
m_RuntimeLastMaxValue = m_RuntimeMaxValue;
m_RuntimeMaxValueChanged = true;
m_RuntimeMaxValueUpdateTime = Time.time;
}
m_RuntimeMaxValue = value;
}
else
{
m_RuntimeMaxValue = value;
m_RuntimeLastMaxValue = value;
m_RuntimeMaxValueUpdateTime = Time.time;
m_RuntimeMaxValueChanged = false;
}
}
}
internal float GetCurrMinValue(float duration)
{
if (!Application.isPlaying) return m_RuntimeMinValue;
if (m_RuntimeMinValue == 0 && m_RuntimeMaxValue == 0) return 0;
if (!m_RuntimeMinValueChanged) return m_RuntimeMinValue;
var time = Time.time - m_RuntimeMinValueUpdateTime;
if (time == 0) return m_RuntimeMinValue;
var total = duration / 1000;
if (duration > 0 && time <= total)
{
var curr = Mathf.Lerp(m_RuntimeLastMinValue, m_RuntimeMinValue, time / total);
return curr;
}
else
{
m_RuntimeMinValueChanged = false;
return m_RuntimeMinValue;
}
}
internal float GetCurrMaxValue(float duration)
{
if (!Application.isPlaying) return m_RuntimeMaxValue;
if (m_RuntimeMinValue == 0 && m_RuntimeMaxValue == 0) return 0;
if (!m_RuntimeMaxValueChanged) return m_RuntimeMaxValue;
var time = Time.time - m_RuntimeMaxValueUpdateTime;
if (time == 0) return m_RuntimeMaxValue;
var total = duration / 1000;
if (duration > 0 && time < total)
{
var curr = Mathf.Lerp(m_RuntimeLastMaxValue, m_RuntimeMaxValue, time / total);
return curr;
}
else
{
m_RuntimeMaxValueChanged = false;
return m_RuntimeMaxValue;
}
}
public bool IsValueChanging(float duration)
{
if (!Application.isPlaying) return false;
if (GetCurrMinValue(duration) != m_RuntimeMinValue || GetCurrMaxValue(duration) != m_RuntimeMaxValue)
{
return true;
}
else
{
return false;
}
}
public float GetLogValue(float value)
{
if (value <= 0 || value == 1) return 0;
return logBaseE ? Mathf.Log(value) : Mathf.Log(value, logBase);
}
public bool IsLeft()
{
return position == AxisPosition.Left;
}
public bool IsRight()
{
return position == AxisPosition.Right;
}
public bool IsTop()
{
return position == AxisPosition.Top;
}
public bool IsBottom()
{
return position == AxisPosition.Bottom;
}
}
/// <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 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_BoundaryGap = true,
m_Position = AxisPosition.Bottom,
m_Offset = 0,
m_Data = new List<string>()
{
"x1","x2","x3","x4","x5"
}
};
axis.splitLine.show = false;
axis.splitLine.lineStyle.type = LineStyle.Type.None;
axis.axisLabel.textLimit.enable = true;
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 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_BoundaryGap = false,
m_Position = AxisPosition.Left,
m_Data = new List<string>(5),
};
axis.splitLine.show = true;
axis.splitLine.lineStyle.type = LineStyle.Type.None;
axis.axisLabel.textLimit.enable = false;
return axis;
}
}
}
/// <summary>
/// Radial axis of polar coordinate.
/// 极坐标系的径向轴。
/// </summary>
[System.Serializable]
public class RadiusAxis : Axis
{
public static RadiusAxis defaultRadiusAxis
{
get
{
var axis = new RadiusAxis
{
m_Show = true,
m_Type = AxisType.Value,
m_Min = 0,
m_Max = 0,
m_SplitNumber = 5,
m_BoundaryGap = false,
m_Data = new List<string>(5),
};
axis.splitLine.show = true;
axis.splitLine.lineStyle.type = LineStyle.Type.Solid;
axis.axisLabel.textLimit.enable = false;
return axis;
}
}
}
/// <summary>
/// Angle axis of Polar Coordinate.
/// 极坐标系的角度轴。
/// </summary>
[System.Serializable]
public class AngleAxis : Axis
{
[SerializeField] private float m_StartAngle = 90;
/// <summary>
/// Starting angle of axis. 90 degrees by default, standing for top position of center. 0 degree stands for right position of center.
/// 起始刻度的角度,默认为 90 度,即圆心的正上方。0 度为圆心的正右方。
/// </summary>
public float startAngle
{
get { return m_StartAngle; }
set { if (PropertyUtil.SetStruct(ref m_StartAngle, value)) SetAllDirty(); }
}
public float runtimeStartAngle { get; set; }
public static AngleAxis defaultAngleAxis
{
get
{
var axis = new AngleAxis
{
m_Show = true,
m_Type = AxisType.Value,
m_SplitNumber = 12,
m_BoundaryGap = false,
m_Data = new List<string>(12),
};
axis.splitLine.show = true;
axis.splitLine.lineStyle.type = LineStyle.Type.Solid;
axis.axisLabel.textLimit.enable = false;
axis.minMaxType = AxisMinMaxType.Custom;
axis.min = 0;
axis.max = 360;
return axis;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f4e87b6a821d94304af45b2955c293bb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,101 @@
using System.Net.Mime;
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using System;
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
/// <summary>
/// Background component.
/// Due to the limitations of the framework, there are two limitations to the use of background component:
/// 1: The parent node of chart cannot have a layout control class component.
/// 2: The parent node of Chart can only have one child node of the current chart.
///
/// 背景组件。
/// 由于框架的局限性,背景组件使用有以下两个限制:
/// 1:chart的父节点不能有布局控制类组件。
/// 2:chart的父节点只能有当前chart一个子节点。
/// 背景组件的开启需要通过接口来开启:BaseChart.EnableBackground(bool flag)
/// </summary>
[Serializable]
public class Background : MainComponent
{
[SerializeField] private bool m_Show = true;
[SerializeField] private Sprite m_Image;
[SerializeField] private Image.Type m_ImageType;
[SerializeField] private Color m_ImageColor = Color.white;
[SerializeField] private bool m_HideThemeBackgroundColor = true;
/// <summary>
/// Whether to enable the background component. However,
/// the ability to activate the background component is subject to other conditions.
/// 是否启用背景组件。但能否激活背景组件还要受其他条件限制。
/// </summary>
public bool show
{
get { return m_Show; }
internal set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetComponentDirty(); }
}
/// <summary>
/// the image of background.
/// 背景图。
/// </summary>
public Sprite image
{
get { return m_Image; }
set { if (PropertyUtil.SetClass(ref m_Image, value)) SetComponentDirty(); }
}
/// <summary>
/// the fill type of background image.
/// 背景图填充类型。
/// </summary>
public Image.Type imageType
{
get { return m_ImageType; }
set { if (PropertyUtil.SetStruct(ref m_ImageType, value)) SetComponentDirty(); }
}
/// <summary>
/// 背景图颜色。
/// </summary>
public Color imageColor
{
get { return m_ImageColor; }
set { if (PropertyUtil.SetColor(ref m_ImageColor, value)) SetComponentDirty(); }
}
/// <summary>
/// Whether to hide the background color set in the theme when the background component is on.
/// 当background组件开启时,是否隐藏主题中设置的背景色。
/// </summary>
public bool hideThemeBackgroundColor
{
get { return m_HideThemeBackgroundColor; }
set { if (PropertyUtil.SetStruct(ref m_HideThemeBackgroundColor, value)) SetVerticesDirty(); }
}
public static Background defaultBackground
{
get
{
var background = new Background
{
m_Show = false,
m_Image = null,
m_ImageType = Image.Type.Sliced,
m_ImageColor = Color.white,
m_HideThemeBackgroundColor = true,
};
return background;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 20bad62e2503e49dcacbecdc99542025
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,634 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using System.Collections.Generic;
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 : MainComponent
{
/// <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_Enable;
[SerializeField] private FilterMode m_FilterMode;
[SerializeField] private List<int> m_XAxisIndexs = new List<int>() { 0 };
[SerializeField] private List<int> m_YAxisIndexs = new List<int>() { };
[SerializeField] private bool m_SupportInside;
[SerializeField] private bool m_SupportSlider;
[SerializeField] private bool m_SupportSelect;
[SerializeField] private bool m_ShowDataShadow;
[SerializeField] private bool m_ShowDetail;
[SerializeField] private bool m_ZoomLock;
[SerializeField] private bool m_Realtime;
[SerializeField] protected Color32 m_FillerColor;
[SerializeField] protected Color32 m_BorderColor;
[SerializeField] protected float m_BorderWidth;
[SerializeField] protected Color32 m_BackgroundColor;
[SerializeField] private float m_Left;
[SerializeField] private float m_Right;
[SerializeField] private float m_Top;
[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;
[SerializeField] private int m_MinShowNum = 1;
[Range(1f, 20f)]
[SerializeField] private float m_ScrollSensitivity = 1.1f;
[SerializeField] private TextStyle m_TextStyle;
[SerializeField] private LineStyle m_LineStyle = new LineStyle(LineStyle.Type.Solid);
[SerializeField] private AreaStyle m_AreaStyle = new AreaStyle();
/// <summary>
/// Whether to show dataZoom.
/// 是否显示缩放区域。
/// </summary>
public bool enable
{
get { return m_Enable; }
set { if (PropertyUtil.SetStruct(ref m_Enable, value)) SetVerticesDirty(); }
}
/// <summary>
/// The mode of data filter.
/// 数据过滤类型。
/// </summary>
public FilterMode filterMode
{
get { return m_FilterMode; }
set { if (PropertyUtil.SetStruct(ref m_FilterMode, value)) SetVerticesDirty(); }
}
/// <summary>
/// Specify which xAxis is controlled by the dataZoom.
/// 控制的 x 轴索引列表。
/// </summary>
public List<int> xAxisIndexs
{
get { return m_XAxisIndexs; }
set { if (PropertyUtil.SetClass(ref m_XAxisIndexs, value)) SetVerticesDirty(); }
}
/// <summary>
/// Specify which yAxis is controlled by the dataZoom.
/// 控制的 y 轴索引列表。
/// </summary>
public List<int> yAxisIndexs
{
get { return m_YAxisIndexs; }
set { if (PropertyUtil.SetClass(ref m_YAxisIndexs, value)) SetVerticesDirty(); }
}
/// <summary>
/// Whether built-in support is supported.
/// Built into the coordinate system to allow the user to zoom in and out of the coordinate system by mouse dragging,
/// mouse wheel, finger swiping (on the touch screen).
///
/// 是否支持内置。内置于坐标系中,使用户可以在坐标系上通过鼠标拖拽、鼠标滚轮、手指滑动(触屏上)来缩放或漫游坐标系。
/// </summary>
public bool supportInside
{
get { return m_SupportInside; }
set { if (PropertyUtil.SetStruct(ref m_SupportInside, value)) SetVerticesDirty(); }
}
/// <summary>
/// Whether a slider is supported. There are separate sliders on which the user zooms or roams.
/// 是否支持滑动条。有单独的滑动条,用户在滑动条上进行缩放或漫游。
/// </summary>
public bool supportSlider
{
get { return m_SupportSlider; }
set { if (PropertyUtil.SetStruct(ref m_SupportSlider, value)) SetVerticesDirty(); }
}
/// <summary>
/// 是否支持框选。提供一个选框进行数据区域缩放。
/// </summary>
private bool supportSelect
{
get { return m_SupportSelect; }
set { if (PropertyUtil.SetStruct(ref m_SupportSelect, value)) SetVerticesDirty(); }
}
/// <summary>
/// Whether to show data shadow, to indicate the data tendency in brief.
/// default:true
/// 是否显示数据阴影。数据阴影可以简单地反应数据走势。
/// </summary>
public bool showDataShadow
{
get { return m_ShowDataShadow; }
set { if (PropertyUtil.SetStruct(ref m_ShowDataShadow, value)) SetVerticesDirty(); }
}
/// <summary>
/// Whether to show detail, that is, show the detailed data information when dragging.
/// 是否显示detail,即拖拽时候显示详细数值信息。
/// [default: false]
/// </summary>
public bool showDetail
{
get { return m_ShowDetail; }
set { if (PropertyUtil.SetStruct(ref m_ShowDetail, value)) SetVerticesDirty(); }
}
/// <summary>
/// Specify whether to lock the size of window (selected area).
/// default:false
/// 是否锁定选择区域(或叫做数据窗口)的大小。
/// 如果设置为 true 则锁定选择区域的大小,也就是说,只能平移,不能缩放。
/// </summary>
public bool zoomLock
{
get { return m_ZoomLock; }
set { if (PropertyUtil.SetStruct(ref m_ZoomLock, value)) SetVerticesDirty(); }
}
/// <summary>
/// Whether to show data shadow in dataZoom-silder component, to indicate the data tendency in brief.
/// default:true
/// 拖动时,是否实时更新系列的视图。如果设置为 false,则只在拖拽结束的时候更新。默认为true,暂不支持修改。
/// </summary>
public bool realtime { get { return true; } }
/// <summary>
/// The background color of the component.
/// 组件的背景颜色。
/// </summary>
public Color backgroundColor
{
get { return m_BackgroundColor; }
set { if (PropertyUtil.SetStruct(ref m_BackgroundColor, value)) SetVerticesDirty(); }
}
/// <summary>
/// the color of dataZoom data area.
/// 数据区域颜色。
/// </summary>
public Color32 fillerColor
{
get { return m_FillerColor; }
set { if (PropertyUtil.SetColor(ref m_FillerColor, value)) SetVerticesDirty(); }
}
/// <summary>
/// the color of dataZoom border.
/// 边框颜色。
/// </summary>
public Color32 borderColor
{
get { return m_BorderColor; }
set { if (PropertyUtil.SetColor(ref m_BorderColor, value)) SetComponentDirty(); }
}
/// <summary>
/// 边框宽。
/// </summary>
public float borderWidth
{
get { return m_BorderWidth; }
set { if (PropertyUtil.SetStruct(ref m_BorderWidth, value)) SetComponentDirty(); }
}
/// <summary>
/// Distance between dataZoom component and the bottom side of the container.
/// bottom value is a instant pixel value like 10 or float value [0-1].
/// default:10
/// 组件离容器下侧的距离。
/// </summary>
public float bottom
{
get { return m_Bottom; }
set { if (PropertyUtil.SetStruct(ref m_Bottom, value)) SetVerticesDirty(); }
}
/// <summary>
/// Distance between dataZoom component and the top side of the container.
/// top value is a instant pixel value like 10 or float value [0-1].
/// default:10
/// 组件离容器上侧的距离。
/// </summary>
public float top
{
get { return m_Top; }
set { if (PropertyUtil.SetStruct(ref m_Top, value)) SetVerticesDirty(); }
}
/// <summary>
/// Distance between dataZoom component and the left side of the container.
/// left value is a instant pixel value like 10 or float value [0-1].
/// default:10
/// 组件离容器左侧的距离。
/// </summary>
public float left
{
get { return m_Left; }
set { if (PropertyUtil.SetStruct(ref m_Left, value)) SetVerticesDirty(); }
}
/// <summary>
/// Distance between dataZoom component and the right side of the container.
/// right value is a instant pixel value like 10 or float value [0-1].
/// default:10
/// 组件离容器右侧的距离。
/// </summary>
public float right
{
get { return m_Right; }
set { if (PropertyUtil.SetStruct(ref m_Right, value)) SetVerticesDirty(); }
}
/// <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 { if (PropertyUtil.SetStruct(ref m_RangeMode, value)) SetVerticesDirty(); }
}
/// <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; if (m_Start < 0) m_Start = 0; if (m_Start > 100) m_Start = 100; SetVerticesDirty(); }
}
/// <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; if (m_End < 0) m_End = 0; if (m_End > 100) m_End = 100; SetVerticesDirty(); }
}
/// <summary>
/// Minimum number of display data. Minimum number of data displayed when DataZoom is enlarged to maximum.
/// 最小显示数据个数。当DataZoom放大到最大时,最小显示的数据个数。
/// </summary>
public int minShowNum
{
get { return m_MinShowNum; }
set { if (PropertyUtil.SetStruct(ref m_MinShowNum, value)) SetVerticesDirty(); }
}
/// <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 { if (PropertyUtil.SetStruct(ref m_ScrollSensitivity, value)) SetVerticesDirty(); }
}
/// <summary>
/// font style.
/// 文字格式。
/// </summary>
public TextStyle textStyle
{
get { return m_TextStyle; }
set { if (PropertyUtil.SetClass(ref m_TextStyle, value)) SetComponentDirty(); }
}
/// <summary>
/// 阴影线条样式。
/// </summary>
public LineStyle lineStyle
{
get { return m_LineStyle; }
set { if (PropertyUtil.SetClass(ref m_LineStyle, value)) SetComponentDirty(); }
}
/// <summary>
/// 阴影填充样式。
/// </summary>
public AreaStyle areaStyle
{
get { return m_AreaStyle; }
set { if (PropertyUtil.SetClass(ref m_AreaStyle, value)) SetComponentDirty(); }
}
public int index { get; internal set; }
public float runtimeX { get; private set; }
public float runtimeY { get; private set; }
public float runtimeWidth { get; private set; }
public float runtimeHeight { get; private set; }
class AxisIndexValueInfo
{
public float min;
public float max;
}
private Dictionary<int, AxisIndexValueInfo> m_XAxisIndexInfos = new Dictionary<int, AxisIndexValueInfo>();
private Dictionary<int, AxisIndexValueInfo> m_YAxisIndexInfos = new Dictionary<int, AxisIndexValueInfo>();
/// <summary>
/// The start label.
/// 组件的开始信息文本。
/// </summary>
private ChartText m_StartLabel { get; set; }
/// <summary>
/// The end label.
/// 组件的结束信息文本。
/// </summary>
private ChartText m_EndLabel { get; set; }
public static DataZoom defaultDataZoom
{
get
{
return new DataZoom()
{
supportInside = true,
supportSlider = true,
filterMode = FilterMode.None,
xAxisIndexs = new List<int>() { 0 },
yAxisIndexs = new List<int>() { },
showDataShadow = true,
showDetail = false,
zoomLock = false,
m_Bottom = 10,
m_Left = 10,
m_Right = 10,
m_Top = 0.9f,
rangeMode = RangeMode.Percent,
start = 30,
end = 70,
m_ScrollSensitivity = 10,
m_TextStyle = new TextStyle(),
m_LineStyle = new LineStyle(LineStyle.Type.Solid)
{
opacity = 0.3f
},
m_AreaStyle = new AreaStyle()
{
show = true,
opacity = 0.3f,
},
};
}
}
/// <summary>
/// 给定的坐标是否在缩放区域内
/// </summary>
/// <param name="pos"></param>
/// <param name="startX"></param>
/// <param name="width"></param>
/// <returns></returns>
public bool IsInZoom(Vector2 pos)
{
if (pos.x < runtimeX - 1 || pos.x > runtimeX + runtimeWidth + 1 ||
pos.y < runtimeY - 1 || pos.y > runtimeY + runtimeHeight + 1)
{
return false;
}
return false;
}
/// <summary>
/// 给定的坐标是否在选中区域内
/// </summary>
/// <param name="pos"></param>
/// <param name="startX"></param>
/// <param name="width"></param>
/// <returns></returns>
public bool IsInSelectedZoom(Vector2 pos)
{
var start = runtimeX + runtimeWidth * m_Start / 100;
var end = runtimeX + runtimeWidth * m_End / 100;
Rect rect = Rect.MinMaxRect(start, runtimeY, end, runtimeY + runtimeHeight);
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)
{
var start = runtimeX + runtimeWidth * m_Start / 100;
Rect rect = Rect.MinMaxRect(start - 10, runtimeY, start + 10, runtimeY + runtimeHeight);
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)
{
var end = runtimeX + runtimeWidth * m_End / 100;
Rect rect = Rect.MinMaxRect(end - 10, runtimeY, end + 10, runtimeY + runtimeHeight);
return rect.Contains(pos);
}
public bool IsContainsAxisIndex(int index)
{
return xAxisIndexs.Contains(index);// || yAxisIndexs.Contains(index);
}
public Color32 GetFillerColor(Color32 themeColor)
{
if (ChartHelper.IsClearColor(fillerColor)) return themeColor;
else return fillerColor;
}
public Color32 GetBackgroundColor(Color32 themeColor)
{
if (ChartHelper.IsClearColor(backgroundColor)) return themeColor;
else return backgroundColor;
}
public Color32 GetBorderColor(Color32 themeColor)
{
if (ChartHelper.IsClearColor(borderColor)) return themeColor;
else return borderColor;
}
/// <summary>
/// 是否显示文本
/// </summary>
/// <param name="flag"></param>
internal void SetLabelActive(bool flag)
{
if (m_StartLabel != null && m_StartLabel.gameObject.activeInHierarchy != flag)
{
m_StartLabel.gameObject.SetActive(flag);
}
if (m_EndLabel != null && m_EndLabel.gameObject.activeInHierarchy != flag)
{
m_EndLabel.gameObject.SetActive(flag);
}
}
/// <summary>
/// 设置开始文本内容
/// </summary>
/// <param name="text"></param>
internal void SetStartLabelText(string text)
{
if (m_StartLabel != null) m_StartLabel.SetText(text);
}
/// <summary>
/// 设置结束文本内容
/// </summary>
/// <param name="text"></param>
internal void SetEndLabelText(string text)
{
if (m_EndLabel != null) m_EndLabel.SetText(text);
}
internal void SetStartLabel(ChartText startLabel)
{
m_StartLabel = startLabel;
}
internal void SetEndLabel(ChartText endLabel)
{
m_EndLabel = endLabel;
}
internal void UpdateStartLabelPosition(Vector3 pos)
{
m_StartLabel.SetLocalPosition(pos);
}
internal void UpdateEndLabelPosition(Vector3 pos)
{
m_EndLabel.SetLocalPosition(pos);
}
internal void UpdateRuntimeData(float chartX, float chartY, float chartWidth, float chartHeight)
{
var runtimeLeft = left <= 1 ? left * chartWidth : left;
var runtimeBottom = bottom <= 1 ? bottom * chartHeight : bottom;
var runtimeTop = top <= 1 ? top * chartHeight : top;
var runtimeRight = right <= 1 ? right * chartWidth : right;
runtimeX = chartX + runtimeLeft;
runtimeY = chartY + runtimeBottom;
runtimeWidth = chartWidth - runtimeLeft - runtimeRight;
runtimeHeight = chartHeight - runtimeTop - runtimeBottom;
}
internal void SetXAxisIndexValueInfo(int xAxisIndex, float min, float max)
{
if (!m_XAxisIndexInfos.ContainsKey(xAxisIndex))
{
m_XAxisIndexInfos[xAxisIndex] = new AxisIndexValueInfo()
{
min = min,
max = max
};
}
else
{
m_XAxisIndexInfos[xAxisIndex].min = min;
m_XAxisIndexInfos[xAxisIndex].max = max;
}
}
internal void SetYAxisIndexValueInfo(int yAxisIndex, float min, float max)
{
if (!m_YAxisIndexInfos.ContainsKey(yAxisIndex))
{
m_YAxisIndexInfos[yAxisIndex] = new AxisIndexValueInfo()
{
min = min,
max = max
};
}
else
{
m_YAxisIndexInfos[yAxisIndex].min = min;
m_YAxisIndexInfos[yAxisIndex].max = max;
}
}
internal bool IsXAxisIndexValue(int axisIndex)
{
return m_XAxisIndexInfos.ContainsKey(axisIndex);
}
internal bool IsYAxisIndexValue(int axisIndex)
{
return m_YAxisIndexInfos.ContainsKey(axisIndex);
}
internal void GetXAxisIndexValue(int axisIndex, out float min, out float max)
{
min = 0;
max = 0;
if (m_XAxisIndexInfos.ContainsKey(axisIndex))
{
var info = m_XAxisIndexInfos[axisIndex];
min = info.min;
max = info.max;
}
}
internal void GetYAxisIndexValue(int axisIndex, out float min, out float max)
{
min = 0;
max = 0;
if (m_YAxisIndexInfos.ContainsKey(axisIndex))
{
var info = m_YAxisIndexInfos[axisIndex];
min = info.min;
max = info.max;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c2aa26f9acb5344a59c924a1f23f90d5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,458 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
/// <summary>
/// Legend component.The legend component shows different sets of tags, colors, and names.
/// You can control which series are not displayed by clicking on the legend.
/// 图例组件。
/// 图例组件展现了不同系列的标记,颜色和名字。可以通过点击图例控制哪些系列不显示。
/// </summary>
[System.Serializable]
public class Legend : MainComponent, IPropertyChanged
{
public enum Type
{
/// <summary>
/// 自动匹配。
/// </summary>
Auto,
/// <summary>
/// 自定义图标。
/// </summary>
Custom,
/// <summary>
/// 空心圆。
/// </summary>
EmptyCircle,
/// <summary>
/// 圆形。
/// </summary>
Circle,
/// <summary>
/// 正方形。可通过Setting的legendIconCornerRadius参数调整圆角。
/// </summary>
Rect,
/// <summary>
/// 三角形。
/// </summary>
Triangle,
/// <summary>
/// 菱形。
/// </summary>
Diamond,
}
/// <summary>
/// Selected mode of legend, which controls whether series can be toggled displaying by clicking legends.
/// 图例选择的模式,控制是否可以通过点击图例改变系列的显示状态。默认开启图例选择,可以设成 None 关闭。
/// </summary>
public enum SelectedMode
{
/// <summary>
/// 多选。
/// </summary>
Multiple,
/// <summary>
/// 单选。
/// </summary>
Single,
/// <summary>
/// 无法选择。
/// </summary>
None
}
[SerializeField] private bool m_Show = true;
[SerializeField] private Type m_IconType;
[SerializeField] private SelectedMode m_SelectedMode;
[SerializeField] private Orient m_Orient = Orient.Horizonal;
[SerializeField] private Location m_Location = Location.defaultRight;
[SerializeField] private float m_ItemWidth = 25.0f;
[SerializeField] private float m_ItemHeight = 12.0f;
[SerializeField] private float m_ItemGap = 10f;
[SerializeField] private bool m_ItemAutoColor = true;
[SerializeField] private string m_Formatter;
[SerializeField] private TextStyle m_TextStyle = new TextStyle();
[SerializeField] private List<string> m_Data = new List<string>();
[SerializeField] private List<Sprite> m_Icons = new List<Sprite>();
private Dictionary<string, LegendItem> m_DataBtnList = new Dictionary<string, LegendItem>();
private Dictionary<int, float> m_RuntimeEachWidth = new Dictionary<int, float>();
/// <summary>
/// Whether to show legend component.
/// 是否显示图例组件。
/// </summary>
public bool show
{
get { return m_Show; }
set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetComponentDirty(); }
}
/// <summary>
/// Type of legend.
/// 图例类型。
/// [default:Type.Auto]
/// </summary>
public Type iconType
{
get { return m_IconType; }
set { if (PropertyUtil.SetStruct(ref m_IconType, value)) SetAllDirty(); }
}
/// <summary>
/// Selected mode of legend, which controls whether series can be toggled displaying by clicking legends.
/// 选择模式。控制是否可以通过点击图例改变系列的显示状态。默认开启图例选择,可以设成 None 关闭。
/// [default:SelectedMode.Multiple]
/// </summary>
public SelectedMode selectedMode
{
get { return m_SelectedMode; }
set { if (PropertyUtil.SetStruct(ref m_SelectedMode, value)) SetComponentDirty(); }
}
/// <summary>
/// Specify whether the layout of legend component is horizontal or vertical.
/// 布局方式是横还是竖。
/// [default:Orient.Horizonal]
/// </summary>
public Orient orient
{
get { return m_Orient; }
set { if (PropertyUtil.SetStruct(ref m_Orient, value)) SetComponentDirty(); }
}
/// <summary>
/// The location of legend.
/// 图例显示的位置。
/// [default:Location.defaultTop]
/// </summary>
public Location location
{
get { return m_Location; }
set { if (PropertyUtil.SetClass(ref m_Location, value)) SetComponentDirty(); }
}
/// <summary>
/// Image width of legend symbol.
/// 图例标记的图形宽度。
/// [default:24f]
/// </summary>
public float itemWidth
{
get { return m_ItemWidth; }
set { if (PropertyUtil.SetStruct(ref m_ItemWidth, value)) SetComponentDirty(); }
}
/// <summary>
/// Image height of legend symbol.
/// 图例标记的图形高度。
/// [default:12f]
/// </summary>
public float itemHeight
{
get { return m_ItemHeight; }
set { if (PropertyUtil.SetStruct(ref m_ItemHeight, value)) SetComponentDirty(); }
}
/// <summary>
/// The distance between each legend, horizontal distance in horizontal layout, and vertical distance in vertical layout.
/// 图例每项之间的间隔。横向布局时为水平间隔,纵向布局时为纵向间隔。
/// [default:10f]
/// </summary>
public float itemGap
{
get { return m_ItemGap; }
set { if (PropertyUtil.SetStruct(ref m_ItemGap, value)) SetComponentDirty(); }
}
/// <summary>
/// Whether the legend symbol matches the color automatically.
/// 图例标记的图形是否自动匹配颜色。
/// [default:true]
/// </summary>
public bool itemAutoColor
{
get { return m_ItemAutoColor; }
set { if (PropertyUtil.SetStruct(ref m_ItemAutoColor, value)) SetComponentDirty(); }
}
/// <summary>
/// Legend content string template formatter. Support for wrapping lines with \n. Template:{name}.
/// 图例内容字符串模版格式器。支持用 \n 换行。
/// 模板变量为图例名称 {name}。
/// [default:null]
/// </summary>
public string formatter
{
get { return m_Formatter; }
set { if (PropertyUtil.SetClass(ref m_Formatter, value)) SetComponentDirty(); }
}
/// <summary>
/// the style of text.
/// 文本样式。
/// </summary>
public TextStyle textStyle
{
get { return m_TextStyle; }
set { if (PropertyUtil.SetClass(ref m_TextStyle, value)) SetComponentDirty(); }
}
/// <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; }
set { if (value != null) { m_Data = value; SetComponentDirty(); } }
}
/// <summary>
/// 自定义的图例标记图形。
/// </summary>
public List<Sprite> icons
{
get { return m_Icons; }
set { if (value != null) { m_Icons = value; SetComponentDirty(); } }
}
public int index { get; internal set; }
/// <summary>
/// 图表是否需要刷新(图例组件不需要刷新图表)
/// </summary>
public override bool vertsDirty { get { return false; } }
/// <summary>
/// 组件是否需要刷新
/// </summary>
public override bool componentDirty
{
get { return m_ComponentDirty || location.componentDirty || textStyle.componentDirty; }
}
internal override void ClearComponentDirty()
{
base.ClearComponentDirty();
location.ClearComponentDirty();
textStyle.ClearComponentDirty();
}
/// <summary>
/// the button list of legend.
/// 图例按钮列表。
/// </summary>
/// <value></value>
public Dictionary<string, LegendItem> buttonList { get { return m_DataBtnList; } }
/// <summary>
/// 运行时图例的总宽度
/// </summary>
public float runtimeWidth { get; internal set; }
/// <summary>
/// 运行时图例的总高度
/// </summary>
public float runtimeHeight { get; internal set; }
/// <summary>
/// 多列时每列的宽度
/// </summary>
public Dictionary<int, float> runtimeEachWidth { get { return m_RuntimeEachWidth; } }
/// <summary>
/// 单列高度
/// </summary>
public float runtimeEachHeight { get; internal set; }
/// <summary>
/// 一个在顶部居中显示的默认图例。
/// </summary>
public static Legend defaultLegend
{
get
{
var legend = new Legend
{
m_IconType = Type.Auto,
m_Show = false,
m_SelectedMode = SelectedMode.Multiple,
m_Orient = Orient.Horizonal,
m_Location = Location.defaultTop,
m_ItemWidth = 25.0f,
m_ItemHeight = 12.0f,
m_ItemGap = 10f,
};
legend.location.top = 35;
legend.textStyle.offset = new Vector2(2, 0);
legend.textStyle.fontSize = 0;
return legend;
}
}
/// <summary>
/// Clear legend data.
/// 清空。
/// </summary>
public void ClearData()
{
m_Data.Clear();
SetComponentDirty();
}
/// <summary>
/// Whether include in legend data by the specified name.
/// 是否包括由指定名字的图例
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public bool ContainsData(string name)
{
return m_Data.Contains(name);
}
/// <summary>
/// Removes the legend with the specified name.
/// 移除指定名字的图例。
/// </summary>
/// <param name="name"></param>
public void RemoveData(string name)
{
if (m_Data.Contains(name))
{
m_Data.Remove(name);
SetComponentDirty();
}
}
/// <summary>
/// Add legend data.
/// 添加图例。
/// </summary>
/// <param name="name"></param>
public void AddData(string name)
{
if (!m_Data.Contains(name) && !string.IsNullOrEmpty(name))
{
m_Data.Add(name);
SetComponentDirty();
}
}
/// <summary>
/// Gets the legend for the specified index.
/// 获得指定索引的图例。
/// </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>
/// Gets the index of the specified legend.
/// 获得指定图例的索引。
/// </summary>
/// <param name="legendName"></param>
/// <returns></returns>
public int GetIndex(string legendName)
{
return m_Data.IndexOf(legendName);
}
/// <summary>
/// Remove all legend buttons.
/// 移除所有图例按钮。
/// </summary>
public void RemoveButton()
{
m_DataBtnList.Clear();
}
/// <summary>
/// Bind buttons to legends.
/// 给图例绑定按钮。
/// </summary>
/// <param name="name"></param>
/// <param name="btn"></param>
/// <param name="total"></param>
public void SetButton(string name, LegendItem item, int total)
{
m_DataBtnList[name] = item;
int index = m_DataBtnList.Values.Count;
item.SetIconActive(iconType == Type.Custom);
item.SetActive(show);
}
/// <summary>
/// Update the legend button color.
/// 更新图例按钮颜色。
/// </summary>
/// <param name="name"></param>
/// <param name="color"></param>
public void UpdateButtonColor(string name, Color color)
{
if (m_DataBtnList.ContainsKey(name))
{
m_DataBtnList[name].SetIconColor(color);
}
}
/// <summary>
/// Update the text color of legend.
/// 更新图例文字颜色。
/// </summary>
/// <param name="name"></param>
/// <param name="color"></param>
public void UpdateContentColor(string name, Color color)
{
if (m_DataBtnList.ContainsKey(name))
{
m_DataBtnList[name].SetContentColor(color);
}
}
/// <summary>
/// Gets the legend button for the specified index.
/// 获得指定索引的图例按钮。
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public Sprite GetIcon(int index)
{
if (index >= 0 && index < m_Icons.Count)
{
return m_Icons[index];
}
else
{
return null;
}
}
/// <summary>
/// Callback handling when parameters change.
/// 参数变更时的回调处理。
/// </summary>
public void OnChanged()
{
m_Location.OnChanged();
}
/// <summary>
/// 获得图例格式化后的显示内容。
/// </summary>
/// <param name="category"></param>
/// <returns></returns>
public string GetFormatterContent(string category)
{
if (string.IsNullOrEmpty(m_Formatter))
return category;
else
{
var content = m_Formatter.Replace("{name}", category);
content = content.Replace("\\n", "\n");
content = content.Replace("<br/>", "\n");
return content;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4a708805f5d8147b3b9a90b2f1d38e75
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,94 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using System;
using UnityEngine;
namespace XCharts
{
/// <summary>
/// Polar coordinate can be used in scatter and line chart. Every polar coordinate has an angleAxis and a radiusAxis.
/// <para>
/// 极坐标系组件。
/// 极坐标系,可以用于散点图和折线图。每个极坐标系拥有一个角度轴和一个半径轴。
/// </para>
/// </summary>
[Serializable]
public class Polar : MainComponent
{
[SerializeField] private bool m_Show = true;
[SerializeField] private float[] m_Center = new float[2] { 0.5f, 0.5f };
[SerializeField] private float m_Radius = 100;
[SerializeField] private Color m_BackgroundColor;
/// <summary>
/// Whether to show the polor component.
/// 是否显示极坐标。
/// </summary>
public bool show
{
get { return m_Show; }
set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetVerticesDirty(); }
}
/// <summary>
/// [default:[0.5f,0.45f]]The center of ploar. The center[0] is the x-coordinate, and the center[1] is the y-coordinate.
/// When value between 0 and 1 represents a percentage relative to the chart.
/// 极坐标的中心点。数组的第一项是横坐标,第二项是纵坐标。
/// 当值为0-1之间时表示百分比,设置成百分比时第一项是相对于容器宽度,第二项是相对于容器高度。
/// </summary>
public float[] center
{
get { return m_Center; }
set { if (value != null) { m_Center = value; SetAllDirty(); } }
}
/// <summary>
/// [default:0.35f]the radius of polar.
/// 极坐标的半径。
/// </summary>
public float radius
{
get { return m_Radius; }
set { if (PropertyUtil.SetStruct(ref m_Radius, value)) SetAllDirty(); }
}
/// <summary>
/// [default:Color.clear]Background color of polar, which is transparent by default.
/// 极坐标的背景色,默认透明。
/// </summary>
public Color backgroundColor
{
get { return m_BackgroundColor; }
set { if (PropertyUtil.SetColor(ref m_BackgroundColor, value)) SetVerticesDirty(); }
}
public int index { get; internal set; }
/// <summary>
/// the center position of polar in container.
/// 极坐标在容器中的具体中心点。
/// </summary>
public Vector3 runtimeCenterPos { get; internal set; }
/// <summary>
/// the true radius of polar.
/// 极坐标的运行时实际半径。
/// </summary>
public float runtimeRadius { get; internal set; }
public static Polar defaultPolar
{
get
{
var polar = new Polar
{
m_Show = true,
m_Radius = 0.35f,
};
polar.center[0] = 0.5f;
polar.center[1] = 0.45f;
return polar;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f9eb9ba0a1d154f11ba169fc07ad7a91
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,377 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using UnityEngine;
using System.Collections.Generic;
using System;
using System.Text.RegularExpressions;
using UnityEngine.UI;
namespace XCharts
{
/// <summary>
/// Radar coordinate conponnet for radar charts.
/// 雷达图坐标系组件,只适用于雷达图。
/// </summary>
[System.Serializable]
public class Radar : MainComponent
{
/// <summary>
/// Radar render type, in which 'Polygon' and 'Circle' are supported.
/// 雷达图绘制类型,支持 'Polygon' 和 'Circle'。
/// </summary>
public enum Shape
{
Polygon,
Circle
}
/// <summary>
/// The position type of radar.
/// 显示位置。
/// </summary>
public enum PositionType
{
/// <summary>
/// Display at the vertex.
/// 显示在顶点处。
/// </summary>
Vertice,
/// <summary>
/// Display at the middle of line.
/// 显示在两者之间。
/// </summary>
Between,
}
/// <summary>
/// Indicator of radar chart, which is used to assign multiple variables(dimensions) in radar chart.
/// 雷达图的指示器,用来指定雷达图中的多个变量(维度)。
/// </summary>
[System.Serializable]
public class Indicator
{
[SerializeField] private string m_Name;
[SerializeField] private float m_Max;
[SerializeField] private float m_Min;
[SerializeField] private TextStyle m_TextStyle = new TextStyle();
/// <summary>
/// The name of indicator.
/// 指示器名称。
/// </summary>
public string name { get { return FormatterHelper.TrimAndReplaceLine(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>
/// the style of text.
/// 文本样式。
/// </summary>
public TextStyle textStyle { get { return m_TextStyle; } set { m_TextStyle = value; } }
/// <summary>
/// the text conponent of indicator.
/// 指示器的文本组件。
/// </summary>
public Text text { get; set; }
}
[SerializeField] private bool m_Show;
[SerializeField] private Shape m_Shape;
[SerializeField] private float m_Radius = 100;
[SerializeField] private int m_SplitNumber = 5;
[SerializeField] private float[] m_Center = new float[2] { 0.5f, 0.5f };
[SerializeField] private AxisLine m_AxisLine = AxisLine.defaultAxisLine;
[SerializeField] private AxisSplitLine m_SplitLine = AxisSplitLine.defaultSplitLine;
[SerializeField] private AxisSplitArea m_SplitArea = AxisSplitArea.defaultSplitArea;
[SerializeField] private bool m_Indicator = true;
[SerializeField] private PositionType m_PositionType = PositionType.Vertice;
[SerializeField] private float m_IndicatorGap = 10;
[SerializeField] private int m_CeilRate = 0;
[SerializeField] private bool m_IsAxisTooltip;
[SerializeField] private List<Indicator> m_IndicatorList = new List<Indicator>();
/// <summary>
/// [default:true]
/// Set this to false to prevent the radar from showing.
/// 是否显示雷达坐标系组件。
/// </summary>
public bool show { get { return m_Show; } set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetComponentDirty(); } }
/// <summary>
/// Radar render type, in which 'Polygon' and 'Circle' are supported.
/// 雷达图绘制类型,支持 'Polygon' 和 'Circle'。
/// </summary>
/// <value></value>
public Shape shape
{
get { return m_Shape; }
set { if (PropertyUtil.SetStruct(ref m_Shape, value)) SetAllDirty(); }
}
/// <summary>
/// the radius of radar.
/// 雷达图的半径。
/// </summary>
public float radius
{
get { return m_Radius; }
set { if (PropertyUtil.SetStruct(ref m_Radius, value)) SetAllDirty(); }
}
/// <summary>
/// Segments of indicator axis.
/// 指示器轴的分割段数。
/// </summary>
public int splitNumber
{
get { return m_SplitNumber; }
set { if (PropertyUtil.SetStruct(ref m_SplitNumber, value)) SetAllDirty(); }
}
/// <summary>
/// the center of radar chart.
/// 雷达图的中心点。数组的第一项是横坐标,第二项是纵坐标。
/// 当值为0-1之间时表示百分比,设置成百分比时第一项是相对于容器宽度,第二项是相对于容器高度。
/// </summary>
public float[] center
{
get { return m_Center; }
set { if (value != null) { m_Center = value; SetAllDirty(); } }
}
/// <summary>
/// axis line.
/// 轴线。
/// </summary>
public AxisLine axisLine
{
get { return m_AxisLine; }
set { if (PropertyUtil.SetClass(ref m_AxisLine, value, true)) SetAllDirty(); }
}
/// <summary>
/// split line.
/// 分割线。
/// </summary>
public AxisSplitLine splitLine
{
get { return m_SplitLine; }
set { if (PropertyUtil.SetClass(ref m_SplitLine, value, true)) SetAllDirty(); }
}
/// <summary>
/// Split area of axis in grid area.
/// 分割区域。
/// </summary>
public AxisSplitArea splitArea
{
get { return m_SplitArea; }
set { if (PropertyUtil.SetClass(ref m_SplitArea, value, true)) SetAllDirty(); }
}
/// <summary>
/// Whether to show indicator.
/// 是否显示指示器。
/// </summary>
public bool indicator
{
get { return m_Indicator; }
set { if (PropertyUtil.SetStruct(ref m_Indicator, value)) SetComponentDirty(); }
}
/// <summary>
/// The gap of indicator and radar.
/// 指示器和雷达的间距。
/// </summary>
public float indicatorGap
{
get { return m_IndicatorGap; }
set { if (PropertyUtil.SetStruct(ref m_IndicatorGap, value)) SetComponentDirty(); }
}
/// <summary>
/// The ratio of maximum and minimum values rounded upward. The default is 0, which is automatically calculated.
/// 最大最小值向上取整的倍率。默认为0时自动计算。
/// </summary>
public int ceilRate
{
get { return m_CeilRate; }
set { if (PropertyUtil.SetStruct(ref m_CeilRate, value < 0 ? 0 : value)) SetAllDirty(); }
}
/// <summary>
/// 是否Tooltip显示轴线上的所有数据。
/// </summary>
public bool isAxisTooltip
{
get { return m_IsAxisTooltip; }
set { if (PropertyUtil.SetStruct(ref m_IsAxisTooltip, value)) SetAllDirty(); }
}
/// <summary>
/// The position type of indicator.
/// 显示位置类型。
/// </summary>
public PositionType positionType
{
get { return m_PositionType; }
set { if (PropertyUtil.SetStruct(ref m_PositionType, value)) SetAllDirty(); }
}
/// <summary>
/// the indicator list.
/// 指示器列表。
/// </summary>
public List<Indicator> indicatorList { get { return m_IndicatorList; } }
public int index { get; internal set; }
/// <summary>
/// the center position of radar in container.
/// 雷达图在容器中的具体中心点。
/// </summary>
public Vector3 runtimeCenterPos { get; internal set; }
/// <summary>
/// the true radius of radar.
/// 雷达图的运行时实际半径。
/// </summary>
public float runtimeRadius { get; internal set; }
public float runtimeDataRadius { get; internal set; }
/// <summary>
/// the data position list of radar.
/// 雷达图的所有数据坐标点列表。
/// </summary>
public Dictionary<int, List<Vector3>> runtimeDataPosList = new Dictionary<int, List<Vector3>>();
public static Radar defaultRadar
{
get
{
var radar = new Radar
{
m_Show = true,
m_Shape = Shape.Polygon,
m_Radius = 0.35f,
m_SplitNumber = 5,
m_Indicator = true,
m_IndicatorList = new List<Indicator>(5){
new Indicator(){name="indicator1",max = 0},
new Indicator(){name="indicator2",max = 0},
new Indicator(){name="indicator3",max = 0},
new Indicator(){name="indicator4",max = 0},
new Indicator(){name="indicator5",max = 0},
}
};
radar.center[0] = 0.5f;
radar.center[1] = 0.4f;
radar.splitLine.show = true;
radar.splitArea.show = true;
return radar;
}
}
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 float GetIndicatorMin(int index)
{
if (index >= 0 && index < m_IndicatorList.Count)
{
return m_IndicatorList[index].min;
}
return 0;
}
public float GetIndicatorMax(int index)
{
if (index >= 0 && index < m_IndicatorList.Count)
{
return m_IndicatorList[index].max;
}
return 0;
}
internal void UpdateRadarCenter(Vector3 chartPosition, float chartWidth, float chartHeight)
{
if (center.Length < 2) return;
var centerX = center[0] <= 1 ? chartWidth * center[0] : center[0];
var centerY = center[1] <= 1 ? chartHeight * center[1] : center[1];
runtimeCenterPos = chartPosition + new Vector3(centerX, centerY);
if (radius <= 0)
{
runtimeRadius = 0;
}
else if (radius <= 1)
{
runtimeRadius = Mathf.Min(chartWidth, chartHeight) * radius;
}
else
{
runtimeRadius = radius;
}
if (shape == Radar.Shape.Polygon && positionType == PositionType.Between)
{
var angle = Mathf.PI / indicatorList.Count;
runtimeDataRadius = runtimeRadius * Mathf.Cos(angle);
}
else
{
runtimeDataRadius = runtimeRadius;
}
}
public Vector3 GetIndicatorPosition(int index)
{
int indicatorNum = indicatorList.Count;
var angle = 0f;
switch (positionType)
{
case PositionType.Vertice:
angle = 2 * Mathf.PI / indicatorNum * index;
break;
case PositionType.Between:
angle = 2 * Mathf.PI / indicatorNum * (index + 0.5f);
break;
}
var x = runtimeCenterPos.x + (runtimeRadius + indicatorGap) * Mathf.Sin(angle);
var y = runtimeCenterPos.y + (runtimeRadius + indicatorGap) * Mathf.Cos(angle);
return new Vector3(x, y);
}
public void AddIndicator(Radar.Indicator indicator)
{
indicatorList.Add(indicator);
SetAllDirty();
}
public Radar.Indicator AddIndicator(string name, float min, float max)
{
var indicator = new Radar.Indicator();
indicator.name = name;
indicator.min = min;
indicator.max = max;
indicatorList.Add(indicator);
SetAllDirty();
return indicator;
}
public bool UpdateIndicator(int indicatorIndex, string name, float min, float max)
{
var indicator = GetIndicator(indicatorIndex);
if (indicator == null) return false;
indicator.name = name;
indicator.min = min;
indicator.max = max;
SetAllDirty();
return true;
}
public Radar.Indicator GetIndicator(int indicatorIndex)
{
if (indicatorIndex < 0 || indicatorIndex > indicatorList.Count - 1) return null;
return indicatorList[indicatorIndex];
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0874fd6b295f24cdb8b3cedb1faaa40f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aa9c09045961a4ea9a34a098f099f2a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,724 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using UnityEngine;
using System.Collections.Generic;
using System;
namespace XCharts
{
/// <summary>
/// the list of series.
/// 系列列表。每个系列通过 type 决定自己的图表类型。
/// </summary>
[System.Serializable]
public class Series : MainComponent
{
[SerializeField] protected List<Serie> m_Series;
[NonSerialized] private bool m_LabelDirty;
/// <summary>
/// the list of serie
/// 系列列表。
/// </summary>
public List<Serie> list { get { return m_Series; } }
/// <summary>
/// the size of serie list.
/// 系列个数。
/// </summary>
public int Count { get { return m_Series.Count; } }
public bool labelDirty { get { return m_LabelDirty; } set { m_LabelDirty = value; } }
public static Series defaultSeries
{
get
{
var series = new Series
{
m_Series = new List<Serie>(){new Serie(){
show = true,
name = "serie1",
index = 0
}}
};
return series;
}
}
public override bool vertsDirty
{
get
{
if (m_VertsDirty) return true;
foreach (var serie in m_Series)
{
if (serie.vertsDirty) return true;
}
return false;
}
}
public void SetLabelDirty()
{
m_LabelDirty = true;
}
internal override void ClearVerticesDirty()
{
base.ClearVerticesDirty();
foreach (var serie in m_Series)
{
serie.ClearVerticesDirty();
}
}
internal void ClearLabelDirty()
{
m_LabelDirty = false;
foreach (var serie in m_Series)
{
serie.label.ClearVerticesDirty();
}
}
public override void SetAllDirty()
{
base.SetAllDirty();
SetLabelDirty();
}
public override void ClearDirty()
{
base.ClearDirty();
ClearLabelDirty();
SeriesHelper.ClearNameDirty(this);
}
/// <summary>
/// 清空所有系列的数据
/// </summary>
public void ClearData()
{
AnimationFadeIn();
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;
}
}
public float GetCurrData(int serieIndex, int dataIndex)
{
if (serieIndex >= 0 && serieIndex < Count)
{
return m_Series[serieIndex].GetYCurrData(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++)
{
bool match = false;
if (string.IsNullOrEmpty(name))
{
if (string.IsNullOrEmpty(m_Series[i].name)) match = true;
}
else if (name.Equals(m_Series[i].name))
{
match = true;
}
if (match)
{
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()
{
AnimationFadeIn();
m_Series.Clear();
}
/// <summary>
/// 添加一个系列到列表中。
/// </summary>
/// <param name="serieName"></param>
/// <param name="type"></param>
/// <param name="show"></param>
/// <returns></returns>
public Serie AddSerie(SerieType type, string serieName, bool show = true)
{
var serie = new Serie();
serie.type = type;
serie.show = show;
serie.name = serieName;
serie.index = m_Series.Count;
if (type == SerieType.Scatter)
{
serie.symbol.show = true;
serie.symbol.type = SerieSymbolType.Circle;
}
else if (type == SerieType.Line)
{
serie.symbol.show = true;
serie.symbol.type = SerieSymbolType.EmptyCircle;
}
else
{
serie.symbol.show = false;
}
serie.animation.Restart();
m_Series.Add(serie);
SetVerticesDirty();
return serie;
}
/// <summary>
/// 添加一个数据到指定系列的维度Y数据中
/// </summary>
/// <param name="serieName"></param>
/// <param name="value"></param>
/// <param name="dataName"></param>
/// <returns>添加成功返回SerieData,否则返回null</returns>
public SerieData AddData(string serieName, float value, string dataName = null)
{
var serie = GetSerie(serieName);
if (serie != null)
{
return serie.AddYData(value, dataName);
}
return null;
}
/// <summary>
/// 添加一个数据到指定系列的维度Y中
/// </summary>
/// <param name="index"></param>
/// <param name="value"></param>
/// <param name="dataName"></param>
/// <returns>添加成功返回SerieData,否则返回null</returns>
public SerieData AddData(int index, float value, string dataName = null)
{
var serie = GetSerie(index);
if (serie != null)
{
return serie.AddYData(value, dataName);
}
return null;
}
/// <summary>
/// 添加[open, close, lowest, highest]数据
/// </summary>
/// <param name="index"></param>
/// <param name="open"></param>
/// <param name="close"></param>
/// <param name="lowest"></param>
/// <param name="heighest"></param>
/// <param name="dataName"></param>
/// <returns></returns>
public SerieData AddData(int index, float open, float close, float lowest, float heighest, string dataName = null)
{
var serie = GetSerie(index);
if (serie != null)
{
return serie.AddData(open, close, lowest, heighest, dataName);
}
return null;
}
public SerieData AddData(string serieName, float open, float close, float lowest, float heighest, string dataName = null)
{
var serie = GetSerie(serieName);
if (serie != null)
{
return serie.AddData(open, close, lowest, heighest, dataName);
}
return null;
}
/// <summary>
/// 添加一组数据到指定的系列中
/// </summary>
/// <param name="serieName"></param>
/// <param name="multidimensionalData"></param>
/// <param name="dataName"></param>
/// <returns>添加成功返回SerieData,否则返回null</returns>
public SerieData AddData(string serieName, List<float> multidimensionalData, string dataName = null)
{
var serie = GetSerie(serieName);
if (serie != null)
{
return serie.AddData(multidimensionalData, dataName);
}
return null;
}
/// <summary>
/// 添加一组数据到指定的系列中
/// </summary>
/// <param name="serieIndex"></param>
/// <param name="multidimensionalData"></param>
/// <param name="dataName"></param>
/// <returns>添加成功返回SerieData,否则返回null</returns>
public SerieData AddData(int serieIndex, List<float> multidimensionalData, string dataName = null)
{
var serie = GetSerie(serieIndex);
if (serie != null)
{
return serie.AddData(multidimensionalData, dataName);
}
return null;
}
/// <summary>
/// 添加(x,y)数据到指定的系列中
/// </summary>
/// <param name="serieName"></param>
/// <param name="xValue"></param>
/// <param name="yValue"></param>
/// <param name="dataName"></param>
/// <returns>添加成功返回SerieData,否则返回null</returns>
public SerieData AddXYData(string serieName, float xValue, float yValue, string dataName = null)
{
var serie = GetSerie(serieName);
if (serie != null)
{
return serie.AddXYData(xValue, yValue, dataName);
}
return null;
}
/// <summary>
/// 添加(x,y)数据到指定的系列中
/// </summary>
/// <param name="index"></param>
/// <param name="xValue"></param>
/// <param name="yValue"></param>
/// <param name="dataName"></param>
/// <returns>添加成功返回SerieData,否则返回null</returns>
public SerieData AddXYData(int index, float xValue, float yValue, string dataName = null)
{
var serie = GetSerie(index);
if (serie != null)
{
return serie.AddXYData(xValue, yValue, dataName);
}
return null;
}
/// <summary>
/// 更新指定系列的维度Y数据
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
/// <param name="dataIndex"></param>
public bool UpdateData(string serieName, int dataIndex, float value)
{
var serie = GetSerie(serieName);
if (serie != null)
{
return serie.UpdateYData(dataIndex, value);
}
return false;
}
/// <summary>
/// 更新指定系列的数据项名称
/// </summary>
/// <param name="serieName"></param>
/// <param name="dataIndex"></param>
/// <param name="dataName"></param>
public bool UpdateDataName(string serieName, int dataIndex, string dataName)
{
var serie = GetSerie(serieName);
if (serie != null)
{
return serie.UpdateDataName(dataIndex, dataName);
}
return false;
}
/// <summary>
/// 更新指定系列的数据项名称
/// </summary>
/// <param name="serieIndex"></param>
/// <param name="dataIndex"></param>
/// <param name="dataName"></param>
public bool UpdateDataName(int serieIndex, int dataIndex, string dataName)
{
var serie = GetSerie(serieIndex);
if (serie != null)
{
return serie.UpdateDataName(dataIndex, dataName);
}
return false;
}
/// <summary>
/// 更新指定系列的维度Y数据项的值
/// </summary>
/// <param name="serieIndex"></param>
/// <param name="dataIndex"></param>
/// <param name="value"></param>
public bool UpdateData(int serieIndex, int dataIndex, float value)
{
var serie = GetSerie(serieIndex);
if (serie != null)
{
return serie.UpdateYData(dataIndex, value);
}
return false;
}
public bool UpdateData(string serieName, int dataIndex, List<float> values)
{
var serie = GetSerie(serieName);
if (serie != null)
{
return serie.UpdateData(dataIndex, values);
}
return false;
}
public bool UpdateData(int serieIndex, int dataIndex, List<float> values)
{
var serie = GetSerie(serieIndex);
if (serie != null)
{
return serie.UpdateData(dataIndex, values);
}
return false;
}
/// <summary>
/// 更新指定系列指定数据项指定维度的数据值
/// </summary>
/// <param name="serieIndex">系列</param>
/// <param name="dataIndex">数据项</param>
/// <param name="dimension">数据维数,从0开始</param>
/// <param name="value">值</param>
public bool UpdateData(int serieIndex, int dataIndex, int dimension, float value)
{
var serie = GetSerie(serieIndex);
if (serie != null)
{
return serie.UpdateData(dataIndex, dimension, value);
}
return false;
}
/// <summary>
/// 更新指定系列指定数据项指定维度的数据值
/// </summary>
/// <param name="serieName"></param>
/// <param name="dataIndex"></param>
/// <param name="dimension">数据维数,从0开始</param>
/// <param name="value"></param>
public bool UpdateData(string serieName, int dataIndex, int dimension, float value)
{
var serie = GetSerie(serieName);
if (serie != null)
{
return serie.UpdateData(dataIndex, dimension, value);
}
return false;
}
/// <summary>
/// 更新指定系列的维度X和维度Y数据
/// </summary>
/// <param name="serieName"></param>
/// <param name="dataIndex"></param>
/// <param name="xValue"></param>
/// <param name="yValue"></param>
public bool UpdateXYData(string serieName, int dataIndex, float xValue, float yValue)
{
var serie = GetSerie(serieName);
if (serie != null)
{
return serie.UpdateXYData(dataIndex, xValue, yValue);
}
return false;
}
/// <summary>
/// 更新指定系列的维度X和维度Y数据
/// </summary>
/// <param name="serieIndex"></param>
/// <param name="dataIndex"></param>
/// <param name="xValue"></param>
/// <param name="yValue"></param>
public bool UpdateXYData(int serieIndex, int dataIndex, float xValue, float yValue)
{
var serie = GetSerie(serieIndex);
if (serie != null)
{
return serie.UpdateXYData(dataIndex, xValue, yValue);
}
return false;
}
/// <summary>
/// dataZoom由变化是更新系列的缓存数据
/// </summary>
/// <param name="dataZoom"></param>
internal void UpdateFilterData(DataZoom dataZoom)
{
if (dataZoom != null && dataZoom.enable)
{
for (int i = 0; i < m_Series.Count; i++)
{
SerieHelper.UpdateFilterData(m_Series[i], 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;
serie.animation.Reset();
if (active) serie.animation.FadeIn();
}
}
/// <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>
/// 设置获得标志图形大小的回调
/// </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>
/// 启用或取消初始动画
/// </summary>
public void AnimationEnable(bool flag)
{
foreach (var serie in m_Series)
{
serie.animation.enable = flag;
}
}
/// <summary>
/// 渐入动画
/// </summary>
public void AnimationFadeIn()
{
foreach (var serie in m_Series)
{
if (serie.animation.enable)
{
serie.animation.FadeIn();
}
}
}
/// <summary>
/// 渐出动画
/// </summary>
public void AnimationFadeOut()
{
foreach (var serie in m_Series)
{
if (serie.animation.enable) serie.animation.FadeOut();
}
}
/// <summary>
/// 暂停动画
/// </summary>
public void AnimationPause()
{
foreach (var serie in m_Series)
{
if (serie.animation.enable) serie.animation.Pause();
}
}
/// <summary>
/// 继续动画
/// </summary>
public void AnimationResume()
{
foreach (var serie in m_Series)
{
if (serie.animation.enable) serie.animation.Resume();
}
}
/// <summary>
/// 重置动画
/// </summary>
public void AnimationReset()
{
foreach (var serie in m_Series)
{
if (serie.animation.enable) serie.animation.Reset();
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 57c808a15402a4d25a51a37cbb655a85
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,133 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using UnityEngine;
using System;
namespace XCharts
{
/// <summary>
/// Global parameter setting component. The default value can be used in general, and can be adjusted when necessary.
/// 全局参数设置组件。一般情况下可使用默认值,当有需要时可进行调整。
/// </summary>
[Serializable]
public class Settings : MainComponent
{
[SerializeField] [Range(1, 20)] protected int m_MaxPainter = 10;
[SerializeField] [Range(1, 10)] protected float m_LineSmoothStyle = 3f;
[SerializeField] [Range(1f, 20)] protected float m_LineSmoothness = 2f;
[SerializeField] [Range(1f, 20)] protected float m_LineSegmentDistance = 3f;
[SerializeField] [Range(1, 10)] protected float m_CicleSmoothness = 2f;
[SerializeField] protected float m_LegendIconLineWidth = 2;
[SerializeField] private float[] m_LegendIconCornerRadius = new float[] { 0.25f, 0.25f, 0.25f, 0.25f };
/// <summary>
/// max painter.
/// 设定的painter数量。
/// </summary>
public int maxPainter
{
get { return m_MaxPainter; }
set { if (PropertyUtil.SetStruct(ref m_MaxPainter, value < 0 ? 1 : value)) SetVerticesDirty(); }
}
/// <summary>
/// Curve smoothing factor. By adjusting the smoothing coefficient, the curvature of the curve can be changed,
/// and different curves with slightly different appearance can be obtained.
/// 曲线平滑系数。通过调整平滑系数可以改变曲线的曲率,得到外观稍微有变化的不同曲线。
/// </summary>
public float lineSmoothStyle
{
get { return m_LineSmoothStyle; }
set { if (PropertyUtil.SetStruct(ref m_LineSmoothStyle, value < 0 ? 1f : value)) SetVerticesDirty(); }
}
/// <summary>
/// Smoothness of curve. The smaller the value, the smoother the curve, but the number of vertices will increase.
/// When the area with gradient is filled, the larger the value, the worse the transition effect.
/// 曲线平滑度。值越小曲线越平滑,但顶点数也会随之增加。当开启有渐变的区域填充时,数值越大渐变过渡效果越差。
/// </summary>
/// <value></value>
public float lineSmoothness
{
get { return m_LineSmoothness; }
set { if (PropertyUtil.SetStruct(ref m_LineSmoothStyle, value < 0 ? 1f : value)) SetVerticesDirty(); }
}
/// <summary>
/// The partition distance of a line segment. A line in a normal line chart is made up of many segments,
/// the number of which is determined by the change in value. The smaller the number of segments,
/// the higher the number of vertices. When the area with gradient is filled, the larger the value, the worse the transition effect.
/// 线段的分割距离。普通折线图的线是由很多线段组成,段数由该数值决定。值越小段数越多,但顶点数也会随之增加。当开启有渐变的区域填充时,数值越大渐变过渡效果越差。
/// </summary>
/// <value></value>
public float lineSegmentDistance
{
get { return m_LineSegmentDistance; }
set { if (PropertyUtil.SetStruct(ref m_LineSegmentDistance, value < 0 ? 1f : value)) SetVerticesDirty(); }
}
/// <summary>
/// the smoothess of cricle.
/// 圆形的平滑度。数越小圆越平滑,但顶点数也会随之增加。
/// </summary>
public float cicleSmoothness
{
get { return m_CicleSmoothness; }
set { if (PropertyUtil.SetStruct(ref m_CicleSmoothness, value < 0 ? 1f : value)) SetVerticesDirty(); }
}
/// <summary>
/// the width of line serie legend.
/// Line类型图例图标的线条宽度。
/// </summary>
public float legendIconLineWidth
{
get { return m_LegendIconLineWidth; }
set { if (PropertyUtil.SetStruct(ref m_LegendIconLineWidth, value)) SetVerticesDirty(); }
}
/// <summary>
/// The radius of rounded corner. Its unit is px. Use array to respectively specify the 4 corner radiuses((clockwise upper left, upper right, bottom right and bottom left)).
/// 图例圆角半径。用数组分别指定4个圆角半径(顺时针左上,右上,右下,左下)。
/// </summary>
public float[] legendIconCornerRadius
{
get { return m_LegendIconCornerRadius; }
set { if (PropertyUtil.SetClass(ref m_LegendIconCornerRadius, value, true)) SetVerticesDirty(); }
}
public void Copy(Settings settings)
{
m_MaxPainter = settings.maxPainter;
m_LineSmoothStyle = settings.lineSmoothStyle;
m_LineSmoothness = settings.lineSmoothness;
m_LineSegmentDistance = settings.lineSegmentDistance;
m_CicleSmoothness = settings.cicleSmoothness;
m_LegendIconLineWidth = settings.legendIconLineWidth;
ChartHelper.CopyArray(m_LegendIconCornerRadius, settings.legendIconCornerRadius);
}
public void Reset()
{
Copy(DefaultSettings);
}
public static Settings DefaultSettings
{
get
{
return new Settings()
{
m_MaxPainter = XChartsSettings.maxPainter,
m_LineSmoothStyle = XChartsSettings.lineSmoothStyle,
m_LineSmoothness = XChartsSettings.lineSmoothness,
m_LineSegmentDistance = XChartsSettings.lineSegmentDistance,
m_CicleSmoothness = XChartsSettings.cicleSmoothness,
m_LegendIconLineWidth = 2,
m_LegendIconCornerRadius = new float[] { 0.25f, 0.25f, 0.25f, 0.25f }
};
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 40d2c2f38d80f4b42acdba7db6918f14
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,125 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using UnityEngine;
using System;
namespace XCharts
{
/// <summary>
/// Title component, including main title and subtitle.
/// 标题组件,包含主标题和副标题。
/// </summary>
[Serializable]
public class Title : MainComponent, IPropertyChanged
{
[SerializeField] private bool m_Show = true;
[SerializeField] private string m_Text;
[SerializeField] private TextStyle m_TextStyle = new TextStyle();
[SerializeField] private string m_SubText;
[SerializeField] private TextStyle m_SubTextStyle = new TextStyle();
[SerializeField] private float m_ItemGap = 8;
[SerializeField] private Location m_Location = Location.defaultTop;
/// <summary>
/// [default:true]
/// Set this to false to prevent the title from showing.
/// 是否显示标题组件。
/// </summary>
public bool show { get { return m_Show; } set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetComponentDirty(); } }
/// <summary>
/// The main title text, supporting \n for newlines.
/// 主标题文本,支持使用 \n 换行。
/// </summary>
public string text { get { return m_Text; } set { if (PropertyUtil.SetClass(ref m_Text, value)) SetComponentDirty(); } }
/// <summary>
/// The text style of main title.
/// 主标题文本样式。
/// </summary>
public TextStyle textStyle
{
get { return m_TextStyle; }
set { if (PropertyUtil.SetClass(ref m_TextStyle, value)) SetComponentDirty(); }
}
/// <summary>
/// Subtitle text, supporting for \n for newlines.
/// 副标题文本,支持使用 \n 换行。
/// </summary>
public string subText
{
get { return m_SubText; }
set { if (PropertyUtil.SetClass(ref m_SubText, value)) SetComponentDirty(); }
}
/// <summary>
/// The text style of sub title.
/// 副标题文本样式。
/// </summary>
public TextStyle subTextStyle
{
get { return m_SubTextStyle; }
set { if (PropertyUtil.SetClass(ref m_SubTextStyle, value)) SetComponentDirty(); }
}
/// <summary>
/// [default:8]
/// The gap between the main title and subtitle.
/// 主副标题之间的间距。
/// </summary>
public float itemGap
{
get { return m_ItemGap; }
set { if (PropertyUtil.SetStruct(ref m_ItemGap, value)) SetComponentDirty(); }
}
/// <summary>
/// The location of title component.
/// 标题显示位置。
/// </summary>
public Location location
{
get { return m_Location; }
set { if (PropertyUtil.SetClass(ref m_Location, value)) SetComponentDirty(); }
}
public int index { get; internal set; }
public override bool vertsDirty { get { return false; } }
public override bool componentDirty
{
get { return m_ComponentDirty || location.componentDirty || textStyle.componentDirty || subTextStyle.componentDirty; }
}
internal override void ClearComponentDirty()
{
base.ClearComponentDirty();
location.ClearComponentDirty();
textStyle.ClearComponentDirty();
subTextStyle.ClearComponentDirty();
}
public static Title defaultTitle
{
get
{
var title = new Title
{
m_Show = true,
m_Text = "Chart Title",
m_TextStyle = new TextStyle(),
m_SubText = "",
m_SubTextStyle = new TextStyle(),
m_ItemGap = 0,
m_Location = Location.defaultTop
};
return title;
}
}
public void OnChanged()
{
m_Location.OnChanged();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 91e9a1a59b4b64142a9aa260f618c1c1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,538 @@
using System.Linq;
using System.Collections.ObjectModel;
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
/// <summary>
/// Tooltip component.
/// 提示框组件。
/// </summary>
[System.Serializable]
public class Tooltip : MainComponent
{
/// <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;
[SerializeField] private string m_Formatter;
[SerializeField] private string m_ItemFormatter;
[SerializeField] private string m_TitleFormatter;
[SerializeField] private float m_FixedWidth = 0;
[SerializeField] private float m_FixedHeight = 0;
[SerializeField] private float m_MinWidth = 0;
[SerializeField] private float m_MinHeight = 0;
[SerializeField] private string m_NumericFormatter = "";
[SerializeField] private float m_PaddingLeftRight = 5f;
[SerializeField] private float m_PaddingTopBottom = 5f;
[SerializeField] private bool m_IgnoreDataShow = false;
[SerializeField] private string m_IgnoreDataDefaultContent = "-";
[SerializeField] private bool m_AlwayShow = false;
[SerializeField] private Vector2 m_Offset = new Vector2(18f, -25f);
[SerializeField] private Sprite m_BackgroundImage;
[SerializeField] private TextStyle m_TextStyle = new TextStyle();
[SerializeField] private LineStyle m_LineStyle = new LineStyle(LineStyle.Type.None);
private GameObject m_GameObject;
private GameObject m_Content;
private ChartText m_ContentText;
private Image m_ContentImage;
private RectTransform m_ContentRect;
private RectTransform m_ContentTextRect;
private List<int> lastDataIndex { get; set; }
/// <summary>
/// Whether to show the tooltip component.
/// 是否显示提示框组件。
/// </summary>
public bool show
{
get { return m_Show; }
set { if (PropertyUtil.SetStruct(ref m_Show, value)) { SetAllDirty(); SetActive(value); } }
}
/// <summary>
/// Indicator type.
/// 提示框指示器类型。
/// </summary>
public Type type
{
get { return m_Type; }
set { if (PropertyUtil.SetStruct(ref m_Type, value)) SetAllDirty(); }
}
/// <summary>
/// A string template formatter for the total content of the prompt box. Support for wrapping lines with \n.
/// When formatter is not null, use formatter first, otherwise use itemFormatter.
/// Template variables are {.}, {a}, {b}, {c}, {d}.
/// {.} is the dot of the corresponding color of a Serie that is currently indicated or whose index is 0.
/// {a} is the series name of the serie that is currently indicated or whose index is 0.
/// {b} is the name of the data item serieData that is currently indicated or whose index is 0, or a category value (such as the X-axis of a line chart).
/// {c} is the value of a Y-dimension (dimesion is 1) from a Serie that is currently indicated or whose index is 0.
/// {d} is the percentage value of Y-dimensions (dimesion is 1) from serie that is currently indicated or whose index is 0, with no % sign.
/// {.1} represents a dot from serie corresponding color that specifies index as 1.
/// 1 in {a1}, {b1}, {c1} represents a serie that specifies an index of 1.
/// {c1:2} represents the third data from serie's current indication data item indexed to 1 (a data item has multiple data, index 2 represents the third data).
/// {c1:2-2} represents the third data item from serie's third data item indexed to 1 (i.e., which data item must be specified to specify).
/// {d1:2: F2} indicates that a formatted string with a value specified separately is F2 (numericFormatter is used when numericFormatter is not specified).
/// {d:0.##} indicates that a formatted string with a value specified separately is 0.## (used for percentage, reserved 2 valid digits while avoiding the situation similar to "100.00%" when using f2 ).
/// Example: "{a}, {c}", "{a1}, {c1: f1}", "{a1}, {c1:0: f1}", "{a1} : {c1:1-1: f1}"
/// 提示框总内容的字符串模版格式器。支持用 \n 换行。当formatter不为空时,优先使用formatter,否则使用itemFormatter。
/// 模板变量有{.}、{a}、{b}、{c}、{d}。
/// {.}为当前所指示或index为0的serie的对应颜色的圆点。
/// {a}为当前所指示或index为0的serie的系列名name。
/// {b}为当前所指示或index为0的serie的数据项serieData的name,或者类目值(如折线图的X轴)。
/// {c}为当前所指示或index为0的serie的y维(dimesion为1)的数值。
/// {d}为当前所指示或index为0的serie的y维(dimesion为1)百分比值,注意不带%号。
/// {.1}表示指定index为1的serie对应颜色的圆点。
/// {a1}、{b1}、{c1}中的1表示指定index为1的serie。
/// {c1:2}表示索引为1的serie的当前指示数据项的第3个数据(一个数据项有多个数据,index为2表示第3个数据)。
/// {c1:2-2}表示索引为1的serie的第3个数据项的第3个数据(也就是要指定第几个数据项时必须要指定第几个数据)。
/// {d1:2:f2}表示单独指定了数值的格式化字符串为f2(不指定时用numericFormatter)。
/// {d:0.##} 表示单独指定了数值的格式化字符串为 0.## (用于百分比,保留2位有效数同时又能避免使用 f2 而出现的类似于"100.00%"的情况 )。
/// 示例:"{a}:{c}"、"{a1}:{c1:f1}"、"{a1}:{c1:0:f1}"、"{a1}:{c1:1-1:f1}"
/// </summary>
public string formatter { get { return m_Formatter; } set { m_Formatter = value; } }
/// <summary>
/// The string template formatter for the tooltip title content. Support for wrapping lines with \n.
/// This is only valid if the itemFormatter is in effect.
/// The placeholder {I} can be set separately to indicate that the title is ignored and not displayed.
/// 提示框标题内容的字符串模版格式器。支持用 \n 换行。仅当itemFormatter生效时才有效。可以单独设置占位符{i}表示忽略不显示title。
/// </summary>
public string titleFormatter { get { return m_TitleFormatter; } set { m_TitleFormatter = value; } }
/// <summary>
/// a string template formatter for a single Serie or data item content. Support for wrapping lines with \n.
/// When formatter is not null, use formatter first, otherwise use itemFormatter.
/// 提示框单个serie或数据项内容的字符串模版格式器。支持用 \n 换行。当formatter不为空时,优先使用formatter,否则使用itemFormatter。
/// </summary>
public string itemFormatter { get { return m_ItemFormatter; } set { m_ItemFormatter = value; } }
/// <summary>
/// Fixed width. Higher priority than minWidth.
/// 固定宽度。比 minWidth 优先。
/// </summary>
public float fixedWidth { get { return m_FixedWidth; } set { m_FixedWidth = value; } }
/// <summary>
/// Fixed height. Higher priority than minHeight.
/// 固定高度。比 minHeight 优先。
/// </summary>
public float fixedHeight { get { return m_FixedHeight; } set { m_FixedHeight = value; } }
/// <summary>
/// Minimum width. If fixedWidth has a value, get fixedWidth first.
/// 最小宽度。如若 fixedWidth 设有值,优先取 fixedWidth。
/// </summary>
public float minWidth { get { return m_MinWidth; } set { m_MinWidth = value; } }
/// <summary>
/// Minimum height. If fixedHeight has a value, take priority over fixedHeight.
/// 最小高度。如若 fixedHeight 设有值,优先取 fixedHeight。
/// </summary>
public float minHeight { get { return m_MinHeight; } set { m_MinHeight = value; } }
/// <summary>
/// Standard numeric format string. Used to format numeric values to display as strings.
/// Using 'Axx' form: 'A' is the single character of the format specifier, supporting 'C' currency,
/// 'D' decimal, 'E' exponent, 'F' number of vertices, 'G' regular, 'N' digits, 'P' percentage,
/// 'R' round tripping, 'X' hex etc. 'XX' is the precision specification, from '0' - '99'.
/// 标准数字格式字符串。用于将数值格式化显示为字符串。
/// 使用Axx的形式:A是格式说明符的单字符,支持C货币、D十进制、E指数、F定点数、G常规、N数字、P百分比、R往返、X十六进制的。xx是精度说明,从0-99。
/// 参考:https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/standard-numeric-format-strings
/// </summary>
/// <value></value>
public string numericFormatter
{
get { return m_NumericFormatter; }
set { if (PropertyUtil.SetClass(ref m_NumericFormatter, value)) SetComponentDirty(); }
}
/// <summary>
/// the text padding of left and right. defaut:5.
/// 左右边距。
/// </summary>
public float paddingLeftRight { get { return m_PaddingLeftRight; } set { m_PaddingLeftRight = value; } }
/// <summary>
/// the text padding of top and bottom. defaut:5.
/// 上下边距。
/// </summary>
public float paddingTopBottom { get { return m_PaddingTopBottom; } set { m_PaddingTopBottom = value; } }
/// <summary>
/// Whether to show ignored data on tooltip.
/// 是否显示忽略数据在tooltip上。
/// </summary>
public bool ignoreDataShow { get { return m_IgnoreDataShow; } set { m_IgnoreDataShow = value; } }
/// <summary>
/// The default display character information for ignored data.
/// 被忽略数据的默认显示字符信息。
/// </summary>
public string ignoreDataDefaultContent { get { return m_IgnoreDataDefaultContent; } set { m_IgnoreDataDefaultContent = value; } }
/// <summary>
/// The image of icon.
/// 图标的图片。
/// </summary>
public Sprite backgroundImage { get { return m_BackgroundImage; } set { m_BackgroundImage = value; SetBackground(m_BackgroundImage); } }
/// <summary>
/// Whether to trigger after always display.
/// 是否触发后一直显示。
/// </summary>
public bool alwayShow { get { return m_AlwayShow; } set { m_AlwayShow = value; } }
/// <summary>
/// The position offset of tooltip relative to the mouse position.
/// 提示框相对于鼠标位置的偏移。
/// </summary>
public Vector2 offset { get { return m_Offset; } set { m_Offset = value; } }
/// <summary>
/// the text style of content.
/// 提示框内容文本样式。
/// </summary>
public TextStyle textStyle
{
get { return m_TextStyle; }
set { if (value != null) { m_TextStyle = value; SetComponentDirty(); } }
}
/// <summary>
/// the line style of indicator line.
/// 指示线样式。
/// </summary>
public LineStyle lineStyle
{
get { return m_LineStyle; }
set { if (value != null) m_LineStyle = value; SetComponentDirty(); }
}
/// <summary>
/// 组件是否需要刷新
/// </summary>
public override bool componentDirty
{
get { return m_ComponentDirty || lineStyle.componentDirty || textStyle.componentDirty; }
}
internal override void ClearComponentDirty()
{
base.ClearComponentDirty();
lineStyle.ClearComponentDirty();
textStyle.ClearComponentDirty();
}
/// <summary>
/// 当前提示框所指示的Serie索引(目前只对散点图有效)。
/// </summary>
public Dictionary<int, List<int>> runtimeSerieIndex { get; internal set; }
/// <summary>
/// The data index currently indicated by Tooltip.
/// 当前提示框所指示的数据项索引。
/// </summary>
public List<int> runtimeDataIndex { get; internal set; }
/// <summary>
/// the value for x indicator label.
/// 指示器X轴上要显示的值。
/// </summary>
public float[] runtimeXValues { get; internal set; }
/// <summary>
/// the value for y indicator label.
/// 指示器Y轴上要显示的值。
/// </summary>
public float[] runtimeYValues { get; internal set; }
/// <summary>
/// the current pointer position.
/// 当前鼠标位置。
/// </summary>
public Vector2 runtimePointerPos { get; internal set; }
/// <summary>
/// the width of tooltip.
/// 提示框宽。
/// </summary>
public float runtimeWidth { get { return m_ContentRect.sizeDelta.x; } }
/// <summary>
/// the height of tooltip.
/// 提示框高。
/// </summary>
public float runtimeHeight { get { return m_ContentRect.sizeDelta.y; } }
/// <summary>
/// Whether the tooltip has been initialized.
/// 提示框是否已初始化。
/// </summary>
public bool runtimeInited { get { return m_GameObject != null; } }
/// <summary>
/// the gameObject of tooltip.
/// 提示框的gameObject。
/// </summary>
public GameObject runtimeGameObject { get { return m_GameObject; } }
/// <summary>
/// 当前指示的角度。
/// </summary>
public float runtimeAngle { get; internal set; }
/// <summary>
/// 当前指示的Grid索引。
/// </summary>
public int runtimeGridIndex { get; internal set; }
public int runtimePolarIndex { get; internal set; }
public static Tooltip defaultTooltip
{
get
{
var tooltip = new Tooltip
{
m_Show = true,
runtimeXValues = new float[2] { -1, -1 },
runtimeYValues = new float[2] { -1, -1 },
runtimeDataIndex = new List<int>() { -1, -1 },
lastDataIndex = new List<int>() { -1, -1 },
runtimeSerieIndex = new Dictionary<int, List<int>>()
};
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_ContentImage = m_Content.GetComponent<Image>();
m_ContentImage.raycastTarget = false;
m_ContentText = new ChartText(m_Content);
if (m_ContentText != null)
{
m_ContentTextRect = m_ContentText.gameObject.GetComponentInChildren<RectTransform>();
}
SetBackground(backgroundImage);
}
/// <summary>
/// Keep Tooltiop displayed at the top.
/// 保持Tooltiop显示在最顶上
/// </summary>
public void UpdateToTop()
{
if (m_GameObject == null) return;
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)
{
if (m_ContentImage != null)
m_ContentImage.color = color;
}
/// <summary>
/// 设置提示框文本背景图片
/// </summary>
/// <param name="sprite"></param>
public void SetBackground(Sprite sprite)
{
if (m_ContentImage != null)
{
m_ContentImage.type = Image.Type.Sliced;
m_ContentImage.sprite = sprite;
}
}
/// <summary>
/// 设置提示框文本字体颜色
/// </summary>
/// <param name="color"></param>
public void SetContentTextColor(Color color)
{
if (m_ContentText != null)
{
m_ContentText.SetColor(color);
}
}
/// <summary>
/// 设置提示框文本内容
/// </summary>
/// <param name="txt"></param>
public void UpdateContentText(string txt)
{
if (m_ContentText != null)
{
m_ContentText.SetText(txt);
float wid, hig;
if (m_FixedWidth > 0) wid = m_FixedWidth;
else if (m_MinWidth > 0 && m_ContentText.GetPreferredWidth() < m_MinWidth) wid = m_MinWidth;
else wid = m_ContentText.GetPreferredWidth() + m_PaddingLeftRight * 2;
if (m_FixedHeight > 0) hig = m_FixedHeight;
else if (m_MinHeight > 0 && m_ContentText.GetPreferredHeight() < m_MinHeight) hig = m_MinHeight;
else hig = m_ContentText.GetPreferredHeight() + m_PaddingTopBottom * 2;
if (m_ContentRect != null) m_ContentRect.sizeDelta = new Vector2(wid, hig);
if (m_ContentTextRect != null)
{
m_ContentTextRect.anchoredPosition = new Vector3(m_PaddingLeftRight, -m_PaddingTopBottom);
}
}
}
/// <summary>
/// 清除提示框指示数据
/// </summary>
internal void ClearValue()
{
for (int i = 0; i < runtimeDataIndex.Count; i++) runtimeDataIndex[i] = -1;
for (int i = 0; i < runtimeXValues.Length; i++) runtimeXValues[i] = -1;
for (int i = 0; i < runtimeYValues.Length; i++) runtimeYValues[i] = -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)
{
if (!flag && m_AlwayShow) return;
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 runtimeDataIndex[0] != lastDataIndex[0] ||
runtimeDataIndex[1] != lastDataIndex[1];
}
/// <summary>
/// 当前索引缓存
/// </summary>
internal void UpdateLastDataIndex()
{
lastDataIndex[0] = runtimeDataIndex[0];
if (runtimeDataIndex.Count > 1)
lastDataIndex[1] = runtimeDataIndex[1];
}
/// <summary>
/// 当前提示框是否选中数据项
/// </summary>
/// <returns></returns>
public bool IsSelected()
{
foreach (var index in runtimeDataIndex)
if (index >= 0) return true;
return false;
}
/// <summary>
/// 指定索引的数据项是否被提示框选中
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public bool IsSelected(int index)
{
foreach (var temp in runtimeDataIndex)
if (temp == index) return true;
return false;
}
public void ClearSerieDataIndex()
{
foreach (var kv in runtimeSerieIndex)
{
kv.Value.Clear();
}
}
public void AddSerieDataIndex(int serieIndex, int dataIndex)
{
if (!runtimeSerieIndex.ContainsKey(serieIndex))
{
runtimeSerieIndex[serieIndex] = new List<int>();
}
runtimeSerieIndex[serieIndex].Add(dataIndex);
}
public bool isAnySerieDataIndex()
{
foreach (var kv in runtimeSerieIndex)
{
if (kv.Value.Count > 0) return true;
}
return false;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c75ff9b455a74482db10158ca81afe89
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,196 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using System;
using UnityEngine;
namespace XCharts
{
/// <summary>
/// Vessel component for liquid chart. There can be multiple vessels in a Chart, which can be matched by vesselIndex in Serie.
/// <para>
/// 容器组件。
/// 一般用于LiquidChart。一个Chart中可以有多个Vessel,Serie中用vesselIndex来对应。
/// </para>
/// </summary>
[Serializable]
public class Vessel : MainComponent
{
public enum Shape
{
/// <summary>
/// 圆形
/// </summary>
Circle,
/// <summary>
/// 正方形。
/// </summary>
Rect,
/// <summary>
/// 三角形。
/// </summary>
Triangle,
/// <summary>
/// 菱形。
/// </summary>
Diamond,
/// <summary>
/// 不显示标记。
/// </summary>
None,
}
[SerializeField] private bool m_Show = true;
[SerializeField] private Shape m_Shape = Shape.Circle;
[SerializeField] private float m_ShapeWidth = 5f;
[SerializeField] private float m_Gap = 10f;
[SerializeField] private Color32 m_Color;
[SerializeField] private Color32 m_BackgroundColor;
[SerializeField] private bool m_AutoColor = true;
[SerializeField] private float[] m_Center = new float[2] { 0.5f, 0.5f };
[SerializeField] private float m_Radius = 0.5f;
[SerializeField] [Range(0.5f, 10f)] private float m_Smoothness = 1f;
/// <summary>
/// Whether to show the vessel.
/// 是否显示容器组件。
/// [defaut: true]
/// </summary>
public bool show
{
get { return m_Show; }
set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetVerticesDirty(); }
}
/// <summary>
/// The shape of vessel.
/// 容器形状。
/// [default: Shape.Circle]
/// </summary>
public Shape shape
{
get { return m_Shape; }
set { if (PropertyUtil.SetStruct(ref m_Shape, value)) SetVerticesDirty(); }
}
/// <summary>
/// Thickness of vessel.
/// 容器厚度。
/// [defaut: 5f]
/// </summary>
public float shapeWidth
{
get { return m_ShapeWidth; }
set { if (PropertyUtil.SetStruct(ref m_ShapeWidth, value)) SetVerticesDirty(); }
}
/// <summary>
/// The gap between the vessel and the liquid.
/// 间隙。容器和液体的间隙。
/// [defaut: 10f]
/// </summary>
public float gap
{
get { return m_Gap; }
set { if (PropertyUtil.SetStruct(ref m_Gap, value)) SetVerticesDirty(); }
}
/// <summary>
/// The center of vesselß. The center[0] is the x-coordinate, and the center[1] is the y-coordinate.
/// When value between 0 and 1 represents a percentage relative to the chart.
/// 中心点。数组的第一项是横坐标,第二项是纵坐标。
/// 当值为0-1之间时表示百分比,设置成百分比时表示图表宽高最小值的百分比。
/// [default:[0.5f,0.45f]]
/// </summary>
public float[] center
{
get { return m_Center; }
set { if (value != null) { m_Center = value; SetAllDirty(); } }
}
/// <summary>
/// The radius of vessel.
/// When value between 0 and 1 represents a percentage relative to the chart.
/// 半径。
/// [default: 0.35f]
/// </summary>
public float radius
{
get { return m_Radius; }
set { if (PropertyUtil.SetStruct(ref m_Radius, value)) SetAllDirty(); }
}
/// <summary>
/// The smoothness of wave.
/// 水波平滑度。
/// [default: 1f]
/// </summary>
public float smoothness
{
get { return m_Smoothness; }
set { if (PropertyUtil.SetStruct(ref m_Smoothness, value)) SetAllDirty(); }
}
/// <summary>
/// Background color of polar, which is transparent by default.
/// 背景色,默认透明。
/// [default: `Color.clear`]
/// </summary>
public Color32 backgroundColor
{
get { return m_BackgroundColor; }
set { if (PropertyUtil.SetColor(ref m_BackgroundColor, value)) SetVerticesDirty(); }
}
/// <summary>
/// Vessel color. The default is consistent with Serie.
/// 容器颜色。默认和serie一致。
/// </summary>
public Color32 color
{
get { return m_Color; }
set { if (PropertyUtil.SetColor(ref m_Color, value)) SetVerticesDirty(); }
}
/// <summary>
/// Whether automatic color. If true, the color matches serie.
/// 是否自动颜色。为true时颜色会和serie一致。
/// [default: true]
/// </summary>
public bool autoColor
{
get { return m_AutoColor; }
set { if (PropertyUtil.SetStruct(ref m_AutoColor, value)) SetVerticesDirty(); }
}
public int index { get; internal set; }
/// <summary>
/// the runtime center position of vessel.
/// 运行时中心点。
/// </summary>
public Vector3 runtimeCenterPos { get; internal set; }
/// <summary>
/// the runtime radius of vessel.
/// 运行时半径。
/// </summary>
public float runtimeRadius { get; internal set; }
/// <summary>
/// The actual radius after deducting shapeWidth and gap.
/// 运行时内半径。扣除厚度和间隙后的实际半径。
/// </summary>
public float runtimeInnerRadius { get; internal set; }
public static Vessel defaultVessel
{
get
{
var vessel = new Vessel
{
m_Show = true,
m_Shape = Shape.Circle,
m_ShapeWidth = 5,
m_Gap = 10,
m_Radius = 0.35f,
m_AutoColor = true,
m_Color = new Color32(70, 70, 240, 255),
m_Smoothness = 1
};
vessel.center[0] = 0.5f;
vessel.center[1] = 0.45f;
return vessel;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 04afad352c62a405691c66f18c3f9db7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,579 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
/// <summary>
/// VisualMap component. Mapping data to visual elements such as colors.
/// 视觉映射组件。用于进行『视觉编码』,也就是将数据映射到视觉元素(视觉通道)。
/// </summary>
[System.Serializable]
public class VisualMap : MainComponent
{
/// <summary>
/// 类型。分为连续型和分段型。
/// </summary>
public enum Type
{
/// <summary>
/// 连续型。
/// </summary>
Continuous,
/// <summary>
/// 分段型。
/// </summary>
Piecewise
}
/// <summary>
/// 方向。X轴还是Y轴。
/// </summary>
public enum Direction
{
/// <summary>
/// 默认方向。
/// </summary>
Default,
/// <summary>
/// X轴方向。
/// </summary>
X,
/// <summary>
/// Y轴方向。
/// </summary>
Y
}
/// <summary>
/// 选择模式
/// </summary>
public enum SelectedMode
{
/// <summary>
/// 多选。
/// </summary>
Multiple,
/// <summary>
/// 单选。
/// </summary>
Single
}
[SerializeField] private bool m_Enable = false;
[SerializeField] private bool m_Show = true;
[SerializeField] private Type m_Type = Type.Continuous;
[SerializeField] private Direction m_Direction = Direction.Default;
[SerializeField] private SelectedMode m_SelectedMode = SelectedMode.Multiple;
[SerializeField] private float m_Min = 0;
[SerializeField] private float m_Max = 100f;
[SerializeField] private float[] m_Range = new float[2] { 0, 100f };
[SerializeField] private string[] m_Text = new string[2] { "", "" };
[SerializeField] private float[] m_TextGap = new float[2] { 10f, 10f };
[SerializeField] private int m_SplitNumber = 5;
[SerializeField] private bool m_Calculable = false;
[SerializeField] private bool m_Realtime = true;
[SerializeField] private float m_ItemWidth = 20f;
[SerializeField] private float m_ItemHeight = 140f;
[SerializeField] private float m_BorderWidth = 0;
[SerializeField] private int m_Dimension = -1;
[SerializeField] private bool m_HoverLink = true;
[SerializeField] private bool m_AutoMinMax = true;
[SerializeField] private Orient m_Orient = Orient.Horizonal;
[SerializeField] private Location m_Location = Location.defaultLeft;
[SerializeField] private List<Color32> m_InRange = new List<Color32>();
[SerializeField] private List<Color32> m_OutOfRange = new List<Color32>();
/// <summary>
/// Whether enable visualMap component.
///
/// 是否开启组件功能。
///
/// [default: false]
/// </summary>
public bool enable
{
get { return m_Enable; }
set { if (PropertyUtil.SetStruct(ref m_Enable, value)) SetVerticesDirty(); }
}
/// <summary>
/// Whether to display components. If set to false, it will not show up, but the data mapping function still exists.
///
/// 是否显示组件。如果设置为 false,不会显示,但是数据映射的功能还存在。
///
/// [default: true]
/// </summary>
public bool show
{
get { return m_Show; }
set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetVerticesDirty(); }
}
/// <summary>
/// the type of visualmap component.
/// 组件类型。
/// </summary>
public Type type
{
get { return m_Type; }
set { if (PropertyUtil.SetStruct(ref m_Type, value)) SetVerticesDirty(); }
}
/// <summary>
/// 映射方向。
/// </summary>
public Direction direction
{
get { return m_Direction; }
set { if (PropertyUtil.SetStruct(ref m_Direction, value)) SetVerticesDirty(); }
}
/// <summary>
/// the selected mode for Piecewise visualMap.
/// 选择模式。
/// </summary>
public SelectedMode selectedMode
{
get { return m_SelectedMode; }
set { if (PropertyUtil.SetStruct(ref m_SelectedMode, value)) SetVerticesDirty(); }
}
/// <summary>
/// The minimum allowed. 'min' must be user specified. [visualmap.min, visualmap.max] forms the "domain" of the visualMap.
///
/// 允许的最小值。`autoMinMax`为`false`时必须指定。[visualMap.min, visualMap.max] 形成了视觉映射的『定义域』。
/// </summary>
public float min
{
get { return m_Min; }
set { if (PropertyUtil.SetStruct(ref m_Min, value)) SetVerticesDirty(); }
}
/// <summary>
/// The maximum allowed. 'max' must be user specified. [visualmap.min, visualmap.max] forms the "domain" of the visualMap.
///
/// 允许的最大值。`autoMinMax`为`false`时必须指定。[visualMap.min, visualMax.max] 形成了视觉映射的『定义域』。
/// </summary>
public float max
{
get { return m_Max; }
set { m_Max = (value < min ? min + 1 : value); SetVerticesDirty(); }
}
/// <summary>
/// Specifies the position of the numeric value corresponding to the handle. Range should be within the range of [min,max].
///
/// 指定手柄对应数值的位置。range 应在[min,max]范围内。
/// </summary>
public float[] range { get { return m_Range; } }
/// <summary>
/// Text on both ends.
/// 两端的文本,如 ['High', 'Low']。
/// </summary>
public string[] text { get { return m_Text; } }
/// <summary>
/// The distance between the two text bodies.
/// 两端文字主体之间的距离,单位为px。
/// </summary>
public float[] textGap { get { return m_TextGap; } }
/// <summary>
/// For continuous data, it is automatically evenly divided into several segments
/// and automatically matches the size of inRange color list when the default is 0.
///
/// 对于连续型数据,自动平均切分成几段,默认为0时自动匹配inRange颜色列表大小。
/// </summary>
/// <value></value>
public int splitNumber
{
get { return m_SplitNumber; }
set { if (PropertyUtil.SetStruct(ref m_SplitNumber, value)) SetVerticesDirty(); }
}
/// <summary>
/// Whether the handle used for dragging is displayed (the handle can be dragged to adjust the selected range).
///
/// 是否显示拖拽用的手柄(手柄能拖拽调整选中范围)。
/// </summary>
public bool calculable
{
get { return m_Calculable; }
set { if (PropertyUtil.SetStruct(ref m_Calculable, value)) SetVerticesDirty(); }
}
/// <summary>
/// Whether to update in real time while dragging.
///
/// 拖拽时,是否实时更新。
/// </summary>
public bool realtime
{
get { return m_Realtime; }
set { if (PropertyUtil.SetStruct(ref m_Realtime, value)) SetVerticesDirty(); }
}
/// <summary>
/// The width of the figure, that is, the width of the color bar.
///
/// 图形的宽度,即颜色条的宽度。
/// </summary>
public float itemWidth
{
get { return m_ItemWidth; }
set { if (PropertyUtil.SetStruct(ref m_ItemWidth, value)) SetVerticesDirty(); }
}
/// <summary>
/// The height of the figure, that is, the height of the color bar.
///
/// 图形的高度,即颜色条的高度。
/// </summary>
public float itemHeight
{
get { return m_ItemHeight; }
set { if (PropertyUtil.SetStruct(ref m_ItemHeight, value)) SetVerticesDirty(); }
}
/// <summary>
/// Border line width.
///
/// 边框线宽,单位px。
/// </summary>
public float borderWidth
{
get { return m_BorderWidth; }
set { if (PropertyUtil.SetStruct(ref m_BorderWidth, value)) SetVerticesDirty(); }
}
/// <summary>
/// Specifies "which dimension" of the data to map to the visual element. "Data" is series.data.
/// Starting at 1, the default is 0 to take the last dimension in data.
///
/// 指定用数据的『哪个维度』,映射到视觉元素上。『数据』即 series.data。从1开始,默认为0取 data 中最后一个维度。
/// </summary>
public int dimension
{
get { return m_Dimension; }
set { if (PropertyUtil.SetStruct(ref m_Dimension, value)) SetVerticesDirty(); }
}
/// <summary>
/// When the hoverLink function is turned on, when the mouse hovers over the visualMap component,
/// the corresponding value of the mouse position is highlighted in the corresponding graphic element in the diagram.
/// Conversely, when the mouse hovers over a graphic element in a diagram,
/// the corresponding value of the visualMap component is triangulated in the corresponding position.
///
/// 打开 hoverLink 功能时,鼠标悬浮到 visualMap 组件上时,鼠标位置对应的数值 在 图表中对应的图形元素,会高亮。
/// 反之,鼠标悬浮到图表中的图形元素上时,在 visualMap 组件的相应位置会有三角提示其所对应的数值。
/// </summary>
/// <value></value>
public bool hoverLink
{
get { return m_HoverLink; }
set { if (PropertyUtil.SetStruct(ref m_HoverLink, value)) SetVerticesDirty(); }
}
/// <summary>
/// Automatically set min, Max value
/// 自动设置min,max的值
/// </summary>
public bool autoMinMax
{
get { return m_AutoMinMax; }
set { if (PropertyUtil.SetStruct(ref m_AutoMinMax, value)) SetVerticesDirty(); }
}
/// <summary>
/// Specify whether the layout of component is horizontal or vertical.
///
/// 布局方式是横还是竖。
/// </summary>
public Orient orient
{
get { return m_Orient; }
set { if (PropertyUtil.SetStruct(ref m_Orient, value)) SetVerticesDirty(); }
}
/// <summary>
/// The location of component.
/// 组件显示的位置。
/// </summary>
public Location location
{
get { return m_Location; }
set { if (PropertyUtil.SetClass(ref m_Location, value)) SetVerticesDirty(); }
}
/// <summary>
/// Defines the visual color in the selected range.
/// 定义 在选中范围中 的视觉颜色。
/// </summary>
public List<Color32> inRange
{
get { return m_InRange; }
set { if (value != null) { m_InRange = value; SetVerticesDirty(); } }
}
/// <summary>
/// Defines a visual color outside of the selected range.
/// 定义 在选中范围外 的视觉颜色。
/// </summary>
public List<Color32> outOfRange
{
get { return m_OutOfRange; }
set { if (value != null) { m_OutOfRange = value; SetVerticesDirty(); } }
}
public override bool vertsDirty { get { return m_VertsDirty || location.anyDirty; } }
internal override void ClearVerticesDirty()
{
base.ClearVerticesDirty();
location.ClearVerticesDirty();
}
internal override void ClearComponentDirty()
{
base.ClearComponentDirty();
location.ClearComponentDirty();
}
/// <summary>
/// 鼠标悬停选中的index
/// </summary>
/// <value></value>
public int runtimeSelectedIndex { get; internal set; }
public float runtimeSelectedValue { get; internal set; }
/// <summary>
/// the current pointer position.
/// 当前鼠标位置。
/// </summary>
public Vector2 runtimePointerPos { get; internal set; }
public bool runtimeIsVertical { get { return orient == Orient.Vertical; } }
public float rangeMin
{
get
{
if (m_Range[0] < min || m_Range[0] > max) return min;
else return m_Range[0];
}
set
{
if (value >= min && value <= m_Range[1]) m_Range[0] = value;
}
}
public float rangeMax
{
get
{
if (m_Range[1] >= m_Range[0] && m_Range[1] < max) return m_Range[1];
else return max;
}
set
{
if (value >= m_Range[0] && value <= max) m_Range[1] = value;
}
}
public int runtimeSplitNumber
{
get
{
if (splitNumber > 0 && splitNumber <= m_InRange.Count) return splitNumber;
else return m_InRange.Count;
}
}
public float runtimeRangeMinHeight { get { return (rangeMin - min) / (max - min) * itemHeight; } }
public float runtimeRangeMaxHeight { get { return (rangeMax - min) / (max - min) * itemHeight; } }
private List<Color32> m_RtInRange = new List<Color32>();
public List<Color32> runtimeInRange
{
get
{
if (splitNumber == 0 || m_InRange.Count >= splitNumber || m_InRange.Count < 1 || IsPiecewise())
{
return m_InRange;
}
else
{
if (m_RtInRange.Count != runtimeSplitNumber)
{
m_RtInRange.Clear();
var total = max - min;
var diff1 = total / (m_InRange.Count - 1);
var diff2 = total / splitNumber;
var inCount = 0;
var inValue = min;
var rtValue = min;
for (int i = 0; i < splitNumber; i++)
{
rtValue += diff2;
if (rtValue > inValue + diff1)
{
inValue += diff1;
inCount++;
}
if (i == splitNumber - 1)
{
m_RtInRange.Add(m_InRange[m_InRange.Count - 1]);
}
else
{
var rate = (rtValue - inValue) / diff1;
m_RtInRange.Add(Color32.Lerp(m_InRange[inCount], m_InRange[inCount + 1], rate));
}
}
}
return m_RtInRange;
}
}
}
public Color32 GetColor(float value)
{
if (value < m_Min || value > m_Max)
{
if (m_OutOfRange.Count > 0) return m_OutOfRange[0];
else return ChartConst.clearColor32;
}
int splitNumber = runtimeInRange.Count;
if (splitNumber <= 0) return ChartConst.clearColor32;
var index = GetIndex(value);
if (m_Type == VisualMap.Type.Piecewise)
{
if (index >= 0 && index < runtimeInRange.Count)
return runtimeInRange[index];
else return ChartConst.clearColor32;
}
else
{
var diff = (m_Max - m_Min) / (splitNumber - 1);
var nowMin = m_Min + index * diff;
var rate = (value - nowMin) / diff;
if (index == splitNumber - 1) return runtimeInRange[index];
else return Color32.Lerp(runtimeInRange[index], runtimeInRange[index + 1], rate);
}
}
public int GetIndex(float value)
{
int splitNumber = runtimeInRange.Count;
if (splitNumber <= 0) return -1;
value = Mathf.Clamp(value, m_Min, m_Max);
var diff = (m_Max - m_Min) / (splitNumber - 1);
var index = -1;
for (int i = 0; i < splitNumber; i++)
{
if (value <= m_Min + (i + 1) * diff)
{
index = i;
break;
}
}
return index;
}
public bool IsPiecewise()
{
return m_Type == VisualMap.Type.Piecewise;
}
public bool IsInSelectedValue(float value)
{
if (runtimeSelectedIndex < 0) return true;
else
{
return runtimeSelectedIndex == GetIndex(value);
}
}
public float GetValue(Vector3 pos, Rect chartRect)
{
var centerPos = new Vector3(chartRect.x, chartRect.y) + location.GetPosition(chartRect.width, chartRect.height);
var pos1 = centerPos + (runtimeIsVertical ? Vector3.down : Vector3.left) * itemHeight / 2;
var pos2 = centerPos + (runtimeIsVertical ? Vector3.up : Vector3.right) * itemHeight / 2;
if (runtimeIsVertical)
{
if (pos.y < pos1.y) return min;
else if (pos.y > pos2.y) return max;
else return min + (pos.y - pos1.y) / (pos2.y - pos1.y) * (max - min);
}
else
{
if (pos.x < pos1.x) return min;
else if (pos.x > pos2.x) return max;
else return min + (pos.x - pos1.x) / (pos2.x - pos1.x) * (max - min);
}
}
public bool IsInRect(Vector3 local, Rect chartRect, float triangleLen = 20)
{
var centerPos = new Vector3(chartRect.x, chartRect.y) + location.GetPosition(chartRect.width, chartRect.height);
var diff = calculable ? triangleLen : 0;
if (local.x >= centerPos.x - itemWidth / 2 - diff && local.x <= centerPos.x + itemWidth / 2 + diff &&
local.y >= centerPos.y - itemHeight / 2 - diff && local.y <= centerPos.y + itemHeight / 2 + diff)
{
return true;
}
else
{
return false;
}
}
public bool IsInRangeRect(Vector3 local, Rect chartRect)
{
var centerPos = new Vector3(chartRect.x, chartRect.y) + location.GetPosition(chartRect.width, chartRect.height);
if (orient == Orient.Vertical)
{
var pos1 = centerPos + Vector3.down * itemHeight / 2;
return local.x >= centerPos.x - itemWidth / 2 && local.x <= centerPos.x + itemWidth / 2 &&
local.y >= pos1.y + runtimeRangeMinHeight && local.y <= pos1.y + runtimeRangeMaxHeight;
}
else
{
var pos1 = centerPos + Vector3.left * itemHeight / 2;
return local.x >= pos1.x + runtimeRangeMinHeight && local.x <= pos1.x + runtimeRangeMaxHeight &&
local.y >= centerPos.y - itemWidth / 2 && local.y <= centerPos.y + itemWidth / 2;
}
}
public bool IsInRangeMinRect(Vector3 local, Rect chartRect, float triangleLen)
{
var centerPos = new Vector3(chartRect.x, chartRect.y) + location.GetPosition(chartRect.width, chartRect.height);
if (orient == Orient.Vertical)
{
var radius = triangleLen / 2;
var pos1 = centerPos + Vector3.down * itemHeight / 2;
var cpos = new Vector3(pos1.x + itemWidth / 2 + radius, pos1.y + runtimeRangeMinHeight - radius);
return local.x >= cpos.x - radius && local.x <= cpos.x + radius &&
local.y >= cpos.y - radius && local.y <= cpos.y + radius;
}
else
{
var radius = triangleLen / 2;
var pos1 = centerPos + Vector3.left * itemHeight / 2;
var cpos = new Vector3(pos1.x + runtimeRangeMinHeight, pos1.y + itemWidth / 2 + radius);
return local.x >= cpos.x - radius && local.x <= cpos.x + radius &&
local.y >= cpos.y - radius && local.y <= cpos.y + radius;
}
}
public bool IsInRangeMaxRect(Vector3 local, Rect chartRect, float triangleLen)
{
var centerPos = new Vector3(chartRect.x, chartRect.y) + location.GetPosition(chartRect.width, chartRect.height);
if (orient == Orient.Vertical)
{
var radius = triangleLen / 2;
var pos1 = centerPos + Vector3.down * itemHeight / 2;
var cpos = new Vector3(pos1.x + itemWidth / 2 + radius, pos1.y + runtimeRangeMaxHeight + radius);
return local.x >= cpos.x - radius && local.x <= cpos.x + radius &&
local.y >= cpos.y - radius && local.y <= cpos.y + radius;
}
else
{
var radius = triangleLen / 2;
var pos1 = centerPos + Vector3.left * itemHeight / 2;
var cpos = new Vector3(pos1.x + runtimeRangeMaxHeight + radius, pos1.y + itemWidth / 2 + radius);
return local.x >= cpos.x - radius && local.x <= cpos.x + radius &&
local.y >= cpos.y - radius && local.y <= cpos.y + radius;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2df2ffc144e3347828462bb972eec23a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,122 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
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 : MainComponent
{
[SerializeField] private bool m_Show = true;
[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 { if (PropertyUtil.SetStruct(ref m_Show, value)) SetVerticesDirty(); }
}
/// <summary>
/// Distance between grid component and the left side of the container.
/// grid 组件离容器左侧的距离。
/// </summary>
public float left
{
get { return m_Left; }
set { if (PropertyUtil.SetStruct(ref m_Left, value)) SetAllDirty(); }
}
/// <summary>
/// Distance between grid component and the right side of the container.
/// grid 组件离容器右侧的距离。
/// </summary>
public float right
{
get { return m_Right; }
set { if (PropertyUtil.SetStruct(ref m_Right, value)) SetAllDirty(); }
}
/// <summary>
/// Distance between grid component and the top side of the container.
/// grid 组件离容器上侧的距离。
/// </summary>
public float top
{
get { return m_Top; }
set { if (PropertyUtil.SetStruct(ref m_Top, value)) SetAllDirty(); }
}
/// <summary>
/// Distance between grid component and the bottom side of the container.
/// grid 组件离容器下侧的距离。
/// </summary>
public float bottom
{
get { return m_Bottom; }
set { if (PropertyUtil.SetStruct(ref m_Bottom, value)) SetAllDirty(); }
}
/// <summary>
/// Background color of grid, which is transparent by default.
/// 网格背景色,默认透明。
/// </summary>
public Color backgroundColor
{
get { return m_BackgroundColor; }
set { if (PropertyUtil.SetColor(ref m_BackgroundColor, value)) SetVerticesDirty(); }
}
public int index { get; internal set; }
public float runtimeX { get; private set; }
public float runtimeY { get; private set; }
public float runtimeWidth { get; private set; }
public float runtimeHeight { get; private set; }
internal void UpdateRuntimeData(float chartX, float chartY, float chartWidth, float chartHeight)
{
var runtimeLeft = left <= 1 ? left * chartWidth : left;
var runtimeBottom = bottom <= 1 ? bottom * chartHeight : bottom;
var runtimeTop = top <= 1 ? top * chartHeight : top;
var runtimeRight = right <= 1 ? right * chartWidth : right;
runtimeX = chartX + runtimeLeft;
runtimeY = chartY + runtimeBottom;
runtimeWidth = chartWidth - runtimeLeft - runtimeRight;
runtimeHeight = chartHeight - runtimeTop - runtimeBottom;
}
public static Grid defaultGrid
{
get
{
var grid = new Grid
{
m_Show = true,
m_Left = 50,
m_Right = 30,
m_Top = 50,
m_Bottom = 30
};
return grid;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 17af60587e8a04a44a1e166cff567af8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: