diff --git a/Editor/ChildComponents/LabelStyleDrawer.cs b/Editor/ChildComponents/LabelStyleDrawer.cs index f2724cd2..bd933807 100644 --- a/Editor/ChildComponents/LabelStyleDrawer.cs +++ b/Editor/ChildComponents/LabelStyleDrawer.cs @@ -30,4 +30,10 @@ namespace XCharts.Editor } } } + + [CustomPropertyDrawer(typeof(EndLabelStyle), true)] + public class EndLabelStyleDrawer : LabelStyleDrawer + { + public override string ClassName { get { return "EndLabel"; } } + } } \ No newline at end of file diff --git a/Runtime/Component/Axis/AxisHelper.cs b/Runtime/Component/Axis/AxisHelper.cs index 4bddf213..5e9b1570 100644 --- a/Runtime/Component/Axis/AxisHelper.cs +++ b/Runtime/Component/Axis/AxisHelper.cs @@ -490,6 +490,22 @@ namespace XCharts.Runtime } } + public static double GetAxisPositionValue(GridCoord grid, Axis axis, Vector3 pos) + { + if (axis is YAxis) + return GetAxisPositionValue(pos.y, grid.context.height, axis.context.minMaxRange, grid.context.y, axis.context.offset); + else if (axis is XAxis) + return GetAxisPositionValue(pos.x, grid.context.width, axis.context.minMaxRange, grid.context.x, axis.context.offset); + else + return 0; + } + + public static double GetAxisPositionValue(float xy, float axisLength, double axisRange, float axisStart, float axisOffset) + { + var yRate = axisRange / axisLength; + return yRate * (xy - axisStart - axisOffset); + } + /// /// 获得数值value在坐标轴上的坐标位置 /// diff --git a/Runtime/Component/Child/EndLabelStyle.cs b/Runtime/Component/Child/EndLabelStyle.cs index 7653775e..2f22c1b5 100644 --- a/Runtime/Component/Child/EndLabelStyle.cs +++ b/Runtime/Component/Child/EndLabelStyle.cs @@ -7,5 +7,12 @@ namespace XCharts.Runtime [System.Serializable] public class EndLabelStyle : LabelStyle { + public EndLabelStyle() + { + m_Offset = new Vector3(5, 0, 0); + m_TextStyle.alignment = TextAnchor.MiddleLeft; + m_NumericFormatter = "f0"; + m_Formatter = "{a}:{c}"; + } } } \ No newline at end of file diff --git a/Runtime/Component/Child/LabelStyle.cs b/Runtime/Component/Child/LabelStyle.cs index fb23053a..86513731 100644 --- a/Runtime/Component/Child/LabelStyle.cs +++ b/Runtime/Component/Child/LabelStyle.cs @@ -67,20 +67,20 @@ namespace XCharts.Runtime End } - [SerializeField] private bool m_Show = true; + [SerializeField] protected bool m_Show = true; [SerializeField] Position m_Position = Position.Outside; - [SerializeField] private Vector3 m_Offset; - [SerializeField] private float m_Distance; - [SerializeField] private string m_Formatter; - [SerializeField] private float m_PaddingLeftRight = 2f; - [SerializeField] private float m_PaddingTopBottom = 2f; - [SerializeField] private float m_BackgroundWidth = 0; - [SerializeField] private float m_BackgroundHeight = 0; - [SerializeField] private string m_NumericFormatter = ""; - [SerializeField] private bool m_AutoOffset = false; + [SerializeField] protected Vector3 m_Offset; + [SerializeField] protected float m_Distance; + [SerializeField] protected string m_Formatter; + [SerializeField] protected float m_PaddingLeftRight = 2f; + [SerializeField] protected float m_PaddingTopBottom = 2f; + [SerializeField] protected float m_BackgroundWidth = 0; + [SerializeField] protected float m_BackgroundHeight = 0; + [SerializeField] protected string m_NumericFormatter = ""; + [SerializeField] protected bool m_AutoOffset = false; - [SerializeField] private TextStyle m_TextStyle = new TextStyle(); - private SerieLabelFormatterFunction m_FormatterFunction; + [SerializeField] protected TextStyle m_TextStyle = new TextStyle(); + protected SerieLabelFormatterFunction m_FormatterFunction; public void Reset() { diff --git a/Runtime/Coord/Grid/GridCoordContext.cs b/Runtime/Coord/Grid/GridCoordContext.cs index 251766fa..961a3585 100644 --- a/Runtime/Coord/Grid/GridCoordContext.cs +++ b/Runtime/Coord/Grid/GridCoordContext.cs @@ -1,4 +1,5 @@ +using System.Collections.Generic; using UnityEngine; namespace XCharts.Runtime @@ -16,5 +17,6 @@ namespace XCharts.Runtime public float bottom; public float top; public bool isPointerEnter; + public List endLabelList = new List(); } } \ No newline at end of file diff --git a/Runtime/Internal/Object/ChartLabel.cs b/Runtime/Internal/Object/ChartLabel.cs index 600e35a3..057a728a 100644 --- a/Runtime/Internal/Object/ChartLabel.cs +++ b/Runtime/Internal/Object/ChartLabel.cs @@ -7,7 +7,7 @@ namespace XCharts.Runtime public class ChartLabel : Image { [SerializeField] private ChartText m_LabelText; - + private bool m_AutoHideIconWhenLabelEmpty = false; private bool m_LabelAutoSize = true; private float m_LabelPaddingLeftRight = 3f; @@ -43,6 +43,7 @@ namespace XCharts.Runtime public bool autoHideIconWhenLabelEmpty { set { m_AutoHideIconWhenLabelEmpty = value; } } public bool isIconActive { get; private set; } + public bool isAnimationEnd { get; internal set; } protected override void Awake() { diff --git a/Runtime/Serie/Line/LineHandler.GridCoord.cs b/Runtime/Serie/Line/LineHandler.GridCoord.cs index 9e92026e..300733b2 100644 --- a/Runtime/Serie/Line/LineHandler.GridCoord.cs +++ b/Runtime/Serie/Line/LineHandler.GridCoord.cs @@ -266,6 +266,10 @@ namespace XCharts.Runtime m_SerieGrid = chart.GetChartComponent(axis.gridIndex); if (m_SerieGrid == null) return; + if (m_EndLabel != null && !m_SerieGrid.context.endLabelList.Contains(m_EndLabel)) + { + m_SerieGrid.context.endLabelList.Add(m_EndLabel); + } var visualMap = chart.GetVisualMapOfSerie(serie); var dataZoom = chart.GetDataZoomOfAxis(axis); diff --git a/Runtime/Serie/Line/LineHandler.cs b/Runtime/Serie/Line/LineHandler.cs index 9b0bdf05..b90bb341 100644 --- a/Runtime/Serie/Line/LineHandler.cs +++ b/Runtime/Serie/Line/LineHandler.cs @@ -60,5 +60,39 @@ namespace XCharts.Runtime } } } + + public override void RefreshEndLabelInternal() + { + base.RefreshEndLabelInternal(); + if (m_SerieGrid == null) return; + if (!serie.animation.IsFinish()) return; + var endLabelList = m_SerieGrid.context.endLabelList; + if (endLabelList.Count <= 1) return; + + endLabelList.Sort(delegate (ChartLabel a, ChartLabel b) + { + return b.transform.position.y.CompareTo(a.transform.position.y); + }); + var lastY = float.NaN; + for (int i = 0; i < endLabelList.Count; i++) + { + var label = endLabelList[i]; + if (!label.isAnimationEnd) continue; + var labelPosition = label.transform.localPosition; + if (float.IsNaN(lastY)) + { + lastY = labelPosition.y; + } + else + { + var labelHeight = label.GetLabelHeight(); + if (labelPosition.y + labelHeight > lastY) + { + label.SetPosition(new Vector3(labelPosition.x, lastY - labelHeight, labelPosition.z)); + } + lastY = label.transform.localPosition.y; + } + } + } } } \ No newline at end of file diff --git a/Runtime/Serie/Line/LineHelper.cs b/Runtime/Serie/Line/LineHelper.cs index d35da898..ff1f71f6 100644 --- a/Runtime/Serie/Line/LineHelper.cs +++ b/Runtime/Serie/Line/LineHelper.cs @@ -295,6 +295,14 @@ namespace XCharts.Runtime { AddLineVertToVertexHelper(vh, ltp, lbp, lineColor, isVisualMapGradient, isLineStyleGradient, visualMap, serie.lineStyle, grid, axis, relativedAxis, false, lastDataIsIgnore, isIgnore); + if (dataCount == 2 || isBreak) + { + AddLineVertToVertexHelper(vh, clp, crp, lineColor, isVisualMapGradient, isLineStyleGradient, + visualMap, serie.lineStyle, grid, axis, relativedAxis, true, lastDataIsIgnore, isIgnore); + serie.context.lineEndPostion = cp; + serie.context.lineEndValue = AxisHelper.GetAxisPositionValue(grid, relativedAxis, cp); + break; + } } if (bitp == bibp) @@ -327,6 +335,8 @@ namespace XCharts.Runtime visualMap, serie.lineStyle, grid, axis, relativedAxis, true, lastDataIsIgnore, isIgnore); } } + serie.context.lineEndPostion = cp; + serie.context.lineEndValue = AxisHelper.GetAxisPositionValue(grid, relativedAxis, cp); lastDataIsIgnore = isIgnore; if (isBreak) break; diff --git a/Runtime/Serie/SerieContext.cs b/Runtime/Serie/SerieContext.cs index d549f635..1298be7b 100644 --- a/Runtime/Serie/SerieContext.cs +++ b/Runtime/Serie/SerieContext.cs @@ -37,6 +37,11 @@ namespace XCharts.Runtime /// public Vector3 center; /// + /// 线段终点 + /// + public Vector3 lineEndPostion; + public double lineEndValue; + /// /// 内半径 /// public float insideRadius; diff --git a/Runtime/Serie/SerieHandler.cs b/Runtime/Serie/SerieHandler.cs index 13bc06cd..b46941c2 100644 --- a/Runtime/Serie/SerieHandler.cs +++ b/Runtime/Serie/SerieHandler.cs @@ -47,6 +47,7 @@ namespace XCharts.Runtime private static readonly string s_SerieLabelObjectName = "label"; private static readonly string s_SerieTitleObjectName = "title"; private static readonly string s_SerieRootObjectName = "serie"; + private static readonly string s_SerieEndLabelObjectName = "end_label"; protected GameObject m_SerieRoot; protected GameObject m_SerieLabelRoot; protected bool m_InitedLabel; @@ -55,6 +56,7 @@ namespace XCharts.Runtime protected bool m_LastCheckContextFlag = false; protected bool m_LegendEnter = false; protected int m_LegendEnterIndex; + protected ChartLabel m_EndLabel; public T serie { get; internal set; } public GameObject labelObject { get { return m_SerieLabelRoot; } } @@ -77,8 +79,8 @@ namespace XCharts.Runtime if (m_RefreshLabel) { m_RefreshLabel = false; - if (m_InitedLabel) - RefreshLabelInternal(); + RefreshLabelInternal(); + RefreshEndLabelInternal(); } if (serie.dataDirty) { @@ -91,6 +93,12 @@ namespace XCharts.Runtime serie.labelDirty = false; serie.label.ClearComponentDirty(); InitSerieLabel(); + InitSerieEndLabel(); + } + if (serie.endLabel != null && serie.endLabel.componentDirty) + { + serie.endLabel.ClearComponentDirty(); + InitSerieEndLabel(); } if (serie.titleStyle != null && (serie.titleDirty || serie.titleStyle.componentDirty)) { @@ -126,6 +134,7 @@ namespace XCharts.Runtime InitRoot(); InitSerieLabel(); InitSerieTitle(); + InitSerieEndLabel(); } public override void RemoveComponent() @@ -265,6 +274,46 @@ namespace XCharts.Runtime return true; } + private void InitSerieEndLabel() + { + if (serie.endLabel == null) + { + if (m_EndLabel != null) + { + m_EndLabel.SetActive(false); + m_EndLabel = null; + } + return; + } + if (m_SerieRoot == null) + InitRoot(); + var serieLabel = serie.endLabel; + var textStyle = serieLabel.textStyle; + var dataAutoColor = (Color)chart.theme.GetColor(serie.index); + + var color = serieLabel.textStyle.autoColor ? dataAutoColor : chart.theme.common.textColor; + + var anchorMin = new Vector2(0f, 0.5f); + var anchorMax = new Vector2(0f, 0.5f); + var pivot = new Vector2(0f, 0.5f); + var sizeDelta = new Vector2(50, textStyle.GetFontSize(chart.theme.common) + 2); + var labelObj = ChartHelper.AddObject(s_SerieEndLabelObjectName, m_SerieRoot.transform, anchorMin, anchorMax, pivot, sizeDelta); + var txt = ChartHelper.AddTextObject("Text", labelObj.transform, anchorMin, anchorMax, pivot, sizeDelta, textStyle, + chart.theme.common); + txt.SetColor(color); + txt.SetAlignment(textStyle.alignment); + txt.SetText("Text"); + txt.SetLocalPosition(new Vector2(0, 0)); + txt.SetLocalEulerAngles(Vector3.zero); + + var isAutoSize = serieLabel.backgroundWidth == 0 || serieLabel.backgroundHeight == 0; + m_EndLabel = ChartHelper.GetOrAddComponent(labelObj); + m_EndLabel.SetLabel(labelObj, isAutoSize, serieLabel.paddingLeftRight, serieLabel.paddingTopBottom); + m_EndLabel.SetIconActive(false); + m_EndLabel.SetActive(true); + RefreshEndLabelInternal(); + } + private void InitSerieTitle() { if (m_SerieRoot == null) @@ -367,6 +416,27 @@ namespace XCharts.Runtime } } + public virtual void RefreshEndLabelInternal() + { + if (m_EndLabel == null) + return; + var endLabelStyle = serie.endLabel; + if (endLabelStyle == null) + return; + var dataCount = serie.context.drawPoints.Count; + var active = endLabelStyle.show && dataCount > 0; + m_EndLabel.SetActive(active); + if (active) + { + var value = serie.context.lineEndValue; + var content = SerieLabelHelper.GetFormatterContent(serie, null, value, 0, + endLabelStyle, Color.clear); + m_EndLabel.SetText(content); + m_EndLabel.SetPosition(serie.context.lineEndPostion + endLabelStyle.offset); + } + m_EndLabel.isAnimationEnd = serie.animation.IsFinish(); + } + private void UpdateLabelPosition(SerieData serieData, LabelStyle currLabel) { var isNeedInvertPositionSerie = serie is Line; diff --git a/Runtime/XUGL/UGLHelper.cs b/Runtime/XUGL/UGLHelper.cs index 650efed1..922783a3 100644 --- a/Runtime/XUGL/UGLHelper.cs +++ b/Runtime/XUGL/UGLHelper.cs @@ -289,20 +289,25 @@ namespace XUGL ref Vector3 ntp, ref Vector3 nbp, ref Vector3 itp, ref Vector3 ibp, ref Vector3 clp, ref Vector3 crp, - ref bool bitp, ref bool bibp, int debugIndex = 0 - ) + ref bool bitp, ref bool bibp, int debugIndex = 0) { var dir1 = (cp - lp).normalized; - var dir2 = (cp - np).normalized; var dir1v = Vector3.Cross(dir1, Vector3.forward).normalized * width; - var dir2v = Vector3.Cross(dir2, Vector3.back).normalized * width; - ltp = lp - dir1v; lbp = lp + dir1v; + if (debugIndex == 1 && cp == np) + { + ntp = np - dir1v; + nbp = np + dir1v; + clp = cp - dir1v; + crp = cp + dir1v; + return; + } + var dir2 = (cp - np).normalized; + var dir2v = Vector3.Cross(dir2, Vector3.back).normalized * width; ntp = np - dir2v; nbp = np + dir2v; - clp = cp - dir2v; crp = cp + dir2v;