diff --git a/Assets/XCharts/CHANGELOG.md b/Assets/XCharts/CHANGELOG.md
index e8168198..174bbf33 100644
--- a/Assets/XCharts/CHANGELOG.md
+++ b/Assets/XCharts/CHANGELOG.md
@@ -38,6 +38,7 @@
## master
+* (2021.07.09) 增加`MarkLine`标线 (#142)
* (2021.07.09) 优化`BarChart`可通过`serieData.show`设置是否显示柱条
* (2021.07.08) 优化数据存储类型由`float`全部转为`double`
* (2021.07.05) 修复`PieChart`的`avoidLabelOverlap`参数不生效的问题
diff --git a/Assets/XCharts/Documentation/XCharts配置项手册.md b/Assets/XCharts/Documentation/XCharts配置项手册.md
index 37508bf9..c9038ecc 100644
--- a/Assets/XCharts/Documentation/XCharts配置项手册.md
+++ b/Assets/XCharts/Documentation/XCharts配置项手册.md
@@ -45,6 +45,7 @@
* [LineArrow 折线图箭头](#LineArrow)
* [LineStyle 折线图样式](#LineStyle)
* [Location 位置](#Location)
+* [MarkLine 标线](#MarkLine)
* [SerieAnimation 动画](#SerieAnimation)
* [SerieData 数据项](#SerieData)
* [SerieLabel 图形上的文本标签](#SerieLabel)
@@ -951,6 +952,27 @@ K线图系列。
* `top`:离容器上侧的距离。
* `bottom`:离容器下侧的距离。
+## `MarkLine`
+
+* `show`:是否显示标线。
+* `animation`:标线的动画样式。
+* `data`:标线的数据项[MarkLineData](#MarkLineData)列表。当数据项的group为0时,每个数据项表示一条标线;当group不为0时,相同group的两个数据项分别表示标线的起始点和终止点来组成一条标线,此时标线的相关样式参数取起始点的参数。
+
+## `MarkLineData`
+
+* `name`:标注名称,将会作为文字显示。label的formatter可通过{b}显示名称,通过{c}显示数值。
+* `type`:特殊的标注类型,用于标注最大值最小值等。。有以下标注类型:
+ * `None`:无类型。此时通过
+ * `Min`:最小值。`dimension`维度上数据的最小值。
+ * `Max`:最大值。`dimension`维度上数据的最大值。
+ * `Average`:平均值。`dimension`维度上数据的平均值。
+ * `Median`:中位数。`dimension`维度上数据的中位数。
+* `dimension`:当type为特殊类型时,指示从哪个维度的数据上计算特殊值。
+* `xPosition`:相对原点的 x 坐标,单位像素。当type为None时有效。
+* `yPosition`:相对原点的 y 坐标,单位像素。当type为None时有效。
+* `xValue`:X轴上的指定值。当X轴为类目轴时指定值表示类目轴数据的索引,否则为具体的值。当type为None时有效。
+* `yValue`:Y轴上的指定值。当Y轴为类目轴时指定值表示类目轴数据的索引,否则为具体的值。当type为None时有效。
+
## `SerieData`
* `name`:数据项名称。
diff --git a/Assets/XCharts/Documentation/xcharts-configuration-EN.md b/Assets/XCharts/Documentation/xcharts-configuration-EN.md
index 1d6db659..7f634ded 100644
--- a/Assets/XCharts/Documentation/xcharts-configuration-EN.md
+++ b/Assets/XCharts/Documentation/xcharts-configuration-EN.md
@@ -48,6 +48,7 @@ __Sub component:__
* [LineArrow](#LineArrow)
* [LineStyle](#LineStyle)
* [Location](#Location)
+* [MarkLine](#MarkLine)
* [SerieAnimation](#SerieAnimation)
* [SerieData](#SerieData)
* [SerieLabel](#SerieLabel)
@@ -845,6 +846,27 @@ K线图系列。
* `top`: 离容器上侧的距离。
* `bottom`: 离容器下侧的距离。
+## `MarkLine`
+
+* `show`:是否显示标线。
+* `animation`:标线的动画样式。
+* `data`:标线的数据项[MarkLineData](#MarkLineData)列表。当数据项的group为0时,每个数据项表示一条标线;当group不为0时,相同group的两个数据项分别表示标线的起始点和终止点来组成一条标线,此时标线的相关样式参数取起始点的参数。
+
+## `MarkLineData`
+
+* `name`:标注名称,将会作为文字显示。label的formatter可通过{b}显示名称,通过{c}显示数值。
+* `type`:特殊的标注类型,用于标注最大值最小值等。。有以下标注类型:
+ * `None`:无类型。此时通过
+ * `Min`:最小值。`dimension`维度上数据的最小值。
+ * `Max`:最大值。`dimension`维度上数据的最大值。
+ * `Average`:平均值。`dimension`维度上数据的平均值。
+ * `Median`:中位数。`dimension`维度上数据的中位数。
+* `dimension`:当type为特殊类型时,指示从哪个维度的数据上计算特殊值。
+* `xPosition`:相对原点的 x 坐标,单位像素。当type为None时有效。
+* `yPosition`:相对原点的 y 坐标,单位像素。当type为None时有效。
+* `xValue`:X轴上的指定值。当X轴为类目轴时指定值表示类目轴数据的索引,否则为具体的值。当type为None时有效。
+* `yValue`:Y轴上的指定值。当Y轴为类目轴时指定值表示类目轴数据的索引,否则为具体的值。当type为None时有效。
+
## `SerieData`
* `name`: 数据项名称。
diff --git a/Assets/XCharts/Editor/PropertyDrawers/MarkLineDrawer.cs b/Assets/XCharts/Editor/PropertyDrawers/MarkLineDrawer.cs
new file mode 100644
index 00000000..38ff32a5
--- /dev/null
+++ b/Assets/XCharts/Editor/PropertyDrawers/MarkLineDrawer.cs
@@ -0,0 +1,69 @@
+/************************************************/
+/* */
+/* Copyright (c) 2018 - 2021 monitor1394 */
+/* https://github.com/monitor1394 */
+/* */
+/************************************************/
+
+using UnityEditor;
+using UnityEngine;
+
+namespace XCharts
+{
+ [CustomPropertyDrawer(typeof(MarkLine), true)]
+ public class MarkLineDrawer : BasePropertyDrawer
+ {
+ public override string ClassName { get { return "MarkLine"; } }
+ public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label)
+ {
+ base.OnGUI(pos, prop, label);
+ if (MakeFoldout(prop, "m_Show"))
+ {
+ ++EditorGUI.indentLevel;
+ PropertyField(prop, "m_Animation");
+ PropertyListField(prop, "m_Data", true);
+ --EditorGUI.indentLevel;
+ }
+ }
+ }
+
+ [CustomPropertyDrawer(typeof(MarkLineData), true)]
+ public class MarkLineDataDrawer : BasePropertyDrawer
+ {
+ public override string ClassName { get { return "MarkLineData"; } }
+ public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label)
+ {
+ base.OnGUI(pos, prop, label);
+ if (MakeFoldout(prop, ""))
+ {
+ ++EditorGUI.indentLevel;
+ var type = (MarkLineType)(prop.FindPropertyRelative("m_Type")).enumValueIndex;
+ var group = prop.FindPropertyRelative("m_Group").intValue;
+ PropertyField(prop, "m_Type");
+ PropertyField(prop, "m_Name");
+ switch (type)
+ {
+ case MarkLineType.None:
+ PropertyField(prop, "m_XPosition");
+ PropertyField(prop, "m_YPosition");
+ PropertyField(prop, "m_XValue");
+ PropertyField(prop, "m_YValue");
+ break;
+ case MarkLineType.Min:
+ case MarkLineType.Max:
+ case MarkLineType.Average:
+ case MarkLineType.Median:
+ PropertyField(prop, "m_Dimension");
+ break;
+ }
+ PropertyField(prop, "m_Group");
+ if (group > 0 && type == MarkLineType.None) PropertyField(prop, "m_ZeroPosition");
+ PropertyField(prop, "m_LineStyle");
+ PropertyField(prop, "m_StartSymbol");
+ PropertyField(prop, "m_EndSymbol");
+ PropertyField(prop, "m_Label");
+ --EditorGUI.indentLevel;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/XCharts/Editor/PropertyDrawers/MarkLineDrawer.cs.meta b/Assets/XCharts/Editor/PropertyDrawers/MarkLineDrawer.cs.meta
new file mode 100644
index 00000000..e633f39a
--- /dev/null
+++ b/Assets/XCharts/Editor/PropertyDrawers/MarkLineDrawer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e9c530aeba79d40a8918424df421d081
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/XCharts/Editor/PropertyDrawers/SerieDrawer.cs b/Assets/XCharts/Editor/PropertyDrawers/SerieDrawer.cs
index 9fdf62e4..14d7aa85 100644
--- a/Assets/XCharts/Editor/PropertyDrawers/SerieDrawer.cs
+++ b/Assets/XCharts/Editor/PropertyDrawers/SerieDrawer.cs
@@ -75,6 +75,7 @@ namespace XCharts
PropertyField(prop, "m_LineStyle");
PropertyField(prop, "m_LineArrow");
PropertyField(prop, "m_AreaStyle");
+ PropertyField(prop, "m_MarkLine");
break;
case SerieType.Bar:
PropertyField(prop, "m_Stack");
@@ -102,6 +103,7 @@ namespace XCharts
PropertyField(prop, "m_ShowAsPositiveNumber");
PropertyField(prop, "m_Large");
PropertyField(prop, "m_LargeThreshold");
+ PropertyField(prop, "m_MarkLine");
break;
case SerieType.Pie:
PropertyField(prop, "m_RoseType");
diff --git a/Assets/XCharts/Runtime/API/BaseChart_API.cs b/Assets/XCharts/Runtime/API/BaseChart_API.cs
index f5f7007d..8303b505 100644
--- a/Assets/XCharts/Runtime/API/BaseChart_API.cs
+++ b/Assets/XCharts/Runtime/API/BaseChart_API.cs
@@ -652,7 +652,7 @@ namespace XCharts
///
public void AnimationEnable(bool flag)
{
- m_Series.AnimationEnable(flag);
+ foreach (var serie in m_Series.list) serie.AnimationEnable(flag);
}
///
@@ -661,8 +661,7 @@ namespace XCharts
///
public void AnimationFadeIn()
{
- m_Series.AnimationFadeIn();
- RefreshChart();
+ foreach (var serie in m_Series.list) serie.AnimationFadeIn();
}
///
@@ -671,8 +670,7 @@ namespace XCharts
///
public void AnimationFadeOut()
{
- m_Series.AnimationFadeOut();
- RefreshChart();
+ foreach (var serie in m_Series.list) serie.AnimationFadeOut();
}
///
@@ -681,8 +679,7 @@ namespace XCharts
///
public void AnimationPause()
{
- m_Series.AnimationPause();
- RefreshChart();
+ foreach (var serie in m_Series.list) serie.AnimationPause();
}
///
@@ -691,8 +688,7 @@ namespace XCharts
///
public void AnimationResume()
{
- m_Series.AnimationResume();
- RefreshChart();
+ foreach (var serie in m_Series.list) serie.AnimationResume();
}
///
@@ -701,8 +697,7 @@ namespace XCharts
///
public void AnimationReset()
{
- m_Series.AnimationReset();
- RefreshChart();
+ foreach (var serie in m_Series.list) serie.AnimationReset();
}
///
diff --git a/Assets/XCharts/Runtime/Component/Main/Serie.cs b/Assets/XCharts/Runtime/Component/Main/Serie.cs
index 78a93af3..0835f782 100644
--- a/Assets/XCharts/Runtime/Component/Main/Serie.cs
+++ b/Assets/XCharts/Runtime/Component/Main/Serie.cs
@@ -319,6 +319,7 @@ namespace XCharts
[SerializeField] private ItemStyle m_ItemStyle = new ItemStyle();
[SerializeField] private Emphasis m_Emphasis = new Emphasis();
[SerializeField] private TitleStyle m_TitleStyle = new TitleStyle();
+ [SerializeField] private MarkLine m_MarkLine = MarkLine.defaultMarkLine;
[SerializeField] [Range(1, 10)] private int m_ShowDataDimension;
[SerializeField] private bool m_ShowDataName;
[SerializeField] private bool m_ShowDataIcon;
@@ -853,6 +854,14 @@ namespace XCharts
set { if (PropertyUtil.SetClass(ref m_TitleStyle, value, true)) SetAllDirty(); }
}
///
+ /// 标线。
+ ///
+ public MarkLine markLine
+ {
+ get { return m_MarkLine; }
+ set { if (PropertyUtil.SetClass(ref m_MarkLine, value, true)) SetAllDirty(); }
+ }
+ ///
/// 数据项里的数据维数。
///
public int showDataDimension { get { return m_ShowDataDimension; } set { m_ShowDataDimension = value; } }
@@ -1068,7 +1077,8 @@ namespace XCharts
label.vertsDirty ||
emphasis.vertsDirty ||
gaugeAxis.vertsDirty ||
- gaugePointer.vertsDirty;
+ gaugePointer.vertsDirty ||
+ markLine.vertsDirty;
}
}
@@ -1086,6 +1096,7 @@ namespace XCharts
gaugeAxis.ClearVerticesDirty();
gaugePointer.ClearVerticesDirty();
titleStyle.ClearVerticesDirty();
+ markLine.ClearVerticesDirty();
}
public override void ClearComponentDirty()
@@ -1101,6 +1112,7 @@ namespace XCharts
gaugeAxis.ClearComponentDirty();
gaugePointer.ClearComponentDirty();
titleStyle.ClearComponentDirty();
+ markLine.ClearComponentDirty();
}
///
@@ -1911,6 +1923,75 @@ namespace XCharts
}
}
+ ///
+ /// 启用或取消初始动画
+ ///
+ public void AnimationEnable(bool flag)
+ {
+ if (animation.enable) animation.enable = flag;
+ if (markLine.show && markLine.animation.enable) markLine.animation.enable = flag;
+ SetVerticesDirty();
+ }
+
+ ///
+ /// 渐入动画
+ ///
+ public void AnimationFadeIn()
+ {
+ if (animation.enable) animation.FadeIn();
+ if (markLine.show && markLine.animation.enable) markLine.animation.FadeIn();
+ SetVerticesDirty();
+ }
+
+ ///
+ /// 渐出动画
+ ///
+ public void AnimationFadeOut()
+ {
+ if (animation.enable) animation.FadeOut();
+ if (markLine.show && markLine.animation.enable) markLine.animation.FadeOut();
+ SetVerticesDirty();
+ }
+
+ ///
+ /// 暂停动画
+ ///
+ public void AnimationPause()
+ {
+ if (animation.enable) animation.Pause();
+ if (markLine.show && markLine.animation.enable) markLine.animation.Pause();
+ SetVerticesDirty();
+ }
+
+ ///
+ /// 继续动画
+ ///
+ public void AnimationResume()
+ {
+ if (animation.enable) animation.Resume();
+ if (markLine.show && markLine.animation.enable) markLine.animation.Resume();
+ SetVerticesDirty();
+ }
+
+ ///
+ /// 重置动画
+ ///
+ public void AnimationReset()
+ {
+ if (animation.enable) animation.Reset();
+ if (markLine.show && markLine.animation.enable) markLine.animation.Reset();
+ SetVerticesDirty();
+ }
+ ///
+ /// 重置动画
+ ///
+ public void AnimationRestart()
+ {
+ if (animation.enable) animation.Restart();
+ if (markLine.show && markLine.animation.enable) markLine.animation.Restart();
+ SetVerticesDirty();
+ }
+
///
/// 从json中导入数据
///
diff --git a/Assets/XCharts/Runtime/Component/Main/Series.cs b/Assets/XCharts/Runtime/Component/Main/Series.cs
index 2a90febb..d7bba41e 100644
--- a/Assets/XCharts/Runtime/Component/Main/Series.cs
+++ b/Assets/XCharts/Runtime/Component/Main/Series.cs
@@ -103,9 +103,9 @@ namespace XCharts
///
public void ClearData()
{
- AnimationFadeIn();
foreach (var serie in m_Series)
{
+ serie.AnimationFadeIn();
serie.ClearData();
}
}
@@ -259,7 +259,7 @@ namespace XCharts
///
public void RemoveAll()
{
- AnimationFadeIn();
+ foreach(var serie in m_Series) serie.AnimationFadeIn();
m_Series.Clear();
}
@@ -302,7 +302,7 @@ namespace XCharts
{
serie.symbol.show = false;
}
- serie.animation.Restart();
+ serie.AnimationRestart();
if (addToHead) m_Series.Insert(0, serie);
else if (index >= 0) m_Series.Insert(index, serie);
else m_Series.Add(serie);
@@ -662,8 +662,8 @@ namespace XCharts
if (serie != null)
{
serie.show = active;
- serie.animation.Reset();
- if (active) serie.animation.FadeIn();
+ serie.AnimationReset();
+ if (active) serie.AnimationFadeIn();
}
}
@@ -692,74 +692,5 @@ namespace XCharts
serie.symbol.selectedSizeCallback = selectedSize;
}
}
-
- ///
- /// 启用或取消初始动画
- ///
- public void AnimationEnable(bool flag)
- {
- foreach (var serie in m_Series)
- {
- serie.animation.enable = flag;
- }
- }
-
- ///
- /// 渐入动画
- ///
- public void AnimationFadeIn()
- {
- foreach (var serie in m_Series)
- {
- if (serie.animation.enable)
- {
- serie.animation.FadeIn();
- }
- }
- }
-
- ///
- /// 渐出动画
- ///
- public void AnimationFadeOut()
- {
- foreach (var serie in m_Series)
- {
- if (serie.animation.enable) serie.animation.FadeOut();
- }
- }
-
- ///
- /// 暂停动画
- ///
- public void AnimationPause()
- {
- foreach (var serie in m_Series)
- {
- if (serie.animation.enable) serie.animation.Pause();
- }
- }
-
- ///
- /// 继续动画
- ///
- public void AnimationResume()
- {
- foreach (var serie in m_Series)
- {
- if (serie.animation.enable) serie.animation.Resume();
- }
- }
-
- ///
- /// 重置动画
- ///
- public void AnimationReset()
- {
- foreach (var serie in m_Series)
- {
- if (serie.animation.enable) serie.animation.Reset();
- }
- }
}
}
diff --git a/Assets/XCharts/Runtime/Component/Main/XGrid.cs b/Assets/XCharts/Runtime/Component/Main/XGrid.cs
index 46e57df9..fb96ef3e 100644
--- a/Assets/XCharts/Runtime/Component/Main/XGrid.cs
+++ b/Assets/XCharts/Runtime/Component/Main/XGrid.cs
@@ -90,6 +90,7 @@ namespace XCharts
public float runtimeY { get; private set; }
public float runtimeWidth { get; private set; }
public float runtimeHeight { get; private set; }
+ public Vector3 runtimePosition { get; private set; }
internal void UpdateRuntimeData(float chartX, float chartY, float chartWidth, float chartHeight)
{
@@ -101,6 +102,7 @@ namespace XCharts
runtimeY = chartY + runtimeBottom;
runtimeWidth = chartWidth - runtimeLeft - runtimeRight;
runtimeHeight = chartHeight - runtimeTop - runtimeBottom;
+ runtimePosition = new Vector3(runtimeX, runtimeY);
}
public static Grid defaultGrid
diff --git a/Assets/XCharts/Runtime/Component/Sub/MarkLine.cs b/Assets/XCharts/Runtime/Component/Sub/MarkLine.cs
new file mode 100644
index 00000000..b272075e
--- /dev/null
+++ b/Assets/XCharts/Runtime/Component/Sub/MarkLine.cs
@@ -0,0 +1,664 @@
+/************************************************/
+/* */
+/* Copyright (c) 2018 - 2021 monitor1394 */
+/* https://github.com/monitor1394 */
+/* */
+/************************************************/
+
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+
+namespace XCharts
+{
+ public enum MarkLineType
+ {
+ None,
+ ///
+ /// 最小值。
+ ///
+ Min,
+ ///
+ /// 最大值。
+ ///
+ Max,
+ ///
+ /// 平均值。
+ ///
+ Average,
+ ///
+ /// 中位数。
+ ///
+ Median
+ }
+ ///
+ /// Data of marking line.
+ /// 图表标线的数据。
+ ///
+ [System.Serializable]
+ public class MarkLineData : SubComponent
+ {
+ [SerializeField] private string m_Name;
+ [SerializeField] private MarkLineType m_Type = MarkLineType.None;
+ [SerializeField] private int m_Dimension = 1;
+ [SerializeField] private float m_XPosition;
+ [SerializeField] private float m_YPosition;
+ [SerializeField] private double m_XValue;
+ [SerializeField] private double m_YValue;
+ [SerializeField] private int m_Group = 0;
+ [SerializeField] private bool m_ZeroPosition = false;
+
+ [SerializeField] private SerieSymbol m_StartSymbol = new SerieSymbol();
+ [SerializeField] private SerieSymbol m_EndSymbol = new SerieSymbol();
+ [SerializeField] private LineStyle m_LineStyle = new LineStyle();
+ [SerializeField] private SerieLabel m_Label = new SerieLabel();
+ //[SerializeField] private Emphasis m_Emphasis = new Emphasis();
+
+ public int index { get; set; }
+ public Vector3 runtimeStartPosition { get; internal set; }
+ public Vector3 runtimeEndPosition { get; internal set; }
+ public Vector3 runtimeCurrentEndPosition { get; internal set; }
+ public ChartLabel runtimeLabel { get; internal set; }
+ public double runtimeValue { get; internal set; }
+
+ ///
+ /// Name of the marker, which will display as a label.
+ /// 标注名称,将会作为文字显示。label的formatter可通过{b}显示名称,通过{c}显示数值。
+ ///
+ public string name
+ {
+ get { return m_Name; }
+ set { if (PropertyUtil.SetClass(ref m_Name, value)) SetVerticesDirty(); }
+ }
+ ///
+ /// Special label types, are used to label maximum value, minimum value and so on.
+ /// 特殊的标注类型,用于标注最大值最小值等。
+ ///
+ public MarkLineType type
+ {
+ get { return m_Type; }
+ set { if (PropertyUtil.SetStruct(ref m_Type, value)) SetVerticesDirty(); }
+ }
+ ///
+ /// From which dimension of data to calculate the maximum and minimum value and so on.
+ /// 从哪个维度的数据计算最大最小值等。
+ ///
+ public int dimension
+ {
+ get { return m_Dimension; }
+ set { if (PropertyUtil.SetStruct(ref m_Dimension, value)) SetVerticesDirty(); }
+ }
+ ///
+ /// The x coordinate relative to the origin, in pixels.
+ /// 相对原点的 x 坐标,单位像素。当type为None时有效。
+ ///
+ public float xPosition
+ {
+ get { return m_XPosition; }
+ set { if (PropertyUtil.SetStruct(ref m_XPosition, value)) SetVerticesDirty(); }
+ }
+ ///
+ /// The y coordinate relative to the origin, in pixels.
+ /// 相对原点的 y 坐标,单位像素。当type为None时有效。
+ ///
+ public float yPosition
+ {
+ get { return m_YPosition; }
+ set { if (PropertyUtil.SetStruct(ref m_YPosition, value)) SetVerticesDirty(); }
+ }
+ ///
+ /// The value specified on the X-axis. A value specified when the X-axis is the category axis represents the index of the category axis data, otherwise a specific value.
+ /// X轴上的指定值。当X轴为类目轴时指定值表示类目轴数据的索引,否则为具体的值。当type为None时有效。
+ ///
+ public double xValue
+ {
+ get { return m_XValue; }
+ set { if (PropertyUtil.SetStruct(ref m_XValue, value)) SetVerticesDirty(); }
+ }
+ ///
+ /// That's the value on the Y-axis. The value specified when the Y axis is the category axis represents the index of the category axis data, otherwise the specific value.
+ /// Y轴上的指定值。当Y轴为类目轴时指定值表示类目轴数据的索引,否则为具体的值。当type为None时有效。
+ ///
+ public double yValue
+ {
+ get { return m_YValue; }
+ set { if (PropertyUtil.SetStruct(ref m_YValue, value)) SetVerticesDirty(); }
+ }
+ ///
+ /// Grouping. When the group is not 0, it means that this data is the starting point or end point of the marking line. Data consistent with the group form a marking line.
+ /// 分组。当group不为0时,表示这个data是标线的起点或终点,group一致的data组成一条标线。
+ ///
+ public int group
+ {
+ get { return m_Group; }
+ set { if (PropertyUtil.SetStruct(ref m_Group, value)) SetVerticesDirty(); }
+ }
+ ///
+ /// Is the origin of the coordinate system.
+ /// 是否为坐标系原点。
+ ///
+ public bool zeroPosition
+ {
+ get { return m_ZeroPosition; }
+ set { if (PropertyUtil.SetStruct(ref m_ZeroPosition, value)) SetVerticesDirty(); }
+ }
+ ///
+ /// The symbol of the start point of markline.
+ /// 起始点的图形标记。
+ ///
+ public SerieSymbol startSymbol
+ {
+ get { return m_StartSymbol; }
+ set { if (PropertyUtil.SetClass(ref m_StartSymbol, value)) SetVerticesDirty(); }
+ }
+ ///
+ /// The symbol of the end point of markline.
+ /// 结束点的图形标记。
+ ///
+ public SerieSymbol endSymbol
+ {
+ get { return m_EndSymbol; }
+ set { if (PropertyUtil.SetClass(ref m_EndSymbol, value)) SetVerticesDirty(); }
+ }
+ ///
+ /// The line style of markline.
+ /// 标线样式。
+ ///
+ public LineStyle lineStyle
+ {
+ get { return m_LineStyle; }
+ set { if (PropertyUtil.SetClass(ref m_LineStyle, value)) SetVerticesDirty(); }
+ }
+ ///
+ /// Text styles of label. You can set position to Start, Middle, and End to display text in different locations.
+ /// 文本样式。可设置position为Start、Middle和End在不同的位置显示文本。
+ ///
+ public SerieLabel label
+ {
+ get { return m_Label; }
+ set { if (PropertyUtil.SetClass(ref m_Label, value)) SetVerticesDirty(); }
+ }
+ // public Emphasis emphasis
+ // {
+ // get { return m_Emphasis; }
+ // set { if (PropertyUtil.SetClass(ref m_Emphasis, value)) SetVerticesDirty(); }
+ // }
+ }
+
+ ///
+ /// Use a line in the chart to illustrate.
+ /// 图表标线。
+ ///
+ [System.Serializable]
+ public class MarkLine : SubComponent
+ {
+ [SerializeField] private bool m_Show;
+ [SerializeField] private SerieAnimation m_Animation = new SerieAnimation();
+ [SerializeField] private List m_Data = new List();
+
+ ///
+ /// Whether to display the marking line.
+ /// 是否显示标线。
+ ///
+ public bool show
+ {
+ get { return m_Show; }
+ set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetVerticesDirty(); }
+ }
+ ///
+ /// The animation of markline.
+ /// 标线的动画样式。
+ ///
+ public SerieAnimation animation
+ {
+ get { return m_Animation; }
+ set { if (PropertyUtil.SetClass(ref m_Animation, value)) SetVerticesDirty(); }
+ }
+ ///
+ /// A list of marked data. When the group of data item is 0, each data item represents a line;
+ /// When the group is not 0, two data items of the same group represent the starting point and
+ /// the ending point of the line respectively to form a line. In this case, the relevant style
+ /// parameters of the line are the parameters of the starting point.
+ /// 标线的数据列表。当数据项的group为0时,每个数据项表示一条标线;当group不为0时,相同group的两个数据项分别表
+ /// 示标线的起始点和终止点来组成一条标线,此时标线的相关样式参数取起始点的参数。
+ ///
+ public List data
+ {
+ get { return m_Data; }
+ set { if (PropertyUtil.SetClass(ref m_Data, value)) SetVerticesDirty(); }
+ }
+ public static MarkLine defaultMarkLine
+ {
+ get
+ {
+ var markLine = new MarkLine
+ {
+ m_Show = false,
+ m_Data = new List()
+ };
+ var data = new MarkLineData();
+ data.type = MarkLineType.Min;
+ data.startSymbol.show = true;
+ data.startSymbol.type = SerieSymbolType.Circle;
+ data.endSymbol.show = true;
+ data.endSymbol.type = SerieSymbolType.Triangle;
+ markLine.data.Add(data);
+ return markLine;
+ }
+ }
+ }
+
+ internal class MarkLineHandler : IComponentHandler
+ {
+ public CoordinateChart chart;
+ private GameObject m_MarkLineLabelRoot;
+ private bool m_RefreshLabel = false;
+
+ public MarkLineHandler(CoordinateChart chart)
+ {
+ this.chart = chart;
+ }
+
+ public void DrawBase(VertexHelper vh)
+ {
+ }
+
+ public void DrawTop(VertexHelper vh)
+ {
+ DrawMarkLine(vh);
+ }
+
+ public void Init()
+ {
+ foreach (var serie in chart.series.list) InitMarkLine(serie);
+ }
+
+ public void OnBeginDrag(PointerEventData eventData)
+ {
+ }
+
+ public void OnDrag(PointerEventData eventData)
+ {
+ }
+
+ public void OnEndDrag(PointerEventData eventData)
+ {
+ }
+
+ public void OnPointerDown(PointerEventData eventData)
+ {
+ }
+
+ public void OnScroll(PointerEventData eventData)
+ {
+ }
+
+ public void Update()
+ {
+ if (m_RefreshLabel)
+ {
+ m_RefreshLabel = false;
+ foreach (var serie in chart.series.list)
+ {
+ if (!serie.show || !serie.markLine.show) continue;
+ foreach (var data in serie.markLine.data)
+ {
+ if (data.runtimeLabel != null)
+ {
+ data.runtimeLabel.SetPosition(MarkLineHelper.GetLabelPosition(data));
+ data.runtimeLabel.SetText(MarkLineHelper.GetFormatterContent(serie, data));
+ }
+ }
+ }
+ }
+ }
+
+ private void InitMarkLine(Serie serie)
+ {
+ if (!serie.show || !serie.markLine.show) return;
+ ResetTempMarkLineGroupData(serie.markLine);
+ m_MarkLineLabelRoot = ChartHelper.AddObject("markline", chart.transform, chart.chartMinAnchor,
+ chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta);
+ m_MarkLineLabelRoot.hideFlags = chart.chartHideFlags;
+ ChartHelper.HideAllObject(m_MarkLineLabelRoot);
+ var serieColor = (Color)chart.theme.GetColor(chart.GetLegendRealShowNameIndex(serie.name));
+ if (m_TempGroupData.Count > 0)
+ {
+ foreach (var kv in m_TempGroupData)
+ {
+ if (kv.Value.Count >= 2)
+ {
+ var data = kv.Value[0];
+ InitMarkLineLabel(serie, data, serieColor);
+ }
+ }
+ }
+ foreach (var data in serie.markLine.data)
+ {
+ if (data.group != 0) continue;
+ InitMarkLineLabel(serie, data, serieColor);
+ }
+ }
+
+ private void InitMarkLineLabel(Serie serie, MarkLineData data, Color serieColor)
+ {
+ data.painter = chart.m_PainterTop;
+ data.refreshComponent = delegate ()
+ {
+ var label = data.label;
+ var textName = string.Format("markLine_{0}_{1}", serie.index, data.index);
+ var color = !ChartHelper.IsClearColor(label.textStyle.color) ? label.textStyle.color : chart.theme.axis.textColor;
+ var element = ChartHelper.AddSerieLabel(textName, m_MarkLineLabelRoot.transform, label.backgroundWidth,
+ label.backgroundHeight, color, label.textStyle, chart.theme);
+ var isAutoSize = label.backgroundWidth == 0 || label.backgroundHeight == 0;
+ var item = new ChartLabel();
+ item.SetLabel(element, isAutoSize, label.paddingLeftRight, label.paddingTopBottom);
+ item.SetIconActive(false);
+ item.SetActive(true);
+ item.SetPosition(MarkLineHelper.GetLabelPosition(data));
+ item.SetText(MarkLineHelper.GetFormatterContent(serie, data));
+ data.runtimeLabel = item;
+ };
+ data.refreshComponent();
+ }
+
+ private void DrawMarkLine(VertexHelper vh)
+ {
+ foreach (var serie in chart.series.list)
+ {
+ DrawMarkLine(vh, serie);
+ }
+ }
+
+ private Dictionary> m_TempGroupData = new Dictionary>();
+ private void DrawMarkLine(VertexHelper vh, Serie serie)
+ {
+ if (!serie.show || !serie.markLine.show) return;
+ if (serie.markLine.data.Count == 0) return;
+ var yAxis = chart.GetSerieYAxisOrDefault(serie);
+ var xAxis = chart.GetSerieXAxisOrDefault(serie);
+ var grid = chart.GetSerieGridOrDefault(serie);
+ var dataZoom = DataZoomHelper.GetAxisRelatedDataZoom(xAxis, chart.dataZooms);
+ var animation = serie.markLine.animation;
+ var showData = serie.GetDataList(dataZoom);
+ var sp = Vector3.zero;
+ var ep = Vector3.zero;
+ var colorIndex = chart.GetLegendRealShowNameIndex(serie.name);
+ var serieColor = SerieHelper.GetLineColor(serie, chart.theme, colorIndex, false);
+ animation.InitProgress(1, 0, 1f);
+ ResetTempMarkLineGroupData(serie.markLine);
+ if (m_TempGroupData.Count > 0)
+ {
+ foreach (var kv in m_TempGroupData)
+ {
+ if (kv.Value.Count >= 2)
+ {
+ sp = GetSinglePos(xAxis, yAxis, grid, serie, dataZoom, kv.Value[0], showData.Count);
+ ep = GetSinglePos(xAxis, yAxis, grid, serie, dataZoom, kv.Value[1], showData.Count);
+ kv.Value[0].runtimeStartPosition = sp;
+ kv.Value[1].runtimeEndPosition = ep;
+ DrawMakLineData(vh, kv.Value[0], animation, serie, grid, serieColor, sp, ep);
+ }
+ }
+ }
+ foreach (var data in serie.markLine.data)
+ {
+ if (data.group != 0) continue;
+ switch (data.type)
+ {
+ case MarkLineType.Min:
+ data.runtimeValue = SerieHelper.GetMinData(serie, data.dimension, dataZoom);
+ GetStartEndPos(xAxis, yAxis, grid, data.runtimeValue, ref sp, ref ep);
+ break;
+ case MarkLineType.Max:
+ data.runtimeValue = SerieHelper.GetMaxData(serie, data.dimension, dataZoom);
+ GetStartEndPos(xAxis, yAxis, grid, data.runtimeValue, ref sp, ref ep);
+ break;
+ case MarkLineType.Average:
+ data.runtimeValue = SerieHelper.GetAverageData(serie, data.dimension, dataZoom);
+ GetStartEndPos(xAxis, yAxis, grid, data.runtimeValue, ref sp, ref ep);
+ break;
+ case MarkLineType.Median:
+ data.runtimeValue = SerieHelper.GetMedianData(serie, data.dimension, dataZoom);
+ GetStartEndPos(xAxis, yAxis, grid, data.runtimeValue, ref sp, ref ep);
+ break;
+ case MarkLineType.None:
+ if (data.xPosition != 0)
+ {
+ data.runtimeValue = data.xPosition;
+ var pX = grid.runtimeX + data.xPosition;
+ sp = new Vector3(pX, grid.runtimeY);
+ ep = new Vector3(pX, grid.runtimeY + grid.runtimeHeight);
+ }
+ else if (data.yPosition != 0)
+ {
+ data.runtimeValue = data.yPosition;
+ var pY = grid.runtimeY + data.yPosition;
+ sp = new Vector3(grid.runtimeX, pY);
+ ep = new Vector3(grid.runtimeX + grid.runtimeWidth, pY);
+ }
+ else if (data.yValue != 0)
+ {
+ data.runtimeValue = data.yValue;
+ if (yAxis.IsCategory())
+ {
+ var categoryIndex = (int)data.yValue;
+ var scaleWid = AxisHelper.GetDataWidth(yAxis, grid.runtimeHeight, showData.Count, dataZoom);
+ float startY = grid.runtimeY + (yAxis.boundaryGap ? scaleWid / 2 : 0);
+ var pY = startY + scaleWid * categoryIndex;
+ sp = new Vector3(grid.runtimeX, pY);
+ ep = new Vector3(grid.runtimeX + grid.runtimeWidth, pY);
+ }
+ else
+ {
+ GetStartEndPos(xAxis, yAxis, grid, data.yValue, ref sp, ref ep);
+ }
+ }
+ else
+ {
+ data.runtimeValue = data.xValue;
+ if (xAxis.IsCategory())
+ {
+ var categoryIndex = (int)data.xValue;
+ var scaleWid = AxisHelper.GetDataWidth(xAxis, grid.runtimeWidth, showData.Count, dataZoom);
+ float startX = grid.runtimeX + (xAxis.boundaryGap ? scaleWid / 2 : 0);
+ var pX = startX + scaleWid * categoryIndex;
+ sp = new Vector3(pX, grid.runtimeY);
+ ep = new Vector3(pX, grid.runtimeY + grid.runtimeHeight);
+ }
+ else
+ {
+ GetStartEndPos(xAxis, yAxis, grid, data.xValue, ref sp, ref ep);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ data.runtimeStartPosition = sp;
+ data.runtimeEndPosition = ep;
+ DrawMakLineData(vh, data, animation, serie, grid, serieColor, sp, ep);
+ }
+ if (!animation.IsFinish())
+ {
+ animation.CheckProgress(1f);
+ chart.RefreshTopPainter();
+ }
+ }
+
+ private void ResetTempMarkLineGroupData(MarkLine markLine)
+ {
+ m_TempGroupData.Clear();
+ for (int i = 0; i < markLine.data.Count; i++)
+ {
+ var data = markLine.data[i];
+ data.index = i;
+ if (data.group == 0) continue;
+ if (!m_TempGroupData.ContainsKey(data.group))
+ {
+ m_TempGroupData[data.group] = new List();
+ }
+ m_TempGroupData[data.group].Add(data);
+ }
+ }
+
+ private void DrawMakLineData(VertexHelper vh, MarkLineData data, SerieAnimation animation, Serie serie,
+ Grid grid, Color32 serieColor, Vector3 sp, Vector3 ep)
+ {
+ if (!animation.IsFinish())
+ ep = Vector3.Lerp(sp, ep, animation.GetCurrDetail());
+ data.runtimeCurrentEndPosition = ep;
+ if (sp != Vector3.zero || ep != Vector3.zero)
+ {
+ m_RefreshLabel = true;
+ chart.ClampInChart(ref sp);
+ chart.ClampInChart(ref ep);
+ var theme = chart.theme.axis;
+ var lineColor = ChartHelper.IsClearColor(data.lineStyle.color) ? serieColor : data.lineStyle.color;
+ var lineWidth = data.lineStyle.width == 0 ? theme.lineWidth : data.lineStyle.width;
+ ChartDrawer.DrawLineStyle(vh, data.lineStyle, sp, ep, lineColor, lineWidth, LineStyle.Type.Dashed);
+ if (data.startSymbol != null && data.startSymbol.show)
+ {
+ DrawMarkLineSymbol(vh, data.startSymbol, serie, grid, chart.theme, sp, sp, lineColor);
+ }
+ if (data.endSymbol != null && data.endSymbol.show)
+ {
+ DrawMarkLineSymbol(vh, data.endSymbol, serie, grid, chart.theme, ep, sp, lineColor);
+ }
+ }
+ }
+
+ private void DrawMarkLineSymbol(VertexHelper vh, SerieSymbol symbol, Serie serie, Grid grid, ChartTheme theme,
+ Vector3 pos, Vector3 startPos, Color32 lineColor)
+ {
+ var symbolSize = symbol.GetSize(null, theme.serie.lineSymbolSize);
+ var tickness = SerieHelper.GetSymbolBorder(serie, null, theme, false);
+ var cornerRadius = SerieHelper.GetSymbolCornerRadius(serie, null, false);
+ chart.Internal_CheckClipAndDrawSymbol(vh, symbol.type, symbolSize, tickness, pos, lineColor, lineColor,
+ symbol.gap, true, cornerRadius, grid, startPos);
+ }
+
+ private void GetStartEndPos(Axis xAxis, Axis yAxis, Grid grid, double value, ref Vector3 sp, ref Vector3 ep)
+ {
+ if (xAxis.IsCategory())
+ {
+ var yDataHig = (value - yAxis.runtimeMinValue) / yAxis.runtimeMinMaxRange * grid.runtimeHeight;
+ var pY = grid.runtimeY + (float)yDataHig;
+ sp = new Vector3(grid.runtimeX, pY);
+ ep = new Vector3(grid.runtimeX + grid.runtimeWidth, pY);
+ }
+ else
+ {
+ var xDataHig = (value - xAxis.runtimeMinValue) / xAxis.runtimeMinMaxRange * grid.runtimeWidth;
+ var pX = grid.runtimeX + (float)xDataHig;
+ sp = new Vector3(pX, grid.runtimeY);
+ ep = new Vector3(pX, grid.runtimeY + grid.runtimeHeight);
+ }
+ }
+
+ private float GetAxisPosition(Grid grid, Axis axis, DataZoom dataZoom, int dataCount, double value)
+ {
+ if (axis is YAxis)
+ {
+ if (axis.IsCategory())
+ {
+ var categoryIndex = (int)value;
+ var scaleWid = AxisHelper.GetDataWidth(axis, grid.runtimeHeight, dataCount, dataZoom);
+ float startY = grid.runtimeY + (axis.boundaryGap ? scaleWid / 2 : 0);
+ return startY + scaleWid * categoryIndex;
+ }
+ var yDataHig = (value - axis.runtimeMinValue) / axis.runtimeMinMaxRange * grid.runtimeHeight;
+ return grid.runtimeY + (float)yDataHig;
+ }
+ else
+ {
+ if (axis.IsCategory())
+ {
+ var categoryIndex = (int)value;
+ var scaleWid = AxisHelper.GetDataWidth(axis, grid.runtimeWidth, dataCount, dataZoom);
+ float startX = grid.runtimeX + (axis.boundaryGap ? scaleWid / 2 : 0);
+ return startX + scaleWid * categoryIndex;
+ }
+ else
+ {
+ var xDataHig = (value - axis.runtimeMinValue) / axis.runtimeMinMaxRange * grid.runtimeWidth;
+ return grid.runtimeX + (float)xDataHig;
+ }
+ }
+ }
+
+ private Vector3 GetSinglePos(Axis xAxis, Axis yAxis, Grid grid, Serie serie, DataZoom dataZoom, MarkLineData data,
+ int serieDataCount)
+ {
+ switch (data.type)
+ {
+ case MarkLineType.Min:
+ var serieData = SerieHelper.GetMinSerieData(serie, data.dimension, dataZoom);
+ data.runtimeValue = serieData.GetData(data.dimension);
+ var pX = GetAxisPosition(grid, xAxis, dataZoom, serieDataCount, serieData.index);
+ var pY = GetAxisPosition(grid, yAxis, dataZoom, serieDataCount, data.runtimeValue);
+ return new Vector3(pX, pY);
+ case MarkLineType.Max:
+ serieData = SerieHelper.GetMaxSerieData(serie, data.dimension, dataZoom);
+ data.runtimeValue = serieData.GetData(data.dimension);
+ pX = GetAxisPosition(grid, xAxis, dataZoom, serieDataCount, serieData.index);
+ pY = GetAxisPosition(grid, yAxis, dataZoom, serieDataCount, data.runtimeValue);
+ return new Vector3(pX, pY);
+ case MarkLineType.None:
+ if (data.zeroPosition)
+ {
+ data.runtimeValue = 0;
+ return grid.runtimePosition;
+ }
+ else
+ {
+ pX = data.xPosition != 0 ? grid.runtimeX + data.xPosition :
+ GetAxisPosition(grid, xAxis, dataZoom, serieDataCount, data.xValue);
+ pY = data.yPosition != 0 ? grid.runtimeY + data.yPosition :
+ GetAxisPosition(grid, yAxis, dataZoom, serieDataCount, data.yValue);
+ data.runtimeValue = data.yValue;
+ return new Vector3(pX, pY);
+ }
+ default:
+ return grid.runtimePosition;
+ }
+ }
+ }
+
+ internal static class MarkLineHelper
+ {
+ public static string GetFormatterContent(Serie serie, MarkLineData data)
+ {
+ var serieLabel = data.label;
+ var numericFormatter = serieLabel.numericFormatter;
+ if (serieLabel.formatterFunction != null)
+ {
+ return serieLabel.formatterFunction(data.index, data.runtimeValue);
+ }
+ if (string.IsNullOrEmpty(serieLabel.formatter))
+ return ChartCached.NumberToStr(data.runtimeValue, numericFormatter);
+ else
+ {
+ var content = serieLabel.formatter;
+ FormatterHelper.ReplaceSerieLabelContent(ref content, numericFormatter, data.runtimeValue,
+ 0, serie.name, data.name, Color.clear);
+ return content;
+ }
+ }
+
+ public static Vector3 GetLabelPosition(MarkLineData data)
+ {
+ if (!data.label.show) return Vector3.zero;
+ switch (data.label.position)
+ {
+ case SerieLabel.Position.Start:
+ return data.runtimeStartPosition + data.label.offset;
+ case SerieLabel.Position.Middle:
+ return (data.runtimeStartPosition + data.runtimeCurrentEndPosition) / 2 + data.label.offset;
+ default:
+ return data.runtimeCurrentEndPosition + data.label.offset;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/XCharts/Runtime/Component/Sub/MarkLine.cs.meta b/Assets/XCharts/Runtime/Component/Sub/MarkLine.cs.meta
new file mode 100644
index 00000000..dba1cc5c
--- /dev/null
+++ b/Assets/XCharts/Runtime/Component/Sub/MarkLine.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fd9631fa54e73444884c717bd04765a6
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/XCharts/Runtime/Component/Sub/SerieLabel.cs b/Assets/XCharts/Runtime/Component/Sub/SerieLabel.cs
index 9bed43ca..bba559d7 100644
--- a/Assets/XCharts/Runtime/Component/Sub/SerieLabel.cs
+++ b/Assets/XCharts/Runtime/Component/Sub/SerieLabel.cs
@@ -58,6 +58,21 @@ namespace XCharts
/// 图形标志的右边。
///
Right,
+ ///
+ /// the start of line.
+ /// 线的起始点。
+ ///
+ Start,
+ ///
+ /// the middle of line.
+ /// 线的中点。
+ ///
+ Middle,
+ ///
+ /// the end of line.
+ /// 线的结束点。
+ ///
+ End
}
///
diff --git a/Assets/XCharts/Runtime/Component/Sub/SerieSymbol.cs b/Assets/XCharts/Runtime/Component/Sub/SerieSymbol.cs
index c9e9ce65..a4658fde 100644
--- a/Assets/XCharts/Runtime/Component/Sub/SerieSymbol.cs
+++ b/Assets/XCharts/Runtime/Component/Sub/SerieSymbol.cs
@@ -40,6 +40,10 @@ namespace XCharts
/// 不显示标记。
///
None,
+ ///
+ /// 箭头。
+ ///
+ Arrow
}
///
diff --git a/Assets/XCharts/Runtime/Helper/FormatterHelper.cs b/Assets/XCharts/Runtime/Helper/FormatterHelper.cs
index 2b43c294..30a59ccf 100644
--- a/Assets/XCharts/Runtime/Helper/FormatterHelper.cs
+++ b/Assets/XCharts/Runtime/Helper/FormatterHelper.cs
@@ -245,8 +245,8 @@ namespace XCharts
var isPercent = p == 'd' || p == 'D';
if (isPercent)
{
- var percent = total == 0 ? 0 : value / total * 100;
- content = content.Replace(old, ChartCached.FloatToStr(percent, numericFormatter));
+ if (total != 0)
+ content = content.Replace(old, ChartCached.FloatToStr(value / total * 100, numericFormatter));
}
else
{
diff --git a/Assets/XCharts/Runtime/Helper/SerieHelper.cs b/Assets/XCharts/Runtime/Helper/SerieHelper.cs
index a77d7758..1856a03d 100644
--- a/Assets/XCharts/Runtime/Helper/SerieHelper.cs
+++ b/Assets/XCharts/Runtime/Helper/SerieHelper.cs
@@ -13,6 +13,111 @@ namespace XCharts
{
public static partial class SerieHelper
{
+ public static double GetMinData(Serie serie, int dimension = 1, DataZoom dataZoom = null)
+ {
+ double min = double.MaxValue;
+ var dataList = serie.GetDataList(dataZoom);
+ for (int i = 0; i < dataList.Count; i++)
+ {
+ var serieData = dataList[i];
+ if (serieData.show && serieData.data.Count > dimension)
+ {
+ var value = serieData.data[dimension];
+ if (value < min) min = value;
+ }
+ }
+ return min == double.MaxValue ? 0 : min;
+ }
+ public static SerieData GetMinSerieData(Serie serie, int dimension = 1, DataZoom dataZoom = null)
+ {
+ double min = double.MaxValue;
+ SerieData minData = null;
+ var dataList = serie.GetDataList(dataZoom);
+ for (int i = 0; i < dataList.Count; i++)
+ {
+ var serieData = dataList[i];
+ if (serieData.show && serieData.data.Count > dimension)
+ {
+ var value = serieData.data[dimension];
+ if (value < min)
+ {
+ min = value;
+ minData = serieData;
+ }
+ }
+ }
+ return minData;
+ }
+ public static double GetMaxData(Serie serie, int dimension = 1, DataZoom dataZoom = null)
+ {
+ double max = double.MinValue;
+ var dataList = serie.GetDataList(dataZoom);
+ for (int i = 0; i < dataList.Count; i++)
+ {
+ var serieData = dataList[i];
+ if (serieData.show && serieData.data.Count > dimension)
+ {
+ var value = serieData.data[dimension];
+ if (value > max) max = value;
+ }
+ }
+ return max == double.MinValue ? 0 : max;
+ }
+ public static SerieData GetMaxSerieData(Serie serie, int dimension = 1, DataZoom dataZoom = null)
+ {
+ double max = double.MinValue;
+ SerieData maxData = null;
+ var dataList = serie.GetDataList(dataZoom);
+ for (int i = 0; i < dataList.Count; i++)
+ {
+ var serieData = dataList[i];
+ if (serieData.show && serieData.data.Count > dimension)
+ {
+ var value = serieData.data[dimension];
+ if (value > max)
+ {
+ max = value;
+ maxData = serieData;
+ }
+ }
+ }
+ return maxData;
+ }
+
+ public static double GetAverageData(Serie serie, int dimension = 1, DataZoom dataZoom = null)
+ {
+ double total = 0;
+ var dataList = serie.GetDataList(dataZoom);
+ for (int i = 0; i < dataList.Count; i++)
+ {
+ var serieData = dataList[i];
+ if (serieData.show && serieData.data.Count > dimension)
+ {
+ total += serieData.data[dimension];
+ }
+ }
+ return total != 0 ? total / dataList.Count : 0;
+ }
+
+ private static List s_TempList = new List();
+ public static double GetMedianData(Serie serie, int dimension = 1, DataZoom dataZoom = null)
+ {
+ s_TempList.Clear();
+ var dataList = serie.GetDataList(dataZoom);
+ for (int i = 0; i < dataList.Count; i++)
+ {
+ var serieData = dataList[i];
+ if (serieData.show && serieData.data.Count > dimension)
+ {
+ s_TempList.Add(serieData.data[dimension]);
+ }
+ }
+ s_TempList.Sort();
+ var n = s_TempList.Count;
+ if (n % 2 == 0) return (s_TempList[n / 2] + s_TempList[n / 2 - 1]) / 2;
+ else return s_TempList[n / 2];
+ }
+
///
/// Gets the maximum and minimum values of the specified dimension of a serie.
/// 获得系列指定维数的最大最小值。
diff --git a/Assets/XCharts/Runtime/Internal/BaseChart.cs b/Assets/XCharts/Runtime/Internal/BaseChart.cs
index 4f42cca2..746b1119 100644
--- a/Assets/XCharts/Runtime/Internal/BaseChart.cs
+++ b/Assets/XCharts/Runtime/Internal/BaseChart.cs
@@ -82,7 +82,7 @@ namespace XCharts
internal bool m_IsPlayingAnimation = false;
internal protected List m_LegendRealShowName = new List();
protected List m_PainterList = new List();
- protected Painter m_PainterTop;
+ internal Painter m_PainterTop;
protected GameObject m_SerieLabelRoot;
private Theme m_CheckTheme = 0;
@@ -120,8 +120,8 @@ namespace XCharts
if (m_Tooltips.Count == 0) m_Tooltips = new List() { Tooltip.defaultTooltip };
CheckTheme();
base.Awake();
- m_Series.AnimationReset();
- m_Series.AnimationFadeIn();
+ AnimationReset();
+ AnimationFadeIn();
XChartsMgr.Instance.AddChart(this);
}
@@ -732,7 +732,7 @@ namespace XCharts
if (!m_CheckAnimation)
{
m_CheckAnimation = true;
- m_Series.AnimationFadeIn();
+ AnimationFadeIn();
}
}
@@ -1011,11 +1011,16 @@ namespace XCharts
public void DrawSymbol(VertexHelper vh, SerieSymbolType type, float symbolSize,
float tickness, Vector3 pos, Color32 color, Color32 toColor, float gap, float[] cornerRadius)
+ {
+ DrawSymbol(vh, type, symbolSize, tickness, pos, color, toColor, gap, cornerRadius, Vector3.zero);
+ }
+ public void DrawSymbol(VertexHelper vh, SerieSymbolType type, float symbolSize,
+ float tickness, Vector3 pos, Color32 color, Color32 toColor, float gap, float[] cornerRadius, Vector3 startPos)
{
var backgroundColor = ThemeHelper.GetBackgroundColor(m_Theme, m_Background);
var smoothness = settings.cicleSmoothness;
ChartDrawer.DrawSymbol(vh, type, symbolSize, tickness, pos, color, toColor, gap,
- cornerRadius, backgroundColor, smoothness);
+ cornerRadius, backgroundColor, smoothness, startPos);
}
public void DrawLabelBackground(VertexHelper vh, Serie serie, SerieData serieData)
diff --git a/Assets/XCharts/Runtime/Internal/CoordinateChart.cs b/Assets/XCharts/Runtime/Internal/CoordinateChart.cs
index 41cb6f2e..9f543288 100644
--- a/Assets/XCharts/Runtime/Internal/CoordinateChart.cs
+++ b/Assets/XCharts/Runtime/Internal/CoordinateChart.cs
@@ -32,6 +32,10 @@ namespace XCharts
InitAxisX();
InitAxisY();
tooltip.UpdateToTop();
+
+ var handler = new MarkLineHandler(this);
+ m_ComponentHandlers.Add(handler);
+ handler.Init();
}
protected override void Update()
@@ -1675,11 +1679,11 @@ namespace XCharts
}
public void Internal_CheckClipAndDrawSymbol(VertexHelper vh, SerieSymbolType type, float symbolSize, float tickness,
- Vector3 pos, Color32 color, Color32 toColor, float gap, bool clip, float[] cornerRadius, Grid grid)
+ Vector3 pos, Color32 color, Color32 toColor, float gap, bool clip, float[] cornerRadius, Grid grid, Vector3 startPos)
{
if (!IsInChart(pos)) return;
if (!clip || (clip && (IsInGrid(grid, pos))))
- DrawSymbol(vh, type, symbolSize, tickness, pos, color, toColor, gap, cornerRadius);
+ DrawSymbol(vh, type, symbolSize, tickness, pos, color, toColor, gap, cornerRadius, startPos);
}
public void Internal_CheckClipAndDrawZebraLine(VertexHelper vh, Vector3 p1, Vector3 p2, float size, float zebraWidth,
diff --git a/Assets/XCharts/Runtime/Internal/CoordinateChart_DrawLine.cs b/Assets/XCharts/Runtime/Internal/CoordinateChart_DrawLine.cs
index 727edc9c..112a6771 100644
--- a/Assets/XCharts/Runtime/Internal/CoordinateChart_DrawLine.cs
+++ b/Assets/XCharts/Runtime/Internal/CoordinateChart_DrawLine.cs
@@ -46,7 +46,7 @@ namespace XCharts
var cornerRadius = SerieHelper.GetSymbolCornerRadius(serie, serieData, highlight);
symbolSize = serie.animation.GetSysmbolSize(symbolSize);
Internal_CheckClipAndDrawSymbol(vh, symbol.type, symbolSize, symbolBorder, serie.dataPoints[i], symbolColor,
- symbolToColor, symbol.gap, clip, cornerRadius, grid);
+ symbolToColor, symbol.gap, clip, cornerRadius, grid, i > 0 ? serie.dataPoints[i - 1] : grid.runtimePosition);
}
}
diff --git a/Assets/XCharts/Runtime/Internal/Utility/ChartDrawer.cs b/Assets/XCharts/Runtime/Internal/Utility/ChartDrawer.cs
index 8e40f5c8..4432e65c 100644
--- a/Assets/XCharts/Runtime/Internal/Utility/ChartDrawer.cs
+++ b/Assets/XCharts/Runtime/Internal/Utility/ChartDrawer.cs
@@ -15,9 +15,10 @@ namespace XCharts
{
public static class ChartDrawer
{
+
public static void DrawSymbol(VertexHelper vh, SerieSymbolType type, float symbolSize,
float tickness, Vector3 pos, Color32 color, Color32 toColor, float gap, float[] cornerRadius,
- Color32 backgroundColor, float smoothness)
+ Color32 backgroundColor, float smoothness, Vector3 startPos)
{
switch (type)
{
@@ -77,6 +78,14 @@ namespace XCharts
UGL.DrawDiamond(vh, pos, symbolSize, color, toColor);
}
break;
+ case SerieSymbolType.Arrow:
+ var arrowWidth = symbolSize * 2;
+ var arrowHeight = arrowWidth * 1.5f;
+ var arrowOffset = 0;
+ var arrowDent = arrowWidth / 3.3f;
+ UGL.DrawArrow(vh, startPos, pos, arrowWidth, arrowHeight,
+ arrowOffset, arrowDent, color);
+ break;
}
}