From 642dde3c27b3a2e80d05dcf6873b43a5ea0680db Mon Sep 17 00:00:00 2001 From: monitor1394 Date: Fri, 5 Mar 2021 08:56:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0`Legend`=E5=87=A0=E7=A7=8D?= =?UTF-8?q?=E5=86=85=E7=BD=AE=E5=9B=BE=E6=A0=87=E7=9A=84=E6=94=AF=E6=8C=81?= =?UTF-8?q?=20#90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/PropertyDrawers/LegendDrawer.cs | 1 + Editor/PropertyDrawers/SettingsDrawer.cs | 5 +- Runtime/Component/Main/Legend.cs | 49 ++++++++++++++- Runtime/Component/Main/Settings.cs | 26 ++++++++ Runtime/Internal/BaseChart.cs | 76 ++++++++++++++++++++++++ Runtime/Internal/Object/LegendItem.cs | 30 ++++++++++ Runtime/Internal/Utility/ChartDrawer.cs | 1 - Runtime/Internal/Utility/ChartHelper.cs | 10 ++++ Runtime/XUGL/UGL.cs | 35 +++++------ 9 files changed, 210 insertions(+), 23 deletions(-) diff --git a/Editor/PropertyDrawers/LegendDrawer.cs b/Editor/PropertyDrawers/LegendDrawer.cs index 09dc977a..a84378f3 100644 --- a/Editor/PropertyDrawers/LegendDrawer.cs +++ b/Editor/PropertyDrawers/LegendDrawer.cs @@ -20,6 +20,7 @@ namespace XCharts if (MakeFoldout(prop, "m_Show")) { ++EditorGUI.indentLevel; + PropertyField(prop, "m_IconType"); PropertyField(prop, "m_ItemWidth"); PropertyField(prop, "m_ItemHeight"); PropertyField(prop, "m_ItemGap"); diff --git a/Editor/PropertyDrawers/SettingsDrawer.cs b/Editor/PropertyDrawers/SettingsDrawer.cs index 016492be..9ff7f66f 100644 --- a/Editor/PropertyDrawers/SettingsDrawer.cs +++ b/Editor/PropertyDrawers/SettingsDrawer.cs @@ -20,7 +20,7 @@ namespace XCharts if (MakeFoldout(prop, "")) { var btnWidth = 50; - var btnRect = new Rect(pos.x + pos.width - btnWidth, pos.y, btnWidth, EditorGUIUtility.singleLineHeight); + var btnRect = new Rect(pos.x + pos.width - btnWidth, pos.y, btnWidth, EditorGUIUtility.singleLineHeight); if (GUI.Button(btnRect, new GUIContent("Reset", "Reset to default settings"))) { var chart = prop.serializedObject.targetObject as BaseChart; @@ -32,7 +32,8 @@ namespace XCharts PropertyField(prop, "m_LineSmoothness"); PropertyField(prop, "m_LineSegmentDistance"); PropertyField(prop, "m_CicleSmoothness"); - + PropertyField(prop, "m_LegendIconLineWidth"); + PropertyListField(prop, "m_LegendIconCornerRadius", true); --EditorGUI.indentLevel; } } diff --git a/Runtime/Component/Main/Legend.cs b/Runtime/Component/Main/Legend.cs index f4bb1336..a20e273b 100644 --- a/Runtime/Component/Main/Legend.cs +++ b/Runtime/Component/Main/Legend.cs @@ -19,6 +19,37 @@ namespace XCharts [System.Serializable] public class Legend : MainComponent, IPropertyChanged { + public enum Type + { + /// + /// 自动匹配。 + /// + Auto, + /// + /// 自定义图标。 + /// + Custom, + /// + /// 空心圆。 + /// + EmptyCircle, + /// + /// 圆形。 + /// + Circle, + /// + /// 正方形。可通过Setting的legendIconCornerRadius参数调整圆角。 + /// + Rect, + /// + /// 三角形。 + /// + Triangle, + /// + /// 菱形。 + /// + Diamond, + } /// /// Selected mode of legend, which controls whether series can be toggled displaying by clicking legends. /// 图例选择的模式,控制是否可以通过点击图例改变系列的显示状态。默认开启图例选择,可以设成 None 关闭。 @@ -39,10 +70,11 @@ namespace XCharts None } [SerializeField] private bool m_Show = true; + [SerializeField] private Type m_IconType; [SerializeField] private SelectedMode m_SelectedMode; [SerializeField] private Orient m_Orient = Orient.Horizonal; [SerializeField] private Location m_Location = Location.defaultRight; - [SerializeField] private float m_ItemWidth = 24.0f; + [SerializeField] private float m_ItemWidth = 25.0f; [SerializeField] private float m_ItemHeight = 12.0f; [SerializeField] private float m_ItemGap = 10f; [SerializeField] private bool m_ItemAutoColor = true; @@ -64,11 +96,20 @@ namespace XCharts set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetComponentDirty(); } } /// + /// Type of legend. + /// 图例类型。 + /// [default:Type.Auto] + /// + public Type iconType + { + get { return m_IconType; } + set { if (PropertyUtil.SetStruct(ref m_IconType, value)) SetAllDirty(); } + } + /// /// Selected mode of legend, which controls whether series can be toggled displaying by clicking legends. /// 选择模式。控制是否可以通过点击图例改变系列的显示状态。默认开启图例选择,可以设成 None 关闭。 /// [default:SelectedMode.Multiple] /// - /// public SelectedMode selectedMode { get { return m_SelectedMode; } @@ -226,11 +267,12 @@ namespace XCharts { var legend = new Legend { + m_IconType = Type.Auto, m_Show = false, m_SelectedMode = SelectedMode.Multiple, m_Orient = Orient.Horizonal, m_Location = Location.defaultTop, - m_ItemWidth = 24.0f, + m_ItemWidth = 25.0f, m_ItemHeight = 12.0f, m_ItemGap = 10f, }; @@ -336,6 +378,7 @@ namespace XCharts { m_DataBtnList[name] = item; int index = m_DataBtnList.Values.Count; + item.SetIconActive(iconType == Type.Custom); item.SetActive(show); } diff --git a/Runtime/Component/Main/Settings.cs b/Runtime/Component/Main/Settings.cs index d81c6737..98e5c6bb 100644 --- a/Runtime/Component/Main/Settings.cs +++ b/Runtime/Component/Main/Settings.cs @@ -22,6 +22,8 @@ namespace XCharts [SerializeField] [Range(1f, 20)] protected float m_LineSmoothness = 2f; [SerializeField] [Range(1f, 20)] protected float m_LineSegmentDistance = 3f; [SerializeField] [Range(1, 10)] protected float m_CicleSmoothness = 2f; + [SerializeField] protected float m_LegendIconLineWidth = 2; + [SerializeField] private float[] m_LegendIconCornerRadius = new float[] { 0.25f, 0.25f, 0.25f, 0.25f }; /// /// max painter. @@ -75,6 +77,26 @@ namespace XCharts set { if (PropertyUtil.SetStruct(ref m_CicleSmoothness, value < 0 ? 1f : value)) SetVerticesDirty(); } } + /// + /// the width of line serie legend. + /// Line类型图例图标的线条宽度。 + /// + public float legendIconLineWidth + { + get { return m_LegendIconLineWidth; } + set { if (PropertyUtil.SetStruct(ref m_LegendIconLineWidth, value)) SetVerticesDirty(); } + } + + /// + /// The radius of rounded corner. Its unit is px. Use array to respectively specify the 4 corner radiuses((clockwise upper left, upper right, bottom right and bottom left)). + /// 图例圆角半径。用数组分别指定4个圆角半径(顺时针左上,右上,右下,左下)。 + /// + public float[] legendIconCornerRadius + { + get { return m_LegendIconCornerRadius; } + set { if (PropertyUtil.SetClass(ref m_LegendIconCornerRadius, value, true)) SetVerticesDirty(); } + } + public void Copy(Settings settings) { m_MaxPainter = settings.maxPainter; @@ -82,6 +104,8 @@ namespace XCharts m_LineSmoothness = settings.lineSmoothness; m_LineSegmentDistance = settings.lineSegmentDistance; m_CicleSmoothness = settings.cicleSmoothness; + m_LegendIconLineWidth = settings.legendIconLineWidth; + ChartHelper.CopyArray(m_LegendIconCornerRadius, settings.legendIconCornerRadius); } public void Reset() @@ -100,6 +124,8 @@ namespace XCharts m_LineSmoothness = XChartsSettings.lineSmoothness, m_LineSegmentDistance = XChartsSettings.lineSegmentDistance, m_CicleSmoothness = XChartsSettings.cicleSmoothness, + m_LegendIconLineWidth = 2, + m_LegendIconCornerRadius = new float[] { 0.25f, 0.25f, 0.25f, 0.25f } }; } } diff --git a/Runtime/Internal/BaseChart.cs b/Runtime/Internal/BaseChart.cs index 1dcf8298..246b3986 100644 --- a/Runtime/Internal/BaseChart.cs +++ b/Runtime/Internal/BaseChart.cs @@ -815,6 +815,7 @@ namespace XCharts vh.Clear(); DrawBackground(vh); DrawPainterBase(vh); + DrawLegend(vh); foreach (var drawSerie in m_DrawSeries) drawSerie.DrawBase(vh); } @@ -868,6 +869,81 @@ namespace XCharts UGL.DrawQuadrilateral(vh, p1, p2, p3, p4, backgroundColor); } + protected virtual void DrawLegend(VertexHelper vh) + { + if (m_Series.Count == 0) return; + foreach (var legend in m_Legends) + { + if (!legend.show) continue; + if (legend.iconType == Legend.Type.Custom) continue; + foreach (var kv in legend.buttonList) + { + var item = kv.Value; + var rect = item.GetIconRect(); + var radius = Mathf.Min(rect.width, rect.height) / 2; + var color = item.GetIconColor(); + var iconType = legend.iconType; + if (legend.iconType == Legend.Type.Auto) + { + var serie = m_Series.GetSerie(item.legendName); + if (serie != null && serie.type == SerieType.Line) + { + var sp = new Vector3(rect.center.x - rect.width / 2, rect.center.y); + var ep = new Vector3(rect.center.x + rect.width / 2, rect.center.y); + UGL.DrawLine(vh, sp, ep, m_Settings.legendIconLineWidth, color); + if (!serie.symbol.show) continue; + switch (serie.symbol.type) + { + case SerieSymbolType.None: + continue; + case SerieSymbolType.Circle: + iconType = Legend.Type.Circle; + break; + case SerieSymbolType.Diamond: + iconType = Legend.Type.Diamond; + break; + case SerieSymbolType.EmptyCircle: + iconType = Legend.Type.EmptyCircle; + break; + case SerieSymbolType.Rect: + iconType = Legend.Type.Rect; + break; + case SerieSymbolType.Triangle: + iconType = Legend.Type.Triangle; + break; + } + } + else + { + iconType = Legend.Type.Rect; + } + } + switch (iconType) + { + case Legend.Type.Rect: + var cornerRadius = m_Settings.legendIconCornerRadius; + UGL.DrawRoundRectangle(vh, rect.center, rect.width, rect.height, color, color, + 0, cornerRadius, false, 0.5f); + break; + case Legend.Type.Circle: + UGL.DrawCricle(vh, rect.center, radius, color); + break; + case Legend.Type.Diamond: + UGL.DrawDiamond(vh, rect.center, radius, color); + break; + case Legend.Type.EmptyCircle: + var backgroundColor = ThemeHelper.GetBackgroundColor(m_Theme, m_Background); + UGL.DrawEmptyCricle(vh, rect.center, radius, 2 * m_Settings.legendIconLineWidth, + color, color, backgroundColor, 1f); + break; + case Legend.Type.Triangle: + UGL.DrawTriangle(vh, rect.center, 1.2f * radius, color); + break; + } + } + } + } + public void DrawSymbol(VertexHelper vh, SerieSymbolType type, float symbolSize, float tickness, Vector3 pos, Color32 color, Color32 toColor, float gap, float[] cornerRadius) { diff --git a/Runtime/Internal/Object/LegendItem.cs b/Runtime/Internal/Object/LegendItem.cs index 40b81be9..4a5acde6 100644 --- a/Runtime/Internal/Object/LegendItem.cs +++ b/Runtime/Internal/Object/LegendItem.cs @@ -105,6 +105,28 @@ namespace XCharts } } + public Rect GetIconRect() + { + if (m_GameObject && m_IconRect) + { + var pos = m_GameObject.transform.localPosition; + var sizeDelta = m_IconRect.sizeDelta; + var y = pos.y - (m_Rect.sizeDelta.y - sizeDelta.y) / 2 - sizeDelta.y; + return new Rect(pos.x, y, m_IconRect.sizeDelta.x, m_IconRect.sizeDelta.y); + } + else + { + return Rect.zero; + } + } + + public Color GetIconColor() + { + if (m_Icon) return m_Icon.color; + else return Color.clear; + } + + public void SetIconColor(Color color) { if (m_Icon) @@ -121,6 +143,14 @@ namespace XCharts } } + public void SetIconActive(bool active) + { + if (m_Icon) + { + m_Icon.gameObject.SetActive(active); + } + } + public void SetContentColor(Color color) { if (m_Text != null) diff --git a/Runtime/Internal/Utility/ChartDrawer.cs b/Runtime/Internal/Utility/ChartDrawer.cs index 62fbde61..2a13fe40 100644 --- a/Runtime/Internal/Utility/ChartDrawer.cs +++ b/Runtime/Internal/Utility/ChartDrawer.cs @@ -52,7 +52,6 @@ namespace XCharts } else { - //UGL.DrawPolygon(vh, pos, symbolSize, color, toColor); UGL.DrawRoundRectangle(vh, pos, symbolSize, symbolSize, color, color, 0, cornerRadius, true); } break; diff --git a/Runtime/Internal/Utility/ChartHelper.cs b/Runtime/Internal/Utility/ChartHelper.cs index d7514332..25b43555 100644 --- a/Runtime/Internal/Utility/ChartHelper.cs +++ b/Runtime/Internal/Utility/ChartHelper.cs @@ -621,6 +621,16 @@ namespace XCharts foreach (var item in fromList) toList.Add(item); return true; } + public static bool CopyArray(T[] toList, T[] fromList) + { + if (toList == null || fromList == null) return false; + if (toList.Length != fromList.Length) + { + toList = new T[fromList.Length]; + } + for (int i = 0; i < fromList.Length; i++) toList[i] = fromList[i]; + return true; + } public static List ParseFloatFromString(string jsonData) { diff --git a/Runtime/XUGL/UGL.cs b/Runtime/XUGL/UGL.cs index 84935c94..3dd25405 100644 --- a/Runtime/XUGL/UGL.cs +++ b/Runtime/XUGL/UGL.cs @@ -566,7 +566,8 @@ namespace XUGL /// /// public static void DrawRoundRectangle(VertexHelper vh, Vector3 center, float rectWidth, float rectHeight, - Color32 color, Color32 toColor, float rotate = 0, float[] cornerRadius = null, bool isYAxis = false) + Color32 color, Color32 toColor, float rotate = 0, float[] cornerRadius = null, bool isYAxis = false, + float smoothness = 2) { var isGradient = !UGLHelper.IsValueEqualsColor(color, toColor); var halfWid = rectWidth / 2; @@ -645,10 +646,10 @@ namespace XUGL if (roundRbLeft.x < roundLb.x) roundRbLeft.x = roundLb.x; if (!isGradient) { - DrawSector(vh, roundLt, brLt, color, color, 270, 360, 1, isYAxis); - DrawSector(vh, roundRt, brRt, toColor, toColor, 0, 90, 1, isYAxis); - DrawSector(vh, roundRb, brRb, toColor, toColor, 90, 180, 1, isYAxis); - DrawSector(vh, roundLb, brLb, color, color, 180, 270, 1, isYAxis); + DrawSector(vh, roundLt, brLt, color, color, 270, 360, 1, isYAxis, smoothness); + DrawSector(vh, roundRt, brRt, toColor, toColor, 0, 90, 1, isYAxis, smoothness); + DrawSector(vh, roundRb, brRb, toColor, toColor, 90, 180, 1, isYAxis, smoothness); + DrawSector(vh, roundLb, brLb, color, color, 180, 270, 1, isYAxis, smoothness); DrawQuadrilateral(vh, ltIn, ltInRight, lbInRight, lbIn, color, color); DrawQuadrilateral(vh, lbIn2, roundLb, roundLbRight, lbIn2Right, color, color); @@ -677,10 +678,10 @@ namespace XUGL var upRightColor = Color32.Lerp(tempRightColor, toColor, (maxRight - brRt) / maxRight); var downRightColor = Color32.Lerp(tempRightColor, toColor, (maxRight - brRb) / maxRight); - DrawSector(vh, roundLt, brLt, color, upLeftColor, 270, 360, 1, isYAxis); - DrawSector(vh, roundRt, brRt, upRightColor, toColor, 0, 90, 1, isYAxis); - DrawSector(vh, roundRb, brRb, downRightColor, toColor, 90, 180, 1, isYAxis); - DrawSector(vh, roundLb, brLb, color, downLeftColor, 180, 270, 1, isYAxis); + DrawSector(vh, roundLt, brLt, color, upLeftColor, 270, 360, 1, isYAxis, smoothness); + DrawSector(vh, roundRt, brRt, upRightColor, toColor, 0, 90, 1, isYAxis, smoothness); + DrawSector(vh, roundRb, brRb, downRightColor, toColor, 90, 180, 1, isYAxis, smoothness); + DrawSector(vh, roundLb, brLb, color, downLeftColor, 180, 270, 1, isYAxis, smoothness); DrawQuadrilateral(vh, lbIn, ltIn, ltInRight, lbInRight, color, tempLeftColor); DrawQuadrilateral(vh, lbIn2, roundLb, roundLbRight, lbIn2Right, downLeftColor, @@ -739,10 +740,10 @@ namespace XUGL if (!isGradient) { - DrawSector(vh, roundLt, brLt, toColor, toColor, 270, 360, 1, isYAxis); - DrawSector(vh, roundRt, brRt, toColor, toColor, 0, 90, 1, isYAxis); - DrawSector(vh, roundRb, brRb, color, color, 90, 180, 1, isYAxis); - DrawSector(vh, roundLb, brLb, color, color, 180, 270, 1, isYAxis); + DrawSector(vh, roundLt, brLt, toColor, toColor, 270, 360, 1, isYAxis, smoothness); + DrawSector(vh, roundRt, brRt, toColor, toColor, 0, 90, 1, isYAxis, smoothness); + DrawSector(vh, roundRb, brRb, color, color, 90, 180, 1, isYAxis, smoothness); + DrawSector(vh, roundLb, brLb, color, color, 180, 270, 1, isYAxis, smoothness); DrawQuadrilateral(vh, ltIn2, rtIn, rtInDown, ltIn2Down, toColor, toColor); DrawQuadrilateral(vh, ltIn, roundLt, roundLtDown, ltInDown, toColor, toColor); @@ -765,10 +766,10 @@ namespace XUGL var leftDownColor = Color32.Lerp(color, tempDownColor, brLb / maxdown); var rightDownColor = Color32.Lerp(color, tempDownColor, brRb / maxdown); - DrawSector(vh, roundLt, brLt, leftUpColor, toColor, 270, 360, 1, isYAxis); - DrawSector(vh, roundRt, brRt, rightUpColor, toColor, 0, 90, 1, isYAxis); - DrawSector(vh, roundRb, brRb, rightDownColor, color, 90, 180, 1, isYAxis); - DrawSector(vh, roundLb, brLb, leftDownColor, color, 180, 270, 1, isYAxis); + DrawSector(vh, roundLt, brLt, leftUpColor, toColor, 270, 360, 1, isYAxis, smoothness); + DrawSector(vh, roundRt, brRt, rightUpColor, toColor, 0, 90, 1, isYAxis, smoothness); + DrawSector(vh, roundRb, brRb, rightDownColor, color, 90, 180, 1, isYAxis, smoothness); + DrawSector(vh, roundLb, brLb, leftDownColor, color, 180, 270, 1, isYAxis, smoothness); DrawQuadrilateral(vh, ltIn2, rtIn, rtInDown, ltIn2Down, toColor, tempUpColor); DrawQuadrilateral(vh, ltIn, roundLt, roundLtDown, ltInDown, leftUpColor,