增加GanttChart甘特图

This commit is contained in:
monitor1394
2021-03-25 12:55:52 +08:00
parent 6a548899fa
commit ac64bd9435
54 changed files with 38355 additions and 6917 deletions

View File

@@ -32,6 +32,7 @@
## Latest
* (2021.03.25) Added `Ganttchart`
* (2021.03.22) Added `Theme` `Unbind` button to unbind theme when copying chart #118
* (2021.03.18) Fixed an issue where the check box after `Foldout` in `Inspector` could not be checked
* (2021.03.18) Fixed an issue with `BarChart` displaying an exception in the `0` value

View File

@@ -32,6 +32,7 @@
## Latest
* (2021.03.25) 增加`GanttChart`甘特图
* (2021.03.22) 增加`Theme``Unbind`按钮用于解绑复制图表时的主题 #118
* (2021.03.18) 修复`Inspector``Foldout`后的勾选框无法选中的问题
* (2021.03.18) 修复`BarChart``0`数值时显示异常的问题

View File

@@ -24,6 +24,7 @@
* [Serie-Ring 环形图](#Serie-Ring)
* [Serie-Liquid 水位图](#Serie-Liquid)
* [Serie-Candlestick K线图](#Serie-Candlestick)
* [Serie-Gantt 甘特图](#Serie-Gantt)
* [Settings 设置](#Settings)
* [Theme 主题](#Theme)
* [Tooltip 提示框](#Tooltip)
@@ -774,6 +775,24 @@ K线图系列。
* `animation`:起始动画 [SerieAnimation](#SerieAnimation)。
* `data`:系列中的数据项 [SerieData](#SerieData) 数组K线图至少需要4个维度的数组`[open, close, lowest, highest]`
## `Serie-Gantt`
甘特图系列。支持类目轴和时间轴的甘特图,当 `X` 轴为类目轴时,数据为类目的索引,`X` 轴为时间轴时,数据为时间戳(秒为单位)。`Y` 轴默认为类目轴,显示的数据来源于`Serie``Data``Name`
甘特图默认支持开始和结束时间,也可以额外支持实际开始和结束时间。
* `show`:系列是否显示在图表上。
* `type``Gantt`
* `name`:系列名称。用于 `tooltip` 的显示,`legend` 的图例筛选。
* `xAxisIndex`使用的坐标轴X轴的 `index`,在单个图表实例中存在多个坐标轴的时候有用。
* `yAxisIndex`使用的坐标轴Y轴的 `index`,在单个图表实例中存在多个坐标轴的时候有用。
* `clip`:是否裁剪超出坐标系部分的图形。
* `large`:是否开启大数据量优化,在数据图形特别多而出现卡顿时候可以开启。开启后配合 largeThreshold 在数据量大于指定阈值的时候对绘制进行优化。缺点优化后不能自定义设置单个数据项的样式不能显示Label折线图不绘制Symbol。
* `largeThreshold`开启大数量优化的阈值。只有当开启了large并且数据量大于该阀值时才进入性能模式。
* `itemStyle`:甘特图的柱条样式,包括设置背景颜色和边框等 [ItemStyle](#ItemStyle)。
* `emphasis`:高亮样式 [Emphasis](#Emphasis)。
* `animation`:起始动画 [SerieAnimation](#SerieAnimation)。
* `data`:系列中的数据项 [SerieData](#SerieData) 数组甘特图至少需要2个维度的数组`[start, end]`也支持4个维度的数组`[start, end, actualStart, actualEnd]`。当 X 轴为类目轴时数据为类目的索引X 轴为时间轴时,数据为时间戳(秒为单位)。
## `Settings`
全局参数设置组件。一般情况下可使用默认值,当有需要时可进行调整。

View File

@@ -26,6 +26,7 @@ __Main component:__
* [Serie-Ring](#Serie-Ring)
* [Serie-Liquid](#Serie-Liquid)
* [Serie-Candlestick](#Serie-Candlestick)
* [Serie-Gantt](#Serie-Gantt)
* [Settings](#Settings)
* [Theme](#Theme)
* [Title](#Title)
@@ -667,6 +668,24 @@ K线图系列。
* `animation`:起始动画 [SerieAnimation](#SerieAnimation)。
* `data`:系列中的数据项 [SerieData](#SerieData) 数组K线图至少需要4个维度的数组`[open, close, lowest, highest]`
## `Serie-Gantt`
甘特图系列。支持类目轴和时间轴的甘特图,当 `X` 轴为类目轴时,数据为类目的索引,`X` 轴为时间轴时,数据为时间戳(秒为单位)。`Y` 轴默认为类目轴,显示的数据来源于`Serie``Data``Name`
甘特图默认支持开始和结束时间,也可以额外支持实际开始和结束时间。
* `show`:系列是否显示在图表上。
* `type``Gantt`
* `name`:系列名称。用于 `tooltip` 的显示,`legend` 的图例筛选。
* `xAxisIndex`使用的坐标轴X轴的 `index`,在单个图表实例中存在多个坐标轴的时候有用。
* `yAxisIndex`使用的坐标轴Y轴的 `index`,在单个图表实例中存在多个坐标轴的时候有用。
* `clip`:是否裁剪超出坐标系部分的图形。
* `large`:是否开启大数据量优化,在数据图形特别多而出现卡顿时候可以开启。开启后配合 largeThreshold 在数据量大于指定阈值的时候对绘制进行优化。缺点优化后不能自定义设置单个数据项的样式不能显示Label折线图不绘制Symbol。
* `largeThreshold`开启大数量优化的阈值。只有当开启了large并且数据量大于该阀值时才进入性能模式。
* `itemStyle`:甘特图的柱条样式,包括设置背景颜色和边框等 [ItemStyle](#ItemStyle)。
* `emphasis`:高亮样式 [Emphasis](#Emphasis)。
* `animation`:起始动画 [SerieAnimation](#SerieAnimation)。
* `data`:系列中的数据项 [SerieData](#SerieData) 数组甘特图至少需要2个维度的数组`[start, end]`也支持4个维度的数组`[start, end, actualStart, actualEnd]`。当 X 轴为类目轴时数据为类目的索引X 轴为时间轴时,数据为时间戳(秒为单位)。
## `Settings`
全局参数设置组件。一般情况下可使用默认值,当有需要时可进行调整。

View File

@@ -19,6 +19,7 @@ namespace XCharts
protected override void OnEnable()
{
base.OnEnable();
if(target == null) return;
m_Chart = (BarChart)target;
}

View File

@@ -123,7 +123,7 @@ namespace XCharts
BlockEnd();
BlockStart();
m_BaseFoldout = EditorGUILayout.Foldout(m_BaseFoldout, "Base");
m_BaseFoldout = EditorGUILayout.Foldout(m_BaseFoldout, "Base", true);
if (m_BaseFoldout)
{
EditorGUILayout.PropertyField(m_Script);
@@ -196,7 +196,7 @@ namespace XCharts
if (all)
{
var flag = m_Flodouts.ContainsKey(prop.displayName) && m_Flodouts[prop.displayName];
m_Flodouts[prop.displayName] = EditorGUILayout.Foldout(flag, prop.displayName);
m_Flodouts[prop.displayName] = EditorGUILayout.Foldout(flag, prop.displayName, true);
if (m_Flodouts[prop.displayName])
{
EditorGUI.indentLevel++;

View File

@@ -18,6 +18,7 @@ namespace XCharts
protected override void OnEnable()
{
base.OnEnable();
if(target == null) return;
m_Chart = (CandlestickChart)target;
}
}

View File

@@ -27,6 +27,7 @@ namespace XCharts
protected override void OnEnable()
{
base.OnEnable();
if(target == null) return;
m_Chart = (CoordinateChart)target;
m_Grids = serializedObject.FindProperty("m_Grids");
m_XAxes = serializedObject.FindProperty("m_XAxes");

View File

@@ -0,0 +1,25 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using UnityEditor;
namespace XCharts
{
/// <summary>
/// Editor class used to edit UI GanttChart.
/// </summary>
[CustomEditor(typeof(GanttChart), false)]
public class GanttChartEditor : CoordinateChartEditor
{
protected override void OnEnable()
{
base.OnEnable();
if(target == null) return;
m_Chart = (GanttChart)target;
}
}
}

View File

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

View File

@@ -18,6 +18,7 @@ namespace XCharts
protected override void OnEnable()
{
base.OnEnable();
if(target == null) return;
m_Chart = (GaugeChart)target;
}
}

View File

@@ -18,6 +18,7 @@ namespace XCharts
protected override void OnEnable()
{
base.OnEnable();
if(target == null) return;
m_Chart = (HeatmapChart)target;
}
}

View File

@@ -18,6 +18,7 @@ namespace XCharts
protected override void OnEnable()
{
base.OnEnable();
if(target == null) return;
m_Chart = (LineChart)target;
}
}

View File

@@ -18,6 +18,7 @@ namespace XCharts
protected override void OnEnable()
{
base.OnEnable();
if(target == null) return;
m_Chart = (PieChart)target;
}
}

View File

@@ -22,6 +22,7 @@ namespace XCharts
protected override void OnEnable()
{
base.OnEnable();
if(target == null) return;
m_Chart = (PolarChart)target;
m_Polars = serializedObject.FindProperty("m_Polars");
m_RadiusAxes = serializedObject.FindProperty("m_RadiusAxes");

View File

@@ -42,7 +42,7 @@ namespace XCharts
}
EditorGUI.EndChangeCheck();
}
if (type == Axis.AxisType.Value)
if (type == Axis.AxisType.Value || type == Axis.AxisType.Time)
{
PropertyField(prop, "m_MinMaxType");
Axis.AxisMinMaxType minMaxType = (Axis.AxisMinMaxType)m_MinMaxType.enumValueIndex;
@@ -60,7 +60,10 @@ namespace XCharts
break;
}
PropertyField(prop, "m_CeilRate");
PropertyField(prop, "m_Inverse");
if (type == Axis.AxisType.Value)
{
PropertyField(prop, "m_Inverse");
}
}
PropertyField(prop, "m_SplitNumber");
if (type == Axis.AxisType.Category)

View File

@@ -197,6 +197,17 @@ namespace XCharts
PropertyField(prop, "m_Label");
PropertyField(prop, "m_Emphasis");
break;
case SerieType.Gantt:
PropertyField(prop, "m_XAxisIndex");
PropertyField(prop, "m_YAxisIndex");
PropertyField(prop, "m_BarWidth");
PropertyField(prop, "m_Clip");
PropertyField(prop, "m_Large");
PropertyField(prop, "m_LargeThreshold");
PropertyField(prop, "m_ItemStyle");
PropertyField(prop, "m_Label");
PropertyField(prop, "m_Emphasis");
break;
}
PropertyField(prop, "m_Animation");
DrawData(pos, prop, serieType, ref m_DrawRect);
@@ -340,7 +351,7 @@ namespace XCharts
var startX = drawRect.x + EditorGUIUtility.labelWidth - EditorGUI.indentLevel * 15 + gap;
var dataWidTotal = (currentWidth - (startX + 20.5f + 1));
var dataWid = dataWidTotal / fieldCount;
var xWid = dataWid - 4;
var xWid = dataWid - 2;
for (int i = 0; i < dimension; i++)
{
var dataCount = i < 1 ? 2 : i + 1;
@@ -407,7 +418,7 @@ namespace XCharts
var str = prop.propertyPath.Substring(sindex + 1, eindex - sindex - 1);
int.TryParse(str, out index);
}
if (index >= m_DataFoldout.Count)
while (index >= m_DataFoldout.Count)
{
m_DataFoldout.Add(false);
}

View File

@@ -18,6 +18,7 @@ namespace XCharts
protected override void OnEnable()
{
base.OnEnable();
if(target == null) return;
m_Chart = (RingChart)target;
}
}

View File

@@ -18,6 +18,7 @@ namespace XCharts
protected override void OnEnable()
{
base.OnEnable();
if(target == null) return;
m_Chart = (ScatterChart)target;
}
}

View File

@@ -146,11 +146,11 @@ namespace XCharts
AddChart<LiquidChart>("LiquidChart");
}
[MenuItem("XCharts/CandlestickChart", priority = 54)]
[MenuItem("GameObject/XCharts/CandlestickChart", priority = 54)]
public static void AddCandlestickChart()
[MenuItem("XCharts/GanttChart", priority = 54)]
[MenuItem("GameObject/XCharts/GanttChart", priority = 54)]
public static void AddGanttChart()
{
AddChart<CandlestickChart>("CandlestickChart");
AddChart<GanttChart>("GanttChart");
}
[MenuItem("XCharts/Themes Reload")]

View File

@@ -0,0 +1,80 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using UnityEngine;
namespace XCharts.Examples
{
[DisallowMultipleComponent]
[ExecuteInEditMode]
public class Example100_Gantt_Category : MonoBehaviour
{
private GanttChart chart;
private float updateTime;
public int dayCount = 10;
public int taskCount = 5;
void Awake()
{
chart = gameObject.GetComponent<GanttChart>();
if (chart == null)
{
chart = gameObject.AddComponent<GanttChart>();
}
GenerateCategoryData();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
AddData();
}
}
void AddData()
{
for (int i = 0; i < taskCount; i++)
{
var taskName = "task-" + (i + 1);
var startIndex = Random.Range(0, (int)(dayCount * 2.0f / 3));
var endIndex = Random.Range(startIndex, dayCount);
chart.UpdateData(0, i, 0, startIndex);
chart.UpdateData(0, i, 1, endIndex);
}
}
void GenerateCategoryData()
{
chart.RemoveData();
chart.grid.left = 100;
chart.xAxis0.type = Axis.AxisType.Category;
chart.xAxis0.boundaryGap = false;
chart.xAxis0.splitNumber = dayCount;
chart.yAxis0.type = Axis.AxisType.Category;
chart.yAxis0.boundaryGap = true;
chart.yAxis0.splitNumber = 0;
for (int i = 0; i < dayCount; i++)
{
chart.AddXAxisData("day" + (i + 1));
}
var serie = chart.AddSerie(SerieType.Gantt, "任务进度表");
for (int i = 0; i < taskCount; i++)
{
var taskName = "task-" + (i + 1);
var startIndex = Random.Range(0, (int)(dayCount * 2.0f / 3));
var endIndex = Random.Range(startIndex, dayCount);
chart.AddData(0, startIndex, endIndex, taskName);
}
}
}
}

View File

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

View File

@@ -0,0 +1,99 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using UnityEngine;
namespace XCharts.Examples
{
[DisallowMultipleComponent]
[ExecuteInEditMode]
public class Example101_Gantt_Time : MonoBehaviour
{
private GanttChart chart;
private float updateTime;
public int taskCount = 5;
void Awake()
{
chart = gameObject.GetComponent<GanttChart>();
if (chart == null)
{
chart = gameObject.AddComponent<GanttChart>();
}
GenerateTimeData();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
AddData();
}
}
void AddData()
{
chart.ClearData();
for (int i = 0; i < taskCount; i++)
{
var taskName = "张三-任务-" + (i + 1);
var nowTimestamp = DateTimeUtil.GetTimestamp();
var startTimestamp = nowTimestamp + Random.Range(1, 6) * 3600 * 24;
var endTimestamp = startTimestamp + Random.Range(1, 10) * 3600 * 24;
chart.AddData(0, startTimestamp, endTimestamp, taskName);
}
var serie2 = chart.AddSerie(SerieType.Gantt, "李四");
for (int i = 0; i < taskCount; i++)
{
var taskName = "李四-任务-" + (i + 1);
var nowTimestamp = DateTimeUtil.GetTimestamp();
var startTimestamp = nowTimestamp + Random.Range(1, 6) * 3600 * 24;
var endTimestamp = startTimestamp + Random.Range(1, 10) * 3600 * 24;
chart.AddData(1, startTimestamp, endTimestamp, taskName);
}
}
void GenerateTimeData()
{
chart.RemoveData();
chart.grid.left = 100;
chart.xAxis0.type = Axis.AxisType.Time;
chart.xAxis0.boundaryGap = false;
chart.xAxis0.splitNumber = 5;
chart.xAxis0.axisLabel.numericFormatter = "HH:mm:ss";
chart.xAxis0.axisLabel.formatter = "time:{value}";
chart.yAxis0.type = Axis.AxisType.Category;
chart.yAxis0.boundaryGap = true;
chart.yAxis0.splitNumber = 0;
var serie1 = chart.AddSerie(SerieType.Gantt, "张三");
serie1.label.show = true;
for (int i = 0; i < taskCount; i++)
{
var taskName = "张三-任务-" + (i + 1);
var nowTimestamp = DateTimeUtil.GetTimestamp();
var startTimestamp = nowTimestamp + Random.Range(1, 6) * 3600 * 24;
var endTimestamp = startTimestamp + Random.Range(1, 10) * 3600 * 24;
chart.AddData(0, startTimestamp, endTimestamp, taskName);
}
var serie2 = chart.AddSerie(SerieType.Gantt, "李四");
for (int i = 0; i < taskCount; i++)
{
var taskName = "李四-任务-" + (i + 1);
var nowTimestamp = DateTimeUtil.GetTimestamp();
var startTimestamp = nowTimestamp + Random.Range(1, 6) * 3600 * 24;
var endTimestamp = startTimestamp + Random.Range(1, 10) * 3600 * 24;
chart.AddData(1, startTimestamp, endTimestamp, taskName);
}
}
}
}

View File

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

View File

@@ -45,7 +45,6 @@ namespace XCharts.Examples
chart.ClearData();
var xValue = System.DateTime.Now;
var minute = 60 * 1000;
var baseValue = Random.Range(0f, 1f) * 12000;
var boxVals = new float[4];
var dayRange = 12;

View File

@@ -134,6 +134,7 @@ namespace XCharts
public void RefreshAllComponent()
{
SetAllComponentDirty();
RefreshGraph();
}
/// <summary>

View File

@@ -89,8 +89,16 @@ namespace XCharts
/// </summary>
public void ClearAxisData()
{
foreach (var item in m_XAxes) item.data.Clear();
foreach (var item in m_YAxes) item.data.Clear();
foreach (var axis in m_XAxes)
{
axis.data.Clear();
axis.SetAllDirty();
}
foreach (var axis in m_YAxes)
{
axis.data.Clear();
axis.SetAllDirty();
}
}
/// <summary>

View File

@@ -39,7 +39,12 @@ namespace XCharts
/// Log axis, suitable for log data.
/// 对数轴。适用于对数数据。
/// </summary>
Log
Log,
/// <summary>
/// Time axis, suitable for continuous time series data.
/// 时间轴。适用于连续的时序数据。
/// </summary>
Time
}
/// <summary>
@@ -408,6 +413,7 @@ namespace XCharts
public int runtimeMaxLogIndex { get { return logBaseE ? (int)Mathf.Log(runtimeMaxValue) : (int)Mathf.Log(runtimeMaxValue, logBase); } }
internal bool runtimeLastCheckInverse { get; set; }
internal float runtimeMinMaxRange { get { return m_MinMaxValueRange; } set { m_MinMaxValueRange = value; } }
internal List<string> runtimeData { get { return m_RuntimeData; } }
private int filterStart;
private int filterEnd;
private int filterMinShow;
@@ -426,6 +432,7 @@ namespace XCharts
private float m_RuntimeMaxValueUpdateTime;
private bool m_RuntimeMinValueFirstChanged = true;
private bool m_RuntimeMaxValueFirstChanged = true;
protected List<string> m_RuntimeData = new List<string>();
public Axis Clone()
{
@@ -484,6 +491,7 @@ namespace XCharts
public void ClearData()
{
m_Data.Clear();
m_RuntimeData.Clear();
SetAllDirty();
}
@@ -574,10 +582,14 @@ namespace XCharts
}
else
{
return m_Data;
return m_Data.Count > 0 ? m_Data : m_RuntimeData;
}
}
internal List<string> GetDataList(){
return m_Data.Count > 0 ? m_Data : m_RuntimeData;
}
private List<string> emptyFliter = new List<string>();
/// <summary>
/// 更新dataZoom对应的类目数据列表
@@ -596,24 +608,25 @@ namespace XCharts
filterEnd = endIndex;
filterMinShow = dataZoom.minShowNum;
m_NeedUpdateFilterData = false;
if (m_Data.Count > 0)
var data = GetDataList();
if (data.Count > 0)
{
var count = endIndex == startIndex ? 1 : endIndex - startIndex + 1;
if (count < dataZoom.minShowNum)
{
if (dataZoom.minShowNum > m_Data.Count) count = m_Data.Count;
if (dataZoom.minShowNum > data.Count) count = data.Count;
else count = dataZoom.minShowNum;
}
if (startIndex + count > m_Data.Count)
if (startIndex + count > data.Count)
{
int start = endIndex - count;
filterData = m_Data.GetRange(start < 0 ? 0 : start, count);
filterData = data.GetRange(start < 0 ? 0 : start, count);
}
else filterData = m_Data.GetRange(startIndex, count);
else filterData = data.GetRange(startIndex, count);
}
else
{
filterData = m_Data;
filterData = data;
}
}
else if (endIndex == 0)

View File

@@ -64,6 +64,10 @@ namespace XCharts
/// K线图。K线图的data至少包含四个数据[open, close, lowest, highest]
/// </summary>
Candlestick,
/// <summary>
/// 甘特图。甘特图的data至少包含两个数据[start, end]
/// </summary>
Gantt,
}
/// <summary>
@@ -781,7 +785,7 @@ namespace XCharts
/// <summary>
/// 数据项里的数据维数。
/// </summary>
public int showDataDimension { get { return m_ShowDataDimension; } }
public int showDataDimension { get { return m_ShowDataDimension; } internal set { m_ShowDataDimension = value; } }
/// <summary>
/// 在Editor的inpsector上是否显示name参数
/// </summary>
@@ -1234,6 +1238,7 @@ namespace XCharts
{
CheckMaxCache();
var serieData = SerieDataPool.Get();
serieData.data.Clear();
serieData.data.Add(xValue);
serieData.data.Add(yValue);
serieData.name = dataName;
@@ -1245,10 +1250,20 @@ namespace XCharts
return serieData;
}
/// <summary>
/// 添加 (open, close, lowest, heighest) 数据
/// </summary>
/// <param name="open"></param>
/// <param name="close"></param>
/// <param name="lowest"></param>
/// <param name="heighest"></param>
/// <param name="dataName"></param>
/// <returns></returns>
public SerieData AddData(float open, float close, float lowest, float heighest, string dataName = null)
{
CheckMaxCache();
var serieData = SerieDataPool.Get();
serieData.data.Clear();
serieData.data.Add(open);
serieData.data.Add(close);
serieData.data.Add(lowest);
@@ -1678,7 +1693,9 @@ namespace XCharts
return type == SerieType.Line
|| type == SerieType.Bar
|| type == SerieType.Scatter
|| type == SerieType.Heatmap;
|| type == SerieType.Heatmap
|| type == SerieType.Gantt
|| type == SerieType.Candlestick;
}
/// <summary>

View File

@@ -188,9 +188,8 @@ namespace XCharts
}
else
{
var content = m_Formatter.Replace("{value}", category);
content = content.Replace("\\n", "\n");
content = content.Replace("<br/>", "\n");
var content = m_Formatter;
FormatterHelper.ReplaceAxisLabelContent(ref content, category);
return m_TextLimit.GetLimitContent(content);
}
}
@@ -224,5 +223,21 @@ namespace XCharts
return content;
}
}
public string GetFormatterDateTime(DateTime dateTime)
{
var format = string.IsNullOrEmpty(numericFormatter) ? "yyyy/M/d" : numericFormatter;
if (!string.IsNullOrEmpty(m_Formatter))
{
var content = m_Formatter;
FormatterHelper.ReplaceAxisLabelContent(ref content, dateTime.ToString(format));
return m_TextLimit.GetLimitContent(content);
}
else
{
var content = dateTime.ToString(format);
return m_TextLimit.GetLimitContent(content);
}
}
}
}

View File

@@ -5,11 +5,8 @@
/* */
/************************************************/
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
namespace XCharts
{
@@ -191,6 +188,10 @@ namespace XCharts
/// </summary>
public float runtimePieOffsetRadius { get; internal set; }
public Vector3 runtimePosition { get; internal set; }
/// <summary>
/// 绘制区域。
/// </summary>
public Rect runtimeRect { get; internal set; }
public float runtimeAngle { get; internal set; }
public Vector3 runtiemPieOffsetCenter { get; internal set; }
public float runtimeStackHig { get; internal set; }

View File

@@ -85,5 +85,13 @@ namespace XCharts
runtimeText.SetText(text);
}
}
public void SetColor(Color color)
{
if (runtimeText != null)
{
runtimeText.SetColor(color);
}
}
}
}

View File

@@ -0,0 +1,137 @@

/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using UnityEngine;
namespace XCharts
{
[AddComponentMenu("XCharts/GanttChart", 22)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public partial class GanttChart : CoordinateChart
{
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
title.text = "GanttChart";
var xCount = 5;
var yCount = 5;
m_Grids[0].left = 60;
m_Grids[0].right = 50;
m_XAxes[0].type = Axis.AxisType.Time;
m_XAxes[0].boundaryGap = false;
m_XAxes[0].splitNumber = xCount;
m_YAxes[0].type = Axis.AxisType.Category;
m_YAxes[0].boundaryGap = true;
m_YAxes[0].splitNumber = 0;
RemoveData();
SerieTemplate.AddDefaultTimeGanttSerie(this, "task", yCount);
}
#endif
protected override void GetSeriesMinMaxValue(Axis axis, int axisIndex, out float tempMinValue, out float tempMaxValue)
{
tempMinValue = int.MaxValue;
tempMaxValue = int.MinValue;
foreach (var serie in m_Series.list)
{
if (serie.type != SerieType.Gantt) continue;
if (serie.xAxisIndex != axis.index) continue;
foreach (var serieData in serie.data)
{
if (serieData.data.Count >= 2)
{
var xData = serieData.data[0];
var yData = serieData.data[1];
if (xData < tempMinValue) tempMinValue = xData;
if (yData > tempMaxValue) tempMaxValue = yData;
}
}
}
if (tempMinValue == int.MaxValue) tempMinValue = 0;
if (tempMaxValue == int.MinValue) tempMaxValue = 0;
//AxisHelper.AdjustMinMaxValue(axis, ref tempMinValue, ref tempMaxValue, true, 60);
}
protected override void OnRefreshLabel()
{
for (int i = 0; i < m_Series.Count; i++)
{
var serie = m_Series.GetSerie(i);
if (serie.IsPerformanceMode()) continue;
if (serie.type != SerieType.Gantt) continue;
foreach (var serieData in serie.data)
{
if (serieData.labelObject == null) continue;
var serieLabel = SerieHelper.GetSerieLabel(serie, serieData);
var labelShow = serie.show && serieLabel.show;
serieData.SetLabelActive(labelShow);
if (labelShow)
{
var labelColor = serieLabel.textStyle.GetColor(m_Theme.axis.textColor);
var labelPos = serieData.runtimePosition;
SerieLabelHelper.ResetLabel(serieData.labelObject.label, serieLabel, m_Theme, i);
serieData.labelObject.SetPosition(labelPos);
serieData.labelObject.SetLabelColor(labelColor);
serieData.labelObject.SetText(serieData.name);
}
}
}
}
protected override void UpdateTooltipValue(Vector2 local)
{
var grid = GetGrid(tooltip.runtimeGridIndex);
if (grid == null) return;
tooltip.runtimeDataIndex.Clear();
foreach (var serie in m_Series.list)
{
var serieGrid = GetSerieGridOrDefault(serie);
if (grid.index != serieGrid.index) continue;
for (int i = 0; i < serie.data.Count; i++)
{
var serieData = serie.GetSerieData(i);
var highlight = serieData.runtimeRect.Contains(local);
serieData.highlighted = highlight;
if (highlight)
{
tooltip.runtimeDataIndex.Add(serie.index);
tooltip.runtimeDataIndex.Add(i);
return;
}
}
}
}
protected override void UpdateTooltip()
{
if (tooltip.runtimeDataIndex.Count == 0)
{
if (tooltip.IsActive())
{
tooltip.SetActive(false);
RefreshChart();
}
return;
}
var serieIndex = tooltip.runtimeDataIndex[0];
var dataIndex = tooltip.runtimeDataIndex[1];
var serie = m_Series.GetSerie(serieIndex);
if (serie == null) return;
var serieData = serie.GetSerieData(dataIndex);
var category = serieData == null ? serie.name : serieData.name;
TooltipHelper.SetContentAndPosition(tooltip, category, chartRect);
tooltip.SetActive(true);
}
}
}

View File

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

View File

@@ -198,6 +198,20 @@ namespace XCharts
content = TrimAndReplaceLine(content);
}
public static void ReplaceAxisLabelContent(ref string content, string value)
{
var mc = s_RegexForAxisLabel.Matches(content);
foreach (var m in mc)
{
var old = m.ToString();
var args = s_RegexSubForAxisLabel.Matches(m.ToString());
var argsCount = args.Count;
if (argsCount <= 0) continue;
content = content.Replace(old, value);
}
content = TrimAndReplaceLine(content);
}
public static void ReplaceSerieLabelContent(ref string content, string numericFormatter, float value, float total,
string serieName, string dataName)
{

View File

@@ -284,6 +284,7 @@ namespace XCharts
foreach (var component in m_Radars) component.SetAllDirty();
m_ReinitLabel = true;
m_ReinitTitle = true;
m_RefreshChart = true;
}
protected override void OnDestroy()

View File

@@ -178,6 +178,9 @@ namespace XCharts
case SerieType.Candlestick:
DrawCandlestickSerie(vh, colorIndex, serie);
break;
case SerieType.Gantt:
DrawGanttSerie(vh, colorIndex, serie);
break;
}
}
@@ -240,7 +243,7 @@ namespace XCharts
}
}
protected void UpdateTooltipValue(Vector2 local)
protected virtual void UpdateTooltipValue(Vector2 local)
{
var isCartesian = IsValue();
var dataCount = m_Series.list.Count > 0 ? m_Series.list[0].GetDataList(dataZoom).Count : 0;
@@ -495,6 +498,7 @@ namespace XCharts
yAxis.painter = m_Painter;
yAxis.refreshComponent = delegate ()
{
InitAxisRuntimeData(yAxis);
string objName = ChartCached.GetYAxisName(yAxisIndex);
var axisObj = ChartHelper.AddObject(objName, transform, graphAnchorMin,
graphAnchorMax, chartPivot, new Vector2(chartWidth, chartHeight));
@@ -593,6 +597,26 @@ namespace XCharts
yAxis.refreshComponent();
}
private void InitAxisRuntimeData(Axis axis)
{
if (axis.type != Axis.AxisType.Category) return;
if (axis.data.Count > 0) return;
var isYAxis = axis is YAxis;
if (this is GanttChart)
{
axis.runtimeData.Clear();
for (int i = 0; i < m_Series.Count; i++)
{
var serie = m_Series.GetSerie(i);
if(serie.yAxisIndex != axis.index) continue;
for (int j = serie.data.Count - 1; j >= 0; j--)
{
axis.runtimeData.Add(serie.data[j].name);
}
}
}
}
private void InitAxisX()
{
for (int i = 0; i < m_XAxes.Count; i++)
@@ -782,7 +806,7 @@ namespace XCharts
return new Vector3(grid.runtimeX + scaleWid, posY);
}
private void CheckMinMaxValue()
protected virtual void CheckMinMaxValue()
{
if (m_XAxes == null || m_YAxes == null) return;
for (int i = 0; i < m_XAxes.Count; i++)
@@ -806,23 +830,7 @@ namespace XCharts
}
float tempMinValue = 0;
float tempMaxValue = 0;
if (IsValue())
{
if (axis is XAxis)
{
SeriesHelper.GetXMinMaxValue(m_Series, null, axisIndex, true, axis.inverse, out tempMinValue, out tempMaxValue);
}
else
{
SeriesHelper.GetYMinMaxValue(m_Series, null, axisIndex, true, axis.inverse, out tempMinValue, out tempMaxValue);
}
}
else
{
SeriesHelper.GetYMinMaxValue(m_Series, null, axisIndex, false, axis.inverse, out tempMinValue, out tempMaxValue);
}
AxisHelper.AdjustMinMaxValue(axis, ref tempMinValue, ref tempMaxValue, true);
GetSeriesMinMaxValue(axis, axisIndex, out tempMinValue, out tempMaxValue);
if (tempMinValue != axis.runtimeMinValue || tempMaxValue != axis.runtimeMaxValue)
{
m_IsPlayingAnimation = true;
@@ -866,6 +874,26 @@ namespace XCharts
}
}
protected virtual void GetSeriesMinMaxValue(Axis axis, int axisIndex, out float tempMinValue, out float tempMaxValue)
{
if (IsValue())
{
if (axis is XAxis)
{
SeriesHelper.GetXMinMaxValue(m_Series, null, axisIndex, true, axis.inverse, out tempMinValue, out tempMaxValue);
}
else
{
SeriesHelper.GetYMinMaxValue(m_Series, null, axisIndex, true, axis.inverse, out tempMinValue, out tempMaxValue);
}
}
else
{
SeriesHelper.GetYMinMaxValue(m_Series, null, axisIndex, false, axis.inverse, out tempMinValue, out tempMaxValue);
}
AxisHelper.AdjustMinMaxValue(axis, ref tempMinValue, ref tempMaxValue, true);
}
protected void UpdateAxisLabelText(Axis axis)
{
var grid = GetAxisGridOrDefault(axis);
@@ -1571,6 +1599,7 @@ namespace XCharts
{
base.OnRefreshLabel();
var anyPercentStack = SeriesHelper.IsPercentStack(m_Series, SerieType.Bar);
for (int i = 0; i < m_Series.Count; i++)
{
var serie = m_Series.GetSerie(i);
@@ -1578,6 +1607,7 @@ namespace XCharts
if (!serie.IsCoordinateSerie()) continue;
var total = serie.yTotal;
var isPercentStack = SeriesHelper.IsPercentStack(m_Series, serie.stack, SerieType.Bar);
for (int j = 0; j < serie.data.Count; j++)
{
var serieData = serie.data[j];
@@ -1602,7 +1632,7 @@ namespace XCharts
dimension = VisualMapHelper.GetDimension(visualMap, serieData.data.Count);
}
SerieLabelHelper.ResetLabel(serieData, serieLabel, theme, i);
SerieLabelHelper.ResetLabel(serieData.labelObject.label, serieLabel, theme, i);
value = serieData.data[dimension];
var content = "";

View File

@@ -0,0 +1,178 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
public partial class CoordinateChart
{
protected void DrawGanttSerie(VertexHelper vh, int colorIndex, Serie serie)
{
if (!IsActive(serie.index)) return;
if (serie.animation.HasFadeOut()) return;
var showData = serie.GetDataList(null);
var yAxis = m_YAxes[serie.yAxisIndex];
var xAxis = m_XAxes[serie.xAxisIndex];
var grid = GetSerieGridOrDefault(serie);
var xCategoryWidth = AxisHelper.GetDataWidth(xAxis, grid.runtimeWidth, showData.Count, dataZoom);
var yCategoryWidth = AxisHelper.GetDataWidth(yAxis, grid.runtimeHeight, showData.Count, dataZoom);
var barGap = GetBarGap();
var barWidth = serie.GetBarWidth(yCategoryWidth);
var space = (yCategoryWidth - barWidth) / 2;
var dataChanging = false;
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
var minValue = xAxis.GetCurrMinValue(dataChangeDuration);
var maxValue = xAxis.GetCurrMaxValue(dataChangeDuration);
var pX = grid.runtimeX + (xAxis.boundaryGap ? xCategoryWidth / 2 : 0);
var pY = 0f;
var startY = grid.runtimeY - (yAxis.boundaryGap ? 0 : yCategoryWidth / 2);
var isTime = xAxis.type == Axis.AxisType.Time;
var categoryIndex = GetGanttSerieCategoryIndex(serie, grid.index);
var dataCount = serie.data.Count;
for (int i = 0; i < dataCount; i++)
{
var serieData = serie.data[i];
pY = startY + (categoryIndex - 1 - i) * yCategoryWidth;
DrawSerieData(vh, grid, serie, serieData, colorIndex, pX, pY, space, barWidth, isTime, minValue,
maxValue, xCategoryWidth);
}
if (dataChanging)
{
RefreshPainter(serie);
}
}
private void DrawSerieData(VertexHelper vh, Grid grid, Serie serie, SerieData serieData, int colorIndex,
float pX, float pY, float space, float barWidth, bool isTime, float minValue, float maxValue,
float xCategoryWidth)
{
var xStart = 0f;
var xEnd = 0f;
var xActualStart = 0f;
var xActualEnd = 0f;
var start = (int)serieData.GetData(0);
var end = (int)serieData.GetData(1);
var actualStart = (int)serieData.GetData(2);
var actualEnd = (int)serieData.GetData(3);
var enableActual = actualStart > 0 && actualEnd > 0;
if (isTime)
{
var valueTotal = maxValue - minValue;
xStart = pX + (start - minValue) / valueTotal * grid.runtimeWidth;
xEnd = pX + (end - minValue) / valueTotal * grid.runtimeWidth;
if (enableActual)
{
xActualStart = pX + (actualStart - minValue) / valueTotal * grid.runtimeWidth;
xActualEnd = pX + (actualEnd - minValue) / valueTotal * grid.runtimeWidth;
}
}
else
{
xStart = pX + start * xCategoryWidth;
xEnd = pX + end * xCategoryWidth;
if (enableActual)
{
xActualStart = pX + actualStart * xCategoryWidth;
xActualEnd = pX + actualEnd * xCategoryWidth;
}
}
var highlight = (serieData != null && serieData.highlighted)
|| serie.highlighted;
var itemStyle = SerieHelper.GetItemStyle(serie, serieData, highlight);
var color = SerieHelper.GetItemColor(serie, serieData, m_Theme, colorIndex, highlight);
var borderWidth = itemStyle.borderWidth;
var rect = DrawGanttBar(vh, grid, serie, serieData, itemStyle, color, pY, pY, space, barWidth, xStart,
xEnd);
if (enableActual)
{
var defaultActualColor = SerieHelper.GetItemColor(serie, serieData, m_Theme, colorIndex, true);
var actualColor = SerieHelper.GetItemColor0(serie, serieData, m_Theme, highlight, defaultActualColor);
var rect2 = DrawGanttBar(vh, grid, serie, serieData, itemStyle, actualColor, pY, pY, space, barWidth,
xActualStart, xActualEnd);
var rect3X = Mathf.Min(rect.x, rect2.x);
var rect3Width = Mathf.Max(rect.x + rect.width, rect2.x + rect2.width) - rect3X;
var rect3 = new Rect(rect3X, rect.y, rect3Width, rect.height);
serie.dataPoints.Add(rect3.center);
serieData.runtimePosition = rect3.center;
serieData.labelPosition = rect3.center;
serieData.runtimeRect = rect3;
}
else
{
serie.dataPoints.Add(rect.center);
serieData.runtimePosition = rect.center;
serieData.labelPosition = rect.center;
serieData.runtimeRect = rect;
}
}
private Rect DrawGanttBar(VertexHelper vh, Grid grid, Serie serie, SerieData serieData, ItemStyle itemStyle,
Color32 color, float pX, float pY, float space, float barWidth, float xStart, float xEnd)
{
var borderWidth = itemStyle.borderWidth;
var plb = new Vector3(xStart + borderWidth, pY + space + borderWidth);
var plt = new Vector3(xStart + borderWidth, pY + space + barWidth - borderWidth);
var prt = new Vector3(xEnd - borderWidth, pY + space + barWidth - borderWidth);
var prb = new Vector3(xEnd - borderWidth, pY + space + borderWidth);
var center = new Vector3((plb.x + prt.x) / 2, (plt.y + prb.y) / 2);
var itemWidth = Mathf.Abs(prt.x - plb.x);
var itemHeight = Mathf.Abs(plt.y - prb.y);
if (serie.clip)
{
plb = ClampInGrid(grid, plb);
plt = ClampInGrid(grid, plt);
prt = ClampInGrid(grid, prt);
prb = ClampInGrid(grid, prb);
center = ClampInGrid(grid, center);
}
if (ItemStyleHelper.IsNeedCorner(itemStyle))
{
UGL.DrawRoundRectangle(vh, center, itemWidth, itemHeight, color, color, 0,
itemStyle.cornerRadius, true, 0.5f);
}
else
{
CheckClipAndDrawPolygon(vh, ref prb, ref plb, ref plt, ref prt, color, color,
serie.clip, grid);
}
if (borderWidth != 0)
{
UGL.DrawBorder(vh, center, itemWidth, itemHeight, borderWidth, itemStyle.borderColor, 0,
itemStyle.cornerRadius, true, 0.5f);
}
return new Rect(plb.x, plb.y, xEnd - xStart, barWidth);
}
private int GetGanttSerieCategoryIndex(Serie currSerie, int gridIndex)
{
var count = m_Series.Count;
var index = 0;
for (int i = 0; i < count; i++)
{
var serie = m_Series.GetSerie(i);
if (serie.type != SerieType.Gantt) continue;
var grid = GetSerieGridOrDefault(serie);
if (grid.index != gridIndex) continue;
foreach (var serieData in serie.data)
{
index++;
}
if (serie.index == currSerie.index)
{
return index;
}
}
return index;
}
}
}

View File

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

View File

@@ -99,7 +99,7 @@ namespace XCharts
{
var value = serieData.GetCurrData(1);
var max = radar.GetIndicatorMax(n);
SerieLabelHelper.ResetLabel(serieData, serieLabel, chart.theme, i);
SerieLabelHelper.ResetLabel(serieData.labelObject.label, serieLabel, chart.theme, i);
serieData.SetLabelActive(serieData.labelPosition != Vector3.zero);
serieData.labelObject.SetLabelPosition(serieLabel.offset);
var content = SerieLabelHelper.GetFormatterContent(serie, serieData, value, max, serieLabel);

View File

@@ -53,6 +53,25 @@ namespace XCharts
return axis.splitNumber > 0 ? axis.splitNumber : 4;
}
}
else if (axis.type == Axis.AxisType.Time)
{
if (axis.interval > 0)
{
if (coordinateWid <= 0) return 0;
int num = Mathf.CeilToInt(axis.runtimeMinMaxRange / axis.interval);
int maxNum = Mathf.CeilToInt(coordinateWid / 15);
if (num > maxNum)
{
axis.interval *= 2;
num = Mathf.CeilToInt(axis.runtimeMinMaxRange / axis.interval);
}
return num;
}
else
{
return axis.splitNumber > 0 ? axis.splitNumber : 4;
}
}
else if (axis.type == Axis.AxisType.Log)
{
return axis.splitNumber > 0 ? axis.splitNumber : 4;
@@ -146,6 +165,23 @@ namespace XCharts
}
return axis.axisLabel.GetFormatterContent(value, minValue, maxValue, true);
}
else if (axis.type == Axis.AxisType.Time)
{
if (minValue == 0 && maxValue == 0) return string.Empty;
var value = 0f;
if (axis.interval > 0)
{
if (index == split) value = maxValue;
else value = minValue + index * axis.interval;
}
else
{
value = minValue + (maxValue - minValue) * index / split;
}
var timestamp = (int)value;
var dateTime = DateTimeUtil.GetDateTime(timestamp);
return axis.axisLabel.GetFormatterDateTime(dateTime);
}
var showData = axis.GetDataList(dataZoom);
int dataCount = showData.Count;
if (dataCount <= 0) return "";
@@ -177,11 +213,12 @@ namespace XCharts
int splitNum = GetSplitNumber(axis, coordinateWidth, dataZoom);
if (axis.IsCategory())
{
int tick = Mathf.RoundToInt(axis.data.Count * 1f / splitNum);
var data = axis.GetDataList();
int tick = Mathf.RoundToInt(data.Count * 1f / splitNum);
if (axis.boundaryGap)
return Mathf.CeilToInt(axis.data.Count * 1.0f / tick) + 1;
return Mathf.CeilToInt(data.Count * 1.0f / tick) + 1;
else
return Mathf.CeilToInt(axis.data.Count * 1.0f / tick);
return Mathf.CeilToInt(data.Count * 1.0f / tick);
}
else
{
@@ -209,10 +246,11 @@ namespace XCharts
}
else
{
if (axis.IsCategory() && axis.data.Count > 0)
var data = axis.GetDataList();
if (axis.IsCategory() && data.Count > 0)
{
int tick = Mathf.RoundToInt(axis.data.Count * 1f / splitNum);
var count = axis.boundaryGap ? axis.data.Count : axis.data.Count - 1;
int tick = Mathf.RoundToInt(data.Count * 1f / splitNum);
var count = axis.boundaryGap ? data.Count : data.Count - 1;
if (count <= 0) return 0;
var each = coordinateWidth / count;
if (index >= num - 1)
@@ -232,9 +270,10 @@ namespace XCharts
internal static float GetEachWidth(Axis axis, float coordinateWidth, DataZoom dataZoom = null)
{
if (axis.data.Count > 0)
var data = axis.GetDataList();
if (data.Count > 0)
{
var count = axis.boundaryGap ? axis.data.Count : axis.data.Count - 1;
var count = axis.boundaryGap ? data.Count : data.Count - 1;
return count > 0 ? coordinateWidth / count : coordinateWidth;
}
else
@@ -249,7 +288,7 @@ namespace XCharts
/// </summary>
/// <param name="minValue"></param>
/// <param name="maxValue"></param>
internal static void AdjustMinMaxValue(Axis axis, ref float minValue, ref float maxValue, bool needFormat)
internal static void AdjustMinMaxValue(Axis axis, ref float minValue, ref float maxValue, bool needFormat, int ceilRate = 0)
{
if (axis.type == Axis.AxisType.Log)
{
@@ -278,6 +317,7 @@ namespace XCharts
}
else
{
if (ceilRate == 0) ceilRate = axis.ceilRate;
switch (axis.minMaxType)
{
case Axis.AxisMinMaxType.Default:
@@ -287,22 +327,22 @@ namespace XCharts
else if (minValue > 0 && maxValue > 0)
{
minValue = 0;
maxValue = needFormat ? ChartHelper.GetMaxDivisibleValue(maxValue, axis.ceilRate) : maxValue;
maxValue = needFormat ? ChartHelper.GetMaxDivisibleValue(maxValue, ceilRate) : maxValue;
}
else if (minValue < 0 && maxValue < 0)
{
minValue = needFormat ? ChartHelper.GetMinDivisibleValue(minValue, axis.ceilRate) : minValue;
minValue = needFormat ? ChartHelper.GetMinDivisibleValue(minValue, ceilRate) : minValue;
maxValue = 0;
}
else
{
minValue = needFormat ? ChartHelper.GetMinDivisibleValue(minValue, axis.ceilRate) : minValue;
maxValue = needFormat ? ChartHelper.GetMaxDivisibleValue(maxValue, axis.ceilRate) : maxValue;
minValue = needFormat ? ChartHelper.GetMinDivisibleValue(minValue, ceilRate) : minValue;
maxValue = needFormat ? ChartHelper.GetMaxDivisibleValue(maxValue, ceilRate) : maxValue;
}
break;
case Axis.AxisMinMaxType.MinMax:
minValue = needFormat ? ChartHelper.GetMinDivisibleValue(minValue, axis.ceilRate) : minValue;
maxValue = needFormat ? ChartHelper.GetMaxDivisibleValue(maxValue, axis.ceilRate) : maxValue;
minValue = needFormat ? ChartHelper.GetMinDivisibleValue(minValue, ceilRate) : minValue;
maxValue = needFormat ? ChartHelper.GetMaxDivisibleValue(maxValue, ceilRate) : maxValue;
break;
}
}
@@ -320,7 +360,7 @@ namespace XCharts
internal static bool NeedShowSplit(Axis axis)
{
if (!axis.show) return false;
if (axis.IsCategory() && axis.data.Count <= 0) return false;
if (axis.IsCategory() && axis.GetDataList().Count <= 0) return false;
else if (axis.IsValue() && axis.runtimeMinValue == 0 && axis.runtimeMaxValue == 0) return false;
else return true;
}

View File

@@ -70,6 +70,32 @@ namespace XCharts
return color;
}
}
internal static Color32 GetItemColor0(Serie serie, SerieData serieData, ChartTheme theme, bool highlight, Color32 defaultColor)
{
if (serie == null) return ChartConst.clearColor32;
if (highlight)
{
var itemStyleEmphasis = GetItemStyleEmphasis(serie, serieData);
if (itemStyleEmphasis != null && !ChartHelper.IsClearColor(itemStyleEmphasis.color))
{
var color = itemStyleEmphasis.color0;
ChartHelper.SetColorOpacity(ref color, itemStyleEmphasis.opacity);
return color;
}
}
var itemStyle = GetItemStyle(serie, serieData);
if (!ChartHelper.IsClearColor(itemStyle.color0))
{
return itemStyle.GetColor0();
}
else
{
var color = defaultColor;
if (highlight) color = ChartHelper.GetHighlightColor(color);
ChartHelper.SetColorOpacity(ref color, itemStyle.opacity);
return color;
}
}
internal static Color32 GetItemToColor(Serie serie, SerieData serieData, ChartTheme theme, int index, bool highlight)
{

View File

@@ -75,14 +75,13 @@ namespace XCharts
}
}
public static void ResetLabel(SerieData serieData, SerieLabel label, ChartTheme theme, int colorIndex)
public static void ResetLabel(ChartText labelObject, SerieLabel label, ChartTheme theme, int colorIndex)
{
if (serieData.labelObject == null) return;
if (serieData.labelObject.label == null) return;
serieData.labelObject.label.SetColor(!ChartHelper.IsClearColor(label.textStyle.color) ? label.textStyle.color :
if (labelObject == null) return;
labelObject.SetColor(!ChartHelper.IsClearColor(label.textStyle.color) ? label.textStyle.color :
(Color)theme.GetColor(colorIndex));
serieData.labelObject.label.SetFontSize(label.textStyle.GetFontSize(theme.common));
serieData.labelObject.label.SetFontStyle(label.textStyle.fontStyle);
labelObject.SetFontSize(label.textStyle.GetFontSize(theme.common));
labelObject.SetFontStyle(label.textStyle.fontStyle);
}
public static bool CanShowLabel(Serie serie, SerieData serieData, SerieLabel label, int dimesion)

View File

@@ -232,6 +232,14 @@ namespace XCharts
}
}
private static void InitGanttTooltip(ref StringBuilder sb, Tooltip tooltip, Serie serie, int index,
ChartTheme theme, string category)
{
//if (tooltip.runtimeGridIndex >= 0) return;
//if (serie.index != index || serie.type != SerieType.Gantt) return;
sb.Append(serie.name);
}
private static void InitDefaultContent(ref StringBuilder sb, Tooltip tooltip, Serie serie, int index,
string category, ChartTheme theme = null, DataZoom dataZoom = null, bool isCartesian = false,
Radar radar = null)
@@ -261,6 +269,9 @@ namespace XCharts
case SerieType.Gauge:
InitGaugeTooltip(ref sb, tooltip, serie, index, theme);
break;
case SerieType.Gantt:
InitGanttTooltip(ref sb, tooltip, serie, index, theme, category);
break;
}
}

