3.0 - unitypackage

This commit is contained in:
monitor1394
2022-01-05 21:40:48 +08:00
parent c160867765
commit 228a4b2840
846 changed files with 105 additions and 467693 deletions

8
Runtime/Chart.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 900b05585ba864df1aa05dcdb36b324b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

33
Runtime/Chart/BarChart.cs Normal file
View File

@@ -0,0 +1,33 @@

using UnityEngine;
namespace XCharts
{
[AddComponentMenu("XCharts/BarChart", 14)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public partial class BarChart : BaseChart
{
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
AddChartComponentWhenNoExist<GridCoord>();
AddChartComponentWhenNoExist<XAxis>();
AddChartComponentWhenNoExist<YAxis>();
var tooltip = GetChartComponent<Tooltip>();
tooltip.type = Tooltip.Type.Shadow;
tooltip.trigger = Tooltip.Trigger.Axis;
RemoveData();
Bar.AddDefaultSerie(this, GenerateDefaultSerieName());
for (int i = 0; i < 5; i++)
{
AddXAxisData("x" + (i + 1));
}
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 535d2697503c2a94a887354e22a5414d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,460 @@

using UnityEngine;
using System.Collections.Generic;
using System;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace XCharts
{
/// <summary>
/// The base class of all charts.
/// 所有Chart的基类。
/// </summary>
public partial class BaseChart
{
/// <summary>
/// The name of chart.
/// </summary>
public string chartName
{
get { return m_ChartName; }
set
{
if (!string.IsNullOrEmpty(value) && XChartsMgr.ContainsChart(value))
{
Debug.LogError("chartName repeated:" + value);
}
else
{
m_ChartName = value;
}
}
}
/// <summary>
/// The theme.
/// </summary>
public ThemeStyle theme { get { return m_Theme; } set { m_Theme = value; } }
/// <summary>
/// Global parameter setting component.
/// 全局设置组件。
/// </summary>
public Settings settings { get { return m_Settings; } }
/// <summary>
/// The x of chart.
/// 图表的X
/// </summary>
public float chartX { get { return m_ChartX; } }
/// <summary>
/// The y of chart.
/// 图表的Y
/// </summary>
public float chartY { get { return m_ChartY; } }
/// <summary>
/// The width of chart.
/// 图表的宽
/// </summary>
public float chartWidth { get { return m_ChartWidth; } }
/// <summary>
/// The height of chart.
/// 图表的高
/// </summary>
public float chartHeight { get { return m_ChartHeight; } }
public Vector2 chartMinAnchor { get { return m_ChartMinAnchor; } }
public Vector2 chartMaxAnchor { get { return m_ChartMaxAnchor; } }
public Vector2 chartPivot { get { return m_ChartPivot; } }
public Vector2 chartSizeDelta { get { return m_ChartSizeDelta; } }
/// <summary>
/// The position of chart.
/// 图表的左下角起始坐标。
/// </summary>
public Vector3 chartPosition { get { return m_ChartPosition; } }
public Rect chartRect { get { return m_ChartRect; } }
/// <summary>
/// 自定义绘制回调。在绘制Serie前调用。
/// </summary>
public Action<VertexHelper> onCustomDraw { set { m_OnCustomDrawBaseCallback = value; } }
/// <summary>
/// 自定义Serie绘制回调。在每个Serie绘制完前调用。
/// </summary>
public Action<VertexHelper, Serie> onCustomDrawBeforeSerie { set { m_OnCustomDrawSerieBeforeCallback = value; } }
/// <summary>
/// 自定义Serie绘制回调。在每个Serie绘制完后调用。
/// </summary>
public Action<VertexHelper, Serie> onCustomDrawAfterSerie { set { m_OnCustomDrawSerieAfterCallback = value; } }
/// <summary>
/// 自定义Top绘制回调。在绘制Tooltip前调用。
/// </summary>
public Action<VertexHelper> onCustomDrawTop { set { m_OnCustomDrawTopCallback = value; } }
/// <summary>
/// the callback function of click pie area.
/// 点击饼图区域回调。参数PointerEventDataSerieIndexSerieDataIndex
/// </summary>
public Action<PointerEventData, int, int> onPointerClickPie { set { m_OnPointerClickPie = value; m_ForceOpenRaycastTarget = true; } get { return m_OnPointerClickPie; } }
/// <summary>
/// the callback function of click bar.
/// 点击柱形图柱条回调。参数eventData, dataIndex
/// </summary>
public Action<PointerEventData, int> onPointerClickBar { set { m_OnPointerClickBar = value; m_ForceOpenRaycastTarget = true; } }
/// <summary>
/// Redraw chart in next frame.
/// 在下一帧刷新图表。
/// </summary>
public void RefreshChart()
{
m_RefreshChart = true;
if (m_Painter) m_Painter.Refresh();
}
/// <summary>
/// Remove all series and legend data.
/// It just emptying all of serie's data without emptying the list of series.
/// 清除所有数据,系列中只是移除数据,列表会保留。
/// </summary>
public virtual void ClearData()
{
foreach(var serie in m_Series)
serie.ClearData();
foreach (var component in m_Components)
component.ClearData();
m_CheckAnimation = false;
RefreshChart();
}
/// <summary>
/// Remove all data from series and legend.
/// The series list is also cleared.
/// 清除所有系列和图例数据,系列的列表也会被清除。
/// </summary>
public virtual void RemoveData()
{
foreach (var component in m_Components)
component.ClearData();
m_Series.Clear();
m_CheckAnimation = false;
RefreshChart();
}
/// <summary>
/// Remove legend and serie by name.
/// 清除指定系列名称的数据。
/// </summary>
/// <param name="serieName">the name of serie</param>
public virtual void RemoveData(string serieName)
{
RemoveSerie(serieName);
foreach (var component in m_Components)
{
if (component is Legend)
{
var legend = component as Legend;
legend.RemoveData(serieName);
}
}
RefreshChart();
}
public virtual void UpdateLegendColor(string legendName, bool active)
{
var legendIndex = m_LegendRealShowName.IndexOf(legendName);
if (legendIndex >= 0)
{
foreach (var component in m_Components)
{
if (component is Legend)
{
var legend = component as Legend;
var iconColor = LegendHelper.GetIconColor(this, legend, legendIndex, legendName, active);
var contentColor = LegendHelper.GetContentColor(legendIndex, legend, m_Theme, active);
legend.UpdateButtonColor(legendName, iconColor);
legend.UpdateContentColor(legendName, contentColor);
}
}
}
}
/// <summary>
/// Whether serie is activated.
/// 获得指定图例名字的系列是否显示。
/// </summary>
/// <param name="legendName"></param>
/// <returns></returns>
public virtual bool IsActiveByLegend(string legendName)
{
foreach (var serie in m_Series)
{
if (serie.show && legendName.Equals(serie.serieName))
{
return true;
}
else
{
foreach (var serieData in serie.data)
{
if (serieData.show && legendName.Equals(serieData.name))
{
return true;
}
}
}
}
return false;
}
/// <summary>
/// Update chart theme.
/// 切换内置主题。
/// </summary>
/// <param name="theme">theme</param>
public bool UpdateTheme(ThemeType theme)
{
if (theme == ThemeType.Custom)
{
Debug.LogError("UpdateTheme: not support switch to Custom theme.");
return false;
}
m_Theme.sharedTheme.CopyTheme(theme);
return true;
}
/// <summary>
/// Update chart theme info.
/// 切换图表主题。
/// </summary>
/// <param name="theme">theme</param>
public void UpdateTheme(Theme theme)
{
m_Theme.sharedTheme = theme;
SetAllComponentDirty();
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(this);
#endif
}
/// <summary>
/// Whether series animation enabel.
/// 启用或关闭起始动画。
/// </summary>
/// <param name="flag"></param>
public void AnimationEnable(bool flag)
{
foreach (var serie in m_Series) serie.AnimationEnable(flag);
}
/// <summary>
/// fadeIn animation.
/// 开始渐入动画。
/// </summary>
public void AnimationFadeIn()
{
foreach (var serie in m_Series) serie.AnimationFadeIn();
}
/// <summary>
/// fadeIn animation.
/// 开始渐出动画。
/// </summary>
public void AnimationFadeOut()
{
foreach (var serie in m_Series) serie.AnimationFadeOut();
}
/// <summary>
/// Pause animation.
/// 暂停动画。
/// </summary>
public void AnimationPause()
{
foreach (var serie in m_Series) serie.AnimationPause();
}
/// <summary>
/// Stop play animation.
/// 继续动画。
/// </summary>
public void AnimationResume()
{
foreach (var serie in m_Series) serie.AnimationResume();
}
/// <summary>
/// Reset animation.
/// 重置动画。
/// </summary>
public void AnimationReset()
{
foreach (var serie in m_Series) serie.AnimationReset();
}
/// <summary>
/// 点击图例按钮
/// </summary>
/// <param name="legendIndex">图例按钮索引</param>
/// <param name="legendName">图例按钮名称</param>
/// <param name="show">显示还是隐藏</param>
public void ClickLegendButton(int legendIndex, string legendName, bool show)
{
OnLegendButtonClick(legendIndex, legendName, show);
RefreshChart();
}
/// <summary>
/// 坐标是否在图表范围内
/// </summary>
/// <param name="local"></param>
/// <returns></returns>
public bool IsInChart(Vector2 local)
{
return IsInChart(local.x, local.y);
}
public bool IsInChart(float x, float y)
{
if (x < m_ChartX || x > m_ChartX + m_ChartWidth ||
y < m_ChartY || y > m_ChartY + m_ChartHeight)
{
return false;
}
return true;
}
public void ClampInChart(ref Vector3 pos)
{
if (!IsInChart(pos.x, pos.y))
{
if (pos.x < m_ChartX) pos.x = m_ChartX;
if (pos.x > m_ChartX + m_ChartWidth) pos.x = m_ChartX + m_ChartWidth;
if (pos.y < m_ChartY) pos.y = m_ChartY;
if (pos.y > m_ChartY + m_ChartHeight) pos.y = m_ChartY + m_ChartHeight;
}
}
public Vector3 ClampInGrid(GridCoord grid, Vector3 pos)
{
if (grid.Contains(pos)) return pos;
else
{
// var pos = new Vector3(pos.x, pos.y);
if (pos.x < grid.context.x) pos.x = grid.context.x;
if (pos.x > grid.context.x + grid.context.width) pos.x = grid.context.x + grid.context.width;
if (pos.y < grid.context.y) pos.y = grid.context.y;
if (pos.y > grid.context.y + grid.context.height) pos.y = grid.context.y + grid.context.height;
return pos;
}
}
/// <summary>
/// 转换X轴和Y轴的配置
/// </summary>
/// <param name="index">坐标轴索引0或1</param>
public void CovertXYAxis(int index)
{
List<MainComponent> m_XAxes;
List<MainComponent> m_YAxes;
m_ComponentMaps.TryGetValue(typeof(XAxis), out m_XAxes);
m_ComponentMaps.TryGetValue(typeof(YAxis), out m_YAxes);
if (index >= 0 && index <= 1)
{
var xAxis = m_XAxes[index] as XAxis;
var yAxis = m_YAxes[index] as YAxis;
var tempX = xAxis.Clone();
xAxis.Copy(yAxis);
yAxis.Copy(tempX);
xAxis.context.offset = 0;
yAxis.context.offset = 0;
xAxis.context.minValue = 0;
xAxis.context.maxValue = 0;
yAxis.context.minValue = 0;
yAxis.context.maxValue = 0;
RefreshChart();
}
}
/// <summary>
/// 在下一帧刷新DataZoom
/// </summary>
public void RefreshDataZoom()
{
foreach (var handler in m_ComponentHandlers)
{
if (handler is DataZoomHandler)
{
(handler as DataZoomHandler).RefreshDataZoomLabel();
}
}
}
/// <summary>
/// 设置可缓存的最大数据量。当数据量超过该值时,会自动删除第一个值再加入最新值。
/// </summary>
public void SetMaxCache(int maxCache)
{
foreach (var serie in m_Series)
serie.maxCache = maxCache;
foreach (var component in m_Components)
{
if (component is Axis)
{
(component as Axis).maxCache = maxCache;
}
}
}
public Vector3 GetTitlePosition(Title title)
{
return chartPosition + title.location.GetPosition(chartWidth, chartHeight);
}
public int GetLegendRealShowNameIndex(string name)
{
return m_LegendRealShowName.IndexOf(name);
}
public Color32 GetLegendRealShowNameColor(string name)
{
var index = GetLegendRealShowNameIndex(name);
return theme.GetColor(index);
}
/// <summary>
/// 设置Base Painter的材质球
/// </summary>
/// <param name="material"></param>
public void SetBasePainterMaterial(Material material)
{
settings.basePainterMaterial = material;
if (m_Painter != null)
{
m_Painter.material = material;
}
}
/// <summary>
/// 设置Serie Painter的材质球
/// </summary>
/// <param name="material"></param>
public void SetSeriePainterMaterial(Material material)
{
settings.basePainterMaterial = material;
if (m_PainterList != null)
{
foreach (var painter in m_PainterList)
painter.material = material;
}
}
/// <summary>
/// 设置Top Painter的材质球
/// </summary>
/// <param name="material"></param>
public void SetTopPainterMaterial(Material material)
{
settings.topPainterMaterial = material;
if (m_PainterTop != null)
{
m_PainterTop.material = material;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1fc3767ca43f44f77a6d017fd55c8fec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,176 @@

using UnityEngine;
using System;
using UnityEngine.EventSystems;
namespace XCharts
{
/// <summary>
/// The base class of all graphs or components.
/// 所有图形的基类。
/// </summary>
public partial class BaseGraph
{
/// <summary>
/// The background component.
/// 背景组件。
/// </summary>
/// <value></value>
///public Background background { get { return m_Background; } }
/// <summary>
/// The x of graph.
/// 图形的X
/// </summary>
public float graphX { get { return m_GraphX; } }
/// <summary>
/// The y of graph.
/// 图形的Y
/// </summary>
public float graphY { get { return m_GraphY; } }
/// <summary>
/// The width of graph.
/// 图形的宽
/// </summary>
public float graphWidth { get { return m_GraphWidth; } }
/// <summary>
/// The height of graph.
/// 图形的高
/// </summary>
public float graphHeight { get { return m_GraphHeight; } }
/// <summary>
/// The position of graph.
/// 图形的左下角起始坐标。
/// </summary>
public Vector3 graphPosition { get { return m_GraphPosition; } }
public Rect graphRect { get { return m_GraphRect; } }
/// <summary>
/// The postion of pointer.
/// 鼠标位置。
/// </summary>
public Vector2 pointerPos { get; protected set; }
/// <summary>
/// Whether the mouse pointer is in the chart.
/// 鼠标是否在图表内。
/// </summary>
public bool isPointerInChart { get; protected set; }
/// <summary>
/// 警告信息。
/// </summary>
public string warningInfo { get; protected set; }
/// <summary>
/// 强制开启鼠标事件检测。
/// </summary>
public bool forceOpenRaycastTarget { get { return m_ForceOpenRaycastTarget; } set { m_ForceOpenRaycastTarget = value; } }
/// <summary>
/// 鼠标点击回调。
/// </summary>
public Action<PointerEventData, BaseGraph> onPointerClick { set { m_OnPointerClick = value; m_ForceOpenRaycastTarget = true; } }
/// <summary>
/// 鼠标按下回调。
/// </summary>
public Action<PointerEventData, BaseGraph> onPointerDown { set { m_OnPointerDown = value; m_ForceOpenRaycastTarget = true; } }
/// <summary>
/// 鼠标弹起回调。
/// </summary>
public Action<PointerEventData, BaseGraph> onPointerUp { set { m_OnPointerUp = value; m_ForceOpenRaycastTarget = true; } }
/// <summary>
/// 鼠标进入回调。
/// </summary>
public Action<PointerEventData, BaseGraph> onPointerEnter { set { m_OnPointerEnter = value; m_ForceOpenRaycastTarget = true; } }
/// <summary>
/// 鼠标退出回调。
/// </summary>
public Action<PointerEventData, BaseGraph> onPointerExit { set { m_OnPointerExit = value; m_ForceOpenRaycastTarget = true; } }
/// <summary>
/// 鼠标开始拖拽回调。
/// </summary>
public Action<PointerEventData, BaseGraph> onBeginDrag { set { m_OnBeginDrag = value; m_ForceOpenRaycastTarget = true; } }
/// <summary>
/// 鼠标拖拽回调。
/// </summary>
public Action<PointerEventData, BaseGraph> onDrag { set { m_OnDrag = value; m_ForceOpenRaycastTarget = true; } }
/// <summary>
/// 鼠标结束拖拽回调。
/// </summary>
public Action<PointerEventData, BaseGraph> onEndDrag { set { m_OnEndDrag = value; m_ForceOpenRaycastTarget = true; } }
/// <summary>
/// 鼠标滚动回调。
/// </summary>
public Action<PointerEventData, BaseGraph> onScroll { set { m_OnScroll = value; m_ForceOpenRaycastTarget = true; } }
/// <summary>
/// 设置图形的宽高在非stretch pivot下才有效其他情况需要自己调整RectTransform
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
public virtual void SetSize(float width, float height)
{
if (LayerHelper.IsFixedWidthHeight(rectTransform))
{
rectTransform.sizeDelta = new Vector2(width, height);
}
else
{
Debug.LogError("Can't set size on stretch pivot,you need to modify rectTransform by yourself.");
}
}
/// <summary>
/// 重新初始化Painter
/// </summary>
public void SetPainterDirty()
{
m_PainerDirty = true;
}
/// <summary>
/// Redraw graph in next frame.
/// 在下一帧刷新图形。
/// </summary>
public void RefreshGraph()
{
m_RefreshChart = true;
}
public void RefreshAllComponent()
{
SetAllComponentDirty();
RefreshGraph();
}
/// <summary>
/// 检测警告信息。
/// </summary>
/// <returns></returns>
public string CheckWarning()
{
warningInfo = CheckHelper.CheckChart(this);
return warningInfo;
}
/// <summary>
/// 移除所有图表子节点,会自动重新初始化。
/// </summary>
public void RemoveChartObject()
{
ChartHelper.DestroyAllChildren(transform);
//SetAllComponentDirty();
}
public bool ScreenPointToChartPoint(Vector2 screenPoint, out Vector2 chartPoint)
{
#if UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX
var relative = Display.RelativeMouseAt(screenPoint);
if(relative != Vector3.zero)
screenPoint = relative;
#endif
var cam = canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : canvas.worldCamera;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform,
screenPoint, cam, out chartPoint))
{
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ec7d385a69cce42fda86960eb0b23c3b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,35 @@

using UnityEngine;
namespace XCharts
{
[AddComponentMenu("XCharts/CandlestickChart", 23)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public class CandlestickChart : BaseChart
{
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
AddChartComponentWhenNoExist<GridCoord>();
AddChartComponentWhenNoExist<XAxis>();
AddChartComponentWhenNoExist<YAxis>();
var tooltip = GetChartComponent<Tooltip>();
tooltip.type = Tooltip.Type.Shadow;
tooltip.trigger = Tooltip.Trigger.Axis;
RemoveData();
Candlestick.AddDefaultSerie(this, GenerateDefaultSerieName());
for (int i = 0; i < GetSerie(0).dataCount; i++)
{
AddXAxisData("x" + (i + 1));
}
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7b64f0bb738cc4acfa72fff2c30212b4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,83 @@

using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
[AddComponentMenu("XCharts/HeatmapChart", 18)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public class HeatmapChart : BaseChart
{
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
var tooltip = GetChartComponent<Tooltip>();
tooltip.type = Tooltip.Type.None;
tooltip.trigger = Tooltip.Trigger.Axis;
var grid = GetOrAddChartComponent<GridCoord>();
grid.left = 100;
grid.right = 60;
grid.bottom = 60;
var xAxis = GetOrAddChartComponent<XAxis>();
xAxis.type = Axis.AxisType.Category;
xAxis.boundaryGap = true;
xAxis.splitNumber = 10;
var yAxis = GetOrAddChartComponent<YAxis>();
yAxis.type = Axis.AxisType.Category;
yAxis.boundaryGap = true;
yAxis.splitNumber = 10;
RemoveData();
var heatmapGridWid = 10f;
int xSplitNumber = (int)(grid.context.width / heatmapGridWid);
int ySplitNumber = (int)(grid.context.height / heatmapGridWid);
Heatmap.AddDefaultSerie(this, GenerateDefaultSerieName());
var visualMap = GetOrAddChartComponent<VisualMap>();
visualMap.max = 10;
visualMap.range[0] = 0f;
visualMap.range[1] = 10f;
visualMap.orient = Orient.Vertical;
visualMap.calculable = true;
visualMap.location.align = Location.Align.BottomLeft;
visualMap.location.bottom = 100;
visualMap.location.left = 30;
var colors = new List<string>{"#313695", "#4575b4", "#74add1", "#abd9e9", "#e0f3f8", "#ffffbf",
"#fee090", "#fdae61", "#f46d43", "#d73027", "#a50026"};
visualMap.inRange.Clear();
foreach (var str in colors)
{
visualMap.inRange.Add(ThemeStyle.GetColor(str));
}
for (int i = 0; i < xSplitNumber; i++)
{
xAxis.data.Add((i + 1).ToString());
}
for (int i = 0; i < ySplitNumber; i++)
{
yAxis.data.Add((i + 1).ToString());
}
for (int i = 0; i < xSplitNumber; i++)
{
for (int j = 0; j < ySplitNumber; j++)
{
var value = 0f;
var rate = Random.Range(0, 101);
if (rate > 70) value = Random.Range(8f, 10f);
else value = Random.Range(1f, 8f);
var list = new List<double> { i, j, value };
AddData(0, list);
}
}
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 31aa03cd4ce594c239ae746791b3b59f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,35 @@

using UnityEngine;
namespace XCharts
{
[AddComponentMenu("XCharts/LineChart", 13)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public class LineChart : BaseChart
{
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
AddChartComponentWhenNoExist<GridCoord>();
AddChartComponentWhenNoExist<XAxis>();
AddChartComponentWhenNoExist<YAxis>();
var tooltip = GetChartComponent<Tooltip>();
tooltip.type = Tooltip.Type.Line;
tooltip.trigger = Tooltip.Trigger.Axis;
RemoveData();
Line.AddDefaultSerie(this, GenerateDefaultSerieName());
for (int i = 0; i < 5; i++)
{
AddXAxisData("x" + (i + 1));
}
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b4f38bd00b4648c448cabfc167538f7c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,27 @@

using UnityEngine;
namespace XCharts
{
/// <summary>
/// 水位图
/// </summary>
[AddComponentMenu("XCharts/LiquidChart", 22)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public class LiquidChart : BaseChart
{
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
GetChartComponent<Tooltip>().type = Tooltip.Type.Line;
RemoveData();
Liquid.AddDefaultSerie(this, GenerateDefaultSerieName());
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 41f7e109291bd44de96fccf526e9c7f1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,34 @@

using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
[AddComponentMenu("XCharts/ParallelChart", 25)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public class ParallelChart : BaseChart
{
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
RemoveData();
AddChartComponent<ParallelCoord>();
for (int i = 0; i < 3; i++)
{
var valueAxis = AddChartComponent<ParallelAxis>();
valueAxis.type = Axis.AxisType.Value;
}
var categoryAxis = AddChartComponent<ParallelAxis>();
categoryAxis.type = Axis.AxisType.Category;
categoryAxis.position = Axis.AxisPosition.Right;
categoryAxis.data = new List<string>() { "x1", "x2", "x3", "x4", "x5" };
Parallel.AddDefaultSerie(this, GenerateDefaultSerieName());
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 161753d0d6ce541c89483f8c3a21343f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

24
Runtime/Chart/PieChart.cs Normal file
View File

@@ -0,0 +1,24 @@

using UnityEngine;
namespace XCharts
{
[AddComponentMenu("XCharts/PieChart", 15)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public class PieChart : BaseChart
{
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
var legend = GetOrAddChartComponent<Legend>();
legend.show = true;
RemoveData();
Pie.AddDefaultSerie(this, GenerateDefaultSerieName());
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d44276ba809fd92408b296835f6f7658
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@

using UnityEngine;
namespace XCharts
{
[AddComponentMenu("XCharts/RadarChart", 16)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public class RadarChart : BaseChart
{
protected override void InitComponent()
{
base.InitComponent();
}
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
RemoveData();
RemoveChartComponents<RadarCoord>();
AddChartComponent<RadarCoord>();
Radar.AddDefaultSerie(this, GenerateDefaultSerieName());
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d2231a0d3e3a5b043b074f6739be4a86
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@

using UnityEngine;
namespace XCharts
{
[AddComponentMenu("XCharts/RingChart", 20)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public class RingChart : BaseChart
{
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
GetChartComponent<Tooltip>().type = Tooltip.Type.Line;
RemoveData();
Ring.AddDefaultSerie(this, GenerateDefaultSerieName());
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0ad8949f652ee4376a4a4fe5cb32029f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,35 @@

using UnityEngine;
namespace XCharts
{
[AddComponentMenu("XCharts/ScatterChart", 17)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public class ScatterChart : BaseChart
{
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
AddChartComponentWhenNoExist<GridCoord>();
var tooltip = GetOrAddChartComponent<Tooltip>();
tooltip.type = Tooltip.Type.None;
tooltip.trigger = Tooltip.Trigger.Item;
var xAxis = GetOrAddChartComponent<XAxis>();
xAxis.type = Axis.AxisType.Value;
xAxis.boundaryGap = false;
var yAxis = GetOrAddChartComponent<YAxis>();
yAxis.type = Axis.AxisType.Value;
yAxis.boundaryGap = false;
RemoveData();
Scatter.AddDefaultSerie(this, GenerateDefaultSerieName());
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bf16aac0bd6c24a8da75846c34c5193e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,35 @@

using UnityEngine;
namespace XCharts
{
[AddComponentMenu("XCharts/SimplifiedBarChart", 27)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public class SimplifiedBarChart : BaseChart
{
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
AddChartComponentWhenNoExist<GridCoord>();
AddChartComponentWhenNoExist<XAxis>();
AddChartComponentWhenNoExist<YAxis>();
var tooltip = GetChartComponent<Tooltip>();
tooltip.type = Tooltip.Type.Line;
tooltip.trigger = Tooltip.Trigger.Axis;
RemoveData();
SimplifiedBar.AddDefaultSerie(this, GenerateDefaultSerieName());
for (int i = 0; i < GetSerie(0).dataCount; i++)
{
AddXAxisData("x" + (i + 1));
}
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aa86c3bbf8877409c9d45716fbaf92f4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,35 @@

using UnityEngine;
namespace XCharts
{
[AddComponentMenu("XCharts/SimplifiedCandlestickChart", 28)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public class SimplifiedCandlestickChart : BaseChart
{
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
AddChartComponentWhenNoExist<GridCoord>();
AddChartComponentWhenNoExist<XAxis>();
AddChartComponentWhenNoExist<YAxis>();
var tooltip = GetChartComponent<Tooltip>();
tooltip.type = Tooltip.Type.Shadow;
tooltip.trigger = Tooltip.Trigger.Axis;
RemoveData();
SimplifiedCandlestick.AddDefaultSerie(this, GenerateDefaultSerieName());
for (int i = 0; i < GetSerie(0).dataCount; i++)
{
AddXAxisData("x" + (i + 1));
}
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6dcc9bd1ca8344d938f386e6b32e8946
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,35 @@

using UnityEngine;
namespace XCharts
{
[AddComponentMenu("XCharts/SimplifiedLineChart", 26)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public class SimplifiedLineChart : BaseChart
{
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
AddChartComponentWhenNoExist<GridCoord>();
AddChartComponentWhenNoExist<XAxis>();
AddChartComponentWhenNoExist<YAxis>();
var tooltip = GetChartComponent<Tooltip>();
tooltip.type = Tooltip.Type.Line;
tooltip.trigger = Tooltip.Trigger.Axis;
RemoveData();
SimplifiedLine.AddDefaultSerie(this, GenerateDefaultSerieName());
for (int i = 0; i < GetSerie(0).dataCount; i++)
{
AddXAxisData("x" + (i + 1));
}
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a8233997c1b324ecd875a03af4d90972
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
Runtime/Component.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3be5f1d3b129a47dd8e41cffe3b8e428
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9f827513754e8436bbc63e64c5b5e6c3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,631 @@

using System.Collections.Generic;
using UnityEngine;
using System;
namespace XCharts
{
public delegate float CustomAnimationDelay(int dataIndex);
public delegate float CustomAnimationDuration(int dataIndex);
public enum AnimationType
{
/// <summary>
/// he default. An animation playback mode will be selected according to the actual situation.
/// 默认。内部会根据实际情况选择一种动画播放方式。
/// </summary>
Default,
/// <summary>
/// Play the animation from left to right.
/// 从左往右播放动画。
/// </summary>
LeftToRight,
/// <summary>
/// Play the animation from bottom to top.
/// 从下往上播放动画。
/// </summary>
BottomToTop,
/// <summary>
/// Play animations from the inside out.
/// 由内到外播放动画。
/// </summary>
InsideOut,
/// <summary>
/// Play the animation along the path.
/// 沿着路径播放动画。
/// </summary>
AlongPath,
/// <summary>
/// Play the animation clockwise.
/// 顺时针播放动画。
/// </summary>
Clockwise,
}
public enum AnimationEasing
{
Linear,
}
/// <summary>
/// the animation of serie.
/// 动画表现。
/// </summary>
[System.Serializable]
public class AnimationStyle : ChildComponent
{
[SerializeField] private bool m_Enable = true;
[SerializeField] private AnimationType m_Type;
[SerializeField] private AnimationEasing m_Easting;
[SerializeField] private int m_Threshold = 2000;
[SerializeField] private float m_FadeInDuration = 1000;
[SerializeField] private float m_FadeInDelay = 0;
[SerializeField] private float m_FadeOutDuration = 1000f;
[SerializeField] private float m_FadeOutDelay = 0;
[SerializeField] private bool m_DataChangeEnable = true;
[SerializeField] private float m_DataChangeDuration = 500;
[SerializeField] private float m_ActualDuration;
[SerializeField] private bool m_AlongWithLinePath;
/// <summary>
/// 自定义渐入动画延时函数。返回ms值。
/// </summary>
public CustomAnimationDelay customFadeInDelay;
/// <summary>
/// 自定义渐入动画时长函数。返回ms值。
/// </summary>
public CustomAnimationDuration customFadeInDuration;
/// <summary>
/// 自定义渐出动画延时函数。返回ms值。
/// </summary>
public CustomAnimationDelay customFadeOutDelay;
/// <summary>
/// 自定义渐出动画时长函数。返回ms值。
/// </summary>
public CustomAnimationDuration customFadeOutDuration;
public AnimationStyleContext context = new AnimationStyleContext();
/// <summary>
/// Whether to enable animation.
/// 是否开启动画效果。
/// </summary>
public bool enable { get { return m_Enable; } set { m_Enable = value; } }
/// <summary>
/// The type of animation.
/// 动画类型。
/// </summary>
public AnimationType type { get { return m_Type; } set { m_Type = value; } }
/// <summary>
/// Easing method used for the first animation.
/// 动画的缓动效果。
/// </summary>
//public Easing easing { get { return m_Easting; } set { m_Easting = value; } }
/// <summary>
/// The milliseconds duration of the fadeIn animation.
/// 设定的渐入动画时长毫秒。如果要设置单个数据项的渐入时长可以用代码定制customFadeInDuration。
/// </summary>
public float fadeInDuration { get { return m_FadeInDuration; } set { m_FadeInDuration = value < 0 ? 0 : value; } }
/// <summary>
/// The milliseconds duration of the fadeOut animation.
/// 设定的渐出动画时长毫秒。如果要设置单个数据项的渐出时长可以用代码定制customFadeOutDuration。
/// </summary>
public float fadeOutDuration { get { return m_FadeOutDuration; } set { m_FadeOutDuration = value < 0 ? 0 : value; } }
/// <summary>
/// The milliseconds actual duration of the first animation.
/// 实际的动画时长(毫秒)。
/// </summary>
public float actualDuration { get { return m_ActualDuration; } }
/// <summary>
/// Whether to set graphic number threshold to animation. Animation will be disabled when graphic number is larger than threshold.
/// 是否开启动画的阈值,当单个系列显示的图形数量大于这个阈值时会关闭动画。
/// </summary>
public int threshold { get { return m_Threshold; } set { m_Threshold = value; } }
/// <summary>
/// The milliseconds delay before updating the first animation.
/// 渐入动画延时毫秒。如果要设置单个数据项的延时可以用代码定制customFadeInDelay。
/// </summary>
public float fadeInDelay { get { return m_FadeInDelay; } set { m_FadeInDelay = value < 0 ? 0 : value; } }
/// <summary>
/// 渐出动画延时毫秒。如果要设置单个数据项的延时可以用代码定制customFadeOutDelay。
/// </summary>
public float fadeOutDelay { get { return m_FadeOutDelay; } set { m_FadeInDelay = value < 0 ? 0 : value; } }
/// <summary>
/// 是否开启数据变更动画。
/// </summary>
public bool dataChangeEnable { get { return m_DataChangeEnable; } set { m_DataChangeEnable = value; } }
/// <summary>
/// The milliseconds duration of the data change animation.
/// 数据变更的动画时长(毫秒)。
/// </summary>
public float dataChangeDuration { get { return m_DataChangeDuration; } set { m_DataChangeDuration = value < 0 ? 0 : value; } }
/// <summary>
/// 渐入动画完成回调
/// </summary>
public Action fadeInFinishCallback { get; set; }
/// <summary>
/// 渐出动画完成回调
/// </summary>
public Action fadeOutFinishCallback { get; set; }
private Dictionary<int, float> m_ItemCurrProgress = new Dictionary<int, float>();
private Dictionary<int, float> m_ItemDestProgress = new Dictionary<int, float>();
private bool m_FadeIn = false;
private bool m_IsEnd = true;
private bool m_IsPause = false;
private bool m_FadeOut = false;
private bool m_FadeOuted = false;
private bool m_IsInit = false;
private float startTime { get; set; }
private float m_CurrDetailProgress;
private float m_DestDetailProgress;
private float m_TotalDetailProgress;
private float m_CurrSymbolProgress;
private Vector3 m_LinePathLastPos;
public void FadeIn()
{
if (m_FadeOut)
return;
if (m_IsPause)
{
m_IsPause = false;
return;
}
if (m_FadeIn)
return;
startTime = Time.time;
m_FadeIn = true;
m_IsEnd = false;
m_IsInit = false;
m_IsPause = false;
m_FadeOuted = false;
m_CurrDetailProgress = 0;
m_DestDetailProgress = 1;
m_CurrSymbolProgress = 0;
m_ItemCurrProgress.Clear();
m_ItemDestProgress.Clear();
}
public void Restart()
{
Reset();
FadeIn();
}
public void FadeOut()
{
if (m_IsPause)
{
m_IsPause = false;
return;
}
m_FadeOut = true;
startTime = Time.time;
m_FadeIn = true;
m_IsEnd = false;
m_IsInit = false;
m_IsPause = false;
m_CurrDetailProgress = 0;
m_DestDetailProgress = 1;
m_CurrSymbolProgress = 0;
m_ItemCurrProgress.Clear();
m_ItemDestProgress.Clear();
}
public void Pause()
{
if (!m_IsPause)
{
m_IsPause = true;
}
}
public void Resume()
{
if (m_IsPause)
{
m_IsPause = false;
}
}
private void End()
{
if (m_IsEnd)
return;
m_ActualDuration = (int)((Time.time - startTime) * 1000) - (m_FadeOut ? fadeOutDelay : fadeInDelay);
m_IsEnd = true;
m_IsInit = false;
if (m_FadeIn)
{
m_FadeIn = false;
if (fadeInFinishCallback != null)
{
fadeInFinishCallback();
}
}
if (m_FadeOut)
{
m_FadeOut = false;
m_FadeOuted = true;
if (fadeOutFinishCallback != null)
{
fadeOutFinishCallback();
}
}
}
public void Reset()
{
m_FadeIn = false;
m_IsEnd = true;
m_IsInit = false;
m_IsPause = false;
m_FadeOut = false;
m_FadeOuted = false;
m_ItemCurrProgress.Clear();
}
public void InitProgress(float curr, float dest)
{
if (m_IsInit || m_IsEnd)
return;
if (curr > dest)
return;
m_IsInit = true;
m_TotalDetailProgress = dest - curr;
if (m_FadeOut)
{
m_CurrDetailProgress = dest;
m_DestDetailProgress = curr;
}
else
{
m_CurrDetailProgress = curr;
m_DestDetailProgress = dest;
}
}
public void InitProgress(List<Vector3> paths, bool isY)
{
if (paths.Count < 1) return;
var sp = paths[0];
var ep = paths[paths.Count - 1];
var currDetailProgress = isY ? sp.y : sp.x;
var totalDetailProgress = isY ? ep.y : ep.x;
if (context.type == AnimationType.AlongPath)
{
currDetailProgress = 0;
totalDetailProgress = 0;
var lp = sp;
for (int i = 1; i < paths.Count; i++)
{
var np = paths[i];
totalDetailProgress += Vector3.Distance(np, lp);
lp = np;
}
m_LinePathLastPos = sp;
context.currentPathDistance = 0;
}
InitProgress(currDetailProgress, totalDetailProgress);
}
private void SetDataCurrProgress(int index, float state)
{
m_ItemCurrProgress[index] = state;
}
private float GetDataCurrProgress(int index, float initValue, float destValue, ref bool isBarEnd)
{
if (IsInDelay())
{
isBarEnd = false;
return initValue;
}
var c1 = !m_ItemCurrProgress.ContainsKey(index);
var c2 = !m_ItemDestProgress.ContainsKey(index);
if (c1 || c2)
{
if (c1)
m_ItemCurrProgress.Add(index, initValue);
if (c2)
m_ItemDestProgress.Add(index, destValue);
isBarEnd = false;
}
else
{
isBarEnd = m_ItemCurrProgress[index] == m_ItemDestProgress[index];
}
return m_ItemCurrProgress[index];
}
public bool IsFinish()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
return true;
#endif
if (!m_Enable || m_IsEnd)
return true;
if (IsIndexAnimation())
return m_CurrDetailProgress > m_DestDetailProgress;
if (IsItemAnimation())
return false;
return true;
}
public bool IsInFadeOut()
{
return m_FadeOut;
}
public bool IsInDelay()
{
if (m_FadeOut)
return (fadeOutDelay > 0 && Time.time - startTime < fadeOutDelay / 1000);
else
return (fadeInDelay > 0 && Time.time - startTime < fadeInDelay / 1000);
}
public bool IsItemAnimation()
{
return context.type == AnimationType.BottomToTop || context.type == AnimationType.InsideOut;
}
public bool IsIndexAnimation()
{
return context.type == AnimationType.LeftToRight
|| context.type == AnimationType.Clockwise
|| context.type == AnimationType.AlongPath;
}
public float GetIndexDelay(int dataIndex)
{
if (m_FadeOut && customFadeOutDelay != null)
return customFadeOutDelay(dataIndex);
else if (m_FadeIn && customFadeInDelay != null)
return customFadeInDelay(dataIndex);
else
return 0;
}
public bool IsInIndexDelay(int dataIndex)
{
return Time.time - startTime < GetIndexDelay(dataIndex) / 1000f;
}
public bool IsAllOutDelay(int dataCount)
{
var nowTime = Time.time - startTime;
for (int i = 0; i < dataCount; i++)
{
if (nowTime < GetIndexDelay(i) / 1000)
return false;
}
return true;
}
public bool CheckDetailBreak(float detail)
{
if (!IsIndexAnimation())
return false;
return !IsFinish() && detail > m_CurrDetailProgress;
}
public bool CheckDetailBreak(Vector3 pos, bool isYAxis)
{
if (!IsIndexAnimation())
return false;
if (IsFinish())
return false;
if (context.type == AnimationType.AlongPath)
{
context.currentPathDistance += Vector3.Distance(pos, m_LinePathLastPos);
m_LinePathLastPos = pos;
return CheckDetailBreak(context.currentPathDistance);
}
else
{
if (isYAxis)
return pos.y > m_CurrDetailProgress;
else
return pos.x > m_CurrDetailProgress;
}
}
public void CheckProgress()
{
if (IsItemAnimation() && context.isAllItemAnimationEnd)
{
End();
return;
}
CheckProgress(m_TotalDetailProgress);
}
public void CheckProgress(double total)
{
if (IsFinish())
return;
if (!m_IsInit || m_IsPause || m_IsEnd)
return;
if (IsInDelay())
return;
m_ActualDuration = (int)((Time.time - startTime) * 1000) - fadeInDelay;
var duration = GetCurrAnimationDuration();
var delta = (float)(total / duration * Time.deltaTime);
if (m_FadeOut)
{
m_CurrDetailProgress -= delta;
if (m_CurrDetailProgress <= m_DestDetailProgress)
{
m_CurrDetailProgress = m_DestDetailProgress;
End();
}
}
else
{
m_CurrDetailProgress += delta;
if (m_CurrDetailProgress >= m_DestDetailProgress)
{
m_CurrDetailProgress = m_DestDetailProgress;
End();
}
}
}
internal float GetCurrAnimationDuration(int dataIndex = -1)
{
if (dataIndex >= 0)
{
if (m_FadeOut && customFadeOutDuration != null)
return customFadeOutDuration(dataIndex) / 1000f;
if (m_FadeIn && customFadeInDuration != null)
return customFadeInDuration(dataIndex) / 1000f;
}
if (m_FadeOut)
return m_FadeOutDuration > 0 ? m_FadeOutDuration / 1000 : 1f;
else
return m_FadeInDuration > 0 ? m_FadeInDuration / 1000 : 1f;
}
internal float CheckItemProgress(int dataIndex, float barHig, ref bool isEnd)
{
isEnd = false;
var initHig = m_FadeOut ? barHig : 0;
var destHig = m_FadeOut ? 0 : barHig;
var currHig = GetDataCurrProgress(dataIndex, initHig, destHig, ref isEnd);
if (isEnd || IsFinish())
{
return m_FadeOuted ? 0 : barHig;
}
else if (IsInDelay() || IsInIndexDelay(dataIndex))
{
return m_FadeOut ? barHig : 0;
}
else if (m_IsPause)
{
return currHig;
}
else
{
var duration = GetCurrAnimationDuration(dataIndex);
var delta = barHig / duration * Time.deltaTime;
currHig = currHig + (m_FadeOut ? -delta : delta);
if (m_FadeOut)
{
if ((initHig > 0 && currHig <= 0) || (initHig < 0 && currHig >= 0))
{
currHig = 0;
isEnd = true;
}
}
else if (Mathf.Abs(currHig) >= Mathf.Abs(barHig))
{
currHig = barHig;
isEnd = true;
}
SetDataCurrProgress(dataIndex, currHig);
return currHig;
}
}
internal void CheckSymbol(float dest)
{
if (!enable || m_IsEnd || m_IsPause || !m_IsInit)
return;
if (IsInDelay())
return;
var duration = GetCurrAnimationDuration();
var delta = dest / duration * Time.deltaTime;
if (m_FadeOut)
{
m_CurrSymbolProgress -= delta;
if (m_CurrSymbolProgress < 0)
m_CurrSymbolProgress = 0;
}
else
{
m_CurrSymbolProgress += delta;
if (m_CurrSymbolProgress > dest)
m_CurrSymbolProgress = dest;
}
}
public float GetSysmbolSize(float dest)
{
#if UNITY_EDITOR
if (!Application.isPlaying)
return dest;
#endif
if (!enable)
return dest;
if (m_IsEnd)
return m_FadeOut ? 0 : dest;
return m_CurrSymbolProgress;
}
public float GetCurrDetail()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
return m_DestDetailProgress;
#endif
return m_CurrDetailProgress;
}
public float GetCurrRate()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
return 1;
#endif
if (!enable || m_IsEnd)
return 1;
return m_CurrDetailProgress;
}
public int GetCurrIndex()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
return -1;
#endif
if (!enable || m_IsEnd)
return -1;
return (int)m_CurrDetailProgress;
}
public float GetUpdateAnimationDuration()
{
if (m_Enable && m_DataChangeEnable && IsFinish())
return m_DataChangeDuration;
else
return 0;
}
public bool HasFadeOut()
{
return enable && m_FadeOuted && m_IsEnd;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e31c30f2ef61c48718a626f93307ce92
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
public struct AnimationStyleContext
{
public AnimationType type;
internal float currentPathDistance;
internal bool isAllItemAnimationEnd;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b3dc504960589413fa6a76267067775c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,66 @@
using UnityEngine;
using XUGL;
namespace XCharts
{
public static class AnimationStyleHelper
{
public static float CheckDataAnimation(BaseChart chart, Serie serie, int dataIndex, float destProgress)
{
if (!serie.animation.IsItemAnimation())
{
serie.animation.context.isAllItemAnimationEnd = false;
return destProgress;
}
if (serie.animation.IsFinish())
{
serie.animation.context.isAllItemAnimationEnd = false;
return destProgress;
}
var isDataAnimationEnd = true;
float currHig = serie.animation.CheckItemProgress(dataIndex, destProgress, ref isDataAnimationEnd);
if (!isDataAnimationEnd)
{
serie.animation.context.isAllItemAnimationEnd = false;
}
return currHig;
}
public static void UpdateSerieAnimation(Serie serie)
{
var serieType = serie.GetType();
var animationType = AnimationType.LeftToRight;
if (serieType.IsDefined(typeof(DefaultAnimationAttribute), false))
{
animationType = serieType.GetAttribute<DefaultAnimationAttribute>().type;
}
UpdateAnimationType(serie.animation, animationType);
serie.animation.context.isAllItemAnimationEnd = true;
}
public static void UpdateAnimationType(AnimationStyle animation, AnimationType defaultType)
{
animation.context.type = animation.type == AnimationType.Default
? defaultType
: animation.type;
}
public static bool GetAnimationPosition(AnimationStyle animation, bool isY, Vector3 lp, Vector3 cp, float progress, ref Vector3 ip)
{
if (animation.context.type == AnimationType.AlongPath)
{
var dist = Vector3.Distance(lp, cp);
var rate = (dist - animation.context.currentPathDistance + animation.GetCurrDetail()) / dist;
ip = Vector3.Lerp(lp, cp, rate);
return true;
}
else
{
var startPos = isY ? new Vector3(-10000, progress) : new Vector3(progress, -10000);
var endPos = isY ? new Vector3(10000, progress) : new Vector3(progress, 10000);
return UGLHelper.GetIntersection(lp, cp, startPos, endPos, ref ip);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 54cadaee0856b4f7085787fd450eec37
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 194a62edf7ec2484fa2eebbf5bde3e95
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 28b88ca3453f04fbdb23a53b5bcb4bf7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,44 @@
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
/// <summary>
/// Angle axis of Polar Coordinate.
/// 极坐标系的角度轴。
/// </summary>
[System.Serializable]
[ComponentHandler(typeof(AngleAxisHandler), true)]
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 override void SetDefaultValue()
{
m_Show = true;
m_Type = AxisType.Value;
m_SplitNumber = 12;
m_StartAngle = 90;
m_BoundaryGap = false;
m_Data = new List<string>(12);
splitLine.show = true;
splitLine.lineStyle.type = LineStyle.Type.Solid;
axisLabel.textLimit.enable = false;
minMaxType = AxisMinMaxType.Custom;
min = 0;
max = 360;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 787015be923a74e1da4000c7abc2dcdf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,134 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class AngleAxisHandler : MainComponentHandler<AngleAxis>
{
public override void InitComponent()
{
InitAngleAxis(component);
}
public override void Update()
{
component.startAngle = 90 - component.startAngle;
UpdateAxisMinMaxValue(component);
}
public override void DrawBase(VertexHelper vh)
{
DrawAngleAxis(vh, component);
}
private void UpdateAxisMinMaxValue(AngleAxis axis, bool updateChart = true)
{
if (axis.IsCategory() || !axis.show) return;
double tempMinValue = 0;
double tempMaxValue = 0;
SeriesHelper.GetYMinMaxValue(chart.series, null, axis.polarIndex, true, axis.inverse, out tempMinValue,
out tempMaxValue, true);
AxisHelper.AdjustMinMaxValue(axis, ref tempMinValue, ref tempMaxValue, true);
if (tempMinValue != axis.context.minValue || tempMaxValue != axis.context.maxValue)
{
axis.UpdateMinMaxValue(tempMinValue, tempMaxValue);
axis.context.offset = 0;
axis.context.lastCheckInverse = axis.inverse;
if (updateChart)
{
UpdateAxisLabelText(axis);
chart.RefreshChart();
}
}
}
internal void UpdateAxisLabelText(AngleAxis axis)
{
var runtimeWidth = 360;
axis.UpdateLabelText(runtimeWidth, null, false);
}
private void InitAngleAxis(AngleAxis axis)
{
var polar = chart.GetChartComponent<PolarCoord>(axis.polarIndex);
if (polar == null) return;
PolarHelper.UpdatePolarCenter(polar, chart.chartPosition, chart.chartWidth, chart.chartHeight);
var radius = polar.context.radius;
axis.context.labelObjectList.Clear();
string objName = "axis_angle" + axis.index;
var axisObj = ChartHelper.AddObject(objName, chart.transform, chart.chartMinAnchor,
chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta);
axisObj.transform.localPosition = Vector3.zero;
axisObj.SetActive(axis.show);
axisObj.hideFlags = chart.chartHideFlags;
ChartHelper.HideAllObject(axisObj);
var splitNumber = AxisHelper.GetSplitNumber(axis, radius, null);
var totalAngle = axis.startAngle;
var total = 360;
var cenPos = polar.context.center;
var txtHig = axis.axisLabel.textStyle.GetFontSize(chart.theme.axis) + 2;
var margin = axis.axisLabel.margin;
var isCategory = axis.IsCategory();
var isPercentStack = SeriesHelper.IsPercentStack<Bar>(chart.series);
for (int i = 0; i < splitNumber; i++)
{
float scaleAngle = AxisHelper.GetScaleWidth(axis, total, i, null);
bool inside = axis.axisLabel.inside;
var labelName = AxisHelper.GetLabelName(axis, total, i, axis.context.minValue, axis.context.maxValue,
null, isPercentStack);
var label = ChartHelper.AddAxisLabelObject(splitNumber, i, objName + i, axisObj.transform, new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(scaleAngle, txtHig), axis,
chart.theme.axis, labelName);
label.label.SetAlignment(axis.axisLabel.textStyle.GetAlignment(TextAnchor.MiddleCenter));
var pos = ChartHelper.GetPos(cenPos, radius + margin,
isCategory ? (totalAngle + scaleAngle / 2) : totalAngle, true);
AxisHelper.AdjustCircleLabelPos(label, pos, cenPos, txtHig, Vector3.zero);
if (i == 0) axis.axisLabel.SetRelatedText(label.label, scaleAngle);
axis.context.labelObjectList.Add(label);
totalAngle += scaleAngle;
}
}
private void DrawAngleAxis(VertexHelper vh, AngleAxis angleAxis)
{
var polar = chart.GetChartComponent<PolarCoord>(angleAxis.polarIndex);
var radius = polar.context.radius;
var cenPos = polar.context.center;
var total = 360;
var size = AxisHelper.GetScaleNumber(angleAxis, total, null);
var currAngle = angleAxis.startAngle;
var tickWidth = angleAxis.axisTick.GetWidth(chart.theme.axis.tickWidth);
var tickLength = angleAxis.axisTick.GetLength(chart.theme.axis.tickLength);
for (int i = 0; i < size; i++)
{
var scaleWidth = AxisHelper.GetScaleWidth(angleAxis, total, i);
var pos = ChartHelper.GetPos(cenPos, radius, currAngle, true);
if (angleAxis.show && angleAxis.splitLine.show)
{
var splitLineColor = angleAxis.splitLine.GetColor(chart.theme.axis.splitLineColor);
var lineWidth = angleAxis.splitLine.GetWidth(chart.theme.axis.splitLineWidth);
UGL.DrawLine(vh, cenPos, pos, lineWidth, splitLineColor);
}
if (angleAxis.show && angleAxis.axisTick.show)
{
var tickY = radius + tickLength;
var tickPos = ChartHelper.GetPos(cenPos, tickY, currAngle, true);
UGL.DrawLine(vh, pos, tickPos, tickWidth, chart.theme.axis.lineColor);
}
currAngle += scaleWidth;
}
if (angleAxis.show && angleAxis.axisLine.show)
{
var lineWidth = angleAxis.axisLine.GetWidth(chart.theme.axis.lineWidth);
var outsideRaidus = radius + lineWidth * 2;
UGL.DrawDoughnut(vh, cenPos, radius, outsideRaidus, chart.theme.axis.lineColor, Color.clear);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 83f228c42435c4619943a2f187c98e7b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,798 @@

using System;
using System.Collections.Generic;
using UnityEngine;
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 int m_ParallelIndex;
[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 = 0;
[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] private bool m_InsertDataToHead;
[SerializeField] private IconStyle m_IconStyle = new IconStyle();
[SerializeField] protected List<Sprite> m_Icons = new List<Sprite>();
[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;
public AxisContext context = new AxisContext();
/// <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 index of the parallel on which the axis are located, by default, is in the first parallel.
/// 坐标轴所在的 parallel 的索引,默认位于第一个 parallel。
/// </summary>
public int parallelIndex
{
get { return m_ParallelIndex; }
set { if (PropertyUtil.SetStruct(ref m_ParallelIndex, 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.
/// 坐标轴的期望的分割段数。默认为0表示自动分割。
/// </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>
/// 类目数据对应的图标。
/// </summary>
public List<Sprite> icons
{
get { return m_Icons; }
set { if (value != null) { m_Icons = 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(); } }
}
/// <summary>
/// Whether to add new data at the head or at the end of the list.
/// 添加新数据时是在列表的头部还是尾部加入。
/// </summary>
public bool insertDataToHead
{
get { return m_InsertDataToHead; }
set { if (PropertyUtil.SetStruct(ref m_InsertDataToHead, value)) SetAllDirty(); }
}
/// <summary>
/// 图标样式。
/// </summary>
public IconStyle iconStyle
{
get { return m_IconStyle; }
set { if (PropertyUtil.SetClass(ref m_IconStyle, value)) SetAllDirty(); }
}
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;
}
}
public override void ClearComponentDirty()
{
base.ClearComponentDirty();
axisName.ClearComponentDirty();
axisLabel.ClearComponentDirty();
}
public override void ClearVerticesDirty()
{
base.ClearVerticesDirty();
axisLine.ClearVerticesDirty();
axisTick.ClearVerticesDirty();
splitLine.ClearVerticesDirty();
splitArea.ClearVerticesDirty();
}
public override void SetComponentDirty()
{
context.isNeedUpdateFilterData = true;
base.SetComponentDirty();
}
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.insertDataToHead = insertDataToHead;
axis.iconStyle = iconStyle.Clone();
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.icons = new List<Sprite>();
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;
insertDataToHead = axis.insertDataToHead;
iconStyle.Copy(axis.iconStyle);
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);
ChartHelper.CopyList<Sprite>(icons, axis.icons);
}
/// <summary>
/// 清空类目数据
/// </summary>
public override void ClearData()
{
m_Data.Clear();
m_Icons.Clear();
context.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>
public bool IsTime()
{
return type == AxisType.Time;
}
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;
}
public void SetNeedUpdateFilterData()
{
context.isNeedUpdateFilterData = true;
}
/// <summary>
/// 添加一个类目到类目数据列表
/// </summary>
/// <param name="category"></param>
public void AddData(string category)
{
if (maxCache > 0)
{
while (m_Data.Count >= maxCache)
{
context.isNeedUpdateFilterData = true;
m_Data.RemoveAt(m_InsertDataToHead ? m_Data.Count - 1 : 0);
}
}
if (m_InsertDataToHead)
m_Data.Insert(0, category);
else
m_Data.Add(category);
SetAllDirty();
}
/// <summary>
/// 更新类目数据
/// </summary>
/// <param name="index"></param>
/// <param name="category"></param>
public void UpdateData(int index, string category)
{
if (index >= 0 && index < m_Data.Count)
{
m_Data[index] = category;
SetComponentDirty();
}
}
/// <summary>
/// 添加图标
/// </summary>
/// <param name="icon"></param>
public void AddIcon(Sprite icon)
{
if (maxCache > 0)
{
while (m_Icons.Count > maxCache)
{
m_Icons.RemoveAt(m_InsertDataToHead ? m_Icons.Count - 1 : 0);
}
}
if (m_InsertDataToHead) m_Icons.Insert(0, icon);
else m_Icons.Add(icon);
SetAllDirty();
}
/// <summary>
/// 更新图标
/// </summary>
/// <param name="index"></param>
/// <param name="icon"></param>
public void UpdateIcon(int index, Sprite icon)
{
if (index >= 0 && index < m_Icons.Count)
{
m_Icons[index] = icon;
SetComponentDirty();
}
}
/// <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 "";
}
public Sprite GetIcon(int index)
{
if (index >= 0 && index < m_Icons.Count)
return m_Icons[index];
else
return null;
}
/// <summary>
/// 获得值在坐标轴上的距离
/// </summary>
/// <param name="value"></param>
/// <param name="axisLength"></param>
/// <returns></returns>
public float GetDistance(double value, float axisLength)
{
if (context.minMaxRange == 0)
return 0;
if (IsCategory() && boundaryGap)
{
var each = axisLength / data.Count;
return (float)(each * (value + 0.5f));
}
else
{
return axisLength * (float)((value - context.minValue) / context.minMaxRange);
}
}
/// <summary>
/// 获得指定区域缩放的类目数据列表
/// </summary>
/// <param name="dataZoom">区域缩放</param>
/// <returns></returns>
internal List<string> GetDataList(DataZoom dataZoom)
{
if (dataZoom != null && dataZoom.enable && dataZoom.IsContainsAxis(this))
{
UpdateFilterData(dataZoom);
return context.filterData;
}
else
{
return m_Data.Count > 0 ? m_Data : context.runtimeData;
}
}
internal List<string> GetDataList()
{
return m_Data.Count > 0 ? m_Data : context.runtimeData;
}
/// <summary>
/// 更新dataZoom对应的类目数据列表
/// </summary>
/// <param name="dataZoom"></param>
internal void UpdateFilterData(DataZoom dataZoom)
{
if (dataZoom != null && dataZoom.enable && dataZoom.IsContainsAxis(this))
{
var data = GetDataList();
context.UpdateFilterData(data, dataZoom);
}
}
/// <summary>
/// 获得类目数据个数
/// </summary>
/// <param name="dataZoom"></param>
/// <returns></returns>
internal int GetDataCount(DataZoom dataZoom)
{
return IsCategory() ? GetDataList(dataZoom).Count : 0;
}
/// <summary>
/// 更新刻度标签文字
/// </summary>
/// <param name="dataZoom"></param>
internal void UpdateLabelText(float coordinateWidth, DataZoom dataZoom, bool forcePercent)
{
for (int i = 0; i < context.labelObjectList.Count; i++)
{
if (context.labelObjectList[i] != null)
{
var text = AxisHelper.GetLabelName(this, coordinateWidth, i, context.minValue, context.maxValue, dataZoom, forcePercent);
context.labelObjectList[i].SetText(text);
}
}
}
internal Vector3 GetLabelObjectPosition(int index)
{
if (context.labelObjectList != null && index < context.labelObjectList.Count)
return context.labelObjectList[index].GetPosition();
else
return Vector3.zero;
}
internal void UpdateMinMaxValue(double minValue, double maxValue)
{
context.minValue = minValue;
context.maxValue = maxValue;
double tempRange = maxValue - minValue;
if (context.minMaxRange != tempRange)
{
context.minMaxRange = tempRange;
if (type == Axis.AxisType.Value && interval > 0)
{
SetComponentDirty();
}
}
}
public float GetLogValue(double value)
{
if (value <= 0 || value == 1)
return 0;
else
return logBaseE ? (float)Math.Log(value) : (float)Math.Log(value, logBase);
}
public int GetLogMinIndex()
{
return logBaseE
? (int)Math.Log(context.minValue)
: (int)Math.Log(context.minValue, logBase);
}
public int GetLogMaxIndex()
{
return logBaseE
? (int)Math.Log(context.maxValue)
: (int)Math.Log(context.maxValue, logBase);
}
public double GetLabelValue(int index)
{
if (index < 0)
return context.minValue;
else if (index > context.labelValueList.Count - 1)
return context.maxValue;
else
return context.labelValueList[index];
}
public double GetLastLabelValue()
{
if (context.labelValueList.Count > 0)
return context.labelValueList[context.labelValueList.Count - 1];
else
return 0;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d5c29555575e04db98ee243c3b17f0ed
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
public class AxisContext : MainComponentContext
{
internal Orient orient { get; set; }
public float x { get; internal set; }
public float y { get; internal set; }
public float width { get; internal set; }
public float height { get; internal set; }
public Vector3 position { get; internal set; }
public float left { get; internal set; }
public float right { get; internal set; }
public float bottom { get; internal set; }
public float top { get; internal set; }
/// <summary>
/// the current minimun value.
/// 当前最小值。
/// </summary>
public double minValue { get; internal set; }
/// <summary>
/// the current maximum value.
/// 当前最大值。
/// </summary>
public double maxValue { get; internal set; }
/// <summary>
/// the offset of zero position.
/// 坐标轴原点在坐标轴的偏移。
/// </summary>
public float offset { get; internal set; }
public double minMaxRange { get; internal set; }
public float scaleWidth { get; internal set; }
public float startAngle { get; set; }
public double pointerValue { get; internal set; }
public Vector3 pointerLabelPosition { get; internal set; }
public double axisTooltipValue { get; internal set; }
public List<string> runtimeData { get { return m_RuntimeData; } }
public List<double> labelValueList { get { return m_LabelValueList; } }
public List<ChartLabel> labelObjectList { get { return m_AxisLabelList; } }
internal List<string> filterData;
internal bool lastCheckInverse { get; set; }
internal bool isNeedUpdateFilterData;
private int filterStart;
private int filterEnd;
private int filterMinShow;
private List<ChartLabel> m_AxisLabelList = new List<ChartLabel>();
private List<double> m_LabelValueList = new List<double>();
private List<string> m_RuntimeData = new List<string>();
internal void Clear()
{
m_RuntimeData.Clear();
}
private List<string> m_EmptyFliter = new List<string>();
/// <summary>
/// 更新dataZoom对应的类目数据列表
/// </summary>
/// <param name="dataZoom"></param>
internal void UpdateFilterData(List<string> data, DataZoom dataZoom)
{
int start = 0, end = 0;
var range = Mathf.RoundToInt(data.Count * (dataZoom.end - dataZoom.start) / 100);
if (range <= 0)
range = 1;
if (dataZoom.context.invert)
{
end = Mathf.CeilToInt(data.Count * dataZoom.end / 100);
start = end - range;
if (start < 0) start = 0;
}
else
{
start = Mathf.FloorToInt(data.Count * dataZoom.start / 100);
end = start + range;
if (end > data.Count) end = data.Count;
}
if (start != filterStart
|| end != filterEnd
|| dataZoom.minShowNum != filterMinShow
|| isNeedUpdateFilterData)
{
filterStart = start;
filterEnd = end;
filterMinShow = dataZoom.minShowNum;
isNeedUpdateFilterData = false;
if (data.Count > 0)
{
if (range < dataZoom.minShowNum)
{
if (dataZoom.minShowNum > data.Count)
range = data.Count;
else
range = dataZoom.minShowNum;
}
filterData = data.GetRange(start, range);
}
else
{
filterData = data;
}
}
else if (end == 0)
{
filterData = m_EmptyFliter;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6525f065fa5d04663ab7026a3467f56e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,808 @@
using System;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
public abstract class AxisHandler<T> : MainComponentHandler
where T : Axis
{
private static readonly string s_DefaultAxisName = "name";
private double m_LastInterval = double.MinValue;
private int m_LastSplitNumber = int.MinValue;
public T component { get; internal set; }
internal override void SetComponent(MainComponent component)
{
this.component = (T)component;
}
protected virtual Vector3 GetLabelPosition(float scaleWid, int i)
{
return Vector3.zero;
}
protected virtual Orient orient { get; }
protected void UpdatePointerValue(Axis axis)
{
var grid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
if (grid == null)
return;
if (!grid.context.isPointerEnter)
{
axis.context.pointerValue = double.PositiveInfinity;
}
else
{
if (axis.IsCategory())
{
var dataZoom = chart.GetDataZoomOfAxis(axis);
var dataCount = chart.series.Count > 0 ? chart.series[0].GetDataList(dataZoom).Count : 0;
var local = chart.pointerPos;
for (int j = 0; j < axis.GetDataCount(dataZoom); j++)
{
if (axis is YAxis)
{
float splitWid = AxisHelper.GetDataWidth(axis, grid.context.height, dataCount, dataZoom);
float pY = grid.context.y + j * splitWid;
if ((axis.boundaryGap && (local.y > pY && local.y <= pY + splitWid))
|| (!axis.boundaryGap && (local.y > pY - splitWid / 2 && local.y <= pY + splitWid / 2)))
{
axis.context.pointerValue = j;
axis.context.pointerLabelPosition = axis.GetLabelObjectPosition(j);
break;
}
}
else
{
float splitWid = AxisHelper.GetDataWidth(axis, grid.context.width, dataCount, dataZoom);
float pX = grid.context.x + j * splitWid;
if ((axis.boundaryGap && (local.x > pX && local.x <= pX + splitWid))
|| (!axis.boundaryGap && (local.x > pX - splitWid / 2 && local.x <= pX + splitWid / 2)))
{
axis.context.pointerValue = j;
axis.context.pointerLabelPosition = axis.GetLabelObjectPosition(j);
break;
}
}
}
}
else
{
if (axis is YAxis)
{
var yRate = axis.context.minMaxRange / grid.context.height;
var yValue = yRate * (chart.pointerPos.y - grid.context.y - axis.context.offset);
if (axis.context.minValue > 0)
yValue += axis.context.minValue;
var labelX = axis.GetLabelObjectPosition(0).x;
axis.context.pointerValue = yValue;
axis.context.pointerLabelPosition = new Vector3(labelX, chart.pointerPos.y);
}
else
{
var xRate = axis.context.minMaxRange / grid.context.width;
var xValue = xRate * (chart.pointerPos.x - grid.context.x - axis.context.offset);
if (axis.context.minValue > 0)
xValue += axis.context.minValue;
var labelY = axis.GetLabelObjectPosition(0).y;
axis.context.pointerValue = xValue;
axis.context.pointerLabelPosition = new Vector3(chart.pointerPos.x, labelY);
}
}
}
}
internal void UpdateAxisMinMaxValue(int axisIndex, Axis axis, bool updateChart = true)
{
if (!axis.show)
return;
if (axis.IsCategory())
{
axis.context.minValue = 0;
axis.context.maxValue = SeriesHelper.GetMaxSerieDataCount(chart.series) - 1;
axis.context.minMaxRange = axis.context.maxValue;
return;
}
double tempMinValue = 0;
double tempMaxValue = 0;
chart.GetSeriesMinMaxValue(axis, axisIndex, out tempMinValue, out tempMaxValue);
if (tempMinValue != axis.context.minValue
|| tempMaxValue != axis.context.maxValue
|| m_LastInterval != axis.interval
|| m_LastSplitNumber != axis.splitNumber)
{
m_LastSplitNumber = axis.splitNumber;
m_LastInterval = axis.interval;
axis.UpdateMinMaxValue(tempMinValue, tempMaxValue);
axis.context.offset = 0;
axis.context.lastCheckInverse = axis.inverse;
UpdateAxisTickValueList(axis);
if (tempMinValue != 0 || tempMaxValue != 0)
{
var grid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
if (grid != null && axis is XAxis && axis.IsValue())
{
axis.context.offset = axis.context.minValue > 0
? 0
: (axis.context.maxValue < 0
? grid.context.width
: (float)(Math.Abs(axis.context.minValue) * (grid.context.width
/ (Math.Abs(axis.context.minValue) + Math.Abs(axis.context.maxValue))))
);
}
if (grid != null && axis is YAxis && axis.IsValue())
{
axis.context.offset = axis.context.minValue > 0
? 0
: (axis.context.maxValue < 0
? grid.context.height
: (float)(Math.Abs(axis.context.minValue) * (grid.context.height
/ (Math.Abs(axis.context.minValue) + Math.Abs(axis.context.maxValue))))
);
}
}
var dataZoom = chart.GetDataZoomOfAxis(axis);
if (dataZoom != null && dataZoom.enable)
{
if (axis is XAxis)
dataZoom.SetXAxisIndexValueInfo(axisIndex, tempMinValue, tempMaxValue);
else
dataZoom.SetYAxisIndexValueInfo(axisIndex, tempMinValue, tempMaxValue);
}
if (updateChart)
{
UpdateAxisLabelText(axis);
chart.RefreshChart();
}
}
}
internal virtual void UpdateAxisLabelText(Axis axis)
{
var grid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
if (grid == null || axis == null)
return;
float runtimeWidth = axis is XAxis ? grid.context.width : grid.context.height;
var isPercentStack = SeriesHelper.IsPercentStack<Bar>(chart.series);
var dataZoom = chart.GetDataZoomOfAxis(axis);
axis.UpdateLabelText(runtimeWidth, dataZoom, isPercentStack);
}
internal static void UpdateAxisTickValueList(Axis axis)
{
if (axis.IsTime())
{
var lastCount = axis.context.labelValueList.Count;
DateTimeUtil.UpdateTimeAxisDateTimeList(axis.context.labelValueList, (int)axis.context.minValue,
(int)axis.context.maxValue, axis.splitNumber);
if (axis.context.labelValueList.Count != lastCount)
axis.SetAllDirty();
}
else if (axis.IsValue())
{
var list = axis.context.labelValueList;
var lastCount = list.Count;
list.Clear();
var range = axis.context.maxValue - axis.context.minValue;
if (range <= 0)
return;
double tick = axis.interval;
if (axis.interval == 0)
{
if (axis.splitNumber > 0)
{
tick = range / axis.splitNumber;
}
else
{
var each = GetTick(range);
tick = each;
if (range / tick > 8)
tick = 2 * each;
else if (range / tick < 4)
tick = each / 2;
}
}
var value = 0d;
if (Mathf.Approximately((float)(axis.context.minValue % tick), 0))
{
value = axis.context.minValue;
}
else
{
list.Add(axis.context.minValue);
value = Math.Ceiling(axis.context.minValue / tick) * tick;
}
while (value <= axis.context.maxValue)
{
list.Add(value);
value += tick;
if (list.Count > 20)
break;
}
if (!ChartHelper.IsEquals(axis.context.maxValue, list[list.Count - 1]))
{
list.Add(axis.context.maxValue);
}
if (lastCount != list.Count)
{
axis.SetAllDirty();
}
}
}
private static double GetTick(double max)
{
var bigger = Math.Ceiling(Math.Abs(max));
int n = 1;
while (bigger / (Mathf.Pow(10, n)) > 10)
{
n++;
}
return Math.Pow(10, n);
}
internal void CheckValueLabelActive(Axis axis, int i, ChartLabel label, Vector3 pos)
{
if (axis.IsValue())
{
if (orient == Orient.Horizonal)
{
if (i == 0)
{
var dist = GetLabelPosition(0, 1).x - pos.x;
label.SetLabelActive(dist > label.label.GetPreferredWidth());
}
else if (i == axis.context.labelValueList.Count - 1)
{
var dist = pos.x - GetLabelPosition(0, i - 1).x;
label.SetLabelActive(dist > label.label.GetPreferredWidth());
}
}
else
{
if (i == 0)
{
var dist = GetLabelPosition(0, 1).y - pos.y;
label.SetLabelActive(dist > label.label.GetPreferredHeight());
}
else if (i == axis.context.labelValueList.Count - 1)
{
var dist = pos.y - GetLabelPosition(0, i - 1).y;
label.SetLabelActive(dist > label.label.GetPreferredHeight());
}
}
}
}
internal static void InitAxis(Axis axis, Axis relativedAxis, BaseChart chart, AxisHandler<T> handler,
Orient orient, float axisStartX, float axisStartY, float axisLength, float relativedLength)
{
chart.InitAxisRuntimeData(axis);
var objName = ChartCached.GetComponentObjectName(axis);
var axisObj = ChartHelper.AddObject(objName,
chart.transform,
chart.chartMinAnchor,
chart.chartMaxAnchor,
chart.chartPivot,
chart.chartSizeDelta);
axisObj.SetActive(axis.show);
axisObj.hideFlags = chart.chartHideFlags;
ChartHelper.HideAllObject(axisObj);
axis.gameObject = axisObj;
axis.context.labelObjectList.Clear();
if (!axis.show)
return;
var axisLabelTextStyle = axis.axisLabel.textStyle;
var dataZoom = chart.GetDataZoomOfAxis(axis);
var splitNumber = AxisHelper.GetScaleNumber(axis, axisLength, dataZoom);
var totalWidth = 0f;
var eachWidth = AxisHelper.GetEachWidth(axis, axisLength, dataZoom);
var gapWidth = axis.boundaryGap ? eachWidth / 2 : 0;
var textWidth = axis.axisLabel.width > 0
? axis.axisLabel.width
: (orient == Orient.Horizonal
? AxisHelper.GetScaleWidth(axis, axisLength, 0, dataZoom)
: (axisStartX - chart.chartX)
);
var textHeight = axis.axisLabel.height > 0
? axis.axisLabel.height
: 20f;
if (axis.IsCategory() && axis.boundaryGap)
{
splitNumber -= 1;
}
for (int i = 0; i < splitNumber; i++)
{
ChartLabel label;
var labelWidth = AxisHelper.GetScaleWidth(axis, axisLength, i + 1, dataZoom);
var inside = axis.axisLabel.inside;
var isPercentStack = SeriesHelper.IsPercentStack<Bar>(chart.series);
var labelName = AxisHelper.GetLabelName(axis, axisLength, i,
axis.context.minValue,
axis.context.maxValue,
dataZoom, isPercentStack);
if (orient == Orient.Horizonal)
{
label = ChartHelper.AddAxisLabelObject(splitNumber, i,
ChartCached.GetAxisLabelName(i),
axisObj.transform,
new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f),
new Vector2(textWidth, textHeight),
axis, chart.theme.axis, labelName);
}
else
{
if ((inside && axis.IsLeft()) || (!inside && axis.IsRight()))
{
label = ChartHelper.AddAxisLabelObject(splitNumber, i,
ChartCached.GetAxisLabelName(i),
axisObj.transform,
Vector2.zero,
Vector2.zero,
new Vector2(0, 0.5f),
new Vector2(textWidth, textHeight),
axis, chart.theme.axis, labelName);
label.label.SetAlignment(axisLabelTextStyle.GetAlignment(TextAnchor.MiddleLeft));
}
else
{
label = ChartHelper.AddAxisLabelObject(splitNumber, i,
ChartCached.GetAxisLabelName(i),
axisObj.transform,
Vector2.zero,
Vector2.zero,
new Vector2(1, 0.5f),
new Vector2(textWidth, textHeight),
axis, chart.theme.axis, labelName);
label.label.SetAlignment(axisLabelTextStyle.GetAlignment(TextAnchor.MiddleRight));
}
}
if (i == 0)
axis.axisLabel.SetRelatedText(label.label, labelWidth);
var pos = handler.GetLabelPosition(totalWidth + gapWidth, i);
if (orient == Orient.Horizonal)
{
label.label.SetAlignment(axisLabelTextStyle.GetAlignment(TextAnchor.MiddleCenter));
}
else
{
if (axis.IsRight())
label.label.SetAlignment(axisLabelTextStyle.GetAlignment(TextAnchor.MiddleLeft));
else
label.label.SetAlignment(axisLabelTextStyle.GetAlignment(TextAnchor.MiddleRight));
}
label.SetPosition(pos);
handler.CheckValueLabelActive(axis, i, label, pos);
axis.context.labelObjectList.Add(label);
totalWidth += labelWidth;
}
if (axis.axisName.show)
{
ChartText axisName = null;
var axisNameTextStyle = axis.axisName.textStyle;
var offset = axisNameTextStyle.offset;
var relativedDist = (relativedAxis == null ? 0 : relativedAxis.context.offset);
var zeroPos = new Vector3(axisStartX, axisStartY + relativedDist);
if (orient == Orient.Horizonal)
{
switch (axis.axisName.location)
{
case AxisName.Location.Start:
axisName = ChartHelper.AddTextObject(s_DefaultAxisName, axisObj.transform,
new Vector2(1, 0.5f),
new Vector2(1, 0.5f),
new Vector2(1, 0.5f),
new Vector2(100, 20),
axisNameTextStyle, chart.theme.axis);
axisName.SetAlignment(axisNameTextStyle.GetAlignment(TextAnchor.MiddleRight));
axisName.SetLocalPosition(axis.position == Axis.AxisPosition.Top
? new Vector2(zeroPos.x - offset.x, axisStartY + relativedLength + offset.y + axis.offset)
: new Vector2(zeroPos.x - offset.x, zeroPos.y + offset.y + axis.offset));
break;
case AxisName.Location.Middle:
axisName = ChartHelper.AddTextObject(s_DefaultAxisName, axisObj.transform,
new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f),
new Vector2(100, 20),
axisNameTextStyle, chart.theme.axis);
axisName.SetAlignment(axisNameTextStyle.GetAlignment(TextAnchor.MiddleCenter));
axisName.SetLocalPosition(axis.position == Axis.AxisPosition.Top
? new Vector2(axisStartX + axisLength / 2 + offset.x, axisStartY + relativedLength - offset.y + axis.offset)
: new Vector2(axisStartX + axisLength / 2 + offset.x, axisStartY - offset.y + axis.offset));
break;
case AxisName.Location.End:
axisName = ChartHelper.AddTextObject(s_DefaultAxisName, axisObj.transform,
new Vector2(0, 0.5f),
new Vector2(0, 0.5f),
new Vector2(0, 0.5f),
new Vector2(100, 20),
axisNameTextStyle, chart.theme.axis);
axisName.SetAlignment(axisNameTextStyle.GetAlignment(TextAnchor.MiddleLeft));
axisName.SetLocalPosition(axis.position == Axis.AxisPosition.Top
? new Vector2(axisStartX + axisLength + offset.x, axisStartY + relativedLength + offset.y + axis.offset)
: new Vector2(axisStartX + axisLength + offset.x, zeroPos.y + offset.y + axis.offset));
break;
}
}
else
{
switch (axis.axisName.location)
{
case AxisName.Location.Start:
axisName = ChartHelper.AddTextObject(s_DefaultAxisName, axisObj.transform, new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(100, 20), axisNameTextStyle,
chart.theme.axis);
axisName.SetAlignment(axisNameTextStyle.GetAlignment(TextAnchor.MiddleCenter));
axisName.SetLocalPosition(axis.position == Axis.AxisPosition.Right ?
new Vector2(axisStartX + relativedLength + offset.x + axis.offset, axisStartY - offset.y) :
new Vector2(zeroPos.x + offset.x + axis.offset, axisStartY - offset.y));
break;
case AxisName.Location.Middle:
axisName = ChartHelper.AddTextObject(s_DefaultAxisName, axisObj.transform, new Vector2(1, 0.5f),
new Vector2(1, 0.5f), new Vector2(1, 0.5f), new Vector2(100, 20), axisNameTextStyle,
chart.theme.axis);
axisName.SetAlignment(axisNameTextStyle.GetAlignment(TextAnchor.MiddleRight));
axisName.SetLocalPosition(axis.position == Axis.AxisPosition.Right ?
new Vector2(axisStartX + relativedLength - offset.x + axis.offset, axisStartY + axisLength / 2 + offset.y) :
new Vector2(axisStartX - offset.x + axis.offset, axisStartY + axisLength / 2 + offset.y));
break;
case AxisName.Location.End:
axisName = ChartHelper.AddTextObject(s_DefaultAxisName, axisObj.transform, new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(100, 20), axisNameTextStyle,
chart.theme.axis);
axisName.SetAlignment(axisNameTextStyle.GetAlignment(TextAnchor.MiddleCenter));
axisName.SetLocalPosition(axis.position == Axis.AxisPosition.Right ?
new Vector2(axisStartX + relativedLength + offset.x + axis.offset, axisStartY + axisLength + offset.y) :
new Vector2(zeroPos.x + offset.x + axis.offset, axisStartY + axisLength + offset.y));
break;
}
}
axisName.SetText(axis.axisName.name);
}
}
internal static Vector3 GetLabelPosition(int i, Orient orient, Axis axis, Axis relativedAxis, AxisTheme theme,
float scaleWid, float axisStartX, float axisStartY, float axisLength, float relativedLength)
{
var inside = axis.axisLabel.inside;
var fontSize = axis.axisLabel.textStyle.GetFontSize(theme);
var current = axis.offset;
if (axis.IsTime() || axis.IsValue())
{
scaleWid = axis.context.minMaxRange != 0
? axis.GetDistance(axis.GetLabelValue(i), axisLength)
: 0;
}
if (orient == Orient.Horizonal)
{
if (axis.axisLabel.onZero && relativedAxis != null)
axisStartY += relativedAxis.context.offset;
if (axis.IsTop())
axisStartY += relativedLength;
if ((inside && axis.IsBottom()) || (!inside && axis.IsTop()))
current += axisStartY + axis.axisLabel.margin + fontSize / 2;
else
current += axisStartY - axis.axisLabel.margin - fontSize / 2;
return new Vector3(axisStartX + scaleWid, current) + axis.axisLabel.textStyle.offsetv3;
}
else
{
if (axis.axisLabel.onZero && relativedAxis != null)
axisStartX += relativedAxis.context.offset;
if (axis.IsRight())
axisStartX += relativedLength;
if ((inside && axis.IsLeft()) || (!inside && axis.IsRight()))
current += axisStartX + axis.axisLabel.margin;
else
current += axisStartX - axis.axisLabel.margin;
return new Vector3(current, axisStartY + scaleWid) + axis.axisLabel.textStyle.offsetv3;
}
}
internal static void DrawAxisLine(VertexHelper vh, Axis axis, AxisTheme theme, Orient orient,
float startX, float startY, float axisLength)
{
var inverse = axis.IsValue() && axis.inverse;
var offset = AxisHelper.GetAxisLineArrowOffset(axis);
var lineWidth = axis.axisLine.GetWidth(theme.lineWidth);
var lineType = axis.axisLine.GetType(theme.lineType);
var lineColor = axis.axisLine.GetColor(theme.lineColor);
if (orient == Orient.Horizonal)
{
var left = new Vector3(startX - lineWidth - (inverse ? offset : 0), startY);
var right = new Vector3(startX + axisLength + lineWidth + (!inverse ? offset : 0), startY);
ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, left, right, lineColor);
}
else
{
var bottom = new Vector3(startX, startY - lineWidth - (inverse ? offset : 0));
var top = new Vector3(startX, startY + axisLength + lineWidth + (!inverse ? offset : 0));
ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, bottom, top, lineColor);
}
}
internal static void DrawAxisTick(VertexHelper vh, Axis axis, AxisTheme theme, DataZoom dataZoom,
Orient orient, float startX, float startY, float axisLength)
{
var lineWidth = axis.axisLine.GetWidth(theme.lineWidth);
var tickLength = axis.axisTick.GetLength(theme.tickLength);
if (AxisHelper.NeedShowSplit(axis))
{
var size = AxisHelper.GetScaleNumber(axis, axisLength, dataZoom);
var current = orient == Orient.Horizonal
? startX
: startY;
for (int i = 0; i < size; i++)
{
var scaleWidth = AxisHelper.GetScaleWidth(axis, axisLength, i + 1, dataZoom);
if (i == 0 && (!axis.axisTick.showStartTick || axis.axisTick.alignWithLabel))
{
current += scaleWidth;
continue;
}
if (i == size - 1 && !axis.axisTick.showEndTick)
{
current += scaleWidth;
continue;
}
if (axis.axisTick.show)
{
if (orient == Orient.Horizonal)
{
float pX = axis.IsTime()
? (startX + axis.GetDistance(axis.GetLabelValue(i), axisLength))
: current;
if (axis.boundaryGap && axis.axisTick.alignWithLabel)
pX -= scaleWidth / 2;
var sY = 0f;
var eY = 0f;
if ((axis.axisTick.inside && axis.IsBottom())
|| (!axis.axisTick.inside && axis.IsTop()))
{
sY = startY + axis.offset + lineWidth;
eY = sY + tickLength;
}
else
{
sY = startY + axis.offset - lineWidth;
eY = sY - tickLength;
}
UGL.DrawLine(vh, new Vector3(pX, sY), new Vector3(pX, eY),
axis.axisTick.GetWidth(theme.tickWidth),
axis.axisTick.GetColor(theme.tickColor));
}
else
{
float pY = axis.IsTime()
? (startY + axis.GetDistance(axis.GetLabelValue(i), axisLength))
: current;
if (axis.boundaryGap && axis.axisTick.alignWithLabel)
pY -= scaleWidth / 2;
var sX = 0f;
var eX = 0f;
if ((axis.axisTick.inside && axis.IsLeft())
|| (!axis.axisTick.inside && axis.IsRight()))
{
sX = startX + axis.offset + lineWidth;
eX = sX + tickLength;
}
else
{
sX = startX + axis.offset - lineWidth;
eX = sX - tickLength;
}
UGL.DrawLine(vh, new Vector3(sX, pY), new Vector3(eX, pY),
axis.axisTick.GetWidth(theme.tickWidth),
axis.axisTick.GetColor(theme.tickColor));
}
}
current += scaleWidth;
}
}
if (axis.show && axis.axisLine.show && axis.axisLine.showArrow)
{
var lineY = startY + axis.offset;
var inverse = axis.IsValue() && axis.inverse;
var axisArrow = axis.axisLine.arrow;
if (orient == Orient.Horizonal)
{
if (inverse)
{
var startPos = new Vector3(startX + axisLength, lineY);
var arrowPos = new Vector3(startX, lineY);
UGL.DrawArrow(vh, startPos, arrowPos, axisArrow.width, axisArrow.height,
axisArrow.offset, axisArrow.dent,
axisArrow.GetColor(axis.axisLine.GetColor(theme.lineColor)));
}
else
{
var arrowPosX = startX + axisLength + lineWidth;
var startPos = new Vector3(startX, lineY);
var arrowPos = new Vector3(arrowPosX, lineY);
UGL.DrawArrow(vh, startPos, arrowPos, axisArrow.width, axisArrow.height,
axisArrow.offset, axisArrow.dent,
axisArrow.GetColor(axis.axisLine.GetColor(theme.lineColor)));
}
}
else
{
if (inverse)
{
var startPos = new Vector3(startX, startY + axisLength);
var arrowPos = new Vector3(startX, startY);
UGL.DrawArrow(vh, startPos, arrowPos, axisArrow.width, axisArrow.height,
axisArrow.offset, axisArrow.dent,
axisArrow.GetColor(axis.axisLine.GetColor(theme.lineColor)));
}
else
{
var startPos = new Vector3(startX, startY);
var arrowPos = new Vector3(startX, startY + axisLength + lineWidth);
UGL.DrawArrow(vh, startPos, arrowPos, axisArrow.width, axisArrow.height,
axisArrow.offset, axisArrow.dent,
axisArrow.GetColor(axis.axisLine.GetColor(theme.lineColor)));
}
}
}
}
internal static void DrawAxisSplit(VertexHelper vh, Axis axis, AxisTheme theme, DataZoom dataZoom,
Orient orient, float startX, float startY, float axisLength, float splitLength)
{
var lineColor = axis.splitLine.GetColor(theme.splitLineColor);
var lineWidth = axis.splitLine.GetWidth(theme.lineWidth);
var lineType = axis.splitLine.GetType(theme.splitLineType);
var size = AxisHelper.GetScaleNumber(axis, axisLength, dataZoom);
if (axis.IsTime())
{
size += 1;
if (!ChartHelper.IsEquals(axis.GetLastLabelValue(), axis.context.maxValue))
size += 1;
}
var current = orient == Orient.Horizonal
? startX
: startY;
for (int i = 0; i < size; i++)
{
var scaleWidth = AxisHelper.GetScaleWidth(axis, axisLength, axis.IsTime() ? i : i + 1, dataZoom);
if (axis.boundaryGap && axis.axisTick.alignWithLabel)
current -= scaleWidth / 2;
if (axis.splitArea.show && i <= size - 1)
{
if (orient == Orient.Horizonal)
{
UGL.DrawQuadrilateral(vh,
new Vector2(current, startY),
new Vector2(current, startY + splitLength),
new Vector2(current + scaleWidth, startY + splitLength),
new Vector2(current + scaleWidth, startY),
axis.splitArea.GetColor(i, theme));
}
else
{
UGL.DrawQuadrilateral(vh,
new Vector2(startX, current),
new Vector2(startX + splitLength, current),
new Vector2(startX + splitLength, current + scaleWidth),
new Vector2(startX, current + scaleWidth),
axis.splitArea.GetColor(i, theme));
}
}
if (axis.splitLine.show)
{
if (axis.splitLine.NeedShow(i))
{
if (orient == Orient.Horizonal)
{
ChartDrawer.DrawLineStyle(vh,
lineType,
lineWidth,
new Vector3(current, startY),
new Vector3(current, startY + splitLength),
lineColor);
}
else
{
ChartDrawer.DrawLineStyle(vh,
lineType,
lineWidth,
new Vector3(startX, current),
new Vector3(startX + splitLength, current),
lineColor);
}
}
}
current += scaleWidth;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0babef8a2708b4745bbb0a0648913a35
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,532 @@
using UnityEngine;
namespace XCharts
{
public static class AxisHelper
{
/// <summary>
/// 包含箭头偏移的轴线长度
/// </summary>
/// <param name="axis"></param>
/// <returns></returns>
public static float GetAxisLineArrowOffset(Axis axis)
{
if (axis.axisLine.show && axis.axisLine.showArrow && axis.axisLine.arrow.offset > 0)
{
return axis.axisLine.arrow.offset;
}
return 0;
}
/// <summary>
/// 获得分割段数
/// </summary>
/// <param name="dataZoom"></param>
/// <returns></returns>
public static int GetSplitNumber(Axis axis, float coordinateWid, DataZoom dataZoom)
{
if (axis.type == Axis.AxisType.Value)
{
return axis.context.labelValueList.Count - 1;
}
else if (axis.type == Axis.AxisType.Time)
{
return axis.context.labelValueList.Count;
}
else if (axis.type == Axis.AxisType.Log)
{
return axis.splitNumber > 0 ? axis.splitNumber : 4;
}
else if (axis.type == Axis.AxisType.Category)
{
int dataCount = axis.GetDataList(dataZoom).Count;
if (!axis.boundaryGap)
dataCount -= 1;
if (dataCount <= 0)
dataCount = 1;
if (axis.splitNumber <= 0)
{
if (dataCount <= 10) return dataCount;
else
{
for (int i = 4; i < 6; i++)
{
if (dataCount % i == 0) return i;
}
return 5;
}
}
else
{
if (axis.splitNumber <= 0 || axis.splitNumber > dataCount)
return dataCount;
if (dataCount >= axis.splitNumber * 2)
return axis.splitNumber;
else
return dataCount;
}
}
return 0;
}
/// <summary>
/// 获得一个类目数据在坐标系中代表的宽度
/// </summary>
/// <param name="coordinateWidth"></param>
/// <param name="dataZoom"></param>
/// <returns></returns>
public static float GetDataWidth(Axis axis, float coordinateWidth, int dataCount, DataZoom dataZoom)
{
if (dataCount < 1)
dataCount = 1;
var categoryCount = axis.GetDataCount(dataZoom);
int segment = (axis.boundaryGap ? categoryCount : categoryCount - 1);
segment = segment <= 0 ? dataCount : segment;
if (segment <= 0)
segment = 1;
return coordinateWidth / segment;
}
/// <summary>
/// 获得标签显示的名称
/// </summary>
/// <param name="index"></param>
/// <param name="minValue"></param>
/// <param name="maxValue"></param>
/// <param name="dataZoom"></param>
/// <returns></returns>
public static string GetLabelName(Axis axis, float coordinateWidth, int index, double minValue, double maxValue,
DataZoom dataZoom, bool forcePercent)
{
int split = GetSplitNumber(axis, coordinateWidth, dataZoom);
if (axis.type == Axis.AxisType.Value)
{
if (minValue == 0 && maxValue == 0)
maxValue = axis.max != 0 ? axis.max : 1;
double value = 0;
if (forcePercent)
maxValue = 100;
value = axis.GetLabelValue(index);
if (axis.inverse)
{
value = -value;
minValue = -minValue;
maxValue = -maxValue;
}
if (forcePercent)
return string.Format("{0}%", (int)value);
else
return axis.axisLabel.GetFormatterContent(index, value, minValue, maxValue);
}
else if (axis.type == Axis.AxisType.Log)
{
float value = axis.logBaseE
? Mathf.Exp(axis.GetLogMinIndex() + index)
: Mathf.Pow(axis.logBase, axis.GetLogMinIndex() + index);
if (axis.inverse)
{
value = -value;
minValue = -minValue;
maxValue = -maxValue;
}
return axis.axisLabel.GetFormatterContent(index, value, minValue, maxValue, true);
}
else if (axis.type == Axis.AxisType.Time)
{
if (minValue == 0 && maxValue == 0)
return string.Empty;
if (index > axis.context.labelValueList.Count - 1)
return string.Empty;
var value = axis.GetLabelValue(index);
return axis.axisLabel.GetFormatterDateTime(index, value, minValue, maxValue);
}
var showData = axis.GetDataList(dataZoom);
int dataCount = showData.Count;
if (dataCount <= 0)
return "";
int rate = axis.boundaryGap ? (dataCount / split) : (dataCount - 1) / split;
if (rate == 0) rate = 1;
if (axis.insertDataToHead)
{
if (index > 0)
{
var residue = (dataCount - 1) - split * rate;
var newIndex = residue + (index - 1) * rate;
if (newIndex < 0)
newIndex = 0;
return axis.axisLabel.GetFormatterContent(newIndex, showData[newIndex]);
}
else
{
if (axis.boundaryGap && coordinateWidth / dataCount > 5)
return string.Empty;
else
return axis.axisLabel.GetFormatterContent(0, showData[0]);
}
}
else
{
int newIndex = index * rate;
if (newIndex < dataCount)
{
return axis.axisLabel.GetFormatterContent(newIndex, showData[newIndex]);
}
else
{
if (axis.boundaryGap && coordinateWidth / dataCount > 5)
return string.Empty;
else
return axis.axisLabel.GetFormatterContent(dataCount - 1, showData[dataCount - 1]);
}
}
}
/// <summary>
/// 获得分割线条数
/// </summary>
/// <param name="dataZoom"></param>
/// <returns></returns>
public static int GetScaleNumber(Axis axis, float coordinateWidth, DataZoom dataZoom = null)
{
int splitNum = GetSplitNumber(axis, coordinateWidth, dataZoom);
if (splitNum == 0)
return 0;
if (axis.IsCategory())
{
var dataCount = axis.GetDataList(dataZoom).Count;
var scaleNum = 0;
if (axis.boundaryGap)
{
scaleNum = dataCount > 2 && dataCount % splitNum == 0
? splitNum + 1
: splitNum + 2;
}
else
{
if (dataCount < splitNum) scaleNum = splitNum;
else scaleNum = dataCount > 2 && dataCount % splitNum == 0
? splitNum
: splitNum + 1;
}
return scaleNum;
}
else if (axis.IsTime())
return splitNum;
else
return splitNum + 1;
}
/// <summary>
/// 获得分割段宽度
/// </summary>
/// <param name="coordinateWidth"></param>
/// <param name="dataZoom"></param>
/// <returns></returns>
public static float GetScaleWidth(Axis axis, float coordinateWidth, int index, DataZoom dataZoom = null)
{
if (index < 0)
return 0;
int num = GetScaleNumber(axis, coordinateWidth, dataZoom);
int splitNum = GetSplitNumber(axis, coordinateWidth, dataZoom);
if (num <= 0)
num = 1;
if (axis.IsTime() || axis.IsValue())
{
var value = axis.GetLabelValue(index);
var lastValue = axis.GetLabelValue(index - 1);
return axis.context.minMaxRange == 0
? 0
: (float)(coordinateWidth * (value - lastValue) / axis.context.minMaxRange);
}
else
{
var data = axis.GetDataList(dataZoom);
if (axis.IsCategory() && data.Count > 0)
{
var count = axis.boundaryGap ? data.Count : data.Count - 1;
int tick = count / splitNum;
if (count <= 0)
return 0;
var each = coordinateWidth / count;
if (axis.insertDataToHead)
{
var max = axis.boundaryGap ? splitNum : splitNum - 1;
if (index == 1)
{
if (axis.axisTick.alignWithLabel)
return each * tick;
else
return coordinateWidth - each * tick * max;
}
else
{
if (count < splitNum)
return each;
else
return each * (count / splitNum);
}
}
else
{
var max = axis.boundaryGap ? num - 1 : num;
if (index >= max)
{
if (axis.axisTick.alignWithLabel)
return each * tick;
else
return coordinateWidth - each * tick * (index - 1);
}
else
{
if (count < splitNum)
return each;
else
return each * (count / splitNum);
}
}
}
else
{
if (splitNum <= 0)
return 0;
else
return coordinateWidth / splitNum;
}
}
}
public static float GetEachWidth(Axis axis, float coordinateWidth, DataZoom dataZoom = null)
{
var data = axis.GetDataList(dataZoom);
if (data.Count > 0)
{
var count = axis.boundaryGap ? data.Count : data.Count - 1;
return count > 0 ? coordinateWidth / count : coordinateWidth;
}
else
{
int num = GetScaleNumber(axis, coordinateWidth, dataZoom) - 1;
return num > 0 ? coordinateWidth / num : coordinateWidth;
}
}
/// <summary>
/// 调整最大最小值
/// </summary>
/// <param name="minValue"></param>
/// <param name="maxValue"></param>
public static void AdjustMinMaxValue(Axis axis, ref double minValue, ref double maxValue, bool needFormat, int ceilRate = 0)
{
if (axis.type == Axis.AxisType.Log)
{
int minSplit = 0;
int maxSplit = 0;
maxValue = ChartHelper.GetMaxLogValue(maxValue, axis.logBase, axis.logBaseE, out maxSplit);
minValue = ChartHelper.GetMinLogValue(minValue, axis.logBase, axis.logBaseE, out minSplit);
axis.splitNumber = (minSplit > 0 && maxSplit > 0) ? (maxSplit + minSplit - 1) : (maxSplit + minSplit);
return;
}
if (axis.type == Axis.AxisType.Time)
{
}
else if (axis.minMaxType == Axis.AxisMinMaxType.Custom)
{
if (axis.min != 0 || axis.max != 0)
{
if (axis.inverse)
{
minValue = -axis.max;
maxValue = -axis.min;
}
else
{
minValue = axis.min;
maxValue = axis.max;
}
}
}
else
{
if (ceilRate == 0) ceilRate = axis.ceilRate;
switch (axis.minMaxType)
{
case Axis.AxisMinMaxType.Default:
if (minValue == 0 && maxValue == 0)
{
}
else if (minValue > 0 && maxValue > 0)
{
minValue = 0;
maxValue = needFormat ? ChartHelper.GetMaxDivisibleValue(maxValue, ceilRate) : maxValue;
}
else if (minValue < 0 && maxValue < 0)
{
minValue = needFormat ? ChartHelper.GetMinDivisibleValue(minValue, ceilRate) : minValue;
maxValue = 0;
}
else
{
minValue = needFormat ? ChartHelper.GetMinDivisibleValue(minValue, ceilRate) : minValue;
maxValue = needFormat ? ChartHelper.GetMaxDivisibleValue(maxValue, ceilRate) : maxValue;
}
break;
case Axis.AxisMinMaxType.MinMax:
minValue = ceilRate != 0 ? ChartHelper.GetMinDivisibleValue(minValue, ceilRate) : minValue;
maxValue = ceilRate != 0 ? ChartHelper.GetMaxDivisibleValue(maxValue, ceilRate) : maxValue;
break;
}
}
}
public static bool NeedShowSplit(Axis axis)
{
if (!axis.show)
return false;
if (axis.IsCategory() && axis.GetDataList().Count <= 0)
return false;
else
return true;
}
public static void AdjustCircleLabelPos(ChartText txt, Vector3 pos, Vector3 cenPos, float txtHig, Vector3 offset)
{
var txtWidth = txt.GetPreferredWidth();
var sizeDelta = new Vector2(txtWidth, txt.GetPreferredHeight());
txt.SetSizeDelta(sizeDelta);
var diff = pos.x - cenPos.x;
if (diff < -1f) //left
{
pos = new Vector3(pos.x - txtWidth / 2, pos.y);
}
else if (diff > 1f) //right
{
pos = new Vector3(pos.x + txtWidth / 2, pos.y);
}
else
{
float y = pos.y > cenPos.y ? pos.y + txtHig / 2 : pos.y - txtHig / 2;
pos = new Vector3(pos.x, y);
}
txt.SetLocalPosition(pos + offset);
}
public static void AdjustCircleLabelPos(ChartLabel txt, Vector3 pos, Vector3 cenPos, float txtHig, Vector3 offset)
{
var txtWidth = txt.label.GetPreferredWidth();
var sizeDelta = new Vector2(txtWidth, txt.label.GetPreferredHeight());
txt.label.SetSizeDelta(sizeDelta);
var diff = pos.x - cenPos.x;
if (diff < -1f) //left
{
pos = new Vector3(pos.x - txtWidth / 2, pos.y);
}
else if (diff > 1f) //right
{
pos = new Vector3(pos.x + txtWidth / 2, pos.y);
}
else
{
float y = pos.y > cenPos.y ? pos.y + txtHig / 2 : pos.y - txtHig / 2;
pos = new Vector3(pos.x, y);
}
txt.SetPosition(pos + offset);
}
public static void AdjustRadiusAxisLabelPos(ChartText txt, Vector3 pos, Vector3 cenPos, float txtHig, Vector3 offset)
{
var txtWidth = txt.GetPreferredWidth();
var sizeDelta = new Vector2(txtWidth, txt.GetPreferredHeight());
txt.SetSizeDelta(sizeDelta);
var diff = pos.y - cenPos.y;
if (diff > 20f) //left
{
pos = new Vector3(pos.x - txtWidth / 2, pos.y);
}
else if (diff < -20f) //right
{
pos = new Vector3(pos.x + txtWidth / 2, pos.y);
}
else
{
float y = pos.y > cenPos.y ? pos.y + txtHig / 2 : pos.y - txtHig / 2;
pos = new Vector3(pos.x, y);
}
txt.SetLocalPosition(pos);
}
public static float GetAxisPosition(GridCoord grid, Axis axis, double value, int dataCount = 0, DataZoom dataZoom = null)
{
var gridHeight = axis is YAxis ? grid.context.height : grid.context.width;
var gridXY = axis is YAxis ? grid.context.y : grid.context.x;
if (axis.IsCategory())
{
if (dataCount == 0) dataCount = axis.data.Count;
var categoryIndex = (int)value;
var scaleWid = AxisHelper.GetDataWidth(axis, gridHeight, dataCount, dataZoom);
float startY = gridXY + (axis.boundaryGap ? scaleWid / 2 : 0);
return startY + scaleWid * categoryIndex;
}
else
{
var yDataHig = (axis.context.minMaxRange == 0) ? 0f :
(float)((value - axis.context.minValue) / axis.context.minMaxRange * gridHeight);
return gridXY + yDataHig;
}
}
public static float GetAxisPosition(GridCoord grid, Axis axis, float scaleWidth, double value)
{
return GetAxisPositionInternal(grid, axis, scaleWidth, value, true);
}
public static float GetAxisValueLength(GridCoord grid, Axis axis, float scaleWidth, double value)
{
return GetAxisPositionInternal(grid, axis, scaleWidth, value, false);
}
private static float GetAxisPositionInternal(GridCoord grid, Axis axis, float scaleWidth, double value, bool includeGridXY)
{
var isY = axis is YAxis;
var gridHeight = isY ? grid.context.height : grid.context.width;
var gridXY = isY ? grid.context.y : grid.context.x;
if (axis.IsLog())
{
int minIndex = axis.GetLogMinIndex();
float nowIndex = axis.GetLogValue(value);
return includeGridXY
? gridXY + (nowIndex - minIndex) / axis.splitNumber * gridHeight
: (nowIndex - minIndex) / axis.splitNumber * gridHeight;
}
else if (axis.IsCategory())
{
var categoryIndex = (int)value;
return includeGridXY
? gridXY + (axis.boundaryGap ? scaleWidth / 2 : 0) + scaleWidth * categoryIndex
: (axis.boundaryGap ? scaleWidth / 2 : 0) + scaleWidth * categoryIndex;
}
else
{
var yDataHig = (axis.context.minMaxRange == 0) ? 0f :
(float)((value - axis.context.minValue) / axis.context.minMaxRange * gridHeight);
return includeGridXY
? gridXY + yDataHig
: yDataHig;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 566e3426780cc4339a1fb92d9604d21f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,311 @@
using System;
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
/// <summary>
/// Settings related to axis label.
/// 坐标轴刻度标签的相关设置。
/// </summary>
[Serializable]
public class AxisLabel : ChildComponent
{
[SerializeField] private bool m_Show = true;
[SerializeField] private string m_Formatter;
[SerializeField] private int m_Interval = 0;
[SerializeField] private bool m_Inside = false;
[SerializeField] private float m_Margin;
[SerializeField] private string m_NumericFormatter = "";
[SerializeField] private bool m_ShowAsPositiveNumber = false;
[SerializeField] private bool m_OnZero = false;
[SerializeField] private float m_Width = 0f;
[SerializeField] private float m_Height = 0f;
[SerializeField] private bool m_ShowStartLabel = true;
[SerializeField] private bool m_ShowEndLabel = true;
[SerializeField] private TextLimit m_TextLimit = new TextLimit();
[SerializeField] private TextStyle m_TextStyle = new TextStyle();
private DelegateAxisLabelFormatter m_FormatterFunction;
/// <summary>
/// Set this to false to prevent the axis label from appearing.
/// 是否显示刻度标签。
/// </summary>
public bool show
{
get { return m_Show; }
set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetComponentDirty(); }
}
/// <summary>
/// The display interval of the axis label.
/// 坐标轴刻度标签的显示间隔在类目轴中有效。0表示显示所有标签1表示隔一个隔显示一个标签以此类推。
/// </summary>
public int interval
{
get { return m_Interval; }
set { if (PropertyUtil.SetStruct(ref m_Interval, value)) SetComponentDirty(); }
}
/// <summary>
/// Set this to true so the axis labels face the inside direction.
/// 刻度标签是否朝内,默认朝外。
/// </summary>
public bool inside
{
get { return m_Inside; }
set { if (PropertyUtil.SetStruct(ref m_Inside, value)) SetComponentDirty(); }
}
/// <summary>
/// The margin between the axis label and the axis line.
/// 刻度标签与轴线之间的距离。
/// </summary>
public float margin
{
get { return m_Margin; }
set { if (PropertyUtil.SetStruct(ref m_Margin, value)) SetComponentDirty(); }
}
/// <summary>
/// 图例内容字符串模版格式器。支持用 \n 换行。
/// 模板变量为图例名称 {value}。
/// </summary>
public string formatter
{
get { return m_Formatter; }
set { if (PropertyUtil.SetClass(ref m_Formatter, value)) SetComponentDirty(); }
}
/// <summary>
/// Standard numeric format strings.
/// 标准数字格式字符串。用于将数值格式化显示为字符串。
/// 使用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>
/// Show negative number as positive number.
/// 将负数数值显示为正数。一般和`Serie`的`showAsPositiveNumber`配合使用。
/// </summary>
public bool showAsPositiveNumber
{
get { return m_ShowAsPositiveNumber; }
set { if (PropertyUtil.SetStruct(ref m_ShowAsPositiveNumber, value)) SetComponentDirty(); }
}
/// <summary>
/// 刻度标签显示在0刻度上。
/// </summary>
public bool onZero
{
get { return m_OnZero; }
set { if (PropertyUtil.SetStruct(ref m_OnZero, value)) SetComponentDirty(); }
}
/// <summary>
/// 文本的宽。为0时会自动匹配。
/// </summary>
public float width
{
get { return m_Width; }
set { if (PropertyUtil.SetStruct(ref m_Width, value)) SetComponentDirty(); }
}
/// <summary>
/// 文本的高。为0时会自动匹配。
/// </summary>
public float height
{
get { return m_Height; }
set { if (PropertyUtil.SetStruct(ref m_Height, value)) SetComponentDirty(); }
}
/// <summary>
/// Whether to display the first label.
/// 是否显示第一个文本。
/// </summary>
public bool showStartLabel
{
get { return m_ShowStartLabel; }
set { if (PropertyUtil.SetStruct(ref m_ShowStartLabel, value)) SetComponentDirty(); }
}
/// <summary>
/// Whether to display the last label.
/// 是否显示最后一个文本。
/// </summary>
public bool showEndLabel
{
get { return m_ShowEndLabel; }
set { if (PropertyUtil.SetStruct(ref m_ShowEndLabel, value)) SetComponentDirty(); }
}
/// <summary>
/// 文本限制。
/// </summary>
public TextLimit textLimit
{
get { return m_TextLimit; }
set { if (value != null) { m_TextLimit = value; SetComponentDirty(); } }
}
/// <summary>
/// The text style of axis name.
/// 文本样式。
/// </summary>
public TextStyle textStyle
{
get { return m_TextStyle; }
set { if (PropertyUtil.SetClass(ref m_TextStyle, value)) SetComponentDirty(); }
}
public DelegateAxisLabelFormatter formatterFunction
{
set { m_FormatterFunction = value; }
}
public override bool componentDirty { get { return m_ComponentDirty || m_TextLimit.componentDirty; } }
public override void ClearComponentDirty()
{
base.ClearComponentDirty();
textLimit.ClearComponentDirty();
}
public static AxisLabel defaultAxisLabel
{
get
{
return new AxisLabel()
{
m_Show = true,
m_Interval = 0,
m_Inside = false,
m_Margin = 8,
m_TextStyle = new TextStyle(),
};
}
}
public AxisLabel Clone()
{
var axisLabel = new AxisLabel();
axisLabel.show = show;
axisLabel.formatter = formatter;
axisLabel.interval = interval;
axisLabel.inside = inside;
axisLabel.margin = margin;
axisLabel.numericFormatter = numericFormatter;
axisLabel.width = width;
axisLabel.height = height;
axisLabel.showStartLabel = showStartLabel;
axisLabel.showEndLabel = showEndLabel;
axisLabel.textLimit = textLimit.Clone();
axisLabel.textStyle.Copy(textStyle);
return axisLabel;
}
public void Copy(AxisLabel axisLabel)
{
show = axisLabel.show;
formatter = axisLabel.formatter;
interval = axisLabel.interval;
inside = axisLabel.inside;
margin = axisLabel.margin;
numericFormatter = axisLabel.numericFormatter;
width = axisLabel.width;
height = axisLabel.height;
showStartLabel = axisLabel.showStartLabel;
showEndLabel = axisLabel.showEndLabel;
textLimit.Copy(axisLabel.textLimit);
textStyle.Copy(axisLabel.textStyle);
}
public void SetRelatedText(ChartText txt, float labelWidth)
{
m_TextLimit.SetRelatedText(txt, labelWidth);
}
public string GetFormatterContent(int labelIndex, string category)
{
if (m_FormatterFunction != null)
{
return m_FormatterFunction(labelIndex, 0, category);
}
if (string.IsNullOrEmpty(category))
return category;
if (string.IsNullOrEmpty(m_Formatter))
{
return m_TextLimit.GetLimitContent(category);
}
else
{
var content = m_Formatter;
FormatterHelper.ReplaceAxisLabelContent(ref content, category);
return m_TextLimit.GetLimitContent(content);
}
}
public string GetFormatterContent(int labelIndex, double value, double minValue, double maxValue, bool isLog = false)
{
if (showAsPositiveNumber && value < 0)
{
value = Math.Abs(value);
}
if (m_FormatterFunction != null)
{
return m_FormatterFunction(labelIndex, value, null);
}
if (string.IsNullOrEmpty(m_Formatter))
{
if (isLog)
{
return ChartCached.NumberToStr(value, numericFormatter);
}
if (minValue >= -1 && minValue <= 1 && maxValue >= -1 && maxValue <= 1)
{
int minAcc = ChartHelper.GetFloatAccuracy(minValue);
int maxAcc = ChartHelper.GetFloatAccuracy(maxValue);
int curAcc = ChartHelper.GetFloatAccuracy(value);
int acc = Mathf.Max(Mathf.Max(minAcc, maxAcc), curAcc);
return ChartCached.FloatToStr(value, numericFormatter, acc);
}
return ChartCached.NumberToStr(value, numericFormatter);
}
else
{
var content = m_Formatter;
FormatterHelper.ReplaceAxisLabelContent(ref content, numericFormatter, value);
return content;
}
}
public string GetFormatterDateTime(int labelIndex, double value, double minValue, double maxValue)
{
if (m_FormatterFunction != null)
{
return m_FormatterFunction(labelIndex, value, null);
}
var timestamp = (int)value;
var dateTime = DateTimeUtil.GetDateTime(timestamp);
var dateString = string.Empty;
if (string.IsNullOrEmpty(numericFormatter))
{
dateString = DateTimeUtil.GetDateTimeFormatString(dateTime, maxValue - minValue);
}
else
{
dateString = dateTime.ToString(numericFormatter);
}
if (!string.IsNullOrEmpty(m_Formatter))
{
var content = m_Formatter;
FormatterHelper.ReplaceAxisLabelContent(ref content, dateString);
return m_TextLimit.GetLimitContent(content);
}
else
{
return m_TextLimit.GetLimitContent(dateString);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 051f9473d1beb4e0bb35aa1600cb44bd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,78 @@
using UnityEngine;
namespace XCharts
{
/// <summary>
/// Settings related to axis line.
/// 坐标轴轴线。
/// </summary>
[System.Serializable]
public class AxisLine : BaseLine
{
[SerializeField] private bool m_OnZero;
[SerializeField] private bool m_ShowArrow;
[SerializeField] private ArrowStyle m_Arrow = new ArrowStyle();
/// <summary>
/// When mutiple axes exists, this option can be used to specify which axis can be "onZero" to.
/// X 轴或者 Y 轴的轴线是否在另一个轴的 0 刻度上,只有在另一个轴为数值轴且包含 0 刻度时有效。
/// </summary>
public bool onZero
{
get { return m_OnZero; }
set { if (PropertyUtil.SetStruct(ref m_OnZero, value)) SetVerticesDirty(); }
}
/// <summary>
/// Whether to show the arrow symbol of axis.
/// 是否显示箭头。
/// </summary>
public bool showArrow
{
get { return m_ShowArrow; }
set { if (PropertyUtil.SetStruct(ref m_ShowArrow, value)) SetVerticesDirty(); }
}
/// <summary>
/// the arrow of line.
/// 轴线箭头。
/// </summary>
public ArrowStyle arrow
{
get { return m_Arrow; }
set { if (PropertyUtil.SetClass(ref m_Arrow, value)) SetVerticesDirty(); }
}
public static AxisLine defaultAxisLine
{
get
{
var axisLine = new AxisLine
{
m_Show = true,
m_OnZero = true,
m_ShowArrow = false,
m_Arrow = new ArrowStyle(),
m_LineStyle = new LineStyle(LineStyle.Type.None),
};
return axisLine;
}
}
public AxisLine Clone()
{
var axisLine = new AxisLine();
axisLine.show = show;
axisLine.onZero = onZero;
axisLine.showArrow = showArrow;
axisLine.arrow = arrow.Clone();
return axisLine;
}
public void Copy(AxisLine axisLine)
{
base.Copy(axisLine);
onZero = axisLine.onZero;
showArrow = axisLine.showArrow;
arrow.Copy(axisLine.arrow);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2748c2a8789724709aa76f6056eb708d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,99 @@
using System;
using UnityEngine;
namespace XCharts
{
/// <summary>
/// the name of axis.
/// 坐标轴名称。
/// </summary>
[Serializable]
public class AxisName : ChildComponent
{
/// <summary>
/// the location of axis name.
/// 坐标轴名称显示位置。
/// </summary>
public enum Location
{
Start,
Middle,
End
}
[SerializeField] private bool m_Show;
[SerializeField] private string m_Name;
[SerializeField] private Location m_Location;
[SerializeField] private TextStyle m_TextStyle = new TextStyle();
/// <summary>
/// Whether to show axis name.
/// 是否显示坐标名称。
/// </summary>
public bool show
{
get { return m_Show; }
set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetComponentDirty(); }
}
/// <summary>
/// the name of axis.
/// 坐标轴名称。
/// </summary>
public string name
{
get { return m_Name; }
set { if (PropertyUtil.SetClass(ref m_Name, value)) SetComponentDirty(); }
}
/// <summary>
/// Location of axis name.
/// 坐标轴名称显示位置。
/// </summary>
public Location location
{
get { return m_Location; }
set { if (PropertyUtil.SetStruct(ref m_Location, value)) SetComponentDirty(); }
}
/// <summary>
/// The text style of axis name.
/// 文本样式。
/// </summary>
public TextStyle textStyle
{
get { return m_TextStyle; }
set { if (PropertyUtil.SetClass(ref m_TextStyle, value)) SetComponentDirty(); }
}
public static AxisName defaultAxisName
{
get
{
return new AxisName()
{
m_Show = false,
m_Name = "axisName",
m_Location = Location.End,
m_TextStyle = new TextStyle(),
};
}
}
public AxisName Clone()
{
var axisName = new AxisName();
axisName.show = show;
axisName.name = name;
axisName.location = location;
axisName.textStyle.Copy(textStyle);
return axisName;
}
public void Copy(AxisName axisName)
{
show = axisName.show;
name = axisName.name;
location = axisName.location;
textStyle.Copy(axisName.textStyle);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 878555ba3c6b1479f94f38185700531e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
/// <summary>
/// Split area of axis in grid area, not shown by default.
/// 坐标轴在 grid 区域中的分隔区域,默认不显示。
/// </summary>
[Serializable]
public class AxisSplitArea : ChildComponent
{
[SerializeField] private bool m_Show;
[SerializeField] private List<Color32> m_Color;
/// <summary>
/// Set this to true to show the splitArea.
/// 是否显示分隔区域。
/// </summary>
public bool show
{
get { return m_Show; }
set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetVerticesDirty(); }
}
/// <summary>
/// Color of split area. SplitArea color could also be set in color array,
/// which the split lines would take as their colors in turns.
/// Dark and light colors in turns are used by default.
/// 分隔区域颜色。分隔区域会按数组中颜色的顺序依次循环设置颜色。默认是一个深浅的间隔色。
/// </summary>
public List<Color32> color
{
get { return m_Color; }
set { if (value != null) { m_Color = value; SetVerticesDirty(); } }
}
public static AxisSplitArea defaultSplitArea
{
get
{
return new AxisSplitArea()
{
m_Show = false,
m_Color = new List<Color32>() { }
};
}
}
public AxisSplitArea Clone()
{
var axisSplitArea = new AxisSplitArea();
axisSplitArea.show = show;
axisSplitArea.color = new List<Color32>();
ChartHelper.CopyList(axisSplitArea.color, color);
return axisSplitArea;
}
public void Copy(AxisSplitArea splitArea)
{
show = splitArea.show;
color.Clear();
ChartHelper.CopyList(color, splitArea.color);
}
public Color32 GetColor(int index, BaseAxisTheme theme)
{
if (color.Count > 0)
{
var i = index % color.Count;
return color[i];
}
else
{
var i = index % theme.splitAreaColors.Count;
return theme.splitAreaColors[i];
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 18702fd7797054670af64546b7304bb4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,59 @@
using System;
using UnityEngine;
namespace XCharts
{
/// <summary>
/// Split line of axis in grid area.
/// 坐标轴在 grid 区域中的分隔线。
/// </summary>
[Serializable]
public class AxisSplitLine : BaseLine
{
[SerializeField] private int m_Interval;
public int interval
{
get { return m_Interval; }
set { if (PropertyUtil.SetStruct(ref m_Interval, value)) SetVerticesDirty(); }
}
public override bool vertsDirty { get { return m_VertsDirty || m_LineStyle.anyDirty; } }
public override void ClearVerticesDirty()
{
base.ClearVerticesDirty();
m_LineStyle.ClearVerticesDirty();
}
public static AxisSplitLine defaultSplitLine
{
get
{
return new AxisSplitLine()
{
m_Show = false,
};
}
}
public AxisSplitLine Clone()
{
var axisSplitLine = new AxisSplitLine();
axisSplitLine.show = show;
axisSplitLine.interval = interval;
axisSplitLine.lineStyle = lineStyle.Clone();
return axisSplitLine;
}
public void Copy(AxisSplitLine splitLine)
{
base.Copy(splitLine);
interval = splitLine.interval;
}
internal bool NeedShow(int index)
{
return show && (interval == 0 || index % (interval + 1) == 0);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3da942a7a6bea44e2998ed993c0641ab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,93 @@
using UnityEngine;
namespace XCharts
{
/// <summary>
/// Settings related to axis tick.
/// 坐标轴刻度相关设置。
/// </summary>
[System.Serializable]
public class AxisTick : BaseLine
{
[SerializeField] private bool m_AlignWithLabel;
[SerializeField] private bool m_Inside;
[SerializeField] private bool m_ShowStartTick;
[SerializeField] private bool m_ShowEndTick;
/// <summary>
/// Align axis tick with label, which is available only when boundaryGap is set to be true in category axis.
/// 类目轴中在 boundaryGap 为 true 的时候有效,可以保证刻度线和标签对齐。
/// </summary>
public bool alignWithLabel
{
get { return m_AlignWithLabel; }
set { if (PropertyUtil.SetStruct(ref m_AlignWithLabel, value)) SetVerticesDirty(); }
}
/// <summary>
/// Set this to true so the axis labels face the inside direction.
/// 坐标轴刻度是否朝内,默认朝外。
/// </summary>
public bool inside
{
get { return m_Inside; }
set { if (PropertyUtil.SetStruct(ref m_Inside, value)) SetVerticesDirty(); }
}
/// <summary>
/// Whether to display the first tick.
/// 是否显示第一个刻度。
/// </summary>
public bool showStartTick
{
get { return m_ShowStartTick; }
set { if (PropertyUtil.SetStruct(ref m_ShowStartTick, value)) SetVerticesDirty(); }
}
/// <summary>
/// Whether to display the last tick.
/// 是否显示最后一个刻度。
/// </summary>
public bool showEndTick
{
get { return m_ShowEndTick; }
set { if (PropertyUtil.SetStruct(ref m_ShowEndTick, value)) SetVerticesDirty(); }
}
public static AxisTick defaultTick
{
get
{
var tick = new AxisTick
{
m_Show = true,
m_AlignWithLabel = false,
m_Inside = false,
m_ShowStartTick = true,
m_ShowEndTick = true
};
return tick;
}
}
public AxisTick Clone()
{
var axisTick = new AxisTick();
axisTick.show = show;
axisTick.alignWithLabel = alignWithLabel;
axisTick.inside = inside;
axisTick.showStartTick = showStartTick;
axisTick.showEndTick = showEndTick;
axisTick.lineStyle = lineStyle.Clone();
return axisTick;
}
public void Copy(AxisTick axisTick)
{
show = axisTick.show;
alignWithLabel = axisTick.alignWithLabel;
inside = axisTick.inside;
showStartTick = axisTick.showStartTick;
showEndTick = axisTick.showEndTick;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 60278762ed892450d85e27b7df8f997e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 24693180b2a2e41b2ab4025b2bbebf01
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,32 @@
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
[System.Serializable]
[RequireChartComponent(typeof(ParallelCoord))]
[ComponentHandler(typeof(ParallelAxisHander), true)]
public class ParallelAxis : Axis
{
public override void SetDefaultValue()
{
m_Show = true;
m_Type = AxisType.Value;
m_Min = 0;
m_Max = 0;
m_SplitNumber = 0;
m_BoundaryGap = true;
m_Position = AxisPosition.Bottom;
m_Offset = 0;
m_Data = new List<string>() { "x1", "x2", "x3", "x4", "x5" };
m_Icons = new List<Sprite>(5);
splitLine.show = false;
splitLine.lineStyle.type = LineStyle.Type.None;
axisLabel.textLimit.enable = true;
iconStyle.show = false;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d7bc01c54f4d6485389fd57c37810c74
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,163 @@
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class ParallelAxisHander : AxisHandler<ParallelAxis>
{
private Orient m_Orient;
private ParallelCoord m_Parallel;
protected override Orient orient { get { return m_Orient; } }
public override void InitComponent()
{
InitParallelAxis(component);
}
public override void Update()
{
UpdateContext(component);
}
public override void DrawBase(VertexHelper vh)
{
UpdateContext(component);
DrawParallelAxisSplit(vh, component);
DrawParallelAxisLine(vh, component);
DrawParallelAxisTick(vh, component);
}
private void UpdateContext(ParallelAxis axis)
{
var parallel = chart.GetChartComponent<ParallelCoord>(axis.parallelIndex);
if (parallel == null)
return;
m_Orient = parallel.orient;
m_Parallel = parallel;
var axisCount = chart.GetChartComponentNum<ParallelAxis>();
if (m_Orient == Orient.Horizonal)
{
var each = axisCount > 1 ? parallel.context.height / (axisCount - 1) : 0;
axis.context.x = parallel.context.x;
axis.context.y = parallel.context.y + (axis.index) * each;
axis.context.width = parallel.context.width;
}
else
{
var each = axisCount > 1 ? parallel.context.width / (axisCount - 1) : 0;
axis.context.x = parallel.context.x + (axis.index) * each;
axis.context.y = parallel.context.y;
axis.context.width = parallel.context.height;
}
axis.context.orient = m_Orient;
axis.context.height = 0;
axis.context.position = new Vector3(axis.context.x, axis.context.y);
}
private void InitParallelAxis(ParallelAxis axis)
{
var theme = chart.theme;
var xAxisIndex = axis.index;
axis.painter = chart.painter;
axis.refreshComponent = delegate ()
{
UpdateContext(axis);
InitAxis(axis, null, chart, this,
m_Orient,
axis.context.x,
axis.context.y,
axis.context.width,
axis.context.height);
};
axis.refreshComponent();
}
internal override void UpdateAxisLabelText(Axis axis)
{
base.UpdateAxisLabelText(axis);
if (axis.IsTime() || axis.IsValue())
{
for (int i = 0; i < axis.context.labelObjectList.Count; i++)
{
var label = axis.context.labelObjectList[i];
if (label != null)
{
var pos = GetLabelPosition(0, i);
label.SetPosition(pos);
CheckValueLabelActive(component, i, label, pos);
}
}
}
}
protected override Vector3 GetLabelPosition(float scaleWid, int i)
{
if (m_Parallel == null)
return Vector3.zero;
return GetLabelPosition(i, m_Orient, component, null,
chart.theme.axis,
scaleWid,
component.context.x,
component.context.y,
component.context.width,
component.context.height);
}
private void DrawParallelAxisSplit(VertexHelper vh, ParallelAxis axis)
{
if (AxisHelper.NeedShowSplit(axis))
{
if (m_Parallel == null)
return;
var dataZoom = chart.GetDataZoomOfAxis(axis);
DrawAxisSplit(vh, axis, chart.theme.axis, dataZoom,
m_Orient,
axis.context.x,
axis.context.y,
axis.context.width,
axis.context.height);
}
}
private void DrawParallelAxisTick(VertexHelper vh, ParallelAxis axis)
{
if (AxisHelper.NeedShowSplit(axis))
{
if (m_Parallel == null)
return;
var dataZoom = chart.GetDataZoomOfAxis(axis);
DrawAxisTick(vh, axis, chart.theme.axis, dataZoom,
m_Orient,
axis.context.x,
axis.context.y,
axis.context.width);
}
}
private void DrawParallelAxisLine(VertexHelper vh, ParallelAxis axis)
{
if (axis.show && axis.axisLine.show)
{
if (m_Parallel == null)
return;
DrawAxisLine(vh, axis,
chart.theme.axis,
m_Orient,
axis.context.x,
axis.context.y,
axis.context.width);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 26ab25bf702c54ad38461c91ba1451af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7c8971958a94d47e68f7ebdff5872b71
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
using System.Collections.Generic;
namespace XCharts
{
/// <summary>
/// Radial axis of polar coordinate.
/// 极坐标系的径向轴。
/// </summary>
[System.Serializable]
[ComponentHandler(typeof(RadiusAxisHandler), true)]
public class RadiusAxis : Axis
{
public override void SetDefaultValue()
{
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);
splitLine.show = true;
splitLine.lineStyle.type = LineStyle.Type.Solid;
axisLabel.textLimit.enable = false;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f6429398a27934726ba49d387d681728
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,154 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class RadiusAxisHandler : MainComponentHandler<RadiusAxis>
{
public override void InitComponent()
{
InitRadiusAxis(component);
}
public override void Update()
{
UpdateAxisMinMaxValue(component);
}
public override void DrawBase(VertexHelper vh)
{
DrawRadiusAxis(vh, component);
}
private void UpdateAxisMinMaxValue(RadiusAxis axis, bool updateChart = true)
{
if (axis.IsCategory() || !axis.show) return;
double tempMinValue = 0;
double tempMaxValue = 0;
SeriesHelper.GetXMinMaxValue(chart.series, null, axis.polarIndex, true, axis.inverse, out tempMinValue,
out tempMaxValue, true);
AxisHelper.AdjustMinMaxValue(axis, ref tempMinValue, ref tempMaxValue, true);
if (tempMinValue != axis.context.minValue || tempMaxValue != axis.context.maxValue)
{
axis.UpdateMinMaxValue(tempMinValue, tempMaxValue);
axis.context.offset = 0;
axis.context.lastCheckInverse = axis.inverse;
if (updateChart)
{
UpdateAxisLabelText(axis);
chart.RefreshChart();
}
}
}
internal void UpdateAxisLabelText(RadiusAxis axis)
{
var polar = chart.GetChartComponent<PolarCoord>(axis.polarIndex);
axis.UpdateLabelText(polar.context.radius, null, false);
}
private void InitRadiusAxis(RadiusAxis axis)
{
var polar = chart.GetChartComponent<PolarCoord>(axis.index);
if (polar == null)
return;
var angleAxis = ComponentHelper.GetAngleAxis(chart.components, polar.index);
if (angleAxis == null)
return;
PolarHelper.UpdatePolarCenter(polar, chart.chartPosition, chart.chartWidth, chart.chartHeight);
axis.context.labelObjectList.Clear();
var radius = polar.context.radius;
var objName = "axis_radius" + axis.index;
var axisObj = ChartHelper.AddObject(objName, chart.transform, chart.chartMinAnchor,
chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta);
axisObj.transform.localPosition = Vector3.zero;
axisObj.SetActive(axis.show && axis.axisLabel.show);
axisObj.hideFlags = chart.chartHideFlags;
ChartHelper.HideAllObject(axisObj);
var textStyle = axis.axisLabel.textStyle;
var splitNumber = AxisHelper.GetSplitNumber(axis, radius, null);
var totalWidth = 0f;
var startAngle = angleAxis.startAngle;
var cenPos = polar.context.center;
var txtHig = textStyle.GetFontSize(chart.theme.axis) + 2;
var dire = ChartHelper.GetDire(startAngle, true).normalized;
var tickWidth = axis.axisTick.GetLength(chart.theme.axis.tickWidth);
var tickVector = ChartHelper.GetVertialDire(dire)
* (tickWidth + axis.axisLabel.margin);
for (int i = 0; i <= splitNumber; i++)
{
var labelWidth = AxisHelper.GetScaleWidth(axis, radius, i, null);
var inside = axis.axisLabel.inside;
var isPercentStack = SeriesHelper.IsPercentStack<Bar>(chart.series);
var labelName = AxisHelper.GetLabelName(axis, radius, i, axis.context.minValue, axis.context.maxValue,
null, isPercentStack);
var label = ChartHelper.AddAxisLabelObject(splitNumber, i, objName + i, axisObj.transform, new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(labelWidth, txtHig), axis, chart.theme.axis,
labelName);
if (i == 0)
axis.axisLabel.SetRelatedText(label.label, labelWidth);
label.label.SetAlignment(textStyle.GetAlignment(TextAnchor.MiddleCenter));
label.SetText(labelName);
label.SetPosition(ChartHelper.GetPos(cenPos, totalWidth, startAngle, true) + tickVector);
label.SetActive(true);
axis.context.labelObjectList.Add(label);
totalWidth += labelWidth;
}
}
private void DrawRadiusAxis(VertexHelper vh, RadiusAxis radiusAxis)
{
var polar = chart.GetChartComponent<PolarCoord>(radiusAxis.polarIndex);
if (polar == null)
return;
var angleAxis = ComponentHelper.GetAngleAxis(chart.components, polar.index);
if (angleAxis == null)
return;
var startAngle = angleAxis.startAngle;
var radius = polar.context.radius;
var cenPos = polar.context.center;
var size = AxisHelper.GetScaleNumber(radiusAxis, radius, null);
var totalWidth = 0f;
var dire = ChartHelper.GetDire(startAngle, true).normalized;
var tickWidth = radiusAxis.axisTick.GetLength(chart.theme.axis.tickWidth);
var tickLength = radiusAxis.axisTick.GetLength(chart.theme.axis.tickLength);
var tickVetor = ChartHelper.GetVertialDire(dire) * tickLength;
for (int i = 0; i < size - 1; i++)
{
var scaleWidth = AxisHelper.GetScaleWidth(radiusAxis, radius, i);
var pos = ChartHelper.GetPos(cenPos, totalWidth, startAngle, true);
if (radiusAxis.show && radiusAxis.splitLine.show)
{
var outsideRaidus = totalWidth + radiusAxis.splitLine.GetWidth(chart.theme.axis.splitLineWidth) * 2;
var splitLineColor = radiusAxis.splitLine.GetColor(chart.theme.axis.splitLineColor);
UGL.DrawDoughnut(vh, cenPos, totalWidth, outsideRaidus, splitLineColor, Color.clear);
}
if (radiusAxis.show && radiusAxis.axisTick.show)
{
UGL.DrawLine(vh, pos, pos + tickVetor, tickWidth, chart.theme.axis.lineColor);
}
totalWidth += scaleWidth;
}
if (radiusAxis.show && radiusAxis.axisLine.show)
{
var lineStartPos = polar.context.center - dire * tickWidth;
var lineEndPos = polar.context.center + dire * (radius + tickWidth);
var lineWidth = radiusAxis.axisLine.GetWidth(chart.theme.axis.lineWidth);
UGL.DrawLine(vh, lineStartPos, lineEndPos, lineWidth, chart.theme.axis.lineColor);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3f2cb79bfe30c4f14a3117f9f30ed3bd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 17498717d39c14b43a91c67401407410
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,146 @@
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
/// <summary>
/// Single axis.
/// 单轴。
/// </summary>
[System.Serializable]
[ComponentHandler(typeof(SingleAxisHander), true)]
public class SingleAxis : Axis, IUpdateRuntimeData
{
[SerializeField] protected Orient m_Orient = Orient.Horizonal;
[SerializeField] private float m_Left = 0.1f;
[SerializeField] private float m_Right = 0.1f;
[SerializeField] private float m_Top = 0f;
[SerializeField] private float m_Bottom = 0.2f;
[SerializeField] private float m_Width = 0;
[SerializeField] private float m_Height = 50;
/// <summary>
/// Orientation of the axis. By default, it's 'Horizontal'. You can set it to be 'Vertical' to make a vertical axis.
/// 坐标轴朝向。默认为水平朝向。
/// </summary>
public Orient orient
{
get { return m_Orient; }
set { if (PropertyUtil.SetStruct(ref m_Orient, value)) SetAllDirty(); }
}
/// <summary>
/// Distance between component and the left side of the container.
/// 组件离容器左侧的距离。
/// </summary>
public float left
{
get { return m_Left; }
set { if (PropertyUtil.SetStruct(ref m_Left, value)) SetAllDirty(); }
}
/// <summary>
/// Distance between component and the right side of the container.
/// 组件离容器右侧的距离。
/// </summary>
public float right
{
get { return m_Right; }
set { if (PropertyUtil.SetStruct(ref m_Right, value)) SetAllDirty(); }
}
/// <summary>
/// Distance between component and the top side of the container.
/// 组件离容器上侧的距离。
/// </summary>
public float top
{
get { return m_Top; }
set { if (PropertyUtil.SetStruct(ref m_Top, value)) SetAllDirty(); }
}
/// <summary>
/// Distance between component and the bottom side of the container.
/// 组件离容器下侧的距离。
/// </summary>
public float bottom
{
get { return m_Bottom; }
set { if (PropertyUtil.SetStruct(ref m_Bottom, value)) SetAllDirty(); }
}
public float width
{
get { return m_Width; }
set { if (PropertyUtil.SetStruct(ref m_Width, value)) SetAllDirty(); }
}
public float height
{
get { return m_Height; }
set { if (PropertyUtil.SetStruct(ref m_Height, value)) SetAllDirty(); }
}
public void UpdateRuntimeData(float chartX, float chartY, float chartWidth, float chartHeight)
{
context.left = left <= 1 ? left * chartWidth : left;
context.bottom = bottom <= 1 ? bottom * chartHeight : bottom;
context.top = top <= 1 ? top * chartHeight : top;
context.right = right <= 1 ? right * chartWidth : right;
context.height = height <= 1 ? height * chartHeight : height;
if (m_Orient == Orient.Horizonal)
{
context.width = width == 0
? chartWidth - context.left - context.right
: (width <= 1 ? chartWidth * width : width);
}
else
{
context.width = width == 0
? chartHeight - context.top - context.bottom
: (width <= 1 ? chartHeight * width : width);
}
if (context.left != 0 && context.right == 0)
context.x = chartX + context.left;
else if (context.left == 0 && context.right != 0)
context.x = chartX + chartWidth - context.right - context.width;
else
context.x = chartX + context.left;
if (context.bottom != 0 && context.top == 0)
context.y = chartY + context.bottom;
else if (context.bottom == 0 && context.top != 0)
context.y = chartY + chartHeight - context.top - context.height;
else
context.y = chartY + context.bottom;
context.position = new Vector3(context.x, context.y);
}
public override void SetDefaultValue()
{
m_Show = true;
m_Type = AxisType.Category;
m_Min = 0;
m_Max = 0;
m_SplitNumber = 0;
m_BoundaryGap = true;
m_Position = AxisPosition.Bottom;
m_Offset = 0;
m_Left = 0.1f;
m_Right = 0.1f;
m_Top = 0;
m_Bottom = 0.2f;
m_Width = 0;
m_Height = 50;
m_Data = new List<string>() { "x1", "x2", "x3", "x4", "x5" };
m_Icons = new List<Sprite>(5);
splitLine.show = false;
splitLine.lineStyle.type = LineStyle.Type.None;
axisLabel.textLimit.enable = true;
axisTick.showStartTick = true;
axisTick.showEndTick = true;
iconStyle.show = false;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aeb871d6555744e609bd651306c601a8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,122 @@
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class SingleAxisHander : AxisHandler<SingleAxis>
{
protected override Orient orient { get { return component.orient; } }
public override void InitComponent()
{
InitXAxis(component);
}
public override void Update()
{
UpdateAxisMinMaxValue(component.index, component);
UpdatePointerValue(component);
}
public override void DrawBase(VertexHelper vh)
{
DrawSingleAxisSplit(vh, component);
DrawSingleAxisLine(vh, component);
DrawSingleAxisTick(vh, component);
}
private void InitXAxis(SingleAxis axis)
{
var theme = chart.theme;
var xAxisIndex = axis.index;
axis.painter = chart.painter;
axis.refreshComponent = delegate ()
{
axis.UpdateRuntimeData(chart.chartX,
chart.chartY,
chart.chartWidth,
chart.chartHeight);
InitAxis(axis, null, chart, this,
axis.orient,
axis.context.x,
axis.context.y,
axis.context.width,
axis.context.height);
};
axis.refreshComponent();
}
internal override void UpdateAxisLabelText(Axis axis)
{
base.UpdateAxisLabelText(axis);
if (axis.IsTime() || axis.IsValue())
{
for (int i = 0; i < axis.context.labelObjectList.Count; i++)
{
var label = axis.context.labelObjectList[i];
if (label != null)
{
var pos = GetLabelPosition(0, i);
label.SetPosition(pos);
CheckValueLabelActive(component, i, label, pos);
}
}
}
}
protected override Vector3 GetLabelPosition(float scaleWid, int i)
{
return GetLabelPosition(i, component.orient, component, null,
chart.theme.axis,
scaleWid,
component.context.x,
component.context.y,
component.context.width,
component.context.height);
}
private void DrawSingleAxisSplit(VertexHelper vh, SingleAxis axis)
{
if (AxisHelper.NeedShowSplit(axis))
{
var dataZoom = chart.GetDataZoomOfAxis(axis);
DrawAxisSplit(vh, axis, chart.theme.axis, dataZoom,
axis.orient,
axis.context.x,
axis.context.y,
axis.context.width,
axis.context.height);
}
}
private void DrawSingleAxisTick(VertexHelper vh, SingleAxis axis)
{
if (AxisHelper.NeedShowSplit(axis))
{
var dataZoom = chart.GetDataZoomOfAxis(axis);
DrawAxisTick(vh, axis, chart.theme.axis, dataZoom,
axis.orient,
axis.context.x,
axis.context.y,
axis.context.width);
}
}
private void DrawSingleAxisLine(VertexHelper vh, SingleAxis axis)
{
if (axis.show && axis.axisLine.show)
{
var axisStartY = axis.context.y + axis.offset;
DrawAxisLine(vh, axis,
chart.theme.axis,
axis.orient,
axis.context.x,
axisStartY,
axis.context.width);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 50b3514e3079543ea9000d21d809cad3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e5e50f8f0f8bb406b99fb32d6b5c7769
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
/// <summary>
/// The x axis in cartesian(rectangular) coordinate.
/// <para>直角坐标系 grid 中的 x 轴。</para>
/// </summary>
[System.Serializable]
[RequireChartComponent(typeof(GridCoord))]
[ComponentHandler(typeof(XAxisHander), true)]
public class XAxis : Axis
{
public override void SetDefaultValue()
{
m_Show = true;
m_Type = AxisType.Category;
m_Min = 0;
m_Max = 0;
m_SplitNumber = 0;
m_BoundaryGap = true;
m_Position = AxisPosition.Bottom;
m_Offset = 0;
m_Data = new List<string>() { "x1", "x2", "x3", "x4", "x5" };
m_Icons = new List<Sprite>(5);
splitLine.show = false;
splitLine.lineStyle.type = LineStyle.Type.None;
axisLabel.textLimit.enable = true;
iconStyle.show = false;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a71be0d36b9745c2894e598b3d9188a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,152 @@
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class XAxisHander : AxisHandler<XAxis>
{
protected override Orient orient { get { return Orient.Horizonal; } }
public override void InitComponent()
{
InitXAxis(component);
}
public override void Update()
{
UpdateAxisMinMaxValue(component.index, component);
UpdatePointerValue(component);
}
public override void DrawBase(VertexHelper vh)
{
DrawXAxisSplit(vh, component);
DrawXAxisLine(vh, component);
DrawXAxisTick(vh, component);
}
private void InitXAxis(XAxis xAxis)
{
var theme = chart.theme;
var xAxisIndex = xAxis.index;
xAxis.painter = chart.painter;
xAxis.refreshComponent = delegate ()
{
var grid = chart.GetChartComponent<GridCoord>(xAxis.gridIndex);
if (grid != null)
{
var yAxis = chart.GetChartComponent<YAxis>(xAxis.index);
InitAxis(xAxis, yAxis, chart, this,
orient,
grid.context.x,
grid.context.y,
grid.context.width,
grid.context.height);
}
};
xAxis.refreshComponent();
}
internal override void UpdateAxisLabelText(Axis axis)
{
base.UpdateAxisLabelText(axis);
if (axis.IsTime() || axis.IsValue())
{
for (int i = 0; i < axis.context.labelObjectList.Count; i++)
{
var label = axis.context.labelObjectList[i];
if (label != null)
{
var pos = GetLabelPosition(0, i);
label.SetPosition(pos);
CheckValueLabelActive(component, i, label, pos);
}
}
}
}
protected override Vector3 GetLabelPosition(float scaleWid, int i)
{
var grid = chart.GetChartComponent<GridCoord>(component.gridIndex);
if (grid == null)
return Vector3.zero;
var yAxis = chart.GetChartComponent<YAxis>(component.index);
return GetLabelPosition(i, Orient.Horizonal, component, yAxis,
chart.theme.axis,
scaleWid,
grid.context.x,
grid.context.y,
grid.context.width,
grid.context.height);
}
private void DrawXAxisSplit(VertexHelper vh, XAxis xAxis)
{
if (AxisHelper.NeedShowSplit(xAxis))
{
var grid = chart.GetChartComponent<GridCoord>(xAxis.gridIndex);
if (grid == null)
return;
var dataZoom = chart.GetDataZoomOfAxis(xAxis);
DrawAxisSplit(vh, xAxis, chart.theme.axis, dataZoom,
Orient.Horizonal,
grid.context.x,
grid.context.y,
grid.context.width,
grid.context.height);
}
}
private void DrawXAxisTick(VertexHelper vh, XAxis xAxis)
{
if (AxisHelper.NeedShowSplit(xAxis))
{
var grid = chart.GetChartComponent<GridCoord>(xAxis.gridIndex);
if (grid == null)
return;
var dataZoom = chart.GetDataZoomOfAxis(xAxis);
var startY = grid.context.y + xAxis.offset;
if (xAxis.IsTop())
startY += grid.context.height;
else
startY += ComponentHelper.GetXAxisOnZeroOffset(chart.components, xAxis);
DrawAxisTick(vh, xAxis, chart.theme.axis, dataZoom,
Orient.Horizonal,
grid.context.x,
startY,
grid.context.width);
}
}
private void DrawXAxisLine(VertexHelper vh, XAxis xAxis)
{
if (xAxis.show && xAxis.axisLine.show)
{
var grid = chart.GetChartComponent<GridCoord>(xAxis.gridIndex);
if (grid == null)
return;
var startY = grid.context.y + xAxis.offset;
if (xAxis.IsTop())
startY += grid.context.height;
else
startY += ComponentHelper.GetXAxisOnZeroOffset(chart.components, xAxis);
DrawAxisLine(vh, xAxis, chart.theme.axis,
Orient.Horizonal,
grid.context.x,
startY,
grid.context.width);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d7818e1175663412196de53f19b5ac08
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 69f8ba8fcc7d84b12b42f837f9f2b94b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
namespace XCharts
{
/// <summary>
/// The x axis in cartesian(rectangular) coordinate.
/// <para>
/// 直角坐标系 grid 中的 y 轴。
/// </para>
/// </summary>
[System.Serializable]
[RequireChartComponent(typeof(GridCoord), typeof(XAxis))]
[ComponentHandler(typeof(YAxisHander), true)]
public class YAxis : Axis
{
public override void SetDefaultValue()
{
m_Show = true;
m_Type = AxisType.Value;
m_Min = 0;
m_Max = 0;
m_SplitNumber = 0;
m_BoundaryGap = false;
m_Position = AxisPosition.Left;
m_Data = new List<string>(5);
splitLine.show = true;
splitLine.lineStyle.type = LineStyle.Type.None;
axisLabel.textLimit.enable = false;
axisTick.showStartTick = true;
iconStyle.show = false;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6ac60b8329f7a45c3898c7539d78f091
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,149 @@
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class YAxisHander : AxisHandler<YAxis>
{
protected override Orient orient { get { return Orient.Vertical; } }
public override void InitComponent()
{
InitYAxis(component);
}
public override void Update()
{
UpdateAxisMinMaxValue(component.index, component);
UpdatePointerValue(component);
}
public override void DrawBase(VertexHelper vh)
{
DrawYAxisSplit(vh, component.index, component);
DrawYAxisLine(vh, component.index, component);
DrawYAxisTick(vh, component.index, component);
}
private void InitYAxis(YAxis yAxis)
{
var theme = chart.theme;
var yAxisIndex = yAxis.index;
yAxis.painter = chart.painter;
yAxis.refreshComponent = delegate ()
{
var grid = chart.GetChartComponent<GridCoord>(yAxis.gridIndex);
if (grid != null)
{
var xAxis = chart.GetChartComponent<YAxis>(yAxis.index);
InitAxis(yAxis, xAxis, chart, this,
orient,
grid.context.x,
grid.context.y,
grid.context.height,
grid.context.width);
}
};
yAxis.refreshComponent();
}
internal override void UpdateAxisLabelText(Axis axis)
{
base.UpdateAxisLabelText(axis);
if (axis.IsTime() || axis.IsValue())
{
for (int i = 0; i < axis.context.labelObjectList.Count; i++)
{
var label = axis.context.labelObjectList[i];
if (label != null)
{
var pos = GetLabelPosition(0, i);
label.SetPosition(pos);
CheckValueLabelActive(axis, i, label, pos);
}
}
}
}
protected override Vector3 GetLabelPosition(float scaleWid, int i)
{
var grid = chart.GetChartComponent<GridCoord>(component.gridIndex);
if (grid == null)
return Vector3.zero;
return GetLabelPosition(i, Orient.Vertical, component, null,
chart.theme.axis,
scaleWid,
grid.context.x,
grid.context.y,
grid.context.height,
grid.context.width);
}
private void DrawYAxisSplit(VertexHelper vh, int yAxisIndex, YAxis yAxis)
{
if (AxisHelper.NeedShowSplit(yAxis))
{
var grid = chart.GetChartComponent<GridCoord>(yAxis.gridIndex);
if (grid == null)
return;
var dataZoom = chart.GetDataZoomOfAxis(yAxis);
DrawAxisSplit(vh, yAxis, chart.theme.axis, dataZoom,
Orient.Vertical,
grid.context.x,
grid.context.y,
grid.context.height,
grid.context.width);
}
}
private void DrawYAxisTick(VertexHelper vh, int yAxisIndex, YAxis yAxis)
{
if (AxisHelper.NeedShowSplit(yAxis))
{
var grid = chart.GetChartComponent<GridCoord>(yAxis.gridIndex);
if (grid == null)
return;
var dataZoom = chart.GetDataZoomOfAxis(yAxis);
var startX = grid.context.x + yAxis.offset;
if (yAxis.IsRight())
startX += grid.context.width;
else
startX += ComponentHelper.GetYAxisOnZeroOffset(chart.components, yAxis);
DrawAxisTick(vh, yAxis, chart.theme.axis, dataZoom,
Orient.Vertical,
startX,
grid.context.y,
grid.context.height);
}
}
private void DrawYAxisLine(VertexHelper vh, int yAxisIndex, YAxis yAxis)
{
if (yAxis.show && yAxis.axisLine.show)
{
var grid = chart.GetChartComponent<GridCoord>(yAxis.gridIndex);
if (grid == null)
return;
var startX = grid.context.x + yAxis.offset;
if (yAxis.IsRight())
startX += grid.context.width;
else
startX += ComponentHelper.GetYAxisOnZeroOffset(chart.components, yAxis);
DrawAxisLine(vh, yAxis, chart.theme.axis,
Orient.Vertical,
startX,
grid.context.y,
grid.context.height);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f09b5dcb5fcc54583bcd7946f18dfa48
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7db6fdcbbbfd148f58ff7a1f1a569d51
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,81 @@

using System;
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
/// <summary>
/// Background component.
///
/// 背景组件。
/// </summary>
[Serializable]
[DisallowMultipleComponent]
[ComponentHandler(typeof(BackgroundHandler), false)]
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.
/// 是否启用背景组件。
/// </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 override void SetDefaultValue()
{
m_Show = false;
m_Image = null;
m_ImageType = Image.Type.Sliced;
m_ImageColor = Color.white;
m_HideThemeBackgroundColor = true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 524f7df5241cc4379ae241a73d5b2ff2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
using System;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class BackgroundHandler : MainComponentHandler<Background>
{
private readonly string s_BackgroundObjectName = "background";
public override void InitComponent()
{
component.painter = chart.painter;
component.refreshComponent = delegate ()
{
var backgroundObj = ChartHelper.AddObject(s_BackgroundObjectName, chart.transform, chart.chartMinAnchor,
chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta);
component.gameObject = backgroundObj;
backgroundObj.hideFlags = chart.chartHideFlags;
var backgroundImage = ChartHelper.GetOrAddComponent<Image>(backgroundObj);
ChartHelper.UpdateRectTransform(backgroundObj, chart.chartMinAnchor,
chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta);
backgroundImage.sprite = component.image;
backgroundImage.type = component.imageType;
backgroundImage.color = component.imageColor;
backgroundObj.transform.SetSiblingIndex(0);
backgroundObj.SetActive(component.show);
};
component.refreshComponent();
}
//protected void DrawBackground(VertexHelper vh)
//{
//TODO: CooridateChart
// if (SeriesHelper.IsAnyClipSerie(m_Series))
// {
// var xLineDiff = xAxis0.axisLine.GetWidth(m_Theme.axis.lineWidth);
// var yLineDiff = yAxis0.axisLine.GetWidth(m_Theme.axis.lineWidth);
// var xSplitDiff = xAxis0.splitLine.GetWidth(m_Theme.axis.splitLineWidth);
// var ySplitDiff = yAxis0.splitLine.GetWidth(m_Theme.axis.splitLineWidth);
// foreach (var grid in m_Grids)
// {
// var cpty = grid.context.runtimeY + grid.context.runtimeHeight + ySplitDiff;
// var cp1 = new Vector3(grid.context.runtimeX - yLineDiff, grid.context.runtimeY - xLineDiff);
// var cp2 = new Vector3(grid.context.runtimeX - yLineDiff, cpty);
// var cp3 = new Vector3(grid.context.runtimeX + grid.context.runtimeWidth + xSplitDiff, cpty);
// var cp4 = new Vector3(grid.context.runtimeX + grid.context.runtimeWidth + xSplitDiff, grid.context.runtimeY - xLineDiff);
// var backgroundColor = ThemeHelper.GetBackgroundColor(m_Theme, m_Background);
// UGL.DrawQuadrilateral(vh, cp1, cp2, cp3, cp4, backgroundColor);
// }
// }
// else
// {
// base.DrawBackground(vh);
// }
// }
public override void DrawBase(VertexHelper vh)
{
if (!component.show)
return;
var p1 = new Vector3(chart.chartX, chart.chartY + chart.chartHeight);
var p2 = new Vector3(chart.chartX + chart.chartWidth, chart.chartY + chart.chartHeight);
var p3 = new Vector3(chart.chartX + chart.chartWidth, chart.chartY);
var p4 = new Vector3(chart.chartX, chart.chartY);
var backgroundColor = chart.theme.GetBackgroundColor(component);
UGL.DrawQuadrilateral(vh, p1, p2, p3, p4, backgroundColor);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f1cb3d1a2aa224bbe84eef2681cf3df4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 20d31ade0390641698e6b846b4294b74
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,141 @@
using UnityEngine;
namespace XCharts
{
/// <summary>
/// The style of area.
/// 区域填充样式。
/// </summary>
[System.Serializable]
public class AreaStyle : ChildComponent, ISerieExtraComponent
{
/// <summary>
/// Origin position of area.
/// 图形区域的起始位置。默认情况下,图形会从坐标轴轴线到数据间进行填充。如果需要填充的区域是坐标轴最大值到数据间,或者坐标轴最小值到数据间,则可以通过这个配置项进行设置。
/// </summary>
public enum AreaOrigin
{
/// <summary>
/// to fill between axis line to data.
/// 填充坐标轴轴线到数据间的区域。
/// </summary>
Auto,
/// <summary>
/// to fill between min axis value (when not inverse) to data.
/// 填充坐标轴底部到数据间的区域。
/// </summary>
Start,
/// <summary>
/// to fill between max axis value (when not inverse) to data.
/// 填充坐标轴顶部到数据间的区域。
/// </summary>
End
}
[SerializeField] private bool m_Show = true;
[SerializeField] private AreaOrigin m_Origin;
[SerializeField] private Color32 m_Color;
[SerializeField] private Color32 m_ToColor;
[SerializeField] [Range(0, 1)] private float m_Opacity = 0.6f;
[SerializeField] private bool m_TooltipHighlight;
[SerializeField] private Color32 m_HighlightColor;
[SerializeField] private Color32 m_HighlightToColor;
/// <summary>
/// Set this to false to prevent the areafrom showing.
/// 是否显示区域填充。
/// </summary>
public bool show
{
get { return m_Show; }
set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetVerticesDirty(); }
}
/// <summary>
/// the origin of area.
/// 区域填充的起始位置。
/// </summary>
public AreaOrigin origin
{
get { return m_Origin; }
set { if (PropertyUtil.SetStruct(ref m_Origin, value)) SetVerticesDirty(); }
}
/// <summary>
/// the color of area,default use serie color.
/// 区域填充的颜色如果toColor不是默认值则表示渐变色的起点颜色。
/// </summary>
public Color32 color
{
get { return m_Color; }
set { if (PropertyUtil.SetColor(ref m_Color, value)) SetVerticesDirty(); }
}
/// <summary>
/// Gradient color, start color to toColor.
/// 渐变色的终点颜色。
/// </summary>
public Color32 toColor
{
get { return m_ToColor; }
set { if (PropertyUtil.SetColor(ref m_ToColor, value)) SetVerticesDirty(); }
}
/// <summary>
/// Opacity of the component. Supports value from 0 to 1, and the component will not be drawn when set to 0.
/// 图形透明度。支持从 0 到 1 的数字,为 0 时不绘制该图形。
/// </summary>
public float opacity
{
get { return m_Opacity; }
set { if (PropertyUtil.SetStruct(ref m_Opacity, value)) SetVerticesDirty(); }
}
/// <summary>
/// 鼠标悬浮时是否高亮之前的区域
/// </summary>
public bool tooltipHighlight
{
get { return m_TooltipHighlight; }
set { if (PropertyUtil.SetStruct(ref m_TooltipHighlight, value)) SetVerticesDirty(); }
}
/// <summary>
/// the color of area,default use serie color.
/// 高亮时区域填充的颜色如果highlightToColor不是默认值则表示渐变色的起点颜色。
/// </summary>
public Color32 highlightColor
{
get { return m_HighlightColor; }
set { if (PropertyUtil.SetColor(ref m_HighlightColor, value)) SetVerticesDirty(); }
}
/// <summary>
/// Gradient color, start highlightColor to highlightToColor.
/// 高亮时渐变色的终点颜色。
/// </summary>
public Color32 highlightToColor
{
get { return m_HighlightToColor; }
set { if (PropertyUtil.SetColor(ref m_HighlightToColor, value)) SetVerticesDirty(); }
}
public Color32 GetColor()
{
if (m_Opacity == 1)
return m_Color;
var color = m_Color;
color.a = (byte)(color.a * m_Opacity);
return color;
}
public Color32 GetColor(Color32 themeColor)
{
if (!ChartHelper.IsClearColor(color))
{
return GetColor();
}
else
{
var color = themeColor;
color.a = (byte)(color.a * opacity);
return color;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ec0d95a9298bb4c159dcae36020beec9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,93 @@
using System;
using UnityEngine;
namespace XCharts
{
/// <summary>
/// </summary>
[Serializable]
public class ArrowStyle : ChildComponent
{
[SerializeField] private float m_Width = 10;
[SerializeField] private float m_Height = 15;
[SerializeField] private float m_Offset = 0;
[SerializeField] private float m_Dent = 3;
[SerializeField] private Color32 m_Color = Color.clear;
/// <summary>
/// The widht of arrow.
/// 箭头宽。
/// </summary>
public float width
{
get { return m_Width; }
set { if (PropertyUtil.SetStruct(ref m_Width, value)) SetVerticesDirty(); }
}
/// <summary>
/// The height of arrow.
/// 箭头高。
/// </summary>
public float height
{
get { return m_Height; }
set { if (PropertyUtil.SetStruct(ref m_Height, value)) SetVerticesDirty(); }
}
/// <summary>
/// The offset of arrow.
/// 箭头偏移。
/// </summary>
public float offset
{
get { return m_Offset; }
set { if (PropertyUtil.SetStruct(ref m_Offset, value)) SetVerticesDirty(); }
}
/// <summary>
/// The dent of arrow.
/// 箭头的凹度。
/// </summary>
public float dent
{
get { return m_Dent; }
set { if (PropertyUtil.SetStruct(ref m_Dent, value)) SetVerticesDirty(); }
}
/// <summary>
/// the color of arrow.
/// 箭头颜色。
/// </summary>
public Color32 color
{
get { return m_Color; }
set { if (PropertyUtil.SetColor(ref m_Color, value)) SetVerticesDirty(); }
}
public ArrowStyle Clone()
{
var arrow = new ArrowStyle();
arrow.width = width;
arrow.height = height;
arrow.offset = offset;
arrow.dent = dent;
arrow.color = color;
return arrow;
}
public void Copy(ArrowStyle arrow)
{
width = arrow.width;
height = arrow.height;
offset = arrow.offset;
dent = arrow.dent;
color = arrow.color;
}
public Color32 GetColor(Color32 defaultColor)
{
if (ChartHelper.IsClearColor(color))
return defaultColor;
else
return color;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2232b812c68f042d29c44863e38d0417
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More