增加LabelStyleshowCondition,showFilter,showThreshold可控制label显示和隐藏

This commit is contained in:
monitor1394
2026-05-23 17:07:00 +08:00
parent f7ccec87d9
commit 4ad2b3268f
6 changed files with 185 additions and 7 deletions

View File

@@ -81,6 +81,7 @@ slug: /changelog
## master
* (2026.05.22) 增加`LabelStyle``showCondition`,`showFilter`,`showThreshold`可控制`label`显示和隐藏
* (2026.05.22) 增加`LabelStyle``minGap`可避免`label`过于密集
* (2026.05.17) 修复`DataZoom`点击时指示区域不准的问题
* (2026.05.17) 增加`Legend``Width``Height`可设置固定宽高

View File

@@ -113,6 +113,15 @@ namespace XCharts.Editor
}
}
protected void PropertyFlagsField(SerializedProperty prop, string relativePropName, System.Type enumType)
{
if (IngorePropertys.Contains(relativePropName)) return;
if (!ChartEditorHelper.PropertyFlagsField(ref m_DrawRect, m_Heights, m_KeyName, prop, relativePropName, enumType))
{
Debug.LogError("PropertyFlagsField ERROR:" + prop.displayName + ", " + relativePropName);
}
}
protected void PropertyFieldLimitMin(SerializedProperty prop, string relativePropName, float minValue)
{
if (IngorePropertys.Contains(relativePropName)) return;

View File

@@ -26,7 +26,10 @@ namespace XCharts.Editor
PropertyField(prop, "m_Height");
PropertyField(prop, "m_FixedX");
PropertyField(prop, "m_FixedY");
PropertyField(prop, "m_MinGap");
PropertyField(prop, "m_ShowCondition");
PropertyField(prop, "m_ShowFilter");
PropertyField(prop, "m_ShowThreshold");
PropertyField(prop, "m_ShowMinGap");
PropertyField(prop, "m_Icon");
PropertyField(prop, "m_Background");
PropertyField(prop, "m_TextStyle");

View File

@@ -507,6 +507,28 @@ namespace XCharts.Editor
{
return PropertyField(ref drawRect, heights, key, parentProp.FindPropertyRelative(relativeName));
}
public static bool PropertyFlagsField(ref Rect drawRect, Dictionary<string, float> heights, string key,
SerializedProperty parentProp, string relativeName, System.Type enumType)
{
return PropertyFlagsField(ref drawRect, heights, key, parentProp.FindPropertyRelative(relativeName), enumType);
}
public static bool PropertyFlagsField(ref Rect drawRect, Dictionary<string, float> heights, string key,
SerializedProperty prop, System.Type enumType)
{
if (prop == null) return false;
var label = GetContent(prop.displayName);
var enumValue = (System.Enum)System.Enum.ToObject(enumType, prop.intValue);
EditorGUI.BeginChangeCheck();
var newValue = EditorGUI.EnumFlagsField(drawRect, label, enumValue);
if (EditorGUI.EndChangeCheck())
prop.intValue = (int)(object)newValue;
var hig = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
drawRect.y += hig;
heights[key] += hig;
return true;
}
public static bool PropertyFieldWithMinValue(ref Rect drawRect, Dictionary<string, float> heights, string key,
SerializedProperty parentProp, string relativeName, float minValue)
{

View File

@@ -68,6 +68,50 @@ namespace XCharts.Runtime
/// </summary>
End
}
/// <summary>
/// The value-based condition for showing label. Controls visibility based on threshold comparison.
/// ||标签基于值的显示条件,通过与阈值比较来控制标签的显示。
/// </summary>
public enum ShowCondition
{
/// <summary>
/// Always show label.
/// ||总是显示标签。
/// </summary>
Always,
/// <summary>
/// Show label when value is greater than showThreshold.
/// ||大于showThreshold才显示标签。
/// </summary>
GreaterThan,
/// <summary>
/// Show label when value is less than showThreshold.
/// ||小于showThreshold才显示标签。
/// </summary>
LessThan,
}
/// <summary>
/// The data-pattern-based filter for showing label. Controls visibility based on data topology.
/// ||标签基于数据形态的显示筛选,通过数据的拓扑特征(波峰/波谷)来控制标签的显示。
/// </summary>
public enum ShowFilter
{
/// <summary>
/// All data points show label.
/// ||所有数据点都显示标签。
/// </summary>
All,
/// <summary>
/// Show label when value is at a peak.
/// ||波峰才显示标签。
/// </summary>
Peak,
/// <summary>
/// Show label when value is at a valley.
/// ||波谷才显示标签。
/// </summary>
Valley
}
[SerializeField] protected bool m_Show = true;
[SerializeField] Position m_Position = Position.Default;
@@ -82,7 +126,10 @@ 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][Since("v3.16.0")] protected ShowCondition m_ShowCondition = ShowCondition.Always;
[SerializeField][Since("v3.16.0")] protected ShowFilter m_ShowFilter = ShowFilter.All;
[SerializeField][Since("v3.16.0")] protected double m_ShowThreshold = 0;
[SerializeField][Since("v3.16.0")] protected float m_ShowMinGap = 0;
[SerializeField] protected IconStyle m_Icon = new IconStyle();
[SerializeField] protected ImageStyle m_Background = new ImageStyle();
@@ -101,6 +148,9 @@ namespace XCharts.Runtime
m_Height = 0;
m_NumericFormatter = "";
m_AutoOffset = false;
m_ShowCondition = ShowCondition.Always;
m_ShowFilter = ShowFilter.All;
m_ShowThreshold = 0;
}
/// <summary>
@@ -309,14 +359,45 @@ namespace XCharts.Runtime
set { if (PropertyUtil.SetStruct(ref m_FixedY, value)) SetComponentDirty(); }
}
/// <summary>
/// The value-based show condition of label. Default is ShowCondition.Always.
/// When set to GreaterThan or LessThan, the label is shown only when the value satisfies the threshold.
/// ||标签基于值的显示条件。默认为ShowCondition.Always总是显示。
/// 设为GreaterThan或LessThan时只有满足showThreshold阈值条件的数据点才显示标签。
/// </summary>
public ShowCondition showCondition
{
get { return m_ShowCondition; }
set { if (PropertyUtil.SetStruct(ref m_ShowCondition, value)) SetComponentDirty(); }
}
/// <summary>
/// The data-pattern-based show filter of label. Default is ShowFilter.All.
/// When set to Peak or Valley, the label is shown only at local maximum or minimum data points.
/// ||标签基于数据形态的显示筛选。默认为ShowFilter.All所有数据点都显示。
/// 设为Peak或Valley时只在局部波峰或波谷的数据点显示标签。
/// </summary>
public ShowFilter showFilter
{
get { return m_ShowFilter; }
set { if (PropertyUtil.SetStruct(ref m_ShowFilter, value)) SetComponentDirty(); }
}
/// <summary>
/// The threshold for showCondition. When showCondition is GreaterThan or LessThan, only values that satisfy the comparison will show label. Default is 0.
/// ||showCondition的阈值。当showCondition为GreaterThan或LessThan时生效只有满足比较条件的值才显示标签。默认值为0。
/// </summary>
public double showThreshold
{
get { return m_ShowThreshold; }
set { if (PropertyUtil.SetStruct(ref m_ShowThreshold, value)) SetComponentDirty(); }
}
/// <summary>
/// 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不开启该功能。
/// </summary>
public float minGap
public float showMinGap
{
get { return m_MinGap; }
set { if (PropertyUtil.SetStruct(ref m_MinGap, value)) SetComponentDirty(); }
get { return m_ShowMinGap; }
set { if (PropertyUtil.SetStruct(ref m_ShowMinGap, value)) SetComponentDirty(); }
}
/// <summary>
/// the sytle of background.