View File

@@ -28,6 +28,7 @@ namespace XCharts
case SerieType.Gauge: AddDefaultGaugeSerie(chart, serieName); break;
case SerieType.Ring: AddDefaultRingSerie(chart, serieName); break;
case SerieType.Candlestick: AddDefaultCandlestickSerie(chart, serieName); break;
case SerieType.Gantt: AddDefaultCategoryGanttSerie(chart, serieName); break;
default: Debug.LogError("AddDefaultSerie: not support serieType yet:" + serieType); break;
}
}
@@ -183,5 +184,35 @@ namespace XCharts
}
return defaultDataCount;
}
public static Serie AddDefaultCategoryGanttSerie(BaseChart chart, string serieName, int dataCount = 0, int min = 0, int max = 0)
{
var serie = chart.AddSerie(SerieType.Gantt, serieName);
serie.showDataName = true;
serie.showDataDimension = 2;
for (int i = 0; i < dataCount; i++)
{
var start = Random.Range(min, max);
var end = Random.Range(start + 1, max);
serie.AddXYData(start, end, "task-" + (i + 1));
}
return serie;
}
public static Serie AddDefaultTimeGanttSerie(BaseChart chart, string serieName, int dataCount = 0)
{
var serie = chart.AddSerie(SerieType.Gantt, serieName);
serie.showDataName = true;
serie.showDataDimension = 2;
var timestamp = DateTimeUtil.GetTimestamp();
var now = DateTimeUtil.GetDateTime(timestamp);
for (int i = 0; i < dataCount; i++)
{
var start = timestamp + Random.Range(1, 6) * 3600 * 24;
var end = start + Random.Range(1, 10) * 3600 * 24;
serie.AddXYData(start, end, "task-" + (i + 1));
}
return serie;
}
}
}

