增加RingChart环形图

This commit is contained in:
monitor1394
2020-03-08 10:47:48 +08:00
parent 16f7781e49
commit 1cf107f47b
37 changed files with 29134 additions and 13866 deletions

View File

@@ -1,6 +1,7 @@
# 更新日志
* (2020.03.08) 增加`RingChart`环形图
* (2020.03.05) 调整`Serie``arcShaped`参数重命名为`roundCap`
* (2020.03.05) 增加运行时和非运行时参数变更自动刷新图表
* (2020.02.26) 重构`Legend`图例,改变样式,增加自定义图标等设置

View File

@@ -107,6 +107,13 @@
* 继承自 `BaseChart`
* 继承自 `CoordinateChart`
## `RingChart`
* 继承自 `BaseChart`
* `RingChart.UpdateMax(int serieIndex, int dataIndex, float value)`:更新指定系列执行数据项的最大值。
* `RingChart.UpdateMax(int serieIndex, float value)`:更新指定系列的所有数据项的最大值。
* `RingChart.UpdateMax(float value)`:更新第一个系列第一个数据项的最大值。
[返回首页](https://github.com/monitor1394/unity-ugui-XCharts)
[XCharts配置项手册](XCharts配置项手册.md)
[XCharts问答](XCharts问答.md)

View File

@@ -19,6 +19,7 @@
* [Serie-Scatter 散点图](#Serie-Scatter)
* [Serie-Heatmap 热力图](#Serie-Heatmap)
* [Serie-Gauge 仪表盘](#Serie-Gauge)
* [Serie-Ring 环形图](#Serie-Ring)
* [Settings 设置](#Settings)
* [Theme 主题](#Theme)
* [Tooltip 提示框](#Tooltip)
@@ -601,6 +602,26 @@
* `animation`:起始动画 [SerieAnimation](#SerieAnimation)。
* `data`:系列中的数据项 [SerieData](#SerieData) 数组,可以设置`1``n`维数据。仪表盘的数据一般只有一个,值通过`label`样式显示,`name`通过`titleStyle`样式显示。
## `Serie-Ring`
环形图系列。
* `show`:系列是否显示在图表上。
* `type``Ring`
* `name`:系列名称。用于 `tooltip` 的显示,`legend` 的图例筛选。
* `center`中心点坐标。当值为0-1的浮点数时表示百分比。
* `radius`:仪表盘半径。
* `startAngle`仪表盘起始角度。和时钟一样12点钟位置是0度顺时针到360度。
* `ringGap`:环形图的环间隙。
* `roundCap`:是否启用圆弧效果。
* `clockwise`:是否顺时针,默认为`true`
* `titleStyle`:环形图中心标题 [TitleStyle](#TitleStyle)。
* `itemStyle`:环形图的圆环样式,包括设置背景颜色和边框等 [ItemStyle](#ItemStyle)。
* `label`:图形上的文本标签 [SerieLabel](#SerieLabel),可用于说明图形的一些数据信息,比如值,名称等。
* `emphasis`:高亮样式 [Emphasis](#Emphasis)。
* `animation`:起始动画 [SerieAnimation](#SerieAnimation)。
* `data`:系列中的数据项 [SerieData](#SerieData) 数组,可以设置`1``n`维数据。环形图的数据只有二维,`data[0]`表示当前值,`data[1]`表示最大值。
## `Settings`
全局参数设置组件。一般情况下可使用默认值,当有需要时可进行调整。
@@ -701,6 +722,8 @@
* `show`:是否启用。
* `color`:颜色。
* `backgroundColor`:背景颜色。
* `backgroundWidth`:背景的宽。
* `borderType`:边框的类型。
* `borderColor`:边框的颜色。
* `borderWidth`:边框宽。

View File

@@ -22,6 +22,10 @@ namespace XCharts
drawRect.height = EditorGUIUtility.singleLineHeight;
SerializedProperty show = prop.FindPropertyRelative("m_Show");
SerializedProperty m_Color = prop.FindPropertyRelative("m_Color");
SerializedProperty m_BackgroundColor = prop.FindPropertyRelative("m_BackgroundColor");
SerializedProperty m_BackgroundWidth = prop.FindPropertyRelative("m_BackgroundWidth");
SerializedProperty m_CenterColor = prop.FindPropertyRelative("m_CenterColor");
SerializedProperty m_CenterGap = prop.FindPropertyRelative("m_CenterGap");
SerializedProperty m_BorderType = prop.FindPropertyRelative("m_BorderType");
SerializedProperty m_BorderWidth = prop.FindPropertyRelative("m_BorderWidth");
SerializedProperty m_BorderColor = prop.FindPropertyRelative("m_BorderColor");
@@ -33,6 +37,14 @@ namespace XCharts
++EditorGUI.indentLevel;
EditorGUI.PropertyField(drawRect, m_Color);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_BackgroundColor);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_BackgroundWidth);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_CenterColor);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_CenterGap);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_BorderType);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_BorderWidth);
@@ -50,7 +62,7 @@ namespace XCharts
float height = 0;
if (ChartEditorHelper.IsToggle(m_ItemStyleToggle, prop))
{
height += 6 * EditorGUIUtility.singleLineHeight + 5 * EditorGUIUtility.standardVerticalSpacing;
height += 10 * EditorGUIUtility.singleLineHeight + 9 * EditorGUIUtility.standardVerticalSpacing;
}
else
{

View File

@@ -62,8 +62,9 @@ namespace XCharts
SerializedProperty m_Max = prop.FindPropertyRelative("m_Max");
SerializedProperty m_StartAngle = prop.FindPropertyRelative("m_StartAngle");
SerializedProperty m_EndAngle = prop.FindPropertyRelative("m_EndAngle");
SerializedProperty m_RingGap = prop.FindPropertyRelative("m_RingGap");
SerializedProperty m_SplitNumber = prop.FindPropertyRelative("m_SplitNumber");
//SerializedProperty m_Clockwise = prop.FindPropertyRelative("m_Clockwise");
SerializedProperty m_Clockwise = prop.FindPropertyRelative("m_Clockwise");
SerializedProperty m_RoundCap = prop.FindPropertyRelative("m_RoundCap");
SerializedProperty m_GaugeType = prop.FindPropertyRelative("m_GaugeType");
SerializedProperty m_GaugeAxis = prop.FindPropertyRelative("m_GaugeAxis");
@@ -189,6 +190,26 @@ namespace XCharts
EditorGUI.PropertyField(drawRect, m_Emphasis);
drawRect.y += EditorGUI.GetPropertyHeight(m_Emphasis);
break;
case SerieType.Ring:
ChartEditorHelper.MakeTwoField(ref drawRect, pos.width, m_Center, "Center");
ChartEditorHelper.MakeTwoField(ref drawRect, pos.width, m_Radius, "Radius");
EditorGUI.PropertyField(drawRect, m_StartAngle);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_RingGap);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_RoundCap);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_Clockwise);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_TitleStyle);
drawRect.y += EditorGUI.GetPropertyHeight(m_TitleStyle);
EditorGUI.PropertyField(drawRect, m_ItemStyle);
drawRect.y += EditorGUI.GetPropertyHeight(m_ItemStyle);
EditorGUI.PropertyField(drawRect, m_Label);
drawRect.y += EditorGUI.GetPropertyHeight(m_Label);
EditorGUI.PropertyField(drawRect, m_Emphasis);
drawRect.y += EditorGUI.GetPropertyHeight(m_Emphasis);
break;
case SerieType.Radar:
EditorGUI.PropertyField(drawRect, m_RadarIndex);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
@@ -452,6 +473,14 @@ namespace XCharts
height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_Emphasis"));
height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_Animation"));
break;
case SerieType.Ring:
height += 10 * EditorGUIUtility.singleLineHeight + 9 * EditorGUIUtility.standardVerticalSpacing;
height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_TitleStyle"));
height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_ItemStyle"));
height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_Label"));
height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_Emphasis"));
height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_Animation"));
break;
case SerieType.Radar:
height += 4 * EditorGUIUtility.singleLineHeight + 3 * EditorGUIUtility.standardVerticalSpacing;
height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_Symbol"));

View File

@@ -21,14 +21,14 @@ namespace XCharts
Rect drawRect = pos;
drawRect.height = EditorGUIUtility.singleLineHeight;
SerializedProperty show = prop.FindPropertyRelative("m_Show");
SerializedProperty m_textStyle = prop.FindPropertyRelative("m_textStyle");
SerializedProperty m_TextStyle = prop.FindPropertyRelative("m_TextStyle");
ChartEditorHelper.MakeFoldout(ref drawRect, ref m_TitleStyleToggle, prop, "Title Style", show, false);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
if (ChartEditorHelper.IsToggle(m_TitleStyleToggle, prop))
{
++EditorGUI.indentLevel;
EditorGUI.PropertyField(drawRect, m_textStyle);
drawRect.y += EditorGUI.GetPropertyHeight(m_textStyle);
EditorGUI.PropertyField(drawRect, m_TextStyle);
drawRect.y += EditorGUI.GetPropertyHeight(m_TextStyle);
--EditorGUI.indentLevel;
}
}
@@ -39,7 +39,7 @@ namespace XCharts
if (ChartEditorHelper.IsToggle(m_TitleStyleToggle, prop))
{
height += 1 * EditorGUIUtility.singleLineHeight + 1 * EditorGUIUtility.standardVerticalSpacing;
height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_textStyle"));
height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_TextStyle"));
}
else
{

View File

@@ -109,5 +109,11 @@ namespace XCharts
{
AddChart<GaugeChart>("GaugeChart");
}
[MenuItem("GameObject/XCharts/RingChart", priority = 51)]
public static void AddRingChart()
{
AddChart<RingChart>("RingChart");
}
}
}

View File

@@ -2,12 +2,12 @@
A powerful, easy-to-use, configurable charting and data visualization library for Unity.
一款基于`UGUI`的功能强大、易用、参数可配置的数据可视化图表插件。支持折线图、柱状图、饼图、雷达图、散点图、热力图、仪表盘等常见图表。
一款基于`UGUI`的功能强大、易用、参数可配置的数据可视化图表插件。支持折线图、柱状图、饼图、雷达图、散点图、热力图、仪表盘、环形图等常见图表。
## 特性
* 内置丰富示例和模板,参数可视化配置,效果实时预览,纯代码绘制。
* 支持折线图、柱状图、饼图、雷达图、散点图、热力图、仪表盘等常见图表。
* 支持折线图、柱状图、饼图、雷达图、散点图、热力图、仪表盘、环形图等常见图表。
* 支持直线图、曲线图、面积图、阶梯线图等折线图。
* 支持并列柱图、堆叠柱图、堆积百分比柱图、斑马柱图等柱状图。
* 支持环形图、玫瑰图等饼图。

View File

@@ -220,7 +220,7 @@ namespace XCharts
/// <param name="yValue">y data</param>
/// <param name="dataName">the name of data</param>
/// <returns>Returns True on success</returns>
public virtual SerieData AddData(string serieName, float xValue, float yValue, string dataName)
public virtual SerieData AddData(string serieName, float xValue, float yValue, string dataName = null)
{
var serieData = m_Series.AddXYData(serieName, xValue, yValue, dataName);
if (serieData != null)

View File

@@ -0,0 +1,95 @@
/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
public partial class RingChart
{
/// <summary>
/// 更新指定系列执行数据项的最大值
/// </summary>
/// <param name="serieIndex"></param>
/// <param name="dataIndex"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool UpdateMax(int serieIndex, int dataIndex, float value)
{
var serie = m_Series.GetSerie(serieIndex);
if (serie != null)
{
var serieData = serie.GetSerieData(dataIndex);
if (serieData != null)
{
return serieData.UpdateData(1, value);
}
}
return false;
}
/// <summary>
/// 更新指定系列的所有数据项的最大值
/// </summary>
/// <param name="serieIndex"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool UpdateMax(int serieIndex, float value)
{
var serie = m_Series.GetSerie(serieIndex);
if (serie != null)
{
var flag = true;
foreach (var serieData in serie.data)
{
if (!serieData.UpdateData(1, value)) flag = false;
}
return flag;
}
return false;
}
/// <summary>
/// 更新第一个系列第一个数据项的最大值
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public bool UpdateMax(float value)
{
return UpdateMax(0, 0, value);
}
/// <summary>
/// Adds the data with the specified maximum value to the specified serie.
/// 添加指定最大值的数据到指定系列中。
/// </summary>
/// <param name="serieName">the name of serie</param>
/// <param name="value">the data</param>
/// <param name="max">the max data</param>
/// <param name="dataName">the name of data</param>
/// <returns>Returns True on success</returns>
public override SerieData AddData(string serieName, float value, float max, string dataName = null)
{
return base.AddData(serieName, value, max, dataName);
}
/// <summary>
/// Adds the data with the specified maximum value to the specified serie.
/// 添加指定最大值的数据到指定系列中。
/// </summary>
/// <param name="serieIndex">the index of serie</param>
/// <param name="value">the data</param>
/// <param name="max">the max data</param>
/// <param name="dataName">the name of data</param>
/// <returns>Returns True on success</returns>
public override SerieData AddData(int serieIndex, float value, float max, string dataName = null)
{
return base.AddData(serieIndex, value, max, dataName);
}
}
}

View File

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

View File

@@ -52,6 +52,10 @@ namespace XCharts
/// 仪表盘。
/// </summary>
Gauge,
/// <summary>
/// 环形图。只支持一个数据的环形图。
/// </summary>
Ring,
}
/// <summary>
@@ -225,9 +229,11 @@ namespace XCharts
[SerializeField] private float m_Max;
[SerializeField] private float m_StartAngle;
[SerializeField] private float m_EndAngle;
[SerializeField] private bool m_Clockwise;
[SerializeField] private bool m_Clockwise = true;
[FormerlySerializedAs("m_ArcShaped")]
[SerializeField] private bool m_RoundCap;
[SerializeField] private float m_RingGap = 10f;
[SerializeField] private int m_SplitNumber;
[SerializeField] private GaugeType m_GaugeType = GaugeType.Pointer;
[SerializeField] private GaugeAxis m_GaugeAxis = new GaugeAxis();
@@ -577,6 +583,15 @@ namespace XCharts
get { return m_Clockwise; }
set { if (PropertyUtility.SetStruct(ref m_Clockwise, value)) SetVerticesDirty(); }
}
/// <summary>
/// 环形图的环间隙。
/// </summary>
public float ringGap
{
get { return m_RingGap; }
set { if (PropertyUtility.SetStruct(ref m_RingGap, value)) SetVerticesDirty(); }
}
/// <summary>
/// 刻度分割段数。最大可设置36。
/// </summary>
@@ -704,10 +719,11 @@ namespace XCharts
label.vertsDirty ||
emphasis.vertsDirty ||
gaugeAxis.vertsDirty ||
gaugePointer.vertsDirty ||
titleStyle.vertsDirty;
gaugePointer.vertsDirty;
}
}
public override bool componentDirty { get { return m_ComponentDirty || titleStyle.componentDirty; } }
internal override void ClearVerticesDirty()
{
base.ClearVerticesDirty();
@@ -995,11 +1011,20 @@ namespace XCharts
m_Data.Add(serieData);
m_ShowDataDimension = 1;
SetVerticesDirty();
CheckDataName(dataName);
return serieData;
}
private void CheckDataName(string dataName)
{
if (string.IsNullOrEmpty(dataName))
{
SetNameDirty();
}
return serieData;
else
{
m_ShowDataName = true;
}
}
/// <summary>
@@ -1028,10 +1053,7 @@ namespace XCharts
m_Data.Add(serieData);
m_ShowDataDimension = 2;
SetVerticesDirty();
if (string.IsNullOrEmpty(dataName))
{
SetNameDirty();
}
CheckDataName(dataName);
return serieData;
}
@@ -1073,10 +1095,7 @@ namespace XCharts
}
m_Data.Add(serieData);
SetVerticesDirty();
if (string.IsNullOrEmpty(dataName))
{
SetNameDirty();
}
CheckDataName(dataName);
return serieData;
}
}

