diff --git a/Documentation~/en/api.md b/Documentation~/en/api.md index c5aa7fd5..980de0cd 100644 --- a/Documentation~/en/api.md +++ b/Documentation~/en/api.md @@ -69,6 +69,8 @@ slug: /api - [SerieDataComponentAttribute](#seriedatacomponentattribute) - [SerieDataContext](#seriedatacontext) - [SerieDataExtraFieldAttribute](#seriedataextrafieldattribute) +- [SerieEventData](#serieeventdata) +- [SerieEventDataPool](#serieeventdatapool) - [SerieHandler](#seriehandler) - [SerieHandler<T>](#seriehandlert) - [SerieHandlerAttribute](#seriehandlerattribute) @@ -870,6 +872,19 @@ Inherits or Implemented: [Attribute](#attribute) | SerieDataExtraFieldAttribute() |public SerieDataExtraFieldAttribute(string field1, string field2, string field3, string field4, string field5, string field6)| | SerieDataExtraFieldAttribute() |public SerieDataExtraFieldAttribute(string field1, string field2, string field3, string field4, string field5, string field6, string field7)| +## SerieEventData + +|public method|description| +|--|--| +| Reset() |public void Reset()| + +## SerieEventDataPool + +|public method|description| +|--|--| +| Get() |public static SerieEventData Get(Vector3 pos, int serieIndex, int dataIndex, int dimension, double value)| +| Release() |public static void Release(SerieEventData toRelease)| + ## SerieHandler |public method|description| @@ -896,6 +911,7 @@ Inherits or Implemented: [Attribute](#attribute) | RefreshLabelNextFrame() |public virtual void RefreshLabelNextFrame() { }| | RemoveComponent() |public virtual void RemoveComponent() { }| | Update() |public virtual void Update() { }| +| UpdateSerieContext() |public virtual void UpdateSerieContext() { }| ## SerieHandler<T> @@ -904,6 +920,8 @@ Inherits or Implemented: [SerieHandler where T](#seriehandler where t),[Serie](# |public method|description| |--|--| | DrawLabelLineSymbol() |public void DrawLabelLineSymbol(VertexHelper vh, LabelLine labelLine, Vector3 startPos, Vector3 endPos, Color32 defaultColor)| +| GetPointerItemDataDimension() |public override int GetPointerItemDataDimension()| +| GetPointerItemDataIndex() |public override int GetPointerItemDataIndex()| | GetSerieDataAutoColor() |public virtual Color GetSerieDataAutoColor(SerieData serieData)| | GetSerieDataLabelOffset() |public virtual Vector3 GetSerieDataLabelOffset(SerieData serieData, LabelStyle label)| | GetSerieDataLabelPosition() |public virtual Vector3 GetSerieDataLabelPosition(SerieData serieData, LabelStyle label)| @@ -912,6 +930,8 @@ Inherits or Implemented: [SerieHandler where T](#seriehandler where t),[Serie](# | OnLegendButtonClick() |public override void OnLegendButtonClick(int index, string legendName, bool show)| | OnLegendButtonEnter() |public override void OnLegendButtonEnter(int index, string legendName)| | OnLegendButtonExit() |public override void OnLegendButtonExit(int index, string legendName)| +| OnPointerClick() |public override void OnPointerClick(PointerEventData eventData)| +| OnPointerDown() |public override void OnPointerDown(PointerEventData eventData)| | RefreshEndLabelInternal() |public virtual void RefreshEndLabelInternal()| | RefreshLabelInternal() |public override void RefreshLabelInternal()| | RefreshLabelNextFrame() |public override void RefreshLabelNextFrame()| diff --git a/Documentation~/zh/api.md b/Documentation~/zh/api.md index 5a9f3078..42d4dae3 100644 --- a/Documentation~/zh/api.md +++ b/Documentation~/zh/api.md @@ -69,6 +69,8 @@ slug: /api - [SerieDataComponentAttribute](#seriedatacomponentattribute) - [SerieDataContext](#seriedatacontext) - [SerieDataExtraFieldAttribute](#seriedataextrafieldattribute) +- [SerieEventData](#serieeventdata) +- [SerieEventDataPool](#serieeventdatapool) - [SerieHandler](#seriehandler) - [SerieHandler<T>](#seriehandlert) - [SerieHandlerAttribute](#seriehandlerattribute) @@ -870,6 +872,19 @@ Inherits or Implemented: [Attribute](#attribute) | SerieDataExtraFieldAttribute() |public SerieDataExtraFieldAttribute(string field1, string field2, string field3, string field4, string field5, string field6)| | SerieDataExtraFieldAttribute() |public SerieDataExtraFieldAttribute(string field1, string field2, string field3, string field4, string field5, string field6, string field7)| +## SerieEventData + +|public method|description| +|--|--| +| Reset() |public void Reset()| + +## SerieEventDataPool + +|public method|description| +|--|--| +| Get() |public static SerieEventData Get(Vector3 pos, int serieIndex, int dataIndex, int dimension, double value)| +| Release() |public static void Release(SerieEventData toRelease)| + ## SerieHandler |public method|description| @@ -896,6 +911,7 @@ Inherits or Implemented: [Attribute](#attribute) | RefreshLabelNextFrame() |public virtual void RefreshLabelNextFrame() { }| | RemoveComponent() |public virtual void RemoveComponent() { }| | Update() |public virtual void Update() { }| +| UpdateSerieContext() |public virtual void UpdateSerieContext() { }| ## SerieHandler<T> @@ -904,6 +920,8 @@ Inherits or Implemented: [SerieHandler where T](#seriehandler where t),[Serie](# |public method|description| |--|--| | DrawLabelLineSymbol() |public void DrawLabelLineSymbol(VertexHelper vh, LabelLine labelLine, Vector3 startPos, Vector3 endPos, Color32 defaultColor)| +| GetPointerItemDataDimension() |public override int GetPointerItemDataDimension()| +| GetPointerItemDataIndex() |public override int GetPointerItemDataIndex()| | GetSerieDataAutoColor() |public virtual Color GetSerieDataAutoColor(SerieData serieData)| | GetSerieDataLabelOffset() |public virtual Vector3 GetSerieDataLabelOffset(SerieData serieData, LabelStyle label)| | GetSerieDataLabelPosition() |public virtual Vector3 GetSerieDataLabelPosition(SerieData serieData, LabelStyle label)| @@ -912,6 +930,8 @@ Inherits or Implemented: [SerieHandler where T](#seriehandler where t),[Serie](# | OnLegendButtonClick() |public override void OnLegendButtonClick(int index, string legendName, bool show)| | OnLegendButtonEnter() |public override void OnLegendButtonEnter(int index, string legendName)| | OnLegendButtonExit() |public override void OnLegendButtonExit(int index, string legendName)| +| OnPointerClick() |public override void OnPointerClick(PointerEventData eventData)| +| OnPointerDown() |public override void OnPointerDown(PointerEventData eventData)| | RefreshEndLabelInternal() |public virtual void RefreshEndLabelInternal()| | RefreshLabelInternal() |public override void RefreshLabelInternal()| | RefreshLabelNextFrame() |public override void RefreshLabelNextFrame()| diff --git a/Documentation~/zh/changelog.md b/Documentation~/zh/changelog.md index 694e2d9d..872efefb 100644 --- a/Documentation~/zh/changelog.md +++ b/Documentation~/zh/changelog.md @@ -65,6 +65,8 @@ slug: /changelog ## master +* (2023.03.09) 增加`Chart`的`onSerieClick`,`onSerieDown`,`onSerieEnter`和`onSerieExit`回调 +* (2023.03.09) 修复`Pie`的点击选中偏移不生效的问题 * (2023.03.04) 增加`Legend`的`Positions`可自定义图例的位置 * (2023.03.03) 修复`Animation`变更动画可能无效的问题 * (2023.02.28) 修复`Legend`点击时`Serie`的`Label`不刷新的问题 diff --git a/Editor/Series/PieEditor.cs b/Editor/Series/PieEditor.cs index 7a66372f..f8e19be5 100644 --- a/Editor/Series/PieEditor.cs +++ b/Editor/Series/PieEditor.cs @@ -18,6 +18,7 @@ namespace XCharts.Editor PropertyField("m_RoundCap"); PropertyField("m_Ignore"); PropertyField("m_IgnoreValue"); + PropertyField("m_ClickOffset"); }); PropertyField("m_ItemStyle"); PropertyField("m_Animation"); diff --git a/Examples/Example30_PieChart.cs b/Examples/Example30_PieChart.cs index e6e5f912..a92d19b7 100644 --- a/Examples/Example30_PieChart.cs +++ b/Examples/Example30_PieChart.cs @@ -64,7 +64,7 @@ namespace XCharts.Example chart.AddData(0, 135, "视频广告"); chart.AddData(0, 1548, "搜索引擎"); - chart.onPointerClickPie = delegate (PointerEventData e, int serieIndex, int dataIndex) + chart.onSerieClick = delegate (SerieEventData data) { }; diff --git a/Examples/Example_Test.cs b/Examples/Example_Test.cs index 33018a71..b70b7c5c 100644 --- a/Examples/Example_Test.cs +++ b/Examples/Example_Test.cs @@ -1,4 +1,5 @@ using UnityEngine; +using UnityEngine.EventSystems; using UnityEngine.UI; using XCharts.Runtime; #if INPUT_SYSTEM_ENABLED @@ -14,6 +15,9 @@ namespace XCharts.Example void Awake() { chart = gameObject.GetComponent(); + chart.onSerieClick = OnPointerClickLine; + chart.onSerieEnter = OnPointerEnterLine; + chart.onSerieExit = OnPointerExitLine; var btnTrans = transform.parent.Find("Button"); if (btnTrans) { @@ -21,6 +25,21 @@ namespace XCharts.Example } } + void OnPointerClickLine(SerieEventData data) + { + Debug.Log("OnPointerClick: " + data.serieIndex+ " " + data.dataIndex +" "+ data.dimension); + } + + void OnPointerEnterLine(SerieEventData data) + { + Debug.Log("OnPointerEnter: " + data.serieIndex + " " + data.dataIndex + " " + data.dimension); + } + + void OnPointerExitLine(SerieEventData data) + { + Debug.Log("OnPointerExit: " + data.serieIndex + " " + data.dataIndex + " " + data.dimension); + } + void Update() { if (Input.GetKeyDown(KeyCode.Space)) diff --git a/README.md b/README.md index b1bf2f3c..4bf30cd0 100644 --- a/README.md +++ b/README.md @@ -18,27 +18,27 @@ - + - + - + - +

- + - + - +

diff --git a/Runtime/Internal/BaseChart.API.cs b/Runtime/Internal/BaseChart.API.cs index 76c8c953..fb8cf4d0 100644 --- a/Runtime/Internal/BaseChart.API.cs +++ b/Runtime/Internal/BaseChart.API.cs @@ -104,21 +104,48 @@ namespace XCharts.Runtime /// public CustomDrawGaugePointerFunction customDrawGaugePointerFunction { set { m_CustomDrawGaugePointerFunction = value; } get { return m_CustomDrawGaugePointerFunction; } } /// + /// the callback function of pointer click serie. + /// |鼠标点击Serie回调。 + /// + [Since("v3.6.0")] + public Action onSerieClick { set { m_OnSerieClick = value; m_ForceOpenRaycastTarget = true; } get { return m_OnSerieClick; } } + /// + /// the callback function of pointer down serie. + /// |鼠标按下Serie回调。 + /// + [Since("v3.6.0")] + public Action onSerieDown { set { m_OnSerieDown = value; m_ForceOpenRaycastTarget = true; } get { return m_OnSerieDown; } } + /// + /// the callback function of pointer enter serie. + /// |鼠标进入Serie回调。 + /// + [Since("v3.6.0")] + public Action onSerieEnter { set { m_OnSerieEnter = value; m_ForceOpenRaycastTarget = true; } get { return m_OnSerieEnter; } } + /// + /// the callback function of pointer exit serie. + /// |鼠标离开Serie回调。 + /// + [Since("v3.6.0")] + public Action onSerieExit { set { m_OnSerieExit = value; m_ForceOpenRaycastTarget = true; } get { return m_OnSerieExit; } } + /// /// the callback function of pointer click pie area. /// |点击饼图区域回调。参数:PointerEventData,SerieIndex,SerieDataIndex /// - public Action onPointerClickPie { set { m_OnPointerClickPie = value; m_ForceOpenRaycastTarget = true; } get { return m_OnPointerClickPie; } } + [Obsolete("Use \"onSerieClick\" instead", true)] + public Action onPointerClickPie { get; set; } /// /// the callback function of pointer enter pie area. /// |鼠标进入和离开饼图区域回调,SerieDataIndex为-1时表示离开。参数:PointerEventData,SerieIndex,SerieDataIndex /// [Since("v3.3.0")] + [Obsolete("Use \"onSerieEnter\" instead", true)] public Action onPointerEnterPie { set { m_OnPointerEnterPie = value; m_ForceOpenRaycastTarget = true; } get { return m_OnPointerEnterPie; } } /// /// the callback function of click bar. /// |点击柱形图柱条回调。参数:eventData, dataIndex /// - public Action onPointerClickBar { set { m_OnPointerClickBar = value; m_ForceOpenRaycastTarget = true; } get { return m_OnPointerClickBar; } } + [Obsolete("Use \"onSerieClick\" instead", true)] + public Action onPointerClickBar { get; set; } /// /// 坐标轴变更数据索引时回调。参数:axis, dataIndex/dataValue /// diff --git a/Runtime/Internal/BaseChart.cs b/Runtime/Internal/BaseChart.cs index 3d90a2d3..46b3d4f9 100644 --- a/Runtime/Internal/BaseChart.cs +++ b/Runtime/Internal/BaseChart.cs @@ -89,9 +89,11 @@ namespace XCharts.Runtime protected Action m_OnDrawTop; protected Action m_OnDrawSerieBefore; protected Action m_OnDrawSerieAfter; - protected Action m_OnPointerClickPie; + protected Action m_OnSerieClick; + protected Action m_OnSerieDown; + protected Action m_OnSerieEnter; + protected Action m_OnSerieExit; protected Action m_OnPointerEnterPie; - protected Action m_OnPointerClickBar; protected Action m_OnAxisPointerValueChanged; protected Action m_OnLegendClick; protected Action m_OnLegendEnter; diff --git a/Runtime/Internal/BaseGraph.cs b/Runtime/Internal/BaseGraph.cs index d5481354..b9ffb696 100644 --- a/Runtime/Internal/BaseGraph.cs +++ b/Runtime/Internal/BaseGraph.cs @@ -228,7 +228,7 @@ namespace XCharts.Runtime protected virtual void CheckRefreshChart() { - if (m_RefreshChart) + if (m_RefreshChart && m_Painter != null) { m_Painter.Refresh(); m_RefreshChart = false; @@ -237,6 +237,7 @@ namespace XCharts.Runtime protected virtual void CheckRefreshPainter() { + if (m_Painter == null) return; m_Painter.CheckRefresh(); } diff --git a/Runtime/Internal/Misc/SerieEventData.cs b/Runtime/Internal/Misc/SerieEventData.cs new file mode 100644 index 00000000..4d3ff773 --- /dev/null +++ b/Runtime/Internal/Misc/SerieEventData.cs @@ -0,0 +1,46 @@ +using UnityEngine; + +namespace XCharts.Runtime +{ + /// + /// the data of serie event. + /// |serie事件的数据。 + /// + public class SerieEventData + { + /// + /// the position of pointer in chart. + /// |鼠标在chart中的位置。 + /// + public Vector3 pointerPos { get; set; } + /// + /// the index of serie in chart.series. + /// |在chart.series中的索引。 + /// + public int serieIndex { get; set; } + /// + /// the index of data in serie.data. + /// |在serie.data中的索引。 + /// + public int dataIndex { get; set; } + /// + /// the dimension of data. + /// |数据的维度。 + /// + public int dimension { get; set; } + /// + /// the value of data. + /// |数据的值。 + /// + public double value { get; set; } + + public void Reset() + { + serieIndex = -1; + dataIndex = -1; + dimension = -1; + value = 0; + pointerPos = Vector3.zero; + } + } +} \ No newline at end of file diff --git a/Runtime/Internal/Misc/SerieEventData.cs.meta b/Runtime/Internal/Misc/SerieEventData.cs.meta new file mode 100644 index 00000000..8d23ec0c --- /dev/null +++ b/Runtime/Internal/Misc/SerieEventData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fdfaa773d93294d78b2fb4b8f42708a3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Internal/Pools/SerieEventDataPool.cs b/Runtime/Internal/Pools/SerieEventDataPool.cs new file mode 100644 index 00000000..899d51f0 --- /dev/null +++ b/Runtime/Internal/Pools/SerieEventDataPool.cs @@ -0,0 +1,33 @@ +using UnityEngine; + +namespace XCharts.Runtime +{ + public static class SerieEventDataPool + { + private static readonly ObjectPool s_ListPool = new ObjectPool(null, OnClear); + + static void OnGet(SerieEventData data) + { + } + + static void OnClear(SerieEventData data) + { + data.Reset(); + } + + public static SerieEventData Get(Vector3 pos, int serieIndex, int dataIndex, int dimension, double value) + { + var data = s_ListPool.Get(); + data.serieIndex = serieIndex; + data.dataIndex = dataIndex; + data.pointerPos = pos; + data.dimension = dimension; + return data; + } + + public static void Release(SerieEventData toRelease) + { + s_ListPool.Release(toRelease); + } + } +} \ No newline at end of file diff --git a/Runtime/Internal/Pools/SerieEventDataPool.cs.meta b/Runtime/Internal/Pools/SerieEventDataPool.cs.meta new file mode 100644 index 00000000..40316cc8 --- /dev/null +++ b/Runtime/Internal/Pools/SerieEventDataPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 30d123dd5c38446f18183f50336322bb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Internal/Utilities/ChartHelper.cs b/Runtime/Internal/Utilities/ChartHelper.cs index f2894d03..8578120e 100644 --- a/Runtime/Internal/Utilities/ChartHelper.cs +++ b/Runtime/Internal/Utilities/ChartHelper.cs @@ -161,11 +161,11 @@ namespace XCharts.Runtime { #if UNITY_EDITOR if (!Application.isPlaying) - GameObject.DestroyImmediate(component as GameObject, true); + GameObject.DestroyImmediate(component as UnityEngine.Object); else - GameObject.Destroy(component as GameObject); + GameObject.Destroy(component as UnityEngine.Object); #else - GameObject.Destroy(component as GameObject); + GameObject.Destroy(component as UnityEngine.Object); #endif } } @@ -389,6 +389,7 @@ namespace XCharts.Runtime var alignment = textStyle.GetAlignment(autoAlignment); UpdateAnchorAndPivotByTextAlignment(alignment, out anchorMin, out anchorMax, out pivot); var labelObj = AddObject(name, parent, anchorMin, anchorMax, pivot, sizeDelta); + ChartHelper.RemoveComponent(labelObj); var label = EnsureComponent(labelObj); label.text = AddTextObject("Text", label.gameObject.transform, anchorMin, anchorMax, pivot, sizeDelta, textStyle, theme, autoColor, autoAlignment, label.text); diff --git a/Runtime/Serie/Bar/BarHandler.cs b/Runtime/Serie/Bar/BarHandler.cs index 3f8c5707..bde1fcc3 100644 --- a/Runtime/Serie/Bar/BarHandler.cs +++ b/Runtime/Serie/Bar/BarHandler.cs @@ -78,16 +78,6 @@ namespace XCharts.Runtime } } - public override void OnPointerDown(PointerEventData eventData) - { - if (!serie.context.pointerEnter) return; - if (serie.context.pointerItemDataIndex < 0) return; - if (chart.onPointerClickBar != null) - { - chart.onPointerClickBar(eventData, serie.context.pointerItemDataIndex); - } - } - private void UpdateSerieGridContext() { if (m_SerieGrid == null) @@ -240,7 +230,7 @@ namespace XCharts.Runtime if (isPercentStack) { var valueTotal = chart.GetSerieSameStackTotalValue(serie.stack, i); - barHig = valueTotal != 0 ? (float) (relativedValue / valueTotal * relativedAxisLength) : 0; + barHig = valueTotal != 0 ? (float)(relativedValue / valueTotal * relativedAxisLength) : 0; } else { @@ -314,7 +304,7 @@ namespace XCharts.Runtime if (axis.context.minMaxRange <= 0) pY = grid.context.y; else { - var valueLen = (float) ((value - axis.context.minValue) / axis.context.minMaxRange) * grid.context.height; + var valueLen = (float)((value - axis.context.minValue) / axis.context.minMaxRange) * grid.context.height; pY = grid.context.y + valueLen - categoryWidth * 0.5f; } } @@ -336,7 +326,7 @@ namespace XCharts.Runtime if (axis.context.minMaxRange <= 0) pX = grid.context.x; else { - var valueLen = (float) ((value - axis.context.minValue) / axis.context.minMaxRange) * grid.context.width; + var valueLen = (float)((value - axis.context.minValue) / axis.context.minMaxRange) * grid.context.width; pX = grid.context.x + valueLen - categoryWidth * 0.5f; } } diff --git a/Runtime/Serie/Bar/SimplifiedBarHandler.cs b/Runtime/Serie/Bar/SimplifiedBarHandler.cs index c70f4a7c..508481fe 100644 --- a/Runtime/Serie/Bar/SimplifiedBarHandler.cs +++ b/Runtime/Serie/Bar/SimplifiedBarHandler.cs @@ -14,7 +14,6 @@ namespace XCharts.Runtime public override void Update() { base.Update(); - UpdateSerieContext(); } public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category, @@ -30,7 +29,7 @@ namespace XCharts.Runtime DrawBarSerie(vh, serie, serie.context.colorIndex); } - private void UpdateSerieContext() + public override void UpdateSerieContext() { if (m_SerieGrid == null) return; diff --git a/Runtime/Serie/Heatmap/HeatmapHandler.cs b/Runtime/Serie/Heatmap/HeatmapHandler.cs index 45984f16..262a908a 100644 --- a/Runtime/Serie/Heatmap/HeatmapHandler.cs +++ b/Runtime/Serie/Heatmap/HeatmapHandler.cs @@ -27,10 +27,6 @@ namespace XCharts.Runtime public override void Update() { base.Update(); - if (serie.IsUseCoord()) - UpdateSerieContext(); - else if (serie.IsUseCoord()) - UpdateSeriePolarContext(); } public override void DrawSerie(VertexHelper vh) @@ -97,7 +93,7 @@ namespace XCharts.Runtime { var xAxis = chart.GetChartComponent(serie.xAxisIndex); if (xAxis != null) - category = xAxis.GetData((int) serieData.GetData(0)); + category = xAxis.GetData((int)serieData.GetData(0)); } title = serie.serieName; @@ -121,7 +117,15 @@ namespace XCharts.Runtime } } - private void UpdateSerieContext() + public override void UpdateSerieContext() + { + if (serie.IsUseCoord()) + UpdateSerieGridContext(); + else if (serie.IsUseCoord()) + UpdateSeriePolarContext(); + } + + private void UpdateSerieGridContext() { if (m_SerieGrid == null) return; diff --git a/Runtime/Serie/Line/LineHandler.cs b/Runtime/Serie/Line/LineHandler.cs index 10a5c5be..6ff1865c 100644 --- a/Runtime/Serie/Line/LineHandler.cs +++ b/Runtime/Serie/Line/LineHandler.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Text; using UnityEngine; +using UnityEngine.EventSystems; using UnityEngine.UI; using XUGL; @@ -69,7 +70,7 @@ namespace XCharts.Runtime var endLabelList = m_SerieGrid.context.endLabelList; if (endLabelList.Count <= 1) return; - endLabelList.Sort(delegate(ChartLabel a, ChartLabel b) + endLabelList.Sort(delegate (ChartLabel a, ChartLabel b) { if (a == null || b == null) return 1; return b.transform.position.y.CompareTo(a.transform.position.y); @@ -96,5 +97,27 @@ namespace XCharts.Runtime } } } + + public override int GetPointerItemDataIndex() + { + var symbolSize = SerieHelper.GetSysmbolSize(serie, null, chart.theme, chart.theme.serie.lineSymbolSize) * 1.5f; + var count = serie.context.dataPoints.Count; + for (int i = 0; i < count; i++) + { + var index = serie.context.dataIndexs[i]; + var serieData = serie.GetSerieData(index); + if (serieData == null) + continue; + if (serieData.context.isClip) + continue; + + var pos = serie.context.dataPoints[i]; + if (Vector2.Distance(pos, chart.pointerPos) < symbolSize) + { + return i; + } + } + return -1; + } } } \ No newline at end of file diff --git a/Runtime/Serie/Line/SimplifiedLineHandler.cs b/Runtime/Serie/Line/SimplifiedLineHandler.cs index d480010b..2e84beea 100644 --- a/Runtime/Serie/Line/SimplifiedLineHandler.cs +++ b/Runtime/Serie/Line/SimplifiedLineHandler.cs @@ -15,7 +15,6 @@ namespace XCharts.Runtime public override void Update() { base.Update(); - UpdateSerieContext(); } public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category, @@ -31,7 +30,7 @@ namespace XCharts.Runtime DrawLineSerie(vh, serie); } - private void UpdateSerieContext() + public override void UpdateSerieContext() { if (m_SerieGrid == null) return; diff --git a/Runtime/Serie/Parallel/ParallelHandler.cs b/Runtime/Serie/Parallel/ParallelHandler.cs index 26a5be3b..5c957c1d 100644 --- a/Runtime/Serie/Parallel/ParallelHandler.cs +++ b/Runtime/Serie/Parallel/ParallelHandler.cs @@ -11,7 +11,6 @@ namespace XCharts.Runtime public override void Update() { base.Update(); - UpdateSerieContext(); } public override void DrawSerie(VertexHelper vh) @@ -19,8 +18,6 @@ namespace XCharts.Runtime DrawParallelSerie(vh, serie); } - private void UpdateSerieContext() { } - private void DrawParallelSerie(VertexHelper vh, Parallel serie) { if (!serie.show) return; diff --git a/Runtime/Serie/Pie/PieHandler.cs b/Runtime/Serie/Pie/PieHandler.cs index 654403c1..f58b9aa2 100644 --- a/Runtime/Serie/Pie/PieHandler.cs +++ b/Runtime/Serie/Pie/PieHandler.cs @@ -12,7 +12,6 @@ namespace XCharts.Runtime public override void Update() { base.Update(); - UpdateSerieContext(); } public override void DrawBase(VertexHelper vh) @@ -79,32 +78,28 @@ namespace XCharts.Runtime public override void OnPointerDown(PointerEventData eventData) { - if (!chart.HasSerie()) return; if (chart.pointerPos == Vector2.zero) return; + var dataIndex = GetPiePosIndex(serie, chart.pointerPos); var refresh = false; - for (int i = 0; i < chart.series.Count; i++) + if (dataIndex >= 0) { - var serie = chart.GetSerie(i); - if (!(serie is Pie)) continue; - var index = GetPiePosIndex(serie, chart.pointerPos); - if (index >= 0) + refresh = true; + for (int j = 0; j < serie.data.Count; j++) { - refresh = true; - for (int j = 0; j < serie.data.Count; j++) - { - if (j == index) serie.data[j].context.selected = !serie.data[j].context.selected; - else serie.data[j].context.selected = false; - } - if (chart.onPointerClickPie != null) - { - chart.onPointerClickPie(eventData, i, index); - } + if (j == dataIndex) serie.data[j].context.selected = !serie.data[j].context.selected; + else serie.data[j].context.selected = false; } } if (refresh) chart.RefreshChart(); + base.OnPointerDown(eventData); } - private void UpdateSerieContext() + public override int GetPointerItemDataIndex() + { + return GetPiePosIndex(serie, chart.pointerPos); + } + + public override void UpdateSerieContext() { var needCheck = m_LegendEnter || (chart.isPointerInChart && PointerIsInPieSerie(serie, chart.pointerPos)); var needInteract = false; @@ -123,14 +118,8 @@ namespace XCharts.Runtime serieData.context.highlight = false; serieData.interact.SetValueAndColor(ref needInteract, serieData.context.outsideRadius, color, toColor); } - if (chart.onPointerEnterPie != null) - { - chart.onPointerEnterPie(serie.index, serie.context.pointerItemDataIndex); - } if (needInteract) - { chart.RefreshPainter(serie); - } } return; } @@ -138,6 +127,7 @@ namespace XCharts.Runtime var lastPointerItemDataIndex = serie.context.pointerItemDataIndex; var dataIndex = GetPiePosIndex(serie, chart.pointerPos); serie.context.pointerItemDataIndex = -1; + serie.context.pointerEnter = dataIndex >= 0; for (int i = 0; i < serie.dataCount; i++) { var serieData = serie.data[i]; @@ -162,10 +152,6 @@ namespace XCharts.Runtime if (lastPointerItemDataIndex != serie.context.pointerItemDataIndex) { needInteract = true; - if (chart.onPointerEnterPie != null) - { - chart.onPointerEnterPie(serie.index, serie.context.pointerItemDataIndex); - } } if (needInteract) { @@ -220,21 +206,21 @@ namespace XCharts.Runtime } float degree = serie.pieRoseType == RoseType.Area ? (totalDegree / showdataCount) : - (float) (totalDegree * value / dataTotalFilterMinAngle); + (float)(totalDegree * value / dataTotalFilterMinAngle); if (serie.minAngle > 0 && degree < serie.minAngle) degree = serie.minAngle; serieData.context.toAngle = startDegree + degree; if (serieData.radius > 0) serieData.context.outsideRadius = ChartHelper.GetActualValue(serieData.radius, Mathf.Min(chart.chartWidth, chart.chartHeight)); else serieData.context.outsideRadius = serie.pieRoseType > 0 ? - serie.context.insideRadius + (float) ((serie.context.outsideRadius - serie.context.insideRadius) * value / serie.context.dataMax) : + serie.context.insideRadius + (float)((serie.context.outsideRadius - serie.context.insideRadius) * value / serie.context.dataMax) : serie.context.outsideRadius; if (serieData.context.highlight) { serieData.context.outsideRadius += chart.theme.serie.pieTooltipExtraRadius; } var offset = 0f; - if (serie.pieClickOffset && serieData.selected) + if (serie.pieClickOffset && (serieData.selected || serieData.context.selected)) { offset += chart.theme.serie.pieSelectedOffset; } @@ -258,7 +244,7 @@ namespace XCharts.Runtime serieData.context.offsetRadius = 0; serieData.context.insideRadius -= serieData.context.offsetRadius; serieData.context.outsideRadius -= serieData.context.offsetRadius; - if (serie.pieClickOffset && serieData.selected) + if (serie.pieClickOffset && (serieData.selected || serieData.context.selected)) { serieData.context.offsetRadius += chart.theme.serie.pieSelectedOffset; if (serieData.context.insideRadius > 0) @@ -350,7 +336,7 @@ namespace XCharts.Runtime serieData.interact.SetValueAndColor(ref interacting, outsideRadius, color, toColor); } - if (serie.pieClickOffset && serieData.selected) + if (serie.pieClickOffset && (serieData.selected || serieData.context.selected)) { var drawEndDegree = serieData.context.currentAngle; var needRoundCap = serie.roundCap && insideRadius > 0; @@ -493,7 +479,7 @@ namespace XCharts.Runtime } var diffAngle = (currAngle - startAngle) % 360; var isLeft = diffAngle > 180 || (diffAngle == 0 && serieData.context.startAngle > 0); - var pos5X = isLeft?pos2.x - labelLine.lineLength2 : pos2.x + labelLine.lineLength2; + var pos5X = isLeft ? pos2.x - labelLine.lineLength2 : pos2.x + labelLine.lineLength2; var pos5 = new Vector3(pos5X, pos2.y); var angle = Vector3.Angle(pos1 - center, pos2 - pos1); if (angle > 15) @@ -538,7 +524,7 @@ namespace XCharts.Runtime var serieData = serie.data[i]; if (angle >= serieData.context.startAngle && angle <= serieData.context.toAngle) { - var ndist = serieData.selected ? + var ndist = (serieData.selected || serieData.context.selected) ? Vector2.Distance(local, serieData.context.offsetCenter) : dist; if (ndist >= serieData.context.insideRadius && ndist <= serieData.context.outsideRadius) diff --git a/Runtime/Serie/Radar/RadarHandler.cs b/Runtime/Serie/Radar/RadarHandler.cs index 8fb0d2fb..d43a6667 100644 --- a/Runtime/Serie/Radar/RadarHandler.cs +++ b/Runtime/Serie/Radar/RadarHandler.cs @@ -12,7 +12,6 @@ namespace XCharts.Runtime public override void Update() { base.Update(); - UpdateSerieContext(); } public override void DrawSerie(VertexHelper vh) @@ -86,22 +85,33 @@ namespace XCharts.Runtime } } - private void UpdateSerieContext() + public override void UpdateSerieContext() { var needCheck = m_LegendEnter || (chart.isPointerInChart && (m_RadarCoord != null && m_RadarCoord.IsPointerEnter())); var needInteract = false; - var needHideAll = false; if (!needCheck) { - if (m_LastCheckContextFlag == needCheck) - return; - needHideAll = true; + if (m_LastCheckContextFlag != needCheck) + { + m_LastCheckContextFlag = needCheck; + serie.context.pointerItemDataIndex = -1; + serie.context.pointerItemDataDimension = -1; + serie.context.pointerEnter = false; + foreach (var serieData in serie.data) + { + serieData.context.highlight = false; + serieData.interact.Reset(); + } + chart.RefreshPainter(serie); + } + return; } m_LastCheckContextFlag = needCheck; serie.highlight = false; serie.context.pointerEnter = false; serie.context.pointerItemDataIndex = -1; + serie.context.pointerItemDataDimension = -1; var areaStyle = serie.areaStyle; var themeSymbolSize = chart.theme.serie.lineSymbolSize; switch (serie.radarType) @@ -112,21 +122,23 @@ namespace XCharts.Runtime var serieData = serie.data[i]; var symbol = SerieHelper.GetSerieSymbol(serie, serieData); var symbolSize = symbol.GetSize(serieData.data, chart.theme.serie.lineSymbolSize); - if (needHideAll || m_LegendEnter) + if (m_LegendEnter) { - serieData.context.highlight = needHideAll ? false : true; + serieData.context.highlight = true; serieData.interact.SetValue(ref needInteract, symbolSize, serieData.context.highlight); } else { serieData.context.highlight = false; - foreach (var pos in serieData.context.dataPoints) + for (int n = 0; n < serieData.context.dataPoints.Count; n++) { + var pos = serieData.context.dataPoints[n]; if (Vector3.Distance(chart.pointerPos, pos) < symbolSize * 2) { serie.highlight = true; serie.context.pointerEnter = true; serie.context.pointerItemDataIndex = i; + serie.context.pointerItemDataDimension = n; serieData.context.highlight = true; break; } @@ -144,6 +156,7 @@ namespace XCharts.Runtime serie.highlight = true; serie.context.pointerEnter = true; serie.context.pointerItemDataIndex = i; + serie.context.pointerItemDataDimension = n; serieData.context.highlight = true; break; } @@ -163,6 +176,7 @@ namespace XCharts.Runtime { serie.context.pointerEnter = true; serie.context.pointerItemDataIndex = i; + serie.context.pointerItemDataDimension = 1; serieData.context.highlight = true; needInteract = true; } @@ -183,6 +197,7 @@ namespace XCharts.Runtime { serie.context.pointerEnter = true; serie.context.pointerItemDataIndex = n; + serie.context.pointerItemDataDimension = 1; p1.context.highlight = true; needInteract = true; break; @@ -264,7 +279,7 @@ namespace XCharts.Runtime max = serie.context.dataMax; } } - var radius = (float) (m_RadarCoord.context.dataRadius * (value - min) / (max - min)); + var radius = (float)(m_RadarCoord.context.dataRadius * (value - min) / (max - min)); var currAngle = startAngle + (n + (m_RadarCoord.positionType == RadarCoord.PositionType.Between ? 0.5f : 0)) * angle; radius *= rate; if (n == 0) @@ -380,7 +395,7 @@ namespace XCharts.Runtime } var lineStyle = SerieHelper.GetLineStyle(serie, serieData); Color32 areaColor, areaToColor; - var colorIndex = serie.colorByData?j : serie.context.colorIndex; + var colorIndex = serie.colorByData ? j : serie.context.colorIndex; var showArea = SerieHelper.GetAreaColor(out areaColor, out areaToColor, serie, serieData, chart.theme, colorIndex - 1); var lineColor = SerieHelper.GetLineColor(serie, serieData, chart.theme, colorIndex); int dataCount = m_RadarCoord.indicatorList.Count; @@ -397,7 +412,7 @@ namespace XCharts.Runtime { lineColor = m_RadarCoord.outRangeColor; } - var radius = (float) (max < 0 ? m_RadarCoord.context.dataRadius - m_RadarCoord.context.dataRadius * value / max : + var radius = (float)(max < 0 ? m_RadarCoord.context.dataRadius - m_RadarCoord.context.dataRadius * value / max : m_RadarCoord.context.dataRadius * value / max); var currAngle = startAngle + (index + (m_RadarCoord.positionType == RadarCoord.PositionType.Between ? 0.5f : 0)) * angle; radius *= rate; diff --git a/Runtime/Serie/Ring/RingHandler.cs b/Runtime/Serie/Ring/RingHandler.cs index 08fdcd29..f31021e9 100644 --- a/Runtime/Serie/Ring/RingHandler.cs +++ b/Runtime/Serie/Ring/RingHandler.cs @@ -16,10 +16,9 @@ namespace XCharts.Runtime public override void Update() { base.Update(); - UpdateSerieContext(); } - private void UpdateSerieContext() + public override void UpdateSerieContext() { var needCheck = chart.isPointerInChart || m_LegendEnter; var needInteract = false; diff --git a/Runtime/Serie/Scatter/BaseScatterHandler.cs b/Runtime/Serie/Scatter/BaseScatterHandler.cs index eb0b895a..6be8113c 100644 --- a/Runtime/Serie/Scatter/BaseScatterHandler.cs +++ b/Runtime/Serie/Scatter/BaseScatterHandler.cs @@ -13,7 +13,6 @@ namespace XCharts.Runtime public override void Update() { base.Update(); - UpdateSerieContext(); } public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category, @@ -63,7 +62,7 @@ namespace XCharts.Runtime } } - private void UpdateSerieContext() + public override void UpdateSerieContext() { var needCheck = m_LegendEnter || (chart.isPointerInChart && (m_Grid == null || m_Grid.IsPointerEnter())); diff --git a/Runtime/Serie/Serie.cs b/Runtime/Serie/Serie.cs index 1f0e47ce..31b9b02d 100644 --- a/Runtime/Serie/Serie.cs +++ b/Runtime/Serie/Serie.cs @@ -309,6 +309,27 @@ namespace XCharts.Runtime [NonSerialized] public List m_FilterData = new List(); [NonSerialized] private bool m_NameDirty; + /// + /// event callback when click serie. + /// |点击系列时的回调。 + /// + public Action onClick { get; set; } + /// + /// event callback when mouse down on serie. + /// |鼠标按下时的回调。 + /// + public Action onDown { get; set; } + /// + /// event callback when mouse enter serie. + /// |鼠标进入时的回调。 + /// + public Action onEnter { get; set; } + /// + /// event callback when mouse leave serie. + /// |鼠标离开时的回调。 + /// + public Action onExit { get; set; } + /// /// The index of serie. /// |系列索引。 diff --git a/Runtime/Serie/SerieContext.cs b/Runtime/Serie/SerieContext.cs index 4408e499..12b98f0d 100644 --- a/Runtime/Serie/SerieContext.cs +++ b/Runtime/Serie/SerieContext.cs @@ -26,6 +26,10 @@ namespace XCharts.Runtime /// public int pointerItemDataIndex = -1; /// + /// 鼠标当前指示的数据项维度 + /// + public int pointerItemDataDimension = 1; + /// /// 鼠标所在轴线上的数据项索引(可能有多个) /// public List pointerAxisDataIndexs = new List(); diff --git a/Runtime/Serie/SerieHandler.cs b/Runtime/Serie/SerieHandler.cs index 184983a3..65762406 100644 --- a/Runtime/Serie/SerieHandler.cs +++ b/Runtime/Serie/SerieHandler.cs @@ -31,14 +31,18 @@ namespace XCharts.Runtime public virtual void OnScroll(PointerEventData eventData) { } public virtual void RefreshLabelNextFrame() { } public virtual void RefreshLabelInternal() { } + public virtual void UpdateSerieContext() { } public virtual void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category, string marker, string itemFormatter, string numericFormatter, string ignoreDataDefaultContent, - ref List paramList, ref string title) { } + ref List paramList, ref string title) + { } public virtual void OnLegendButtonClick(int index, string legendName, bool show) { } public virtual void OnLegendButtonEnter(int index, string legendName) { } public virtual void OnLegendButtonExit(int index, string legendName) { } internal abstract void SetSerie(Serie serie); + public virtual int GetPointerItemDataIndex() { return -1; } + public virtual int GetPointerItemDataDimension() { return 1; } } public abstract class SerieHandler : SerieHandler where T : Serie @@ -62,7 +66,7 @@ namespace XCharts.Runtime internal override void SetSerie(Serie serie) { - this.serie = (T) serie; + this.serie = (T)serie; this.serie.context.param.serieType = typeof(T); m_NeedInitComponent = true; AnimationStyleHelper.UpdateSerieAnimation(serie); @@ -121,6 +125,36 @@ namespace XCharts.Runtime serie.ResetInteract(); serie.ClearVerticesDirty(); } + UpdateSerieContextInternal(); + } + + private void UpdateSerieContextInternal() + { + var lastEnter = serie.context.pointerEnter; + var lastDataIndex = serie.context.pointerItemDataIndex; + UpdateSerieContext(); + if (lastEnter != serie.context.pointerEnter || lastDataIndex != serie.context.pointerItemDataIndex) + { + if (chart.onSerieEnter != null || chart.onSerieExit != null || serie.onEnter != null || serie.onExit != null) + { + var dataIndex = GetPointerItemDataIndex(); + var dimension = GetPointerItemDataDimension(); + var value = serie.GetData(dataIndex, dimension); + var data = SerieEventDataPool.Get(chart.pointerPos, serie.index, dataIndex, dimension, value); + if (serie.context.pointerEnter) + { + if (serie.onEnter != null) serie.onEnter(data); + if (chart.onSerieEnter != null) chart.onSerieEnter(data); + } + else + { + data.dataIndex = lastDataIndex; + if (serie.onExit != null) serie.onExit(data); + if (chart.onSerieExit != null) chart.onSerieExit(data); + } + SerieEventDataPool.Release(data); + } + } } public override void RefreshLabelNextFrame() @@ -289,7 +323,7 @@ namespace XCharts.Runtime return; } InitRoot(); - var dataAutoColor = (Color) chart.GetLegendRealShowNameColor(serie.legendName); + var dataAutoColor = (Color)chart.GetLegendRealShowNameColor(serie.legendName); m_EndLabel = ChartHelper.AddChartLabel(s_SerieEndLabelObjectName, m_SerieRoot.transform, serie.endLabel, chart.theme.common, "", dataAutoColor, TextAnchor.MiddleLeft); m_EndLabel.SetActive(serie.endLabel.show); @@ -493,7 +527,7 @@ namespace XCharts.Runtime var colorIndex = serie.colorByData ? serieData.index : serie.index; Color32 color, toColor; SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, colorIndex, SerieState.Normal, false); - return (Color) color; + return (Color)color; } protected void UpdateCoordSerieParams(ref List paramList, ref string title, @@ -537,7 +571,7 @@ namespace XCharts.Runtime param.columns.Add(param.marker); param.columns.Add(showCategory ? category : serie.serieName); - param.columns.Add(ignore?ignoreDataDefaultContent : ChartCached.NumberToStr(param.value, param.numericFormatter)); + param.columns.Add(ignore ? ignoreDataDefaultContent : ChartCached.NumberToStr(param.value, param.numericFormatter)); paramList.Add(param); } @@ -566,7 +600,7 @@ namespace XCharts.Runtime return; if (colorIndex < 0) - colorIndex = serie.colorByData?dataIndex : chart.GetLegendRealShowNameIndex(serieData.name); + colorIndex = serie.colorByData ? dataIndex : chart.GetLegendRealShowNameIndex(serieData.name); Color32 color, toColor; SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, colorIndex, SerieState.Normal); @@ -580,7 +614,7 @@ namespace XCharts.Runtime param.dataCount = serie.dataCount; param.value = serieData.GetData(param.dimension); param.ignore = ignore; - param.total = serie.multiDimensionLabel? serieData.GetTotalData() : serie.GetDataTotal(defaultDimension); + param.total = serie.multiDimensionLabel ? serieData.GetTotalData() : serie.GetDataTotal(defaultDimension); param.color = color; param.marker = SerieHelper.GetItemMarker(serie, serieData, marker); param.itemFormatter = itemFormatter; @@ -590,7 +624,7 @@ namespace XCharts.Runtime param.columns.Add(param.marker); param.columns.Add(serieData.name); - param.columns.Add(ignore?ignoreDataDefaultContent : ChartCached.NumberToStr(param.value, param.numericFormatter)); + param.columns.Add(ignore ? ignoreDataDefaultContent : ChartCached.NumberToStr(param.value, param.numericFormatter)); paramList.Add(param); } @@ -613,5 +647,47 @@ namespace XCharts.Runtime chart.DrawSymbol(vh, symbol.type, symbol.size, 1, pos, color, color, ColorUtil.clearColor32, color, symbol.gap, null); } + + public override void OnPointerDown(PointerEventData eventData) + { + if (serie.onDown == null && chart.onSerieDown == null) return; + if (!serie.context.pointerEnter) return; + var dataIndex = GetPointerItemDataIndex(); + if (dataIndex < 0) return; + var dimension = GetPointerItemDataDimension(); + var value = serie.GetData(dataIndex, dimension); + var data = SerieEventDataPool.Get(chart.pointerPos, serie.index, dataIndex, dimension, value); + if (chart.onSerieDown != null) + chart.onSerieDown(data); + if (serie.onDown != null) + serie.onDown(data); + SerieEventDataPool.Release(data); + } + + public override void OnPointerClick(PointerEventData eventData) + { + if (serie.onClick == null && chart.onSerieClick == null) return; + if (!serie.context.pointerEnter) return; + var dataIndex = GetPointerItemDataIndex(); + if (dataIndex < 0) return; + var dimension = GetPointerItemDataDimension(); + var value = serie.GetData(dataIndex, dimension); + var data = SerieEventDataPool.Get(chart.pointerPos, serie.index, dataIndex, dimension, value); + if (chart.onSerieClick != null) + chart.onSerieClick(data); + if (serie.onClick != null) + serie.onClick(data); + SerieEventDataPool.Release(data); + } + + public override int GetPointerItemDataIndex() + { + return serie.context.pointerItemDataIndex; + } + + public override int GetPointerItemDataDimension() + { + return serie.context.pointerItemDataDimension; + } } } \ No newline at end of file