View File

@@ -0,0 +1,33 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using System;
using UnityEngine;
namespace XCharts
{
public static class DateTimeUtil
{
private static readonly DateTime k_DateTime1970 = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
public static int GetTimestamp()
{
return (int)(DateTime.Now - k_DateTime1970).TotalSeconds;
}
public static int GetTimestamp(DateTime time)
{
return (int)(time - k_DateTime1970).TotalSeconds;
}
public static DateTime GetDateTime(int timestamp)
{
long span = ((long)timestamp) * 10000000;
return k_DateTime1970.Add(new TimeSpan(span));
}
}
}

View File

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

View File

@@ -5,14 +5,24 @@
/* */
/************************************************/
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace XChartsDemo
{
[CustomPropertyDrawer(typeof(ChartModule), true)]
public class ChartModuleDrawer : PropertyDrawer
internal class ChartModuleDrawer : PropertyDrawer
{
public class Styles
{
public static readonly GUIContent iconAdd = new GUIContent("+", "Add");
public static readonly GUIContent iconRemove = new GUIContent("-", "Remove");
public static readonly GUIContent iconUp = new GUIContent("↑", "Up");
public static readonly GUIContent iconDown = new GUIContent("↓", "Down");
public static readonly GUIStyle invisibleButton = "InvisibleButton";
}
public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label)
{
Rect drawRect = pos;
@@ -25,9 +35,29 @@ namespace XChartsDemo
SerializedProperty m_Title = prop.FindPropertyRelative("m_Title");
SerializedProperty m_Selected = prop.FindPropertyRelative("m_Selected");
SerializedProperty m_Panel = prop.FindPropertyRelative("m_Panel");
var fieldWid = EditorGUIUtility.currentViewWidth - 30 - 5 - 40 - 80 - 50 - 100 - 6 * 2;
var fieldWid = EditorGUIUtility.currentViewWidth - 30 - 5 - 40 - 80 - 50 - 100 - 6 * 2 - 70;
drawRect.width = 15;
EditorGUI.BeginChangeCheck();
var oldFlag = m_Selected.boolValue;
EditorGUI.PropertyField(drawRect, m_Selected, GUIContent.none);
if (EditorGUI.EndChangeCheck())
{
var demo = prop.serializedObject.targetObject as Demo;
var index = GetIndex(prop);
var selectedIndex = demo.GetSelectedModule();
if (selectedIndex != index)
{
for (int i = 0; i < demo.chartModules.Count; i++)
{
demo.chartModules[i].select = i == index && m_Selected.boolValue;
}
demo.InitModuleButton();
}
else
{
m_Selected.boolValue = oldFlag;
}
}
drawRect.x += 17;
drawRect.width = 80;
EditorGUI.PropertyField(drawRect, m_Name, GUIContent.none);
@@ -43,11 +73,83 @@ namespace XChartsDemo
drawRect.x += 102;
drawRect.width = 40;
EditorGUI.PropertyField(drawRect, m_Column, GUIContent.none);
var btnWidth = 12;
drawRect.x += 42;
drawRect.width = btnWidth;
if (GUI.Button(drawRect, Styles.iconUp, Styles.invisibleButton))
{
var demo = prop.serializedObject.targetObject as Demo;
var index = GetIndex(prop);
if (index >= 0)
{
Swap(demo.chartModules, index, index - 1);
demo.InitModuleButton();
}
}
drawRect.x += btnWidth + 1;
if (GUI.Button(drawRect, Styles.iconDown, Styles.invisibleButton))
{
var demo = prop.serializedObject.targetObject as Demo;
var index = GetIndex(prop);
if (index >= 0)
{
Swap(demo.chartModules, index, index + 1);
demo.InitModuleButton();
}
}
drawRect.x += btnWidth + 1;
if (GUI.Button(drawRect, Styles.iconAdd, Styles.invisibleButton))
{
var demo = prop.serializedObject.targetObject as Demo;
var index = GetIndex(prop);
if (index >= 0)
{
demo.chartModules.Insert(index + 1, new ChartModule());
demo.InitModuleButton();
}
}
drawRect.x += 16;
if (GUI.Button(drawRect, Styles.iconRemove, Styles.invisibleButton))
{
var demo = prop.serializedObject.targetObject as Demo;
var index = GetIndex(prop);
if (index >= 0)
{
demo.chartModules.RemoveAt(index);
demo.InitModuleButton();
}
}
}
public override float GetPropertyHeight(SerializedProperty prop, GUIContent label)
{
return 1 * EditorGUIUtility.singleLineHeight + 1 * EditorGUIUtility.standardVerticalSpacing;
}
private int GetIndex(SerializedProperty prop)
{
int index = -1;
var sindex = prop.propertyPath.LastIndexOf('[');
var eindex = prop.propertyPath.LastIndexOf(']');
if (sindex >= 0 && eindex >= 0)
{
var str = prop.propertyPath.Substring(sindex + 1, eindex - sindex - 1);
int.TryParse(str, out index);
}
return index;
}
private static bool Swap<T>(List<T> list, int index1, int index2)
{
if (index1 < 0 || index1 >= list.Count) return false;
if (index2 < 0 || index2 >= list.Count) return false;
var temp = list[index1];
list[index1] = list[index2];
list[index2] = temp;
return true;
}
}
}

View File

@@ -15,7 +15,7 @@ namespace XChartsDemo
/// </summary>
[CustomEditor(typeof(Demo), false)]
public class DemoEditor : Editor
internal class DemoEditor : Editor
{
protected Demo m_Target;
protected SerializedProperty m_Script;

View File

@@ -16,11 +16,11 @@ namespace XChartsDemo
[System.Serializable]
public class ChartModule
{
[SerializeField] private string m_Name;
[SerializeField] private string m_SubName;
[SerializeField] private string m_Name = "Name";
[SerializeField] private string m_SubName = "SubName";
[SerializeField] private int m_Column = 3;
[SerializeField] private string m_Title;
[SerializeField] private string m_Title = "Title";
[SerializeField] private bool m_Selected;
[SerializeField] private GameObject m_Panel;
@@ -31,6 +31,7 @@ namespace XChartsDemo
public bool select { get { return m_Selected; } set { m_Selected = value; } }
public GameObject panel { get { return m_Panel; } set { m_Panel = value; } }
public Button button { get; set; }
public int index { get; internal set; }
}
[DisallowMultipleComponent]
@@ -44,6 +45,7 @@ namespace XChartsDemo
[SerializeField] private Color m_ButtonNormalColor;
[SerializeField] private Color m_ButtonSelectedColor;
[SerializeField] private Color m_ButtonHighlightColor;
[SerializeField] public int lastSelectedModuleIndex = -1;
[SerializeField] private List<ChartModule> m_ChartModule = new List<ChartModule>();
private GameObject m_BtnClone;
@@ -60,6 +62,8 @@ namespace XChartsDemo
private ScrollRect m_ScrollRect;
private Mask m_Mark;
public List<ChartModule> chartModules { get { return m_ChartModule; } }
void Awake()
{
m_SelectedTheme = Theme.Default;
@@ -118,6 +122,7 @@ namespace XChartsDemo
private void SetChartRootInfo(ChartModule module)
{
var chartRoot = module.panel;
if (chartRoot == null) return;
var grid = chartRoot.GetComponent<GridLayoutGroup>();
var hig = Mathf.CeilToInt(chartRoot.transform.childCount * 1f / module.column) * (grid.cellSize.y + grid.spacing.y);
SetChartGridLayoutGroup(grid, module.column);
@@ -137,23 +142,6 @@ namespace XChartsDemo
{
#if UNITY_EDITOR
if (m_ChartModule.Count <= 0) return;
int selectedModuleIndex = -1;
for (int i = 0; i < m_ChartModule.Count; i++)
{
if (selectedModuleIndex >= 0 && i > selectedModuleIndex)
{
m_ChartModule[i].select = false;
}
else if (m_ChartModule[i].select)
{
selectedModuleIndex = i;
}
}
if (selectedModuleIndex < 0) selectedModuleIndex = 0;
if (selectedModuleIndex != m_LastSelectedModuleIndex)
{
InitModuleButton();
}
if (!Application.isPlaying) m_Mark.enabled = false;
if (m_LastCheckLeftWidth != m_LeftWidth)
@@ -164,14 +152,25 @@ namespace XChartsDemo
#endif
}
void InitModuleButton()
public int GetSelectedModule()
{
for (int i = 0; i < m_ChartModule.Count; i++)
{
if (m_ChartModule[i].select) return i;
}
return -1;
}
public void InitModuleButton()
{
var btnPanel = transform.Find("chart_list");
m_BtnClone = transform.Find("btn_clone").gameObject;
m_BtnClone.SetActive(false);
ChartHelper.HideAllObject(btnPanel);
foreach (var module in m_ChartModule)
ChartHelper.DestroyAllChildren(btnPanel.transform);
for (int i = 0; i < m_ChartModule.Count; i++)
{
var module = m_ChartModule[i];
module.index = i;
var btnName = "btn_" + module.name;
GameObject btn;
if (btnPanel.Find(btnName))
@@ -193,19 +192,19 @@ namespace XChartsDemo
module.button.transform.Find("Text").GetComponent<Text>().text = module.name.Replace("\\n", "\n");
module.button.transform.Find("SubText").GetComponent<Text>().text = module.subName.Replace("\\n", "\n");
ChartHelper.ClearEventListener(btn.gameObject);
ChartHelper.AddEventListener(btn.gameObject, EventTriggerType.PointerDown, (data) =>
{
ClickModule(module);
});
}
for (int i = 0; i < m_ChartModule.Count; i++)
{
var module = m_ChartModule[i];
module.index = i;
if (module.select)
{
ClickModule(module);
m_LastSelectedModuleIndex = i;
break;
}
}
@@ -213,28 +212,38 @@ namespace XChartsDemo
void ClickModule(ChartModule selectedModule)
{
if (lastSelectedModuleIndex >= 0)
{
m_ChartModule[lastSelectedModuleIndex].select = false;
}
lastSelectedModuleIndex = selectedModule.index;
foreach (var module in m_ChartModule)
{
if (selectedModule != module)
if (module.index != lastSelectedModuleIndex)
{
var block = module.button.colors;
block.highlightedColor = m_ButtonHighlightColor;
block.selectedColor = m_ButtonNormalColor;
block.normalColor = m_ButtonNormalColor;
module.button.colors = block;
module.panel.SetActive(false);
module.select = false;
if (module.panel != null)
module.panel.SetActive(false);
//module.select = false;
}
else
{
var block = module.button.colors;
block.highlightedColor = m_ButtonSelectedColor;
block.selectedColor = m_ButtonSelectedColor;
block.normalColor = m_ButtonSelectedColor;
module.button.colors = block;
module.panel.SetActive(true);
module.select = true;
if (module.panel != null)
module.panel.SetActive(true);
// module.select = true;
}
}
m_ScrollRect.content = selectedModule.panel.GetComponent<RectTransform>();
if (selectedModule.panel != null)
m_ScrollRect.content = selectedModule.panel.GetComponent<RectTransform>();
SetChartRootInfo(selectedModule);
m_Title.text = string.IsNullOrEmpty(selectedModule.title) ?
selectedModule.name : selectedModule.title;

View File

@@ -14,7 +14,7 @@ namespace XChartsDemo
{
[DisallowMultipleComponent]
[ExecuteInEditMode]
public class Demo_Animation : MonoBehaviour
internal class Demo_Animation : MonoBehaviour
{
[SerializeField] private int m_FadeInDuration = 1000;
[SerializeField] private int m_FadeOutDuration = 1000;

View File

@@ -14,7 +14,7 @@ namespace XChartsDemo
{
[DisallowMultipleComponent]
[ExecuteInEditMode]
public class Demo_Performance : MonoBehaviour
internal class Demo_Performance : MonoBehaviour
{
[SerializeField] private float fps = 0;
[SerializeField] private int m_MaxCacheDataNumber = 3000;

View File

@@ -10,7 +10,7 @@ using UnityEngine.UI;
namespace XChartsDemo
{
public static class UIUtil
internal static class UIUtil
{
public static RectTransform GetRectTransform(Transform transform, string path)

File diff suppressed because it is too large Load Diff