diff --git a/Documentation~/en/api.md b/Documentation~/en/api.md index 4b9da63d..6b971eb0 100644 --- a/Documentation~/en/api.md +++ b/Documentation~/en/api.md @@ -835,6 +835,7 @@ Bar chart shows different data through the height of a bar, which is used in rec |ResetChartStatus()|v3.10.0|public void ResetChartStatus()
reset chart status. When some parameters are set, due to the animation effect, the chart status may not be correct. | |ResetDataIndex()||public bool ResetDataIndex(int serieIndex)
重置serie的数据项索引。避免数据项索引异常。 | |SetBasePainterMaterial()||public void SetBasePainterMaterial(Material material)
设置Base Painter的材质球 | +|SetInsertDataToHead()|v3.11.0|public void SetInsertDataToHead(bool insertDataToHead)
set insert data to head. | |SetMaxCache()||public void SetMaxCache(int maxCache)
设置可缓存的最大数据量。当数据量超过该值时,会自动删除第一个值再加入最新值。 | |SetPainterActive()||public void SetPainterActive(int index, bool flag)| |SetSerieActive()||public void SetSerieActive(int serieIndex, bool active)
Whether to show serie. | @@ -3093,6 +3094,7 @@ Tooltip component. |public method|since|description| |--|--|--| +|onClickIndex||public System.Action<int> onClickIndex
the callback of tooltip click index. | |AddSerieDataIndex()||public void AddSerieDataIndex(int serieIndex, int dataIndex)| |ClearComponentDirty()||public override void ClearComponentDirty()| |ClearData()||public override void ClearData()| diff --git a/Documentation~/en/configuration.md b/Documentation~/en/configuration.md index ecdbbd29..3d34f3f9 100644 --- a/Documentation~/en/configuration.md +++ b/Documentation~/en/configuration.md @@ -2302,6 +2302,7 @@ Tooltip component. |show|true||Whether to show the tooltip component. |type|||Indicator type.
`Tooltip.Type`:
- `Line`: line indicator.
- `Shadow`: shadow crosshair indicator.
- `None`: no indicator displayed.
- `Corss`: crosshair indicator, which is actually the shortcut of enable two axisPointers of two orthometric axes.
- `Auto`: Auto select indicator according to serie type.
| |trigger|||Type of triggering.
`Tooltip.Trigger`:
- `Item`: Triggered by data item, which is mainly used for charts that don't have a category axis like scatter charts or pie charts.
- `Axis`: Triggered by axes, which is mainly used for charts that have category axes, like bar charts or line charts.
- `None`: Trigger nothing.
- `Auto`: Auto select trigger according to serie type.
| +|triggerOn||v3.11.0|Condition of trigger tooltip.
`Tooltip.TriggerOn`:
- `MouseMove`: Trigger when mouse move.
- `Click`: Trigger when mouse click.
| |position||v3.3.0|Type of position.
`Tooltip.Position`:
- `Auto`: Auto. The mobile platform is displayed at the top, and the non-mobile platform follows the mouse position.
- `Custom`: Custom. Fully customize display position (x,y).
- `FixedX`: Just fix the coordinate X. Y follows the mouse position.
- `FixedY`:
| |itemFormatter|||a string template formatter for a single Serie or data item content. Support for wrapping lines with \n. Template variables are {.}, {a}, {b}, {c}, {d}.
{.} is the dot of the corresponding color of a Serie that is currently indicated or whose index is 0.
{a} is the series name of the serie that is currently indicated or whose index is 0.
{b} is the name of the data item serieData that is currently indicated or whose index is 0, or a category value (such as the X-axis of a line chart).
{c} is the value of a Y-dimension (dimesion is 1) from a Serie that is currently indicated or whose index is 0.
{d} is the percentage value of Y-dimensions (dimesion is 1) from serie that is currently indicated or whose index is 0, with no % sign.
{e} is the name of the data item serieData that is currently indicated or whose index is 0.
{f} is sum of data.
{y} is category value of y axis.
{.1} represents a dot from serie corresponding color that specifies index as 1.
1 in {a1}, {b1}, {c1} represents a serie that specifies an index of 1.
{c1:2} represents the third data from serie's current indication data item indexed to 1 (a data item has multiple data, index 2 represents the third data).
{c1:2-2} represents the third data item from serie's third data item indexed to 1 (i.e., which data item must be specified to specify).
{d1:2: F2} indicates that a formatted string with a value specified separately is F2 (numericFormatter is used when numericFormatter is not specified).
{d:0.##} indicates that a formatted string with a value specified separately is 0.## (used for percentage, reserved 2 valid digits while avoiding the situation similar to "100.00%" when using f2 ).
Example: "{a}, {c}", "{a1}, {c1: f1}", "{a1}, {c1:0: f1}", "{a1} : {c1:1-1: f1}"
|titleFormatter|||String template formatter for tooltip title content. \n line wrapping is supported. The placeholder {i} can be set separately to indicate that title is ignored and not displayed. Template variables are {.}, {a}, {b}, {c}, {d}, {e}, {f}, and {g}.
{.} is the dot of the corresponding color of serie currently indicated or index 0.
{a} is the series name name of serie currently indicated or index 0.
{b} is the name of the serie data item serieData currently indicated or index 0, or the category value (such as the X-axis of a line chart).
{c} is the value of the serie y-dimension (dimesion is 1) currently indicated or index is 0.
{d} is the serie y-dimensional (dimesion 1) percentage value of the currently indicated or index 0, note without the % sign.
{e} is the name of the serie data item serieData currently indicated or whose index is 0.
{h} is the hexadecimal color value of serieData for the serie data item currently indicated or index 0.
{f} is the sum of data.
{g} indicates the total number of data.
{y} is category value of y axis.
{.1} represents a dot of the corresponding color with serie specified as index 1.
The 1 in {a1}, {b1}, {c1} represents serie where index is specified as 1.
{c1:2} represents the third data of the current indicator data item in serie with index 1 (one data item has multiple data, index 2 represents the third data).
{c1:2-2} represents the third data of serie third data item with index 1 (that is, the number of data items must be specified when specifying the number of data items).
{d1:2:f2} indicates that a format string with a single value is f2 (numericFormatter is used if no value is specified).
{d:0.##} indicates that the format string with a value specified alone is 0.## # (for percentages, preserving a 2-digit significant number while avoiding the "100.00%" situation with f2).
example: "{a}, {c}", "{a1}, {c1: f1}", "{a1}, {c1:0: f1}", "{a1}, {c1:1-1: f1}" diff --git a/Documentation~/zh/api.md b/Documentation~/zh/api.md index 910ab3d5..8955a3ac 100644 --- a/Documentation~/zh/api.md +++ b/Documentation~/zh/api.md @@ -835,6 +835,7 @@ slug: /api |ResetChartStatus()|v3.10.0|public void ResetChartStatus()
重置图表状态。当设置某些参数后,由于动画影响,可能导致图表状态不正确,此时可以调用该接口重置图表状态。 | |ResetDataIndex()||public bool ResetDataIndex(int serieIndex)
重置serie的数据项索引。避免数据项索引异常。 | |SetBasePainterMaterial()||public void SetBasePainterMaterial(Material material)
设置Base Painter的材质球 | +|SetInsertDataToHead()|v3.11.0|public void SetInsertDataToHead(bool insertDataToHead)
设置数据插入到头部。 | |SetMaxCache()||public void SetMaxCache(int maxCache)
设置可缓存的最大数据量。当数据量超过该值时,会自动删除第一个值再加入最新值。 | |SetPainterActive()||public void SetPainterActive(int index, bool flag)| |SetSerieActive()||public void SetSerieActive(int serieIndex, bool active)
设置指定系列是否显示。 | @@ -3093,6 +3094,7 @@ Serie的状态样式。Serie的状态有正常,高亮,淡出,选中四种 |API|版本|描述| |--|--|--| +|onClickIndex||public System.Action<int> onClickIndex
Tooltip为Click触发时,点击的X轴索引的回调。 | |AddSerieDataIndex()||public void AddSerieDataIndex(int serieIndex, int dataIndex)| |ClearComponentDirty()||public override void ClearComponentDirty()| |ClearData()||public override void ClearData()| diff --git a/Documentation~/zh/changelog.md b/Documentation~/zh/changelog.md index 8656fed8..03fd4317 100644 --- a/Documentation~/zh/changelog.md +++ b/Documentation~/zh/changelog.md @@ -73,6 +73,8 @@ slug: /changelog ## master +* (2024.03.20) 增加`Tooltip`的`triggerOn`设置触发条件 + ## v3.10.2 * (2024.03.11) 发布`v3.10.2`版本 diff --git a/Documentation~/zh/configuration.md b/Documentation~/zh/configuration.md index 885954ea..db80a6fe 100644 --- a/Documentation~/zh/configuration.md +++ b/Documentation~/zh/configuration.md @@ -2231,6 +2231,7 @@ Serie的状态样式。Serie的状态有正常,高亮,淡出,选中四种 |show|true||是否显示提示框组件。 |type|||提示框指示器类型。
`Tooltip.Type`:
- `Line`: 直线指示器
- `Shadow`: 阴影指示器
- `None`: 无指示器
- `Corss`: 十字准星指示器。坐标轴显示Label和交叉线。
- `Auto`: 根据serie的类型自动选择显示指示器。
| |trigger|||触发类型。
`Tooltip.Trigger`:
- `Item`: 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用。
- `Axis`: 坐标轴触发,主要在柱状图,折线图等会使用类目轴的图表中使用。
- `None`: 什么都不触发。
- `Auto`: 根据serie的类型自动选择触发类型。
| +|triggerOn||v3.11.0|触发条件。
`Tooltip.TriggerOn`:
- `MouseMove`: 鼠标移动时触发。
- `Click`: 鼠标点击时触发。
| |position||v3.3.0|显示位置类型。
`Tooltip.Position`:
- `Auto`: 自适应。移动平台靠顶部显示,非移动平台跟随鼠标位置。
- `Custom`: 自定义。完全自定义显示位置(x,y)。
- `FixedX`: 只固定坐标X。Y跟随鼠标位置。
- `FixedY`:
| |itemFormatter|||提示框单个serie或数据项内容的字符串模版格式器。支持用 \n 换行。用|来表示多个列的分隔。 模板变量有{.}、{a}、{b}、{c}、{d}、{e}、{f}、{g}。
{i}或-表示忽略当前项。 {.}为当前所指示的serie或数据项的对应颜色的圆点。
{a}为当前所指示的serie或数据项的系列名name。
{b}为当前所指示的serie或数据项的数据项serieData的name,或者类目值(如折线图的X轴)。
{c}为当前所指示的serie或数据项的y维(dimesion为1)的数值。
{d}为当前所指示的serie或数据项的y维(dimesion为1)百分比值,注意不带%号。
{e}为当前所指示的serie或数据项的数据项serieData的name。
{f}为当前所指示的serie的默认维度的数据总和。
{g}为当前所指示的serie的数据总个数。
{h}为当前所指示的serie的十六进制颜色值。
{y}为当前所指示的serie的y轴的类目值。
{c0}表示当前数据项维度为0的数据。
{c1}表示当前数据项维度为1的数据。
{d3}表示维度3的数据的百分比。它的分母是默认维度(一般是1维度)数据。
|表示多个列的分隔。
示例:"{i}", "{.}|{a}|{c}", "{.}|{b}|{c2:f2}", "{.}|{b}|{y}" |titleFormatter|||提示框标题内容的字符串模版格式器。支持用 \n 换行。可以单独设置占位符{i}表示忽略不显示title。 模板变量有{.}、{a}、{b}、{c}、{d}、{e}、{f}、{g}。
{.}为当前所指示或index为0的serie的对应颜色的圆点。
{a}为当前所指示或index为0的serie的系列名name。
{b}为当前所指示或index为0的serie的数据项serieData的name,或者类目值(如折线图的X轴)。
{c}为当前所指示或index为0的serie的y维(dimesion为1)的数值。
{d}为当前所指示或index为0的serie的y维(dimesion为1)百分比值,注意不带%号。
{e}为当前所指示或index为0的serie的数据项serieData的name。
{h}为当前所指示或index为0的serie的数据项serieData的十六进制颜色值。
{f}为数据总和。
{g}为数据总个数。
{f}为value所对应的y轴的类目值。
{.1}表示指定index为1的serie对应颜色的圆点。
{a1}、{b1}、{c1}中的1表示指定index为1的serie。
{c1:2}表示索引为1的serie的当前指示数据项的第3个数据(一个数据项有多个数据,index为2表示第3个数据)。
{c1:2-2}表示索引为1的serie的第3个数据项的第3个数据(也就是要指定第几个数据项时必须要指定第几个数据)。
{d1:2:f2}表示单独指定了数值的格式化字符串为f2(不指定时用numericFormatter)。
{d:0.##} 表示单独指定了数值的格式化字符串为 0.## (用于百分比,保留2位有效数同时又能避免使用 f2 而出现的类似于"100.00%"的情况 )。
示例:"{a}:{c}"、"{a1}:{c1:f1}"、"{a1}:{c1:0:f1}"、"{a1}:{c1:1-1:f1}" diff --git a/Editor/MainComponents/TooltipEditor.cs b/Editor/MainComponents/TooltipEditor.cs index 179048e5..1fe592f5 100644 --- a/Editor/MainComponents/TooltipEditor.cs +++ b/Editor/MainComponents/TooltipEditor.cs @@ -11,6 +11,7 @@ namespace XCharts.Editor ++EditorGUI.indentLevel; PropertyField("m_Type"); PropertyField("m_Trigger"); + PropertyField("m_TriggerOn"); PropertyField("m_Position"); PropertyField("m_FixedX"); PropertyField("m_FixedY"); diff --git a/Examples/Example01_RandomData.cs b/Examples/Example01_RandomData.cs index c3c32376..80eb1281 100644 --- a/Examples/Example01_RandomData.cs +++ b/Examples/Example01_RandomData.cs @@ -17,24 +17,52 @@ namespace XCharts.Example public bool loopUpdate = false; public float loopUpadteTime = 1f; public int maxCache = 0; + public bool insertDataToHead = false; BaseChart chart; float lastAddTime; float lastUpdateTime; int dataCount; + int lastMaxCache = 0; + bool lastInsertDataToHead = false; + void Awake() { chart = gameObject.GetComponent(); + chart.onInit = () => + { + dataCount = chart.GetSerie(0).dataCount; + SetMaxCache(maxCache); + SetInsertDataToHead(insertDataToHead); + lastMaxCache = maxCache; + lastInsertDataToHead = insertDataToHead; + }; } - void Start() + void SetMaxCache(int maxCache) { - if (maxCache > 0) + chart.SetMaxCache(maxCache); + } + + void SetInsertDataToHead(bool insertDataToHead) + { + foreach (var serie in chart.series) + serie.insertDataToHead = insertDataToHead; + + var coms = chart.GetChartComponents(); + if (coms != null) { - chart.SetMaxCache(maxCache); + foreach (var com in coms) + { + var axis = com as XAxis; + if (axis.type == Axis.AxisType.Category) + { + axis.insertDataToHead = insertDataToHead; + Debug.LogError("axis:" + axis + "," + insertDataToHead); + } + } } - dataCount = chart.GetSerie(0).dataCount; } void Update() @@ -51,6 +79,16 @@ namespace XCharts.Example { chart.ClearData(); } + if (lastMaxCache != maxCache) + { + lastMaxCache = maxCache; + SetMaxCache(maxCache); + } + if (lastInsertDataToHead != insertDataToHead) + { + lastInsertDataToHead = insertDataToHead; + SetInsertDataToHead(insertDataToHead); + } lastAddTime += Time.deltaTime; if (loopAdd && lastAddTime >= loopAddTime) { @@ -84,14 +122,8 @@ namespace XCharts.Example } else { + AddXAxisData(); var xAxis = chart.GetChartComponent(); - if (xAxis != null) - { - if (xAxis.type == Axis.AxisType.Category) - { - chart.AddXAxisData("x" + (xAxis.GetAddedDataCount() + 1)); - } - } foreach (var serie in chart.series) { AddSerieRandomData(serie, xAxis); @@ -99,6 +131,19 @@ namespace XCharts.Example } } + void AddXAxisData() + { + var xAxes = chart.GetChartComponents(); + foreach (var com in xAxes) + { + var xAxis = com as XAxis; + if (xAxis.type == Axis.AxisType.Category) + { + chart.AddXAxisData("x" + (xAxis.GetAddedDataCount() + 1), xAxis.index); + } + } + } + void UpdateData() { foreach (var serie in chart.series) diff --git a/Runtime/Component/Axis/XAxis/XAxisHander.cs b/Runtime/Component/Axis/XAxis/XAxisHander.cs index c1b5cf14..04731658 100644 --- a/Runtime/Component/Axis/XAxis/XAxisHander.cs +++ b/Runtime/Component/Axis/XAxis/XAxisHander.cs @@ -1,5 +1,6 @@ using UnityEngine; using UnityEngine.UI; +using UnityEngine.EventSystems; namespace XCharts.Runtime { @@ -16,7 +17,28 @@ namespace XCharts.Runtime public override void Update() { UpdateAxisMinMaxValue(component.index, component); - UpdatePointerValue(component); + if (!chart.isTriggerOnClick) + { + UpdatePointerValue(component); + } + } + + public override void OnPointerClick(PointerEventData eventData) + { + base.OnPointerClick(eventData); + if (chart.isTriggerOnClick) + { + UpdatePointerValue(component); + } + } + + public override void OnPointerExit(PointerEventData eventData) + { + base.OnPointerExit(eventData); + if (chart.isTriggerOnClick) + { + component.context.pointerValue = double.PositiveInfinity; + } } public override void DrawBase(VertexHelper vh) diff --git a/Runtime/Component/Tooltip/Tooltip.cs b/Runtime/Component/Tooltip/Tooltip.cs index 13cac7f7..fd6718b0 100644 --- a/Runtime/Component/Tooltip/Tooltip.cs +++ b/Runtime/Component/Tooltip/Tooltip.cs @@ -73,6 +73,23 @@ namespace XCharts.Runtime Auto } /// + /// the condition of trigger tooltip. + /// ||触发条件。 + /// + public enum TriggerOn + { + /// + /// Trigger when mouse move. + /// ||鼠标移动时触发。 + /// + MouseMove, + /// + /// Trigger when mouse click. + /// ||鼠标点击时触发。 + /// + Click, + } + /// /// Position type. /// ||坐标类型。 /// @@ -102,6 +119,7 @@ namespace XCharts.Runtime [SerializeField] private bool m_Show = true; [SerializeField] private Type m_Type = Type.Auto; [SerializeField] private Trigger m_Trigger = Trigger.Auto; + [SerializeField][Since("v3.11.0")] private TriggerOn m_TriggerOn = TriggerOn.MouseMove; [SerializeField][Since("v3.3.0")] private Position m_Position = Position.Auto; [SerializeField] private string m_ItemFormatter; [SerializeField] private string m_TitleFormatter; @@ -144,6 +162,12 @@ namespace XCharts.Runtime public TooltipContext context = new TooltipContext(); public TooltipView view; + /// + /// the callback of tooltip click index. + /// ||Tooltip为Click触发时,点击的X轴索引的回调。 + /// + public System.Action onClickIndex { get; set; } + /// /// Whether to show the tooltip component. /// ||是否显示提示框组件。 @@ -172,6 +196,15 @@ namespace XCharts.Runtime set { if (PropertyUtil.SetStruct(ref m_Trigger, value)) SetAllDirty(); } } /// + /// Condition of trigger tooltip. + /// ||触发条件。 + /// + public TriggerOn triggerOn + { + get { return m_TriggerOn; } + set { if (PropertyUtil.SetStruct(ref m_TriggerOn, value)) SetAllDirty(); } + } + /// /// Type of position. /// ||显示位置类型。 /// diff --git a/Runtime/Component/Tooltip/TooltipContext.cs b/Runtime/Component/Tooltip/TooltipContext.cs index e0674e3a..b7e090ed 100644 --- a/Runtime/Component/Tooltip/TooltipContext.cs +++ b/Runtime/Component/Tooltip/TooltipContext.cs @@ -19,6 +19,7 @@ namespace XCharts.Runtime public float width; public float height; public float angle; + public int xAxisClickIndex = -1; public Tooltip.Type type; public Tooltip.Trigger trigger; public TooltipData data = new TooltipData(); diff --git a/Runtime/Component/Tooltip/TooltipHandler.cs b/Runtime/Component/Tooltip/TooltipHandler.cs index aec2878a..aeb21bea 100644 --- a/Runtime/Component/Tooltip/TooltipHandler.cs +++ b/Runtime/Component/Tooltip/TooltipHandler.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Text; using UnityEngine; +using UnityEngine.EventSystems; using UnityEngine.UI; using XUGL; @@ -36,6 +37,15 @@ namespace XCharts.Runtime DrawTooltipIndicator(vh, component); } + public override void OnPointerExit(PointerEventData eventData) + { + base.OnPointerExit(eventData); + if (chart.isTriggerOnClick) + { + component.context.xAxisClickIndex = -1; + } + } + private void InitTooltip(Tooltip tooltip) { tooltip.painter = chart.m_PainterUpper; @@ -70,6 +80,7 @@ namespace XCharts.Runtime m_IndicatorLabels[labelName] = item; } } + chart.isTriggerOnClick = tooltip.triggerOn == Tooltip.TriggerOn.Click; }; tooltip.refreshComponent(); } @@ -93,39 +104,54 @@ namespace XCharts.Runtime private void UpdateTooltipData(Tooltip tooltip) { - showTooltip = false; + m_ShowTooltip = false; if (tooltip.trigger == Tooltip.Trigger.None) return; - if (chart.isPointerInChart && tooltip.show) + chart.isTriggerOnClick = tooltip.triggerOn == Tooltip.TriggerOn.Click; + if (!chart.isPointerInChart || !tooltip.show || (chart.isTriggerOnClick && !chart.isPointerClick)) { for (int i = chart.series.Count - 1; i >= 0; i--) { var serie = chart.series[i]; if (!(serie is INeedSerieContainer)) { - showTooltip = true; - containerSeries = null; + m_ShowTooltip = true; + m_ContainerSeries = null; return; } } - containerSeries = ListPool.Get(); - UpdatePointerContainerAndSeriesAndTooltip(tooltip, ref containerSeries); - if (containerSeries.Count > 0) + m_ContainerSeries = ListPool.Get(); + UpdatePointerContainerAndSeriesAndTooltip(tooltip, ref m_ContainerSeries); + if (m_ContainerSeries.Count > 0) { - showTooltip = true; + m_ShowTooltip = true; + m_ContainerSeries = null; + return; } } - if (!showTooltip && tooltip.IsActive()) + m_ContainerSeries = ListPool.Get(); + UpdatePointerContainerAndSeriesAndTooltip(tooltip, ref m_ContainerSeries); + if (m_ContainerSeries.Count > 0) { - tooltip.ClearValue(); - tooltip.SetActive(false); + m_ShowTooltip = true; + } + else + { + m_ShowTooltip = false; + if (tooltip.IsActive()) + { + tooltip.ClearValue(); + tooltip.SetActive(false); + component.context.xAxisClickIndex = -1; + chart.pointerClickEventData = null; + } } } - private bool showTooltip; - private List containerSeries; + private bool m_ShowTooltip; + private List m_ContainerSeries; private void UpdateTooltip(Tooltip tooltip) { - if (!showTooltip) return; + if (!m_ShowTooltip) return; var anyTrigger = false; for (int i = chart.series.Count - 1; i >= 0; i--) { @@ -140,24 +166,27 @@ namespace XCharts.Runtime } } } - if (containerSeries != null) + if (m_ContainerSeries != null) { - if (!SetSerieTooltip(tooltip, containerSeries)) - showTooltip = false; + if (!SetSerieTooltip(tooltip, m_ContainerSeries)) + m_ShowTooltip = false; else anyTrigger = true; - ListPool.Release(containerSeries); + ListPool.Release(m_ContainerSeries); } - if (!showTooltip || !anyTrigger) + if (!m_ShowTooltip || !anyTrigger) { if (tooltip.context.type == Tooltip.Type.Corss && m_PointerContainer != null && m_PointerContainer.IsPointerEnter()) { + m_ShowTooltip = true; tooltip.SetActive(true); tooltip.SetContentActive(false); } else { + m_ShowTooltip = false; tooltip.SetActive(false); + chart.pointerClickEventData = null; } } else @@ -274,20 +303,26 @@ namespace XCharts.Runtime serie.context.tooltipTrigger : tooltip.trigger; } var isTriggerAxis = tooltip.IsTriggerAxis(); + var inchart = true; if (container is GridCoord) { var xAxis = chart.GetChartComponent(serie.xAxisIndex); var yAxis = chart.GetChartComponent(serie.yAxisIndex); - UpdateAxisPointerDataIndex(serie, xAxis, yAxis, container as GridCoord, isTriggerAxis); + inchart = UpdateAxisPointerDataIndex(serie, xAxis, yAxis, container as GridCoord, isTriggerAxis); } else if (container is PolarCoord) { var m_AngleAxis = ComponentHelper.GetAngleAxis(chart.components, container.index); tooltip.context.angle = (float)m_AngleAxis.context.pointerValue; } - list.Add(serie); - if (!isTriggerAxis) - chart.RefreshTopPainter(); + if (inchart) + { + list.Add(serie); + if (!isTriggerAxis) + { + chart.RefreshTopPainter(); + } + } } } m_PointerContainer = container; @@ -296,10 +331,11 @@ namespace XCharts.Runtime } } - private void UpdateAxisPointerDataIndex(Serie serie, XAxis xAxis, YAxis yAxis, GridCoord grid, bool isTriggerAxis) + private bool UpdateAxisPointerDataIndex(Serie serie, XAxis xAxis, YAxis yAxis, GridCoord grid, bool isTriggerAxis) { serie.context.pointerAxisDataIndexs.Clear(); - if (xAxis == null || yAxis == null) return; + if (xAxis == null || yAxis == null) return false; + var flag = true; if (serie is Heatmap) { GetSerieDataByXYAxis(serie, xAxis, yAxis); @@ -328,20 +364,45 @@ namespace XCharts.Runtime if (isTriggerAxis) { var index = serie.context.dataZoomStartIndex + (int)xAxis.context.pointerValue; + if (chart.isTriggerOnClick) + { + if (serie.insertDataToHead) + index = index + (serie.context.totalDataIndex - serie.context.clickTotalDataIndex); + else if (serie.context.totalDataIndex >= serie.dataCount) + index = index - (serie.context.totalDataIndex - serie.context.clickTotalDataIndex); + if (index < 0 || index >= serie.dataCount) + { + index = -1; + flag = false; + } + } + if (component.context.xAxisClickIndex != index) + { + component.context.xAxisClickIndex = index; + if (component.onClickIndex != null) + { + component.onClickIndex(index); + } + } serie.context.pointerEnter = true; serie.context.pointerAxisDataIndexs.Add(index); serie.context.pointerItemDataIndex = index; - xAxis.context.axisTooltipValue = xAxis.context.pointerValue; + xAxis.context.axisTooltipValue = index; } } else { - serie.context.pointerEnter = true; if (isTriggerAxis) + { + serie.context.pointerEnter = true; GetSerieDataIndexByAxis(serie, xAxis, grid); + } else + { GetSerieDataIndexByItem(serie, xAxis, grid); + } } + return flag; } private void GetSerieDataByXYAxis(Serie serie, Axis xAxis, Axis yAxis) @@ -464,7 +525,7 @@ namespace XCharts.Runtime if (tooltip.context.trigger == Tooltip.Trigger.None) return false; tooltip.context.data.param.Clear(); tooltip.context.data.title = serie.serieName; - tooltip.context.pointer = chart.pointerPos; + tooltip.context.pointer = GetTooltipPointerPos(); serie.handler.UpdateTooltipSerieParams(serie.context.pointerItemDataIndex, false, null, tooltip.marker, tooltip.itemFormatter, tooltip.numericFormatter, tooltip.ignoreDataDefaultContent, @@ -472,12 +533,20 @@ namespace XCharts.Runtime ref tooltip.context.data.title); TooltipHelper.ResetTooltipParamsByItemFormatter(tooltip, chart); - tooltip.SetActive(true); + tooltip.SetActive(m_ShowTooltip); tooltip.view.Refresh(); TooltipHelper.LimitInRect(tooltip, chart.chartRect); return true; } + private Vector2 GetTooltipPointerPos() + { + if (chart.isTriggerOnClick && chart.isPointerClick) + return chart.clickPos; + else + return chart.pointerPos; + } + private bool SetSerieTooltip(Tooltip tooltip, List series) { if (tooltip.context.trigger == Tooltip.Trigger.None) @@ -489,10 +558,10 @@ namespace XCharts.Runtime string category = null; var showCategory = false; var isTriggerByAxis = false; - var isTriggerByItem = false; + var isTriggerByItem = tooltip.context.trigger == Tooltip.Trigger.Item; var dataIndex = -1; tooltip.context.data.param.Clear(); - tooltip.context.pointer = chart.pointerPos; + tooltip.context.pointer = GetTooltipPointerPos(); if (m_PointerContainer is GridCoord) { GetAxisCategory(m_PointerContainer.index, ref dataIndex, ref category); @@ -514,11 +583,13 @@ namespace XCharts.Runtime } } + var triggerSerieCount = 0; for (int i = 0; i < series.Count; i++) { var serie = series[i]; if (!serie.show) continue; if (isTriggerByItem && serie.context.pointerItemDataIndex < 0) continue; + triggerSerieCount++; serie.context.isTriggerByAxis = isTriggerByAxis; if (isTriggerByAxis && dataIndex >= 0 && serie.context.pointerItemDataIndex < 0) serie.context.pointerItemDataIndex = dataIndex; @@ -528,10 +599,14 @@ namespace XCharts.Runtime ref tooltip.context.data.param, ref tooltip.context.data.title); } + if (triggerSerieCount <= 0) + { + return false; + } TooltipHelper.ResetTooltipParamsByItemFormatter(tooltip, chart); if (tooltip.context.data.param.Count > 0 || !string.IsNullOrEmpty(tooltip.context.data.title)) { - tooltip.SetActive(true); + tooltip.SetActive(m_ShowTooltip); if (tooltip.view != null) tooltip.view.Refresh(); TooltipHelper.LimitInRect(tooltip, chart.chartRect); @@ -551,7 +626,7 @@ namespace XCharts.Runtime { dataIndex = double.IsNaN(axis.context.pointerValue) ? axis.context.dataZoomStartIndex - : axis.context.dataZoomStartIndex + (int)axis.context.pointerValue; + : axis.context.dataZoomStartIndex + (int)axis.context.axisTooltipValue; category = axis.GetData(dataIndex); return true; } @@ -616,7 +691,7 @@ namespace XCharts.Runtime case Tooltip.Type.Line: float pX = grid.context.x; pX += xAxis.IsCategory() ? - (float)(xAxis.context.pointerValue * splitWidth + (xAxis.boundaryGap ? splitWidth / 2 : 0)) : + (float)(xAxis.context.axisTooltipValue * splitWidth + (xAxis.boundaryGap ? splitWidth / 2 : 0)) : xAxis.GetDistance(xAxis.context.axisTooltipValue, grid.context.width); if (pX < grid.context.x) break; diff --git a/Runtime/Internal/BaseChart.API.cs b/Runtime/Internal/BaseChart.API.cs index 9da4fdf2..f61a647f 100644 --- a/Runtime/Internal/BaseChart.API.cs +++ b/Runtime/Internal/BaseChart.API.cs @@ -566,6 +566,26 @@ namespace XCharts.Runtime } } + /// + /// set insert data to head. + /// ||设置数据插入到头部。 + /// + /// + [Since("v3.11.0")] + public void SetInsertDataToHead(bool insertDataToHead) + { + foreach (var serie in m_Series) + serie.insertDataToHead = insertDataToHead; + + var coms = GetChartComponents(); + foreach (var com in coms) + { + var axis = com as XAxis; + if (axis.type == Axis.AxisType.Category) + axis.insertDataToHead = insertDataToHead; + } + } + public Vector3 GetTitlePosition(Title title) { return chartPosition + title.location.GetPosition(chartWidth, chartHeight); @@ -735,7 +755,8 @@ namespace XCharts.Runtime [Since("v3.7.0")] public void CancelTooltip() { - m_PointerEventData = null; + pointerMoveEventData = null; + pointerClickEventData = null; var tooltip = GetChartComponent(); if (tooltip != null) { diff --git a/Runtime/Internal/BaseGraph.API.cs b/Runtime/Internal/BaseGraph.API.cs index f659a233..210d681e 100644 --- a/Runtime/Internal/BaseGraph.API.cs +++ b/Runtime/Internal/BaseGraph.API.cs @@ -43,16 +43,21 @@ namespace XCharts.Runtime public Vector2 graphMaxAnchor { get { return m_GraphMaxAnchor; } } public Vector2 graphAnchoredPosition { get { return m_GraphAnchoredPosition; } } /// - /// The postion of pointer. + /// The postion of pointer move. /// ||鼠标位置。 /// public Vector2 pointerPos { get; protected set; } + public Vector2 clickPos { get; protected set; } /// /// Whether the mouse pointer is in the chart. /// ||鼠标是否在图表内。 /// - public bool isPointerInChart - { get { return m_PointerEventData != null; } } + public bool isPointerInChart { get { return pointerMoveEventData != null; } } + /// + /// Whether the mouse click the chart. + /// ||鼠标是否点击了图表。 + /// + public bool isPointerClick { get { return pointerClickEventData != null; } } /// /// 警告信息。 /// diff --git a/Runtime/Internal/BaseGraph.cs b/Runtime/Internal/BaseGraph.cs index c723a829..2bf81ac1 100644 --- a/Runtime/Internal/BaseGraph.cs +++ b/Runtime/Internal/BaseGraph.cs @@ -35,7 +35,9 @@ namespace XCharts.Runtime protected bool m_PainerDirty = false; protected bool m_IsOnValidate = false; protected Vector3 m_LastLocalPosition; - protected PointerEventData m_PointerEventData; + internal PointerEventData pointerMoveEventData; + internal PointerEventData pointerClickEventData; + internal bool isTriggerOnClick = false; protected Action m_OnPointerClick; protected Action m_OnPointerDown; @@ -213,17 +215,23 @@ namespace XCharts.Runtime private void CheckPointerPos() { - if (!isPointerInChart) return; if (canvas == null) return; - Vector2 mousePos = m_PointerEventData.position; + if (pointerMoveEventData != null) + { + pointerPos = MousePos2ChartPos(pointerMoveEventData.position); + } + } + + private Vector2 MousePos2ChartPos(Vector2 mousePos) + { Vector2 local; if (!ScreenPointToChartPoint(mousePos, out local)) { - pointerPos = Vector2.zero; + return Vector2.zero; } else { - pointerPos = local; + return local; } } @@ -269,6 +277,8 @@ namespace XCharts.Runtime public virtual void OnPointerClick(PointerEventData eventData) { + pointerClickEventData = eventData; + clickPos = MousePos2ChartPos(pointerClickEventData.position); if (m_OnPointerClick != null) m_OnPointerClick(eventData, this); } @@ -284,13 +294,14 @@ namespace XCharts.Runtime public virtual void OnPointerEnter(PointerEventData eventData) { - m_PointerEventData = eventData; + pointerMoveEventData = eventData; if (m_OnPointerEnter != null) m_OnPointerEnter(eventData, this); } public virtual void OnPointerExit(PointerEventData eventData) { - m_PointerEventData = null; + pointerMoveEventData = null; + pointerClickEventData = null; if (m_OnPointerExit != null) m_OnPointerExit(eventData, this); } diff --git a/Runtime/Serie/SerieContext.cs b/Runtime/Serie/SerieContext.cs index 624e0d9e..d3b3931a 100644 --- a/Runtime/Serie/SerieContext.cs +++ b/Runtime/Serie/SerieContext.cs @@ -119,6 +119,7 @@ namespace XCharts.Runtime public Tooltip.Type tooltipType; public Tooltip.Trigger tooltipTrigger; public int totalDataIndex; + public int clickTotalDataIndex; /// /// 水平方向的 /// diff --git a/Runtime/Serie/SerieHandler.cs b/Runtime/Serie/SerieHandler.cs index 7ebfc2c7..fd232af3 100644 --- a/Runtime/Serie/SerieHandler.cs +++ b/Runtime/Serie/SerieHandler.cs @@ -741,6 +741,7 @@ namespace XCharts.Runtime public override void OnPointerClick(PointerEventData eventData) { + serie.context.clickTotalDataIndex = serie.context.totalDataIndex; if (serie.onClick == null && chart.onSerieClick == null) return; if (!serie.context.pointerEnter) return; var dataIndex = GetPointerItemDataIndex(); diff --git a/package.json b/package.json index a5b150d6..6425d8bc 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,9 @@ "displayName": "XCharts", "author": "monitor1394", "license": "MIT", - "version": "3.10.2", - "date": "20240311", - "checkdate": "20240311", + "version": "3.11.0-preview1", + "date": "20240223", + "checkdate": "20240223", "unity": "2018.3", "description": "A charting and data visualization library for Unity. Support line chart, bar chart, pie chart, radar chart, scatter chart, heatmap chart, ring chart, candlestick chart, polar chart and parallel coordinates.", "keywords": [