View File

@@ -546,6 +546,7 @@ namespace XCharts.Runtime
currLabel, color, chart);
var offset = GetSerieDataLabelOffset(serieData, currLabel);
var active = currLabel.show && !isIgnore && !serie.IsMinShowLabelValue(value);
if (active) active = CheckLabelVisible(currLabel, serieData.index, value, i);
if (active)
{
anyLabelActive = true;
@@ -577,10 +578,11 @@ 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)
if (active) active = CheckLabelVisible(currLabel, serieData.index, value, defaultDimension);
if (active && currLabel.showMinGap > 0 && lastActiveLabelSerieData != null)
{
var dist = Mathf.Abs(labelPos.x - lastActiveLabelPos.x);
if (dist < currLabel.minGap)
if (dist < currLabel.showMinGap)
{
var currValue = serieData.GetData(1);
if (Math.Abs(currValue) >= Math.Abs(lastActiveLabelValue))
@@ -641,6 +643,66 @@ namespace XCharts.Runtime
}
}
private bool CheckLabelVisible(LabelStyle label, int dataIndex, double value, int dimension)
{
// showCondition: 基于阈值的条件检查AND showFilter
bool conditionResult;
switch (label.showCondition)
{
case LabelStyle.ShowCondition.GreaterThan:
conditionResult = value > label.showThreshold;
break;
case LabelStyle.ShowCondition.LessThan:
conditionResult = value < label.showThreshold;
break;
default: // Always
conditionResult = true;
break;
}
if (!conditionResult)
return false;
// showFilter: 基于数据形态的过滤检查
switch (label.showFilter)
{
case LabelStyle.ShowFilter.Peak:
{
bool isPeak = true;
bool hasNeighbor = false;
if (dataIndex > 0)
{
hasNeighbor = true;
isPeak &= value > serie.data[dataIndex - 1].GetData(dimension);
}
if (dataIndex < serie.dataCount - 1)
{
hasNeighbor = true;
isPeak &= value > serie.data[dataIndex + 1].GetData(dimension);
}
return isPeak && hasNeighbor;
}
case LabelStyle.ShowFilter.Valley:
{
bool isValley = true;
bool hasNeighbor = false;
if (dataIndex > 0)
{
hasNeighbor = true;
isValley &= value < serie.data[dataIndex - 1].GetData(dimension);
}
if (dataIndex < serie.dataCount - 1)
{
hasNeighbor = true;
isValley &= value < serie.data[dataIndex + 1].GetData(dimension);
}
return isValley && hasNeighbor;
}
default: // All
return true;
}
}
public virtual void RefreshEndLabelInternal()
{
if (m_EndLabel == null)