From eedafa70115ec4a443081f71fbd395966f67d720 Mon Sep 17 00:00:00 2001 From: monitor1394 Date: Sun, 17 Jul 2022 20:57:38 +0800 Subject: [PATCH] [feature][radar] support smooth line --- Editor/MainComponents/RadarCoordEditor.cs | 2 +- Editor/Series/RadarEditor.cs | 1 + .../Axis/RadiusAxis/RadiusAxisHandler.cs | 2 +- Runtime/Component/Tooltip/TooltipHandler.cs | 2 +- Runtime/Internal/Attributes/SinceAttribute.cs | 2 +- Runtime/Serie/Parallel/ParallelHandler.cs | 8 +- Runtime/Serie/Radar/Radar.cs | 14 ++- Runtime/Serie/Radar/RadarHandler.cs | 37 ++++++-- Runtime/XUGL/UGL.cs | 85 ++++++++++++++----- Runtime/XUGL/UGLHelper.cs | 10 +-- 10 files changed, 120 insertions(+), 43 deletions(-) diff --git a/Editor/MainComponents/RadarCoordEditor.cs b/Editor/MainComponents/RadarCoordEditor.cs index 752ec816..2d5b9b40 100644 --- a/Editor/MainComponents/RadarCoordEditor.cs +++ b/Editor/MainComponents/RadarCoordEditor.cs @@ -24,7 +24,7 @@ namespace XCharts.Editor PropertyField("m_AxisName"); PropertyField("m_SplitLine"); PropertyField("m_SplitArea"); - PropertyField("m_IndicatorList"); + PropertyListField("m_IndicatorList"); --EditorGUI.indentLevel; } } diff --git a/Editor/Series/RadarEditor.cs b/Editor/Series/RadarEditor.cs index aedf9832..969c7436 100644 --- a/Editor/Series/RadarEditor.cs +++ b/Editor/Series/RadarEditor.cs @@ -9,6 +9,7 @@ namespace XCharts.Editor { PropertyField("m_RadarType"); PropertyField("m_RadarIndex"); + PropertyField("m_Smooth"); PropertyField("m_Symbol"); PropertyField("m_LineStyle"); diff --git a/Runtime/Component/Axis/RadiusAxis/RadiusAxisHandler.cs b/Runtime/Component/Axis/RadiusAxis/RadiusAxisHandler.cs index 630a0612..4e295923 100644 --- a/Runtime/Component/Axis/RadiusAxis/RadiusAxisHandler.cs +++ b/Runtime/Component/Axis/RadiusAxis/RadiusAxisHandler.cs @@ -32,7 +32,7 @@ namespace XCharts.Runtime if (!polar.context.isPointerEnter) { - axis.context.pointerValue = double.PositiveInfinity; + axis.context.pointerValue = double.NaN; return; } diff --git a/Runtime/Component/Tooltip/TooltipHandler.cs b/Runtime/Component/Tooltip/TooltipHandler.cs index e06b11cc..67bac520 100644 --- a/Runtime/Component/Tooltip/TooltipHandler.cs +++ b/Runtime/Component/Tooltip/TooltipHandler.cs @@ -180,7 +180,7 @@ namespace XCharts.Runtime private void SetTooltipIndicatorLabel(Tooltip tooltip, Axis axis, ChartLabel label) { if (label == null) return; - if (double.IsPositiveInfinity(axis.context.pointerValue)) return; + if (double.IsNaN(axis.context.pointerValue)) return; label.SetActive(true); label.SetTextActive(true); label.SetPosition(axis.context.pointerLabelPosition); diff --git a/Runtime/Internal/Attributes/SinceAttribute.cs b/Runtime/Internal/Attributes/SinceAttribute.cs index 958d5ad2..1e3499e9 100644 --- a/Runtime/Internal/Attributes/SinceAttribute.cs +++ b/Runtime/Internal/Attributes/SinceAttribute.cs @@ -2,7 +2,7 @@ using System; namespace XCharts.Runtime { - [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] + [AttributeUsage(AttributeTargets.All, AllowMultiple = false)] public class Since : Attribute { public readonly string version; diff --git a/Runtime/Serie/Parallel/ParallelHandler.cs b/Runtime/Serie/Parallel/ParallelHandler.cs index 38a64534..c56c4d41 100644 --- a/Runtime/Serie/Parallel/ParallelHandler.cs +++ b/Runtime/Serie/Parallel/ParallelHandler.cs @@ -21,8 +21,7 @@ namespace XCharts.Runtime DrawParallelSerie(vh, serie); } - private void UpdateSerieContext() - { } + private void UpdateSerieContext() { } private void DrawParallelSerie(VertexHelper vh, Parallel serie) { @@ -116,7 +115,10 @@ namespace XCharts.Runtime lp = pos; } if (isSmooth) - UGL.DrawCurves(vh, m_Points, lineWidth, lineColor, chart.settings.lineSmoothness, currProgress, isHorizonal); + UGL.DrawCurves(vh, m_Points, lineWidth, lineColor, + chart.settings.lineSmoothStyle, + chart.settings.lineSmoothness, + UGL.Direction.XAxis, currProgress, isHorizonal); else UGL.DrawLine(vh, m_Points, lineWidth, lineColor, isSmooth); } diff --git a/Runtime/Serie/Radar/Radar.cs b/Runtime/Serie/Radar/Radar.cs index 8af45a95..dc44ec02 100644 --- a/Runtime/Serie/Radar/Radar.cs +++ b/Runtime/Serie/Radar/Radar.cs @@ -11,9 +11,21 @@ namespace XCharts.Runtime [SerieDataExtraField()] public class Radar : Serie, INeedSerieContainer { + [SerializeField][Since("3.2.0")] private bool m_Smooth = false; + + /// + /// Whether use smooth curve. + /// |是否平滑曲线。平滑曲线时不支持区域填充颜色。 + /// + public bool smooth + { + get { return m_Smooth; } + set { if (PropertyUtil.SetStruct(ref m_Smooth, value)) { SetVerticesDirty(); } } + } + public int containerIndex { get; internal set; } public int containterInstanceId { get; internal set; } - public override bool useDataNameForColor { get { return true; } } + public override bool useDataNameForColor { get { return radarType == RadarType.Multiple; } } public override bool multiDimensionLabel { get { return radarType == RadarType.Multiple; } } public static Serie AddDefaultSerie(BaseChart chart, string serieName) diff --git a/Runtime/Serie/Radar/RadarHandler.cs b/Runtime/Serie/Radar/RadarHandler.cs index 374455db..5bda0afb 100644 --- a/Runtime/Serie/Radar/RadarHandler.cs +++ b/Runtime/Serie/Radar/RadarHandler.cs @@ -262,11 +262,11 @@ namespace XCharts.Runtime { toPoint = new Vector3(centerPos.x + radius * Mathf.Sin(currAngle), centerPos.y + radius * Mathf.Cos(currAngle)); - if (areaStyle != null && areaStyle.show) + if (areaStyle != null && areaStyle.show && !serie.smooth) { UGL.DrawTriangle(vh, startPoint, toPoint, centerPos, areaColor, areaColor, areaToColor); } - if (lineStyle.show) + if (lineStyle.show && !serie.smooth) { ChartDrawer.DrawLineStyle(vh, lineStyle.type, lineWidth, startPoint, toPoint, lineColor); } @@ -274,14 +274,24 @@ namespace XCharts.Runtime } serieData.context.dataPoints.Add(startPoint); } - if (areaStyle != null && areaStyle.show) + if (areaStyle != null && areaStyle.show && !serie.smooth) { UGL.DrawTriangle(vh, startPoint, firstPoint, centerPos, areaColor, areaColor, areaToColor); } - if (lineStyle.show) + if (lineStyle.show && !serie.smooth) { ChartDrawer.DrawLineStyle(vh, lineStyle.type, lineWidth, startPoint, firstPoint, lineColor); } + + if (serie.smooth) + { + UGL.DrawCurves(vh, serieData.context.dataPoints, lineWidth, lineColor, + chart.settings.lineSmoothStyle, + chart.settings.lineSmoothness, + UGL.Direction.Random, + float.NaN, true); + } + if (symbol.show && symbol.type != SymbolType.None) { for (int m = 0; m < serieData.context.dataPoints.Count; m++) @@ -394,11 +404,11 @@ namespace XCharts.Runtime { toPoint = new Vector3(p.x + radius * Mathf.Sin(currAngle), p.y + radius * Mathf.Cos(currAngle)); - if (areaStyle != null && areaStyle.show) + if (areaStyle != null && areaStyle.show && !serie.smooth) { UGL.DrawTriangle(vh, startPoint, toPoint, p, areaColor, areaColor, areaToColor); } - if (lineStyle.show) + if (lineStyle.show && !serie.smooth) { if (radar.connectCenter) ChartDrawer.DrawLineStyle(vh, lineStyle, startPoint, centerPos, @@ -409,14 +419,15 @@ namespace XCharts.Runtime startPoint = toPoint; lastColor = lineColor; } + serie.context.dataPoints.Add(startPoint); serieData.context.position = startPoint; serieData.context.labelPosition = startPoint; - if (areaStyle != null && areaStyle.show && j == endIndex) + if (areaStyle != null && areaStyle.show && j == endIndex && !serie.smooth) { UGL.DrawTriangle(vh, startPoint, firstPoint, centerPos, areaColor, areaColor, areaToColor); } - if (lineStyle.show && j == endIndex) + if (lineStyle.show && j == endIndex && !serie.smooth) { if (radar.connectCenter) ChartDrawer.DrawLineStyle(vh, lineStyle, startPoint, centerPos, @@ -425,6 +436,16 @@ namespace XCharts.Runtime LineStyle.Type.Solid, lineColor, radar.lineGradient ? firstColor : lineColor); } } + if (serie.smooth) + { + var lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth); + var lineColor = SerieHelper.GetLineColor(serie, null, chart.theme, serie.context.colorIndex, false); + UGL.DrawCurves(vh, serie.context.dataPoints, lineWidth, lineColor, + chart.settings.lineSmoothStyle, + chart.settings.lineSmoothness, + UGL.Direction.Random, + float.NaN, true); + } if (serie.symbol.show && serie.symbol.type != SymbolType.None) { for (int j = 0; j < serie.data.Count; j++) diff --git a/Runtime/XUGL/UGL.cs b/Runtime/XUGL/UGL.cs index b260a52e..595342f3 100644 --- a/Runtime/XUGL/UGL.cs +++ b/Runtime/XUGL/UGL.cs @@ -10,6 +10,24 @@ namespace XUGL /// public static class UGL { + /// + /// 曲线方向 + /// + public enum Direction + { + /// + /// 沿X轴方向 + /// + XAxis, + /// + /// 沿Y轴方向 + /// + YAxis, + /// + /// 随机无序的。如一个闭合的环状曲线。 + /// + Random + } private static readonly Color32 s_ClearColor32 = new Color32(0, 0, 0, 0); private static readonly Vector2 s_ZeroVector2 = Vector2.zero; private static UIVertex[] s_Vertex = new UIVertex[4]; @@ -134,7 +152,7 @@ namespace XUGL } else if (smooth) { - DrawCurves(vh, points, width, color, 2); + DrawCurves(vh, points, width, color, 2, 2, Direction.XAxis, float.NaN, closepath); } else { @@ -1752,42 +1770,67 @@ namespace XUGL /// 曲线宽 /// 曲线颜色 public static void DrawCurves(VertexHelper vh, Vector3 sp, Vector3 ep, Vector3 cp1, Vector3 cp2, - float lineWidth, Color32 lineColor, float smoothness) + float lineWidth, Color32 lineColor, float smoothness, Direction dire = Direction.XAxis) { var dist = Vector3.Distance(sp, ep); var segment = (int) (dist / (smoothness <= 0 ? 2f : smoothness)); UGLHelper.GetBezierList2(ref s_CurvesPosList, sp, ep, segment, cp1, cp2); - DrawCurvesInternal(vh, s_CurvesPosList, lineWidth, lineColor); + DrawCurvesInternal(vh, s_CurvesPosList, lineWidth, lineColor, dire); } + /// + /// 画贝塞尔曲线 + /// + /// + /// 坐标点列表 + /// 曲线宽 + /// 曲线颜色 + /// 曲线样式 + /// 平滑度 + /// 曲线方向 + /// 当前绘制进度 + /// 曲线是否闭合 public static void DrawCurves(VertexHelper vh, List points, float width, Color32 color, - float smoothness, float currProgress = float.PositiveInfinity, bool isYAxis = false) + float smoothStyle, float smoothness, Direction dire, float currProgress = float.NaN, + bool closed = false) { - for (int i = 0; i < points.Count - 1; i++) + var count = points.Count; + var size = (closed?count : count - 1); + if (closed) + dire = Direction.Random; + for (int i = 0; i < size; i++) { var sp = points[i]; - var ep = points[i + 1]; - var lsp = i > 0 ? points[i - 1] : sp; - var nep = i < points.Count - 2 ? points[i + 2] : ep; + var ep = closed?(i == size - 1 ? points[0] : points[i + 1]) : points[i + 1]; + var lsp = i > 0 ? points[i - 1] : (closed?points[count - 1] : sp); + var nep = i < points.Count - 2 ? points[i + 2] : (closed?points[(i + 2) % count] : ep); var smoothness2 = smoothness; - if (currProgress != float.PositiveInfinity) + if (currProgress != float.NaN) { - if (isYAxis) - smoothness2 = ep.y <= currProgress ? smoothness : smoothness * 0.5f; - else - smoothness2 = ep.x <= currProgress ? smoothness : smoothness * 0.5f; + switch (dire) + { + case Direction.XAxis: + smoothness2 = ep.x <= currProgress ? smoothness : smoothness * 0.5f; + break; + case Direction.YAxis: + smoothness2 = ep.y <= currProgress ? smoothness : smoothness * 0.5f; + break; + case Direction.Random: + smoothness2 = smoothness * 0.5f; + break; + } } - if (isYAxis) - UGLHelper.GetBezierListVertical(ref s_CurvesPosList, sp, ep, smoothness2); + if (dire == Direction.YAxis) + UGLHelper.GetBezierListVertical(ref s_CurvesPosList, sp, ep, smoothness2, smoothStyle); else - UGLHelper.GetBezierList(ref s_CurvesPosList, sp, ep, lsp, nep, smoothness2); + UGLHelper.GetBezierList(ref s_CurvesPosList, sp, ep, lsp, nep, smoothness2, smoothStyle); - DrawCurvesInternal(vh, s_CurvesPosList, width, color, currProgress, isYAxis); + DrawCurvesInternal(vh, s_CurvesPosList, width, color, dire, currProgress); } } private static void DrawCurvesInternal(VertexHelper vh, List curvesPosList, float lineWidth, - Color32 lineColor, float currProgress = float.PositiveInfinity, bool isYAxis = false) + Color32 lineColor, Direction dire, float currProgress = float.NaN) { if (curvesPosList.Count > 1) { @@ -1805,11 +1848,11 @@ namespace XUGL for (int i = 1; i < curvesPosList.Count; i++) { to = curvesPosList[i]; - if (currProgress != float.PositiveInfinity) + if (currProgress != float.NaN) { - if (isYAxis && to.y > currProgress) + if (dire == Direction.YAxis && to.y > currProgress) break; - if (!isYAxis && to.x > currProgress) + if (dire == Direction.XAxis && to.x > currProgress) break; } diff --git a/Runtime/XUGL/UGLHelper.cs b/Runtime/XUGL/UGLHelper.cs index 2f7166cb..4076b525 100644 --- a/Runtime/XUGL/UGLHelper.cs +++ b/Runtime/XUGL/UGLHelper.cs @@ -110,22 +110,21 @@ namespace XUGL public static void GetBezierList(ref List posList, Vector3 sp, Vector3 ep, Vector3 lsp, Vector3 nep, float smoothness = 2f, float k = 2.0f, bool limit = false) { - float dist = Mathf.Abs(sp.x - ep.x); + var dist = Vector3.Distance(sp, ep); Vector3 cp1, cp2; var dir = (ep - sp).normalized; var diff = dist / k; if (lsp == sp) { - cp1 = sp + dist / k * dir * 1; - cp1.y = sp.y; - cp1 = sp; + cp1 = sp + (nep - ep).normalized * diff; + if (limit) + cp1.y = sp.y; } else { cp1 = sp + (ep - lsp).normalized * diff; if (limit) cp1.y = sp.y; - } if (nep == ep) { @@ -137,7 +136,6 @@ namespace XUGL if (limit) cp2.y = ep.y; } - dist = Vector3.Distance(sp, ep); int segment = (int) (dist / (smoothness <= 0 ? 2f : smoothness)); if (segment < 1) segment = (int) (dist / 0.5f); if (segment < 4) segment = 4;