mirror of
https://github.com/XCharts-Team/XCharts.git
synced 2026-05-14 20:00:09 +00:00
增加MarkLine标线 (#142)
This commit is contained in:
@@ -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`参数不生效的问题
|
||||
|
||||
@@ -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`:数据项名称。
|
||||
|
||||
@@ -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`: 数据项名称。
|
||||
|
||||
69
Assets/XCharts/Editor/PropertyDrawers/MarkLineDrawer.cs
Normal file
69
Assets/XCharts/Editor/PropertyDrawers/MarkLineDrawer.cs
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/XCharts/Editor/PropertyDrawers/MarkLineDrawer.cs.meta
Normal file
11
Assets/XCharts/Editor/PropertyDrawers/MarkLineDrawer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9c530aeba79d40a8918424df421d081
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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");
|
||||
|
||||
@@ -652,7 +652,7 @@ namespace XCharts
|
||||
/// <param name="flag"></param>
|
||||
public void AnimationEnable(bool flag)
|
||||
{
|
||||
m_Series.AnimationEnable(flag);
|
||||
foreach (var serie in m_Series.list) serie.AnimationEnable(flag);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -661,8 +661,7 @@ namespace XCharts
|
||||
/// </summary>
|
||||
public void AnimationFadeIn()
|
||||
{
|
||||
m_Series.AnimationFadeIn();
|
||||
RefreshChart();
|
||||
foreach (var serie in m_Series.list) serie.AnimationFadeIn();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -671,8 +670,7 @@ namespace XCharts
|
||||
/// </summary>
|
||||
public void AnimationFadeOut()
|
||||
{
|
||||
m_Series.AnimationFadeOut();
|
||||
RefreshChart();
|
||||
foreach (var serie in m_Series.list) serie.AnimationFadeOut();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -681,8 +679,7 @@ namespace XCharts
|
||||
/// </summary>
|
||||
public void AnimationPause()
|
||||
{
|
||||
m_Series.AnimationPause();
|
||||
RefreshChart();
|
||||
foreach (var serie in m_Series.list) serie.AnimationPause();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -691,8 +688,7 @@ namespace XCharts
|
||||
/// </summary>
|
||||
public void AnimationResume()
|
||||
{
|
||||
m_Series.AnimationResume();
|
||||
RefreshChart();
|
||||
foreach (var serie in m_Series.list) serie.AnimationResume();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -701,8 +697,7 @@ namespace XCharts
|
||||
/// </summary>
|
||||
public void AnimationReset()
|
||||
{
|
||||
m_Series.AnimationReset();
|
||||
RefreshChart();
|
||||
foreach (var serie in m_Series.list) serie.AnimationReset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// 标线。
|
||||
/// </summary>
|
||||
public MarkLine markLine
|
||||
{
|
||||
get { return m_MarkLine; }
|
||||
set { if (PropertyUtil.SetClass(ref m_MarkLine, value, true)) SetAllDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// 数据项里的数据维数。
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1911,6 +1923,75 @@ namespace XCharts
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启用或取消初始动画
|
||||
/// </summary>
|
||||
public void AnimationEnable(bool flag)
|
||||
{
|
||||
if (animation.enable) animation.enable = flag;
|
||||
if (markLine.show && markLine.animation.enable) markLine.animation.enable = flag;
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 渐入动画
|
||||
/// </summary>
|
||||
public void AnimationFadeIn()
|
||||
{
|
||||
if (animation.enable) animation.FadeIn();
|
||||
if (markLine.show && markLine.animation.enable) markLine.animation.FadeIn();
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 渐出动画
|
||||
/// </summary>
|
||||
public void AnimationFadeOut()
|
||||
{
|
||||
if (animation.enable) animation.FadeOut();
|
||||
if (markLine.show && markLine.animation.enable) markLine.animation.FadeOut();
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停动画
|
||||
/// </summary>
|
||||
public void AnimationPause()
|
||||
{
|
||||
if (animation.enable) animation.Pause();
|
||||
if (markLine.show && markLine.animation.enable) markLine.animation.Pause();
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 继续动画
|
||||
/// </summary>
|
||||
public void AnimationResume()
|
||||
{
|
||||
if (animation.enable) animation.Resume();
|
||||
if (markLine.show && markLine.animation.enable) markLine.animation.Resume();
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置动画
|
||||
/// </summary>
|
||||
public void AnimationReset()
|
||||
{
|
||||
if (animation.enable) animation.Reset();
|
||||
if (markLine.show && markLine.animation.enable) markLine.animation.Reset();
|
||||
SetVerticesDirty();
|
||||
}
|
||||
/// <summary>
|
||||
/// 重置动画
|
||||
/// </summary>
|
||||
public void AnimationRestart()
|
||||
{
|
||||
if (animation.enable) animation.Restart();
|
||||
if (markLine.show && markLine.animation.enable) markLine.animation.Restart();
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从json中导入数据
|
||||
/// </summary>
|
||||
|
||||
@@ -103,9 +103,9 @@ namespace XCharts
|
||||
/// </summary>
|
||||
public void ClearData()
|
||||
{
|
||||
AnimationFadeIn();
|
||||
foreach (var serie in m_Series)
|
||||
{
|
||||
serie.AnimationFadeIn();
|
||||
serie.ClearData();
|
||||
}
|
||||
}
|
||||
@@ -259,7 +259,7 @@ namespace XCharts
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启用或取消初始动画
|
||||
/// </summary>
|
||||
public void AnimationEnable(bool flag)
|
||||
{
|
||||
foreach (var serie in m_Series)
|
||||
{
|
||||
serie.animation.enable = flag;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 渐入动画
|
||||
/// </summary>
|
||||
public void AnimationFadeIn()
|
||||
{
|
||||
foreach (var serie in m_Series)
|
||||
{
|
||||
if (serie.animation.enable)
|
||||
{
|
||||
serie.animation.FadeIn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 渐出动画
|
||||
/// </summary>
|
||||
public void AnimationFadeOut()
|
||||
{
|
||||
foreach (var serie in m_Series)
|
||||
{
|
||||
if (serie.animation.enable) serie.animation.FadeOut();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停动画
|
||||
/// </summary>
|
||||
public void AnimationPause()
|
||||
{
|
||||
foreach (var serie in m_Series)
|
||||
{
|
||||
if (serie.animation.enable) serie.animation.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 继续动画
|
||||
/// </summary>
|
||||
public void AnimationResume()
|
||||
{
|
||||
foreach (var serie in m_Series)
|
||||
{
|
||||
if (serie.animation.enable) serie.animation.Resume();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置动画
|
||||
/// </summary>
|
||||
public void AnimationReset()
|
||||
{
|
||||
foreach (var serie in m_Series)
|
||||
{
|
||||
if (serie.animation.enable) serie.animation.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
664
Assets/XCharts/Runtime/Component/Sub/MarkLine.cs
Normal file
664
Assets/XCharts/Runtime/Component/Sub/MarkLine.cs
Normal file
@@ -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,
|
||||
/// <summary>
|
||||
/// 最小值。
|
||||
/// </summary>
|
||||
Min,
|
||||
/// <summary>
|
||||
/// 最大值。
|
||||
/// </summary>
|
||||
Max,
|
||||
/// <summary>
|
||||
/// 平均值。
|
||||
/// </summary>
|
||||
Average,
|
||||
/// <summary>
|
||||
/// 中位数。
|
||||
/// </summary>
|
||||
Median
|
||||
}
|
||||
/// <summary>
|
||||
/// Data of marking line.
|
||||
/// 图表标线的数据。
|
||||
/// </summary>
|
||||
[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; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the marker, which will display as a label.
|
||||
/// 标注名称,将会作为文字显示。label的formatter可通过{b}显示名称,通过{c}显示数值。
|
||||
/// </summary>
|
||||
public string name
|
||||
{
|
||||
get { return m_Name; }
|
||||
set { if (PropertyUtil.SetClass(ref m_Name, value)) SetVerticesDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// Special label types, are used to label maximum value, minimum value and so on.
|
||||
/// 特殊的标注类型,用于标注最大值最小值等。
|
||||
/// </summary>
|
||||
public MarkLineType type
|
||||
{
|
||||
get { return m_Type; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_Type, value)) SetVerticesDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// From which dimension of data to calculate the maximum and minimum value and so on.
|
||||
/// 从哪个维度的数据计算最大最小值等。
|
||||
/// </summary>
|
||||
public int dimension
|
||||
{
|
||||
get { return m_Dimension; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_Dimension, value)) SetVerticesDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The x coordinate relative to the origin, in pixels.
|
||||
/// 相对原点的 x 坐标,单位像素。当type为None时有效。
|
||||
/// </summary>
|
||||
public float xPosition
|
||||
{
|
||||
get { return m_XPosition; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_XPosition, value)) SetVerticesDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The y coordinate relative to the origin, in pixels.
|
||||
/// 相对原点的 y 坐标,单位像素。当type为None时有效。
|
||||
/// </summary>
|
||||
public float yPosition
|
||||
{
|
||||
get { return m_YPosition; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_YPosition, value)) SetVerticesDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// 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时有效。
|
||||
/// </summary>
|
||||
public double xValue
|
||||
{
|
||||
get { return m_XValue; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_XValue, value)) SetVerticesDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// 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时有效。
|
||||
/// </summary>
|
||||
public double yValue
|
||||
{
|
||||
get { return m_YValue; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_YValue, value)) SetVerticesDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// 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组成一条标线。
|
||||
/// </summary>
|
||||
public int group
|
||||
{
|
||||
get { return m_Group; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_Group, value)) SetVerticesDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// Is the origin of the coordinate system.
|
||||
/// 是否为坐标系原点。
|
||||
/// </summary>
|
||||
public bool zeroPosition
|
||||
{
|
||||
get { return m_ZeroPosition; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_ZeroPosition, value)) SetVerticesDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The symbol of the start point of markline.
|
||||
/// 起始点的图形标记。
|
||||
/// </summary>
|
||||
public SerieSymbol startSymbol
|
||||
{
|
||||
get { return m_StartSymbol; }
|
||||
set { if (PropertyUtil.SetClass(ref m_StartSymbol, value)) SetVerticesDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The symbol of the end point of markline.
|
||||
/// 结束点的图形标记。
|
||||
/// </summary>
|
||||
public SerieSymbol endSymbol
|
||||
{
|
||||
get { return m_EndSymbol; }
|
||||
set { if (PropertyUtil.SetClass(ref m_EndSymbol, value)) SetVerticesDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The line style of markline.
|
||||
/// 标线样式。
|
||||
/// </summary>
|
||||
public LineStyle lineStyle
|
||||
{
|
||||
get { return m_LineStyle; }
|
||||
set { if (PropertyUtil.SetClass(ref m_LineStyle, value)) SetVerticesDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// Text styles of label. You can set position to Start, Middle, and End to display text in different locations.
|
||||
/// 文本样式。可设置position为Start、Middle和End在不同的位置显示文本。
|
||||
/// </summary>
|
||||
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(); }
|
||||
// }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use a line in the chart to illustrate.
|
||||
/// 图表标线。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class MarkLine : SubComponent
|
||||
{
|
||||
[SerializeField] private bool m_Show;
|
||||
[SerializeField] private SerieAnimation m_Animation = new SerieAnimation();
|
||||
[SerializeField] private List<MarkLineData> m_Data = new List<MarkLineData>();
|
||||
|
||||
/// <summary>
|
||||
/// Whether to display the marking line.
|
||||
/// 是否显示标线。
|
||||
/// </summary>
|
||||
public bool show
|
||||
{
|
||||
get { return m_Show; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetVerticesDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The animation of markline.
|
||||
/// 标线的动画样式。
|
||||
/// </summary>
|
||||
public SerieAnimation animation
|
||||
{
|
||||
get { return m_Animation; }
|
||||
set { if (PropertyUtil.SetClass(ref m_Animation, value)) SetVerticesDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// 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的两个数据项分别表
|
||||
/// 示标线的起始点和终止点来组成一条标线,此时标线的相关样式参数取起始点的参数。
|
||||
/// </summary>
|
||||
public List<MarkLineData> 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<MarkLineData>()
|
||||
};
|
||||
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<int, List<MarkLineData>> m_TempGroupData = new Dictionary<int, List<MarkLineData>>();
|
||||
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<MarkLineData>();
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/XCharts/Runtime/Component/Sub/MarkLine.cs.meta
Normal file
11
Assets/XCharts/Runtime/Component/Sub/MarkLine.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd9631fa54e73444884c717bd04765a6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -58,6 +58,21 @@ namespace XCharts
|
||||
/// 图形标志的右边。
|
||||
/// </summary>
|
||||
Right,
|
||||
/// <summary>
|
||||
/// the start of line.
|
||||
/// 线的起始点。
|
||||
/// </summary>
|
||||
Start,
|
||||
/// <summary>
|
||||
/// the middle of line.
|
||||
/// 线的中点。
|
||||
/// </summary>
|
||||
Middle,
|
||||
/// <summary>
|
||||
/// the end of line.
|
||||
/// 线的结束点。
|
||||
/// </summary>
|
||||
End
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -40,6 +40,10 @@ namespace XCharts
|
||||
/// 不显示标记。
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// 箭头。
|
||||
/// </summary>
|
||||
Arrow
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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<double> s_TempList = new List<double>();
|
||||
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];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum and minimum values of the specified dimension of a serie.
|
||||
/// 获得系列指定维数的最大最小值。
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace XCharts
|
||||
internal bool m_IsPlayingAnimation = false;
|
||||
internal protected List<string> m_LegendRealShowName = new List<string>();
|
||||
protected List<Painter> m_PainterList = new List<Painter>();
|
||||
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>() { 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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user