View File

@@ -1033,6 +1033,7 @@ namespace XCharts
{
case SerieType.Pie:
case SerieType.Radar:
case SerieType.Ring:
for (int i = 0; i < serie.data.Count; i++)
{
if (string.IsNullOrEmpty(serie.data[i].name))

View File

@@ -36,6 +36,10 @@ namespace XCharts
}
[SerializeField] private bool m_Show = false;
[SerializeField] private Color m_Color;
[SerializeField] private Color m_BackgroundColor;
[SerializeField] private float m_BackgroundWidth;
[SerializeField] private Color m_CenterColor;
[SerializeField] private float m_CenterGap;
[SerializeField] private Type m_BorderType = Type.Solid;
[SerializeField] private float m_BorderWidth = 0;
[SerializeField] private Color m_BorderColor;
@@ -58,6 +62,38 @@ namespace XCharts
set { if (PropertyUtility.SetColor(ref m_Color, value)) SetVerticesDirty(); }
}
/// <summary>
/// 数据项背景颜色。
/// </summary>
public Color backgroundColor
{
get { return m_BackgroundColor; }
set { if (PropertyUtility.SetColor(ref m_BackgroundColor, value)) SetVerticesDirty(); }
}
/// <summary>
/// 中心区域颜色。
/// </summary>
public Color centerColor
{
get { return m_CenterColor; }
set { if (PropertyUtility.SetColor(ref m_CenterColor, value)) SetVerticesDirty(); }
}
/// <summary>
/// 中心区域间隙。
/// </summary>
public float centerGap
{
get { return m_CenterGap; }
set { if (PropertyUtility.SetStruct(ref m_CenterGap, value)) SetVerticesDirty(); }
}
/// <summary>
/// 数据项背景颜色。
/// </summary>
public float backgroundWidth
{
get { return m_BackgroundWidth; }
set { if (PropertyUtility.SetStruct(ref m_BackgroundWidth, value)) SetVerticesDirty(); }
}
/// <summary>
/// 边框的类型。
/// </summary>
public Type borderType

