From ea819bfa4242b3ceac399d58abd7c9ea4a323654 Mon Sep 17 00:00:00 2001 From: monitor1394 Date: Fri, 4 Aug 2023 08:26:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0`Ring`=E7=9A=84`avoidLabelOve?= =?UTF-8?q?rlap`=E9=81=BF=E5=85=8D=E6=96=87=E6=9C=AC=E5=A0=86=E5=8F=A0?= =?UTF-8?q?=E7=9A=84=E6=94=AF=E6=8C=81=20(#247)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/Series/RingEditor.cs | 1 + Runtime/Serie/Ring/RingHandler.cs | 188 +++++++++++++++++++----------- Runtime/Serie/Serie.cs | 5 +- 3 files changed, 127 insertions(+), 67 deletions(-) diff --git a/Editor/Series/RingEditor.cs b/Editor/Series/RingEditor.cs index 71ec6db6..03cbd2b6 100644 --- a/Editor/Series/RingEditor.cs +++ b/Editor/Series/RingEditor.cs @@ -13,6 +13,7 @@ namespace XCharts.Editor PropertyField("m_Gap"); PropertyField("m_RoundCap"); PropertyField("m_Clockwise"); + PropertyField("m_AvoidLabelOverlap"); PropertyField("m_ItemStyle"); PropertyField("m_Animation"); diff --git a/Runtime/Serie/Ring/RingHandler.cs b/Runtime/Serie/Ring/RingHandler.cs index dd921e2d..d9007afb 100644 --- a/Runtime/Serie/Ring/RingHandler.cs +++ b/Runtime/Serie/Ring/RingHandler.cs @@ -10,7 +10,6 @@ namespace XCharts.Runtime [UnityEngine.Scripting.Preserve] internal sealed class RingHandler : SerieHandler { - public override int defaultDimension { get { return 0; } } public override void Update() @@ -110,57 +109,6 @@ namespace XCharts.Runtime paramList.Add(param); } - public override Vector3 GetSerieDataLabelPosition(SerieData serieData, LabelStyle label) - { - var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData); - var centerRadius = (serieData.context.outsideRadius + serieData.context.insideRadius) / 2; - var startAngle = serieData.context.startAngle; - var toAngle = serieData.context.toAngle; - switch (label.position) - { - case LabelStyle.Position.Bottom: - case LabelStyle.Position.Start: - var px1 = Mathf.Sin(startAngle * Mathf.Deg2Rad) * centerRadius; - var py1 = Mathf.Cos(startAngle * Mathf.Deg2Rad) * centerRadius; - var xDiff = serie.clockwise ? -label.distance : label.distance; - - if (labelLine != null && labelLine.show) - { - serieData.context.labelLinePosition = serie.context.center + new Vector3(px1, py1) + labelLine.GetStartSymbolOffset(); - serieData.context.labelPosition = GetLabelLineEndPosition(serie, serieData, labelLine) + new Vector3(xDiff, 0); - } - else - { - serieData.context.labelLinePosition = serie.context.center + new Vector3(px1 + xDiff, py1); - serieData.context.labelPosition = serieData.context.labelLinePosition; - } - break; - case LabelStyle.Position.Top: - case LabelStyle.Position.End: - startAngle += serie.clockwise ? -label.distance : label.distance; - toAngle += serie.clockwise ? label.distance : -label.distance; - var px2 = Mathf.Sin(toAngle * Mathf.Deg2Rad) * centerRadius; - var py2 = Mathf.Cos(toAngle * Mathf.Deg2Rad) * centerRadius; - - if (labelLine != null && labelLine.show) - { - serieData.context.labelLinePosition = serie.context.center + new Vector3(px2, py2) + labelLine.GetStartSymbolOffset(); - serieData.context.labelPosition = GetLabelLineEndPosition(serie, serieData, labelLine); - } - else - { - serieData.context.labelLinePosition = serie.context.center + new Vector3(px2, py2); - serieData.context.labelPosition = serieData.context.labelLinePosition; - } - break; - default: //LabelStyle.Position.Center - serieData.context.labelLinePosition = serie.context.center + label.offset; - serieData.context.labelPosition = serieData.context.labelLinePosition; - break; - } - return serieData.context.labelPosition; - } - private Vector3 GetLabelLineEndPosition(Serie serie, SerieData serieData, LabelLine labelLine) { var isRight = !serie.clockwise; @@ -170,16 +118,22 @@ namespace XCharts.Runtime var lineLength2 = ChartHelper.GetActualValue(labelLine.lineLength2, serie.context.outsideRadius); var pos1 = serieData.context.labelLinePosition; var pos2 = pos1 + new Vector3(Mathf.Cos(rad) * lineLength1, Mathf.Sin(rad) * lineLength1); - var pos5 = pos2 + dire * lineLength2; - return pos5 + labelLine.GetEndSymbolOffset(); + var pos5 = labelLine.lineType == LabelLine.LineType.HorizontalLine + ? pos1 + dire * (lineLength1 + lineLength2) + labelLine.GetEndSymbolOffset() + : pos2 + dire * lineLength2 + labelLine.GetEndSymbolOffset(); + if (labelLine.lineEndX != 0) + { + pos5.x = labelLine.lineEndX; + } + return pos5; } public override void DrawSerie(VertexHelper vh) { if (!serie.show || serie.animation.HasFadeOut()) return; + UpdateRuntimeData(); var data = serie.data; serie.animation.InitProgress(serie.startAngle, serie.startAngle + 360); - SerieHelper.UpdateCenter(serie, chart.chartPosition, chart.chartWidth, chart.chartHeight); var ringWidth = serie.context.outsideRadius - serie.context.insideRadius; var dataChanging = false; for (int j = 0; j < data.Count; j++) @@ -203,18 +157,21 @@ namespace XCharts.Runtime var borderWidth = itemStyle.borderWidth; var borderColor = itemStyle.borderColor; var roundCap = serie.roundCap && insideRadius > 0; - - serieData.context.startAngle = startDegree; - serieData.context.toAngle = toDegree; - serieData.context.insideRadius = insideRadius; - serieData.context.outsideRadius = serieData.radius > 0 ? serieData.radius : outsideRadius; DrawBackground(vh, serie, serieData, j, insideRadius, outsideRadius); UGL.DrawDoughnut(vh, serie.context.center, insideRadius, outsideRadius, itemColor, itemToColor, Color.clear, startDegree, toDegree, borderWidth, borderColor, 0, chart.settings.cicleSmoothness, roundCap, serie.clockwise); DrawCenter(vh, serie, serieData, insideRadius, j == data.Count - 1); + } + for (int j = 0; j < data.Count; j++) + { + var serieData = data[j]; + if (!serieData.show) continue; var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); + var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName); + Color32 itemColor, itemToColor; + SerieHelper.GetItemColor(out itemColor, out itemToColor, serie, serieData, chart.theme, colorIndex); if (SerieLabelHelper.CanShowLabel(serie, serieData, serieLabel, 0)) { DrawRingLabelLine(vh, serie, serieData, itemColor); @@ -231,6 +188,32 @@ namespace XCharts.Runtime } } + private void UpdateRuntimeData() + { + var data = serie.data; + SerieHelper.UpdateCenter(serie, chart.chartPosition, chart.chartWidth, chart.chartHeight); + var ringWidth = serie.context.outsideRadius - serie.context.insideRadius; + for (int j = 0; j < data.Count; j++) + { + var serieData = data[j]; + if (!serieData.show) continue; + var outsideRadius = serie.context.outsideRadius - j * (ringWidth + serie.gap); + if (outsideRadius < 0) continue; + var value = serieData.GetCurrData(0, serie.animation, false, false); + var max = serieData.GetLastData(); + var degree = (float)(360 * value / max); + var startDegree = GetStartAngle(serie); + var toDegree = GetToAngle(serie, degree); + var insideRadius = outsideRadius - ringWidth; + serieData.context.startAngle = startDegree; + serieData.context.toAngle = toDegree; + serieData.context.insideRadius = insideRadius; + serieData.context.outsideRadius = serieData.radius > 0 ? serieData.radius : outsideRadius; + UpdateLabelPosition(serieData); + } + AvoidLabelOverlap(); + } + public override void OnLegendButtonClick(int index, string legendName, bool show) { if (!serie.IsLegendName(legendName)) @@ -372,6 +355,85 @@ namespace XCharts.Runtime return angle; } + private void UpdateLabelPosition(SerieData serieData) + { + if (serieData.labelObject == null) return; + var label = SerieHelper.GetSerieLabel(serie, serieData); + var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData); + var centerRadius = (serieData.context.outsideRadius + serieData.context.insideRadius) / 2; + var startAngle = serieData.context.startAngle; + var toAngle = serieData.context.toAngle; + switch (label.position) + { + case LabelStyle.Position.Bottom: + case LabelStyle.Position.Start: + var px1 = Mathf.Sin(startAngle * Mathf.Deg2Rad) * centerRadius; + var py1 = Mathf.Cos(startAngle * Mathf.Deg2Rad) * centerRadius; + var xDiff = serie.clockwise ? -label.distance : label.distance; + + if (labelLine != null && labelLine.show) + { + serieData.context.labelLinePosition = serie.context.center + new Vector3(px1, py1) + labelLine.GetStartSymbolOffset(); + serieData.context.labelPosition = GetLabelLineEndPosition(serie, serieData, labelLine) + new Vector3(xDiff, 0); + } + else + { + serieData.context.labelLinePosition = serie.context.center + new Vector3(px1 + xDiff, py1); + serieData.context.labelPosition = serieData.context.labelLinePosition; + } + break; + case LabelStyle.Position.Top: + case LabelStyle.Position.End: + case LabelStyle.Position.Outside: + startAngle += serie.clockwise ? -label.distance : label.distance; + toAngle += serie.clockwise ? label.distance : -label.distance; + var px2 = Mathf.Sin(toAngle * Mathf.Deg2Rad) * centerRadius; + var py2 = Mathf.Cos(toAngle * Mathf.Deg2Rad) * centerRadius; + + if (labelLine != null && labelLine.show) + { + serieData.context.labelLinePosition = serie.context.center + new Vector3(px2, py2) + labelLine.GetStartSymbolOffset(); + serieData.context.labelPosition = GetLabelLineEndPosition(serie, serieData, labelLine); + } + else + { + serieData.context.labelLinePosition = serie.context.center + new Vector3(px2, py2); + serieData.context.labelPosition = serieData.context.labelLinePosition; + } + break; + default: //LabelStyle.Position.Center + serieData.context.labelLinePosition = serie.context.center + label.offset; + serieData.context.labelPosition = serieData.context.labelLinePosition; + break; + } + } + + private void AvoidLabelOverlap() + { + if (!serie.avoidLabelOverlap) return; + serie.context.sortedData.Clear(); + foreach (var serieData in serie.data) + { + serie.context.sortedData.Add(serieData); + } + serie.context.sortedData.Sort(delegate (SerieData a, SerieData b) + { + if (a == null || b == null) return 0; + return a.context.labelPosition.y.CompareTo(b.context.labelPosition.y); + }); + var startY = serie.context.sortedData[0].context.labelPosition.y; + for (int i = 1; i < serie.context.sortedData.Count; i++) + { + var serieData = serie.context.sortedData[i]; + var fontSize = serieData.labelObject.GetHeight(); + if (serieData.context.labelPosition.y - startY < fontSize) + { + serieData.context.labelPosition.y = startY + fontSize; + } + startY = serieData.context.labelPosition.y; + } + } + private void DrawRingLabelLine(VertexHelper vh, Serie serie, SerieData serieData, Color32 defaltColor) { var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); @@ -386,11 +448,9 @@ namespace XCharts.Runtime var dire = isRight ? Vector3.right : Vector3.left; var rad = Mathf.Deg2Rad * (isRight ? labelLine.lineAngle : 180 - labelLine.lineAngle); var lineLength1 = ChartHelper.GetActualValue(labelLine.lineLength1, serie.context.outsideRadius); - var lineLength2 = ChartHelper.GetActualValue(labelLine.lineLength2, serie.context.outsideRadius); var pos1 = serieData.context.labelLinePosition; var pos2 = pos1 + new Vector3(Mathf.Cos(rad) * lineLength1, Mathf.Sin(rad) * lineLength1); - var pos5 = pos2 + dire * lineLength2 + labelLine.GetEndSymbolOffset(); - serieData.context.labelPosition = pos5; + var pos5 = serieData.context.labelPosition; switch (labelLine.lineType) { case LabelLine.LineType.BrokenLine: @@ -401,8 +461,6 @@ namespace XCharts.Runtime chart.settings.lineSmoothness, UGL.Direction.XAxis); break; case LabelLine.LineType.HorizontalLine: - pos5 = pos1 + dire * (lineLength1 + lineLength2); - serieData.context.labelPosition = pos5; UGL.DrawLine(vh, pos1, pos5, labelLine.lineWidth, color); break; } diff --git a/Runtime/Serie/Serie.cs b/Runtime/Serie/Serie.cs index 103d2bd6..9af513f9 100644 --- a/Runtime/Serie/Serie.cs +++ b/Runtime/Serie/Serie.cs @@ -1463,7 +1463,8 @@ namespace XCharts.Runtime serieData.name = name; serieData.index = m_Data.Count; serieData.id = id; - serieData.data = new List() { m_Data.Count, value }; + serieData.data.Add(m_Data.Count); + serieData.data.Add(value); AddChildData(parent, serieData); return serieData; } @@ -1474,7 +1475,7 @@ namespace XCharts.Runtime serieData.name = name; serieData.index = m_Data.Count; serieData.id = id; - serieData.data = new List(value); + serieData.data.AddRange(value); AddChildData(parent, serieData); return serieData; }