diff --git a/Documentation~/zh/changelog.md b/Documentation~/zh/changelog.md
index 9eafac57..e01c7ea0 100644
--- a/Documentation~/zh/changelog.md
+++ b/Documentation~/zh/changelog.md
@@ -81,6 +81,7 @@ slug: /changelog
## master
+* (2026.05.22) 增加`LabelStyle`的`minGap`可避免`label`过于密集
* (2026.05.17) 修复`DataZoom`点击时指示区域不准的问题
* (2026.05.17) 增加`Legend`的`Width`和`Height`可设置固定宽高
* (2026.05.17) 修复`Serie`的`EndLabel`在`Y`轴是`MinMax`类型时显示的数值不对的问题
diff --git a/Editor/ChildComponents/LabelStyleDrawer.cs b/Editor/ChildComponents/LabelStyleDrawer.cs
index a6b760f3..1a6db5e6 100644
--- a/Editor/ChildComponents/LabelStyleDrawer.cs
+++ b/Editor/ChildComponents/LabelStyleDrawer.cs
@@ -26,6 +26,7 @@ namespace XCharts.Editor
PropertyField(prop, "m_Height");
PropertyField(prop, "m_FixedX");
PropertyField(prop, "m_FixedY");
+ PropertyField(prop, "m_MinGap");
PropertyField(prop, "m_Icon");
PropertyField(prop, "m_Background");
PropertyField(prop, "m_TextStyle");
diff --git a/Runtime/Component/Label/LabelStyle.cs b/Runtime/Component/Label/LabelStyle.cs
index 563ad1ac..243aafa3 100644
--- a/Runtime/Component/Label/LabelStyle.cs
+++ b/Runtime/Component/Label/LabelStyle.cs
@@ -82,6 +82,7 @@ namespace XCharts.Runtime
[SerializeField] protected float m_Height = 0;
[SerializeField][Since("v3.15.0")] protected float m_FixedX = 0;
[SerializeField][Since("v3.15.0")] protected float m_FixedY = 0;
+ [SerializeField][Since("v3.16.0")] protected float m_MinGap = 0;
[SerializeField] protected IconStyle m_Icon = new IconStyle();
[SerializeField] protected ImageStyle m_Background = new ImageStyle();
@@ -308,6 +309,16 @@ namespace XCharts.Runtime
set { if (PropertyUtil.SetStruct(ref m_FixedY, value)) SetComponentDirty(); }
}
///
+ /// the gap between label and the previous label. When the distance to the previous label is less than this value,
+ /// the label with smaller y value will be hidden. Default is 0, which means this function is turned off.
+ /// 和上一个标签的最小间距。当和上一个标签的距离小于该值时,隐藏对应y值较小的标签。默认为0不开启该功能。
+ ///
+ public float minGap
+ {
+ get { return m_MinGap; }
+ set { if (PropertyUtil.SetStruct(ref m_MinGap, value)) SetComponentDirty(); }
+ }
+ ///
/// the sytle of background.
/// ||背景图样式。
///
diff --git a/Runtime/Serie/SerieHandler.cs b/Runtime/Serie/SerieHandler.cs
index e503068b..5209e311 100644
--- a/Runtime/Serie/SerieHandler.cs
+++ b/Runtime/Serie/SerieHandler.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
@@ -507,6 +508,9 @@ namespace XCharts.Runtime
var needCheck = serie.context.dataIndexs.Count > 0;
var allLabelZeroPosition = true;
var anyLabelActive = false;
+ SerieData lastActiveLabelSerieData = null;
+ var lastActiveLabelPos = Vector3.zero;
+ double lastActiveLabelValue = 0;
foreach (var serieData in serie.data)
{
if (serieData.labelObject == null && serieData.context.dataLabels.Count <= 0)
@@ -573,6 +577,37 @@ namespace XCharts.Runtime
currLabel, color, chart);
var labelPos = UpdateLabelPosition(serieData, currLabel);
var active = currLabel.show && !isIgnore && !serie.IsMinShowLabelValue(value);
+ if (active && currLabel.minGap > 0 && lastActiveLabelSerieData != null)
+ {
+ var dist = Mathf.Abs(labelPos.x - lastActiveLabelPos.x);
+ if (dist < currLabel.minGap)
+ {
+ var currValue = serieData.GetData(1);
+ if (Math.Abs(currValue) >= Math.Abs(lastActiveLabelValue))
+ {
+ lastActiveLabelSerieData.SetLabelActive(false);
+ lastActiveLabelSerieData = serieData;
+ lastActiveLabelPos = labelPos;
+ lastActiveLabelValue = currValue;
+ }
+ else
+ {
+ active = false;
+ }
+ }
+ else
+ {
+ lastActiveLabelSerieData = serieData;
+ lastActiveLabelPos = labelPos;
+ lastActiveLabelValue = serieData.GetData(1);
+ }
+ }
+ else if (active)
+ {
+ lastActiveLabelSerieData = serieData;
+ lastActiveLabelPos = labelPos;
+ lastActiveLabelValue = serieData.GetData(1);
+ }
if (active)
{
anyLabelActive = true;