View File

@@ -237,7 +237,7 @@ namespace XCharts
return (delay > 0 && Time.time - startTime < delay / 1000);
}
public bool CheckDetailBreak(int dataIndex, float detail)
public bool CheckDetailBreak(float detail)
{
return !IsFinish() && detail > m_CurrDetailProgress;
}

View File

@@ -153,7 +153,7 @@ namespace XCharts
public float runtimePieOffsetRadius { get; internal set; }
public Vector3 runtiemPieOffsetCenter { get; internal set; }
private List<float> m_LastData = new List<float>();
private List<float> m_PreviousData = new List<float>();
private List<float> m_DataUpdateTime = new List<float>();
private List<bool> m_DataUpdateFlag = new List<bool>();
@@ -166,15 +166,27 @@ namespace XCharts
else return 0;
}
public float GetLastData(int index)
public float GetPreviousData(int index)
{
if (index >= 0 && index < m_LastData.Count)
if (index >= 0 && index < m_PreviousData.Count)
{
return m_LastData[index];
return m_PreviousData[index];
}
else return 0;
}
public float GetFirstData(float animationDuration = 500f)
{
if (m_Data.Count > 0) return GetCurrData(0, animationDuration);
return 0;
}
public float GetLastData()
{
if (m_Data.Count > 0) return m_Data[m_Data.Count - 1];
return 0;
}
public float GetCurrData(int index, float animationDuration = 500f)
{
if (index < m_DataUpdateFlag.Count && m_DataUpdateFlag[index] && animationDuration > 0)
@@ -184,7 +196,7 @@ namespace XCharts
if (time <= total)
{
CheckLastData();
var curr = Mathf.Lerp(GetLastData(index), GetData(index), time / total);
var curr = Mathf.Lerp(GetPreviousData(index), GetData(index), time / total);
return curr;
}
else
@@ -204,7 +216,7 @@ namespace XCharts
if (dimension >= 0 && dimension < data.Count)
{
CheckLastData();
m_LastData[dimension] = data[dimension];
m_PreviousData[dimension] = data[dimension];
m_DataUpdateTime[dimension] = Time.time;
m_DataUpdateFlag[dimension] = true;
data[dimension] = value;
@@ -215,14 +227,14 @@ namespace XCharts
private void CheckLastData()
{
if (m_LastData.Count != m_Data.Count)
if (m_PreviousData.Count != m_Data.Count)
{
m_LastData.Clear();
m_PreviousData.Clear();
m_DataUpdateTime.Clear();
m_DataUpdateFlag.Clear();
for (int i = 0; i < m_Data.Count; i++)
{
m_LastData.Add(m_Data[i]);
m_PreviousData.Add(m_Data[i]);
m_DataUpdateTime.Add(Time.time);
m_DataUpdateFlag.Add(false);
}

View File

@@ -193,7 +193,7 @@ namespace XCharts
public float backgroundHeight
{
get { return m_BackgroundHeight; }
set { if (PropertyUtility.SetStruct(ref m_BackgroundWidth, value)) SetComponentDirty(); }
set { if (PropertyUtility.SetStruct(ref m_BackgroundHeight, value)) SetComponentDirty(); }
}
/// <summary>
/// Rotate label.
@@ -202,7 +202,7 @@ namespace XCharts
public float rotate
{
get { return m_Rotate; }
set { if (PropertyUtility.SetStruct(ref m_BackgroundWidth, value)) SetComponentDirty(); }
set { if (PropertyUtility.SetStruct(ref m_Rotate, value)) SetComponentDirty(); }
}
/// <summary>
/// the text padding of left and right. defaut:2.
@@ -211,7 +211,7 @@ namespace XCharts
public float paddingLeftRight
{
get { return m_PaddingLeftRight; }
set { if (PropertyUtility.SetStruct(ref m_BackgroundWidth, value)) SetComponentDirty(); }
set { if (PropertyUtility.SetStruct(ref m_PaddingLeftRight, value)) SetComponentDirty(); }
}
/// <summary>
/// the text padding of top and bottom. defaut:2.
@@ -220,7 +220,7 @@ namespace XCharts
public float paddingTopBottom
{
get { return m_PaddingTopBottom; }
set { if (PropertyUtility.SetStruct(ref m_BackgroundWidth, value)) SetComponentDirty(); }
set { if (PropertyUtility.SetStruct(ref m_PaddingTopBottom, value)) SetComponentDirty(); }
}
/// <summary>
/// font size.
@@ -229,7 +229,7 @@ namespace XCharts
public int fontSize
{
get { return m_FontSize; }
set { if (PropertyUtility.SetStruct(ref m_BackgroundWidth, value)) SetAllDirty(); }
set { if (PropertyUtility.SetStruct(ref m_FontSize, value)) SetAllDirty(); }
}
/// <summary>
/// font style.

View File

@@ -15,7 +15,7 @@ namespace XCharts
/// 文本的相关设置。
/// </summary>
[Serializable]
public class TextStyle : SubComponent, IEquatable<TextStyle>
public class TextStyle : SubComponent
{
[SerializeField] private Font m_Font;
[SerializeField] private float m_Rotate = 0;
@@ -135,65 +135,5 @@ namespace XCharts
this.color = color;
this.rotate = rotate;
}
public void Copy(TextStyle style)
{
this.fontSize = style.fontSize;
this.fontStyle = style.fontStyle;
this.color = style.color;
this.backgroundColor = style.backgroundColor;
this.rotate = style.rotate;
this.offset = style.offset;
this.lineSpacing = style.lineSpacing;
}
public TextStyle Clone()
{
var textStyle = new TextStyle();
textStyle.rotate = rotate;
textStyle.color = color;
textStyle.backgroundColor = backgroundColor;
textStyle.fontSize = fontSize;
textStyle.fontStyle = fontStyle;
textStyle.offset = offset;
textStyle.lineSpacing = lineSpacing;
return textStyle;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
else if (obj is TextStyle)
{
return Equals((TextStyle)obj);
}
else
{
return false;
}
}
public bool Equals(TextStyle other)
{
if (ReferenceEquals(null, other))
{
return false;
}
return rotate == other.rotate &&
fontSize == other.fontSize &&
fontStyle == other.fontStyle &&
offset == other.offset &&
lineSpacing == other.lineSpacing &&
ChartHelper.IsValueEqualsColor(m_BackgroundColor, other.backgroundColor) &&
ChartHelper.IsValueEqualsColor(m_Color, other.color);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
}

View File

@@ -9,6 +9,7 @@
using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Serialization;
namespace XCharts
{
@@ -17,62 +18,42 @@ namespace XCharts
/// 标题相关设置。
/// </summary>
[Serializable]
public class TitleStyle : SubComponent, IEquatable<TitleStyle>
public class TitleStyle : SubComponent
{
[SerializeField] private bool m_Show;
[SerializeField] private TextStyle m_textStyle = new TextStyle(18);
[FormerlySerializedAs("m_textStyle")]
[SerializeField] private TextStyle m_TextStyle = new TextStyle(18);
/// <summary>
/// Whether to show title.
/// 是否显示标题。
/// </summary>
public bool show { get { return m_Show; } set { m_Show = value; } }
public bool show
{
get { return m_Show; }
set { if (PropertyUtility.SetStruct(ref m_Show, value)) SetComponentDirty(); }
}
/// <summary>
/// the color of text.
/// 文本的颜色。
/// </summary>
public TextStyle textStyle { get { return m_textStyle; } set { m_textStyle = value; } }
public TextStyle textStyle
{
get { return m_TextStyle; }
set { if (PropertyUtility.SetClass(ref m_TextStyle, value, true)) SetComponentDirty(); }
}
public override bool componentDirty { get { return m_ComponentDirty || textStyle.componentDirty; } }
internal override void ClearComponentDirty()
{
base.ClearComponentDirty();
textStyle.ClearComponentDirty();
}
public Text runtimeText { get; set; }
public TitleStyle Clone()
{
var title = new TitleStyle();
title.show = show;
title.textStyle = textStyle.Clone();
return title;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
else if (obj is TitleStyle)
{
return Equals((TitleStyle)obj);
}
else
{
return false;
}
}
public bool Equals(TitleStyle other)
{
if (ReferenceEquals(null, other))
{
return false;
}
return textStyle.Equals(other.textStyle);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public bool IsInited()
{
return runtimeText != null;
@@ -90,13 +71,13 @@ namespace XCharts
{
if (runtimeText)
{
runtimeText.transform.localPosition = pos + new Vector3(m_textStyle.offset.x, m_textStyle.offset.y);
runtimeText.transform.localPosition = pos + new Vector3(m_TextStyle.offset.x, m_TextStyle.offset.y);
}
}
public void SetText(string text)
{
if (runtimeText)
if (runtimeText && !runtimeText.text.Equals(text))
{
if (textStyle.color != Color.clear) runtimeText.color = textStyle.color;
runtimeText.text = text;

View File

@@ -32,20 +32,25 @@ namespace XCharts
base.Start();
foreach (var serie in m_Series.list)
{
UpdateTitle(serie);
UpdateLabel(serie);
TitleStyleHelper.CheckTitle(serie, ref m_ReinitTitle, ref m_UpdateTitleText);
SerieLabelHelper.CheckLabel(serie, ref m_ReinitLabel, ref m_UpdateLabelText);
}
UpdateTitleAndLabelText();
UpdateAxisLabel();
}
protected override void Update()
{
base.Update();
if (m_UpdateLabelText || m_UpdateTitleText)
if (m_UpdateTitleText)
{
m_UpdateTitleText = false;
TitleStyleHelper.UpdateTitleText(m_Series);
}
if (m_UpdateLabelText)
{
m_UpdateLabelText = false;
UpdateTitleAndLabelText();
SerieLabelHelper.UpdateLabelText(m_Series,m_ThemeInfo);
UpdateAxisLabel();
}
}
@@ -134,16 +139,14 @@ namespace XCharts
serie.UpdateCenter(chartWidth, chartHeight);
var destAngle = GetCurrAngle(serie, true);
serie.animation.InitProgress(0, serie.startAngle, destAngle);
//var currAngle = serie.animation.GetCurrDetail();
var currAngle = serie.animation.IsFinish() ? GetCurrAngle(serie, false) : serie.animation.GetCurrDetail();
DrawProgressBar(vh, serie, currAngle);
DrawStageColor(vh, serie);
DrawLineStyle(vh, serie);
DrawAxisTick(vh, serie);
DrawPointer(vh, serie, currAngle);
UpdateTitle(serie);
// UpdateAxisLabel(serie);
UpdateLabel(serie);
TitleStyleHelper.CheckTitle(serie, ref m_ReinitTitle, ref m_UpdateTitleText);
SerieLabelHelper.CheckLabel(serie, ref m_ReinitLabel, ref m_UpdateLabelText);
CheckAnimation(serie);
if (!serie.animation.IsFinish())
@@ -168,15 +171,15 @@ namespace XCharts
backgroundColor, m_ThemeInfo.backgroundColor, m_Settings.cicleSmoothness, serie.startAngle, serie.endAngle);
if (serie.roundCap)
{
DrawArcShape(vh, serie, serie.startAngle, backgroundColor, true);
DrawArcShape(vh, serie, serie.endAngle, backgroundColor);
DrawRoundCap(vh, serie, serie.startAngle, backgroundColor, true);
DrawRoundCap(vh, serie, serie.endAngle, backgroundColor);
}
ChartDrawer.DrawDoughnut(vh, serie.runtimeCenterPos, serie.runtimeInsideRadius, outsideRadius,
color, m_ThemeInfo.backgroundColor, m_Settings.cicleSmoothness, serie.startAngle, currAngle);
if (serie.roundCap && currAngle != serie.startAngle)
{
DrawArcShape(vh, serie, currAngle, color);
DrawArcShape(vh, serie, serie.startAngle, color, true);
DrawRoundCap(vh, serie, currAngle, color);
DrawRoundCap(vh, serie, serie.startAngle, color, true);
}
}
@@ -275,7 +278,7 @@ namespace XCharts
return false;
}
private void DrawArcShape(VertexHelper vh, Serie serie, float angle, Color color, bool invert = false)
private void DrawRoundCap(VertexHelper vh, Serie serie, float angle, Color color, bool invert = false)
{
var radius = serie.gaugeAxis.axisLine.width / 2;
var len = serie.runtimeInsideRadius + radius;
@@ -296,27 +299,6 @@ namespace XCharts
}
}
private void UpdateTitle(Serie serie)
{
if (serie.titleStyle.show)
{
if (serie.titleStyle.IsInited())
{
serie.titleStyle.SetActive(true);
serie.titleStyle.UpdatePosition(serie.runtimeCenterPos);
m_UpdateTitleText = true;
}
else
{
m_ReinitTitle = true;
}
}
else
{
serie.titleStyle.SetActive(false);
}
}
private void UpdateAxisLabel(Serie serie)
{
var show = serie.gaugeAxis.show && serie.gaugeAxis.axisLabel.show;
@@ -347,56 +329,12 @@ namespace XCharts
}
}
private void UpdateLabel(Serie serie)
{
var serieData = serie.GetSerieData(0);
if (serieData != null)
{
if (serie.label.show)
{
if (serieData.IsInitLabel())
{
serieData.SetLabelActive(true);
serieData.SetLabelPosition(serie.runtimeCenterPos + serie.label.offset);
m_UpdateLabelText = true;
}
else
{
m_ReinitLabel = true;
}
}
else
{
serieData.SetLabelActive(false);
}
}
}
private void UpdateTitleAndLabelText()
private void UpdateAxisLabel()
{
foreach (var serie in m_Series.list)
{
if (serie.type == SerieType.Gauge)
{
var serieData = serie.GetSerieData(0);
if (serieData != null)
{
if (serie.label.show && serieData.IsInitLabel())
{
var value = serieData.GetData(1);
var total = serie.max;
var content = serie.label.GetFormatterContent(serie.name, serieData.name, value, total);
serieData.SetLabelText(content);
if (serie.label.color != Color.clear)
{
serieData.SetLabelColor(serie.label.color);
}
}
if (serie.titleStyle.show && serie.titleStyle.IsInited())
{
serie.titleStyle.SetText(serieData.name);
}
}
UpdateAxisLabel(serie);
}
}
@@ -415,6 +353,7 @@ namespace XCharts
if (serie.dataCount > 0)
{
var serieData = serie.data[0];
serieData.labelPosition = serie.runtimeCenterPos + serie.label.offset;
value = dest ? serieData.GetData(1) : serieData.GetCurrData(1, serie.animation.GetUpdateAnimationDuration());
value = Mathf.Clamp(value, serie.min, serie.max);
}

View File

@@ -0,0 +1,50 @@
/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
internal static class SerieHelper
{
internal static Color GetItemBackgroundColor(Serie serie, ThemeInfo theme, int index, bool highlight)
{
if (serie.itemStyle.backgroundColor != Color.clear)
{
var color = serie.itemStyle.backgroundColor;
if (highlight) color *= color;
color.a *= serie.itemStyle.opacity;
return color;
}
else
{
var color = (Color)theme.GetColor(index);
if (highlight) color *= color;
color.a = 0.2f;
return color;
}
}
internal static Color GetItemColor(Serie serie, ThemeInfo theme, int index, bool highlight)
{
if (serie.itemStyle.color != Color.clear)
{
var color = serie.itemStyle.color;
if (highlight) color *= color;
color.a *= serie.itemStyle.opacity;
return color;
}
else
{
var color = (Color)theme.GetColor(index);
if (highlight) color *= color;
color.a *= serie.itemStyle.opacity;
return color;
}
}
}
}

View File

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

View File

@@ -0,0 +1,128 @@
/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
internal static class SerieLabelHelper
{
public static void CheckLabel(Serie serie, ref bool m_ReinitLabel, ref bool m_UpdateLabelText)
{
switch (serie.type)
{
case SerieType.Gauge:
case SerieType.Ring:
var serieData = serie.GetSerieData(0);
if (serieData != null)
{
if (serie.label.show && serie.show)
{
if (serieData.IsInitLabel())
{
serieData.SetLabelActive(true);
m_UpdateLabelText = true;
}
else
{
m_ReinitLabel = true;
}
}
else
{
serieData.SetLabelActive(false);
}
}
break;
}
}
public static void UpdateLabelText(Series series, ThemeInfo themeInfo)
{
foreach (var serie in series.list)
{
if (!serie.label.show) continue;
switch (serie.type)
{
case SerieType.Gauge:
SetGaugeLabelText(serie);
break;
case SerieType.Ring:
SetRingLabelText(serie, themeInfo);
break;
}
}
}
public static Color GetLabelColor(Serie serie, ThemeInfo themeInfo, int index)
{
if (serie.label.color != Color.clear)
{
return serie.label.color;
}
else
{
return themeInfo.GetColor(index);
}
}
private static void SetGaugeLabelText(Serie serie)
{
var serieData = serie.GetSerieData(0);
if (serieData != null)
{
if (serieData.IsInitLabel())
{
var value = serieData.GetData(1);
var total = serie.max;
var content = serie.label.GetFormatterContent(serie.name, serieData.name, value, total);
serieData.SetLabelText(content);
serieData.SetLabelPosition(serie.runtimeCenterPos + serie.label.offset);
if (serie.label.color != Color.clear)
{
serieData.SetLabelColor(serie.label.color);
}
}
}
}
private static void SetRingLabelText(Serie serie, ThemeInfo themeInfo)
{
for (int i = 0; i < serie.dataCount; i++)
{
var serieData = serie.data[i];
if (serieData.IsInitLabel())
{
if (!serie.show || !serieData.show)
{
serieData.SetLabelActive(false);
continue;
}
var value = serieData.GetData(0);
var total = serieData.GetData(1);
var content = serie.label.GetFormatterContent(serie.name, serieData.name, value, total);
serieData.SetLabelActive(true);
serieData.SetLabelText(content);
serieData.SetLabelColor(GetLabelColor(serie, themeInfo, i));
if (serie.label.position == SerieLabel.Position.Bottom)
{
var labelWidth = serieData.GetLabelWidth();
if (serie.clockwise)
serieData.SetLabelPosition(serieData.labelPosition - new Vector3(labelWidth / 2, 0));
else
serieData.SetLabelPosition(serieData.labelPosition + new Vector3(labelWidth / 2, 0));
}
else
{
serieData.SetLabelPosition(serieData.labelPosition);
}
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,43 @@
/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
internal static class TitleStyleHelper
{
public static void CheckTitle(Serie serie, ref bool m_ReinitTitle, ref bool m_UpdateTitleText)
{
if (serie.titleStyle.show)
{
if (serie.titleStyle.IsInited())
{
serie.titleStyle.UpdatePosition(serie.runtimeCenterPos);
m_UpdateTitleText = true;
}
else
{
m_ReinitTitle = true;
}
}
}
public static void UpdateTitleText(Series series)
{
foreach (var serie in series.list) UpdateTitleText(serie);
}
public static void UpdateTitleText(Serie serie)
{
if (serie.titleStyle.show)
{
serie.titleStyle.SetText(serie.name);
}
}
}
}

View File

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

View File

@@ -0,0 +1,20 @@
/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
namespace XCharts
{
public class APIException : System.Exception
{
public APIException() { }
public APIException(string message) : base(message) { }
public APIException(string message, System.Exception inner) : base(message, inner) { }
protected APIException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
}

View File

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

View File

@@ -163,6 +163,10 @@ namespace XCharts
if (m_Series.vertsDirty) RefreshChart();
if (m_Series.labelDirty) m_ReinitLabel = true;
if (m_Series.labelUpdate && !m_RefreshChart) m_RefreshLabel = true;
foreach (var serie in m_Series.list)
{
if (serie.titleStyle.componentDirty) m_ReinitTitle = true;
}
m_Series.ClearDirty();
}
}
@@ -203,6 +207,7 @@ namespace XCharts
m_Legend.SetAllDirty();
m_Tooltip.SetAllDirty();
m_ReinitLabel = true;
m_ReinitTitle = true;
}
#endif
@@ -388,10 +393,10 @@ namespace XCharts
var isAutoSize = serieLabel.backgroundWidth == 0 || serieLabel.backgroundHeight == 0;
serieData.InitLabel(labelObj, isAutoSize, serieLabel.paddingLeftRight, serieLabel.paddingTopBottom);
serieData.SetLabelActive(false);
//serieData.SetLabelText(serieData.name);
count++;
}
}
SerieLabelHelper.UpdateLabelText(m_Series,m_ThemeInfo);
}
private void InitSerieTitle()
@@ -415,8 +420,9 @@ namespace XCharts
txt.text = "";
txt.transform.localPosition = new Vector2(0, 0);
txt.transform.localEulerAngles = Vector2.zero;
ChartHelper.SetActive(txt, false);
ChartHelper.SetActive(txt, serie.titleStyle.show);
serie.titleStyle.runtimeText = txt;
serie.titleStyle.UpdatePosition(serie.runtimeCenterPos);
var serieData = serie.GetSerieData(0);
if (serieData != null)
{

View File

@@ -123,7 +123,7 @@ namespace XCharts
serieData.runtimePieCurrAngle = serieData.runtimePieToAngle;
serieData.runtiemPieOffsetCenter = center;
serieData.runtimePieInsideRadius = serie.runtimeInsideRadius;
if (serie.animation.CheckDetailBreak(n, serieData.runtimePieToAngle))
if (serie.animation.CheckDetailBreak(serieData.runtimePieToAngle))
{
isFinish = false;
serieData.runtimePieCurrAngle = serie.animation.GetCurrDetail();
@@ -144,7 +144,7 @@ namespace XCharts
center.y + serieData.runtimePieOffsetRadius * currCos);
var drawStartDegree = startDegree + serie.pieSpace;
var drawEndDegree = serieData.runtimePieCurrAngle - serie.pieSpace;
DrawArcShape(vh, serie, serieData, serieData.runtiemPieOffsetCenter, color, ref drawStartDegree, ref drawEndDegree);
DrawRoundCap(vh, serie, serieData, serieData.runtiemPieOffsetCenter, color, ref drawStartDegree, ref drawEndDegree);
ChartDrawer.DrawDoughnut(vh, serieData.runtiemPieOffsetCenter, serieData.runtimePieInsideRadius, serieData.runtimePieOutsideRadius,
color, m_ThemeInfo.backgroundColor, m_Settings.cicleSmoothness, drawStartDegree, drawEndDegree);
}
@@ -152,7 +152,7 @@ namespace XCharts
{
var drawStartDegree = startDegree + serie.pieSpace;
var drawEndDegree = serieData.runtimePieCurrAngle - serie.pieSpace;
DrawArcShape(vh, serie, serieData, center, color, ref drawStartDegree, ref drawEndDegree);
DrawRoundCap(vh, serie, serieData, center, color, ref drawStartDegree, ref drawEndDegree);
ChartDrawer.DrawDoughnut(vh, center, serieData.runtimePieInsideRadius, serieData.runtimePieOutsideRadius,
color, m_ThemeInfo.backgroundColor, m_Settings.cicleSmoothness, drawStartDegree, drawEndDegree);
}
@@ -178,7 +178,7 @@ namespace XCharts
raycastTarget = isClickOffset && isDataHighlight;
}
private void DrawArcShape(VertexHelper vh, Serie serie, SerieData serieData, Vector3 centerPos,
private void DrawRoundCap(VertexHelper vh, Serie serie, SerieData serieData, Vector3 centerPos,
Color color, ref float drawStartDegree, ref float drawEndDegree)
{
if (serie.roundCap && serieData.runtimePieInsideRadius > 0)
@@ -189,14 +189,8 @@ namespace XCharts
drawStartDegree += diffDegree;
drawEndDegree -= diffDegree;
var px = Mathf.Sin(drawStartDegree * Mathf.Deg2Rad) * radius;
var py = Mathf.Cos(drawStartDegree * Mathf.Deg2Rad) * radius;
var pos = new Vector3(px, py) + centerPos;
ChartDrawer.DrawSector(vh, pos, width, color, drawStartDegree + 180, drawStartDegree + 360);
px = Mathf.Sin(drawEndDegree * Mathf.Deg2Rad) * radius;
py = Mathf.Cos(drawEndDegree * Mathf.Deg2Rad) * radius;
pos = new Vector3(px, py) + centerPos;
ChartDrawer.DrawSector(vh, pos, width, color, drawEndDegree, drawEndDegree + 180);
ChartDrawer.DrawRoundCap(vh, centerPos, width, radius, drawStartDegree, serie.clockwise, color, false);
ChartDrawer.DrawRoundCap(vh, centerPos, width, radius, drawEndDegree, serie.clockwise, color, true);
}
}

View File

@@ -0,0 +1,364 @@

/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
[AddComponentMenu("XCharts/RingChart", 20)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public partial class RingChart : BaseChart
{
private bool m_UpdateTitleText = false;
private bool m_UpdateLabelText = false;
private bool m_IsEnterLegendButtom;
protected override void Update()
{
base.Update();
if (m_UpdateTitleText)
{
m_UpdateTitleText = false;
TitleStyleHelper.UpdateTitleText(m_Series);
}
if (m_UpdateLabelText)
{
m_UpdateLabelText = false;
SerieLabelHelper.UpdateLabelText(m_Series, m_ThemeInfo);
}
}
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
m_Title.text = "RingChart";
m_Tooltip.type = Tooltip.Type.Line;
RemoveData();
var serie = AddSerie(SerieType.Ring, "serie1");
serie.roundCap = true;
serie.radius = new float[] { 0.3f, 0.35f };
serie.titleStyle.show = false;
serie.titleStyle.textStyle.offset = new Vector2(0, 30);
serie.label.show = true;
serie.label.position = SerieLabel.Position.Center;
serie.label.formatter = "{d:f0}%";
serie.label.fontSize = 28;
var value = Random.Range(30, 90);
var max = 100;
AddData(0, value, max, "data1");
}
#endif
protected override void DrawChart(VertexHelper vh)
{
base.DrawChart(vh);
for (int i = 0; i < m_Series.list.Count; i++)
{
var serie = m_Series.list[i];
var data = serie.data;
serie.index = i;
if (!serie.show || serie.type != SerieType.Ring || serie.animation.HasFadeOut())
{
continue;
}
serie.animation.InitProgress(data.Count, serie.startAngle, serie.startAngle + 360);
serie.UpdateCenter(chartWidth, chartHeight);
TitleStyleHelper.CheckTitle(serie, ref m_ReinitTitle, ref m_UpdateTitleText);
SerieLabelHelper.CheckLabel(serie, ref m_ReinitLabel, ref m_UpdateLabelText);
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
var ringWidth = serie.runtimeOutsideRadius - serie.runtimeInsideRadius;
var dataChanging = false;
for (int j = 0; j < data.Count; j++)
{
var serieData = data[j];
if (!serieData.show) continue;
if (serieData.IsDataChanged()) dataChanging = true;
var value = serieData.GetFirstData(dataChangeDuration);
var max = serieData.GetLastData();
var degree = 360 * value / max;
var startDegree = GetStartAngle(serie);
var toDegree = GetToAngle(serie, degree);
var itemColor = SerieHelper.GetItemColor(serie, m_ThemeInfo, j, serieData.highlighted);
var outsideRadius = serie.runtimeOutsideRadius - j * (ringWidth + serie.ringGap);
var insideRadius = outsideRadius - ringWidth;
var centerRadius = (outsideRadius + insideRadius) / 2;
serieData.runtimePieStartAngle = serie.clockwise ? startDegree : toDegree;
serieData.runtimePieToAngle = serie.clockwise ? toDegree : startDegree;
serieData.runtimePieInsideRadius = insideRadius;
serieData.runtimePieOutsideRadius = outsideRadius;
DrawBackground(vh, serie, j, insideRadius, outsideRadius);
DrawRoundCap(vh, serie, serie.runtimeCenterPos, itemColor, insideRadius, outsideRadius,
ref startDegree, ref toDegree);
ChartDrawer.DrawDoughnut(vh, serie.runtimeCenterPos, insideRadius,
outsideRadius, itemColor, Color.clear, m_Settings.cicleSmoothness,
startDegree, toDegree);
DrawBorder(vh, serie, insideRadius, outsideRadius);
DrawCenter(vh, serie, insideRadius, j == data.Count - 1);
UpateLabelPosition(serie, serieData, j, startDegree, toDegree, centerRadius);
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress(360);
serie.animation.CheckSymbol(serie.symbol.size);
RefreshChart();
}
if (dataChanging)
{
RefreshChart();
}
}
}
private float GetStartAngle(Serie serie)
{
return serie.clockwise ? serie.startAngle : 360 - serie.startAngle;
}
private float GetToAngle(Serie serie, float angle)
{
var toAngle = angle + serie.startAngle;
if (!serie.clockwise)
{
toAngle = 360 - toAngle - serie.startAngle;
}
if (!serie.animation.IsFinish())
{
var currAngle = serie.animation.GetCurrDetail();
if (serie.clockwise)
{
toAngle = toAngle > currAngle ? currAngle : toAngle;
}
else
{
toAngle = toAngle < 360 - currAngle ? 360 - currAngle : toAngle;
}
}
return toAngle;
}
private void DrawCenter(VertexHelper vh, Serie serie, float insideRadius, bool last)
{
if (serie.itemStyle.centerColor != Color.clear && last)
{
var radius = insideRadius - serie.itemStyle.centerGap;
ChartDrawer.DrawCricle(vh, serie.runtimeCenterPos, radius, serie.itemStyle.centerColor);
}
}
private void UpateLabelPosition(Serie serie, SerieData serieData, int index, float startAngle,
float toAngle, float centerRadius)
{
if (!serie.label.show) return;
switch (serie.label.position)
{
case SerieLabel.Position.Center:
serieData.labelPosition = serie.runtimeCenterPos + serie.label.offset;
break;
case SerieLabel.Position.Bottom:
var px1 = Mathf.Sin(startAngle * Mathf.Deg2Rad) * centerRadius;
var py1 = Mathf.Cos(startAngle * Mathf.Deg2Rad) * centerRadius;
var xDiff = serie.clockwise ? -serie.label.margin : serie.label.margin;
serieData.labelPosition = serie.runtimeCenterPos + new Vector3(px1 + xDiff, py1);
break;
case SerieLabel.Position.Top:
startAngle += serie.clockwise ? -serie.label.margin : serie.label.margin;
toAngle += serie.clockwise ? serie.label.margin : -serie.label.margin;
var px2 = Mathf.Sin(toAngle * Mathf.Deg2Rad) * centerRadius;
var py2 = Mathf.Cos(toAngle * Mathf.Deg2Rad) * centerRadius;
serieData.labelPosition = serie.runtimeCenterPos + new Vector3(px2, py2);
break;
}
}
private void DrawBackground(VertexHelper vh, Serie serie, int index, float insideRadius, float outsideRadius)
{
var backgroundColor = SerieHelper.GetItemBackgroundColor(serie, m_ThemeInfo, index, false);
if (serie.itemStyle.backgroundWidth != 0)
{
var centerRadius = (outsideRadius + insideRadius) / 2;
var inradius = centerRadius - serie.itemStyle.backgroundWidth / 2;
var outradius = centerRadius + serie.itemStyle.backgroundWidth / 2;
ChartDrawer.DrawDoughnut(vh, serie.runtimeCenterPos, inradius,
outradius, backgroundColor, Color.clear, m_Settings.cicleSmoothness);
}
else
{
ChartDrawer.DrawDoughnut(vh, serie.runtimeCenterPos, insideRadius,
outsideRadius, backgroundColor, Color.clear, m_Settings.cicleSmoothness);
}
}
private void DrawBorder(VertexHelper vh, Serie serie, float insideRadius, float outsideRadius)
{
if (serie.itemStyle.show && serie.itemStyle.borderWidth > 0 && serie.itemStyle.borderColor != Color.clear)
{
ChartDrawer.DrawDoughnut(vh, serie.runtimeCenterPos, outsideRadius,
outsideRadius + serie.itemStyle.borderWidth, serie.itemStyle.borderColor,
Color.clear, m_Settings.cicleSmoothness);
ChartDrawer.DrawDoughnut(vh, serie.runtimeCenterPos, insideRadius,
insideRadius + serie.itemStyle.borderWidth, serie.itemStyle.borderColor,
Color.clear, m_Settings.cicleSmoothness);
}
}
private void DrawRoundCap(VertexHelper vh, Serie serie, Vector3 centerPos, Color color,
float insideRadius, float outsideRadius, ref float drawStartDegree, ref float drawEndDegree)
{
if (serie.roundCap && insideRadius > 0 && drawStartDegree != drawEndDegree)
{
var width = (outsideRadius - insideRadius) / 2;
var radius = insideRadius + width;
var diffDegree = Mathf.Asin(width / radius) * Mathf.Rad2Deg;
drawStartDegree += serie.clockwise ? diffDegree : -diffDegree;
drawEndDegree -= serie.clockwise ? diffDegree : -diffDegree;
ChartDrawer.DrawRoundCap(vh, centerPos, width, radius, drawStartDegree, serie.clockwise, color, false);
ChartDrawer.DrawRoundCap(vh, centerPos, width, radius, drawEndDegree, serie.clockwise, color, true);
}
}
protected override void OnLegendButtonClick(int index, string legendName, bool show)
{
CheckDataShow(legendName, show);
UpdateLegendColor(legendName, show);
RefreshChart();
}
protected override void OnLegendButtonEnter(int index, string legendName)
{
m_IsEnterLegendButtom = true;
CheckDataHighlighted(legendName, true);
RefreshChart();
}
protected override void OnLegendButtonExit(int index, string legendName)
{
m_IsEnterLegendButtom = false;
CheckDataHighlighted(legendName, false);
RefreshChart();
}
protected override void CheckTootipArea(Vector2 local)
{
if (m_IsEnterLegendButtom) return;
m_Tooltip.runtimeDataIndex.Clear();
bool selected = false;
foreach (var serie in m_Series.list)
{
int index = GetRingIndex(serie, local);
m_Tooltip.runtimeDataIndex.Add(index);
if (serie.type != SerieType.Ring) continue;
bool refresh = false;
for (int j = 0; j < serie.data.Count; j++)
{
var serieData = serie.data[j];
if (serieData.highlighted != (j == index)) refresh = true;
serieData.highlighted = j == index;
}
if (index >= 0) selected = true;
if (refresh) RefreshChart();
}
if (selected)
{
m_Tooltip.UpdateContentPos(new Vector2(local.x + 18, local.y - 25));
UpdateTooltip();
}
else if (m_Tooltip.IsActive())
{
m_Tooltip.SetActive(false);
RefreshChart();
}
}
private int GetRingIndex(Serie serie, Vector2 local)
{
if (serie.type != SerieType.Ring) return -1;
var dist = Vector2.Distance(local, serie.runtimeCenterPos);
if (dist > serie.runtimeOutsideRadius) return -1;
Vector2 dir = local - new Vector2(serie.runtimeCenterPos.x, serie.runtimeCenterPos.y);
float angle = VectorAngle(Vector2.up, dir);
for (int i = 0; i < serie.data.Count; i++)
{
var serieData = serie.data[i];
if (dist >= serieData.runtimePieInsideRadius &&
dist <= serieData.runtimePieOutsideRadius &&
angle >= serieData.runtimePieStartAngle &&
angle <= serieData.runtimePieToAngle)
{
return i;
}
}
return -1;
}
float VectorAngle(Vector2 from, Vector2 to)
{
float angle;
Vector3 cross = Vector3.Cross(from, to);
angle = Vector2.Angle(from, to);
angle = cross.z > 0 ? -angle : angle;
angle = (angle + 360) % 360;
return angle;
}
StringBuilder sb = new StringBuilder();
protected override void UpdateTooltip()
{
base.UpdateTooltip();
bool showTooltip = false;
foreach (var serie in m_Series.list)
{
int index = m_Tooltip.runtimeDataIndex[serie.index];
if (index < 0) continue;
showTooltip = true;
if (tooltip.IsNoFormatter())
{
var serieData = serie.GetSerieData(index);
float value = serieData.GetFirstData();
sb.Length = 0;
if (!string.IsNullOrEmpty(serieData.name))
{
sb.Append("<color=#").Append(m_ThemeInfo.GetColorStr(index)).Append(">● </color>")
.Append(serieData.name).Append(": ").Append(ChartCached.FloatToStr(value, 0, m_Tooltip.forceENotation));
}
else
{
sb.Append(ChartCached.FloatToStr(value, 0, m_Tooltip.forceENotation));
}
m_Tooltip.UpdateContentText(sb.ToString());
}
else
{
m_Tooltip.UpdateContentText(m_Tooltip.GetFormatterContent(index, m_Series, null, m_ThemeInfo));
}
var pos = m_Tooltip.GetContentPos();
if (pos.x + m_Tooltip.runtimeWidth > chartWidth)
{
pos.x = chartWidth - m_Tooltip.runtimeWidth;
}
if (pos.y - m_Tooltip.runtimeHeight < 0)
{
pos.y = m_Tooltip.runtimeHeight;
}
m_Tooltip.UpdateContentPos(pos);
}
m_Tooltip.SetActive(showTooltip);
}
}
}

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

@@ -335,6 +335,28 @@ namespace XCharts
}
}
public static void DrawRoundCap(VertexHelper vh, Vector3 center, float width, float radius, float angle,
bool clockwise, Color color, bool end)
{
var px = Mathf.Sin(angle * Mathf.Deg2Rad) * radius;
var py = Mathf.Cos(angle * Mathf.Deg2Rad) * radius;
var pos = new Vector3(px, py) + center;
if (end)
{
if (clockwise)
ChartDrawer.DrawSector(vh, pos, width, color, angle, angle + 180);
else
ChartDrawer.DrawSector(vh, pos, width, color, angle, angle - 180);
}
else
{
if (clockwise)
ChartDrawer.DrawSector(vh, pos, width, color, angle + 180, angle + 360);
else
ChartDrawer.DrawSector(vh, pos, width, color, angle - 180, angle - 360);
}
}
public static void DrawDoughnut(VertexHelper vh, Vector3 p, float insideRadius, float outsideRadius,
Color32 color, Color emptyColor, float smoothness = 2f, float startDegree = 0, float toDegree = 360)
{

View File

@@ -25,7 +25,7 @@ namespace XCharts
public class XChartsMgr : MonoBehaviour
{
public const string version = "1.2.0";
public const int date = 20200226;
public const int date = 20200308;
[SerializeField] private string m_NowVersion;
[SerializeField] private string m_NewVersion;

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

View File

@@ -7,7 +7,7 @@
A powerful, easy-to-use, configurable charting and data visualization library for Unity.
一款基于`UGUI`的功能强大、易用、参数可配置的数据可视化图表插件。支持折线图、柱状图、饼图、雷达图、散点图、热力图等常见图表。
一款基于`UGUI`的功能强大、易用、参数可配置的数据可视化图表插件。支持折线图、柱状图、饼图、雷达图、散点图、热力图、仪表盘、环形图等常见图表。
[XCharts问答](https://github.com/monitor1394/unity-ugui-XCharts/blob/master/Assets/XCharts/Documentation/XCharts问答.md)
[XChartsAPI手册](https://github.com/monitor1394/unity-ugui-XCharts/blob/master/Assets/XCharts/Documentation/XChartsAPI.md)
@@ -66,6 +66,8 @@ XCharts的图表由组件和数据组成。不同的组件和数据可以组合
* `RadarChart` 雷达图:雷达图主要用于表现多变量的数据,例如球员的各个属性分析。依赖 radar 组件。
* `ScatterChart` 散点图:直角坐标系上的散点图可以用来展现数据的 xy 之间的关系,如果数据项有多个维度,其它维度的值可以通过不同大小的 symbol 展现成气泡图,也可以用颜色来表现。
* `HeatmapChart` 热力图:热力图主要通过颜色去表现数值的大小,必须要配合 visualMap 组件使用。
* `GuageChart` 仪表盘。
* `RingChart` 环形图。区别于`PieChart`中的环形图,`RingChart`只支持一个数据,一般用于表示百分比。
以下是LineChart折线图和主组件、子组件的关系结构