diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a266932..a7d201d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ ## master +* (2022.09.16) 增加`PolarChart`对`Bar`柱图的支持 * (2022.09.14) 增加`PolarCoord`可通过`radius`设置环形极坐标的支持 * (2022.09.09) 修复`Editor`下编辑参数部分组件可能不会实时刷新的问题 * (2022.09.08) 增加`RingChart`可设置`LabelLine`引导线的支持 diff --git a/Runtime/Component/Axis/AngleAxis/AngleAxis.cs b/Runtime/Component/Axis/AngleAxis/AngleAxis.cs index 46909d73..51436a3c 100644 --- a/Runtime/Component/Axis/AngleAxis/AngleAxis.cs +++ b/Runtime/Component/Axis/AngleAxis/AngleAxis.cs @@ -29,6 +29,11 @@ namespace XCharts.Runtime return (value + context.startAngle + 360) % 360; } + public float GetValueAngle(double value) + { + return (float) (value + context.startAngle + 360) % 360; + } + public override void SetDefaultValue() { m_Show = true; diff --git a/Runtime/Component/Axis/AngleAxis/AngleAxisHandler.cs b/Runtime/Component/Axis/AngleAxis/AngleAxisHandler.cs index e29dfb79..c464b8c0 100644 --- a/Runtime/Component/Axis/AngleAxis/AngleAxisHandler.cs +++ b/Runtime/Component/Axis/AngleAxis/AngleAxisHandler.cs @@ -139,7 +139,13 @@ namespace XCharts.Runtime { var lineWidth = angleAxis.axisLine.GetWidth(chart.theme.axis.lineWidth); var outsideRaidus = radius + lineWidth * 2; - UGL.DrawDoughnut(vh, cenPos, radius, outsideRaidus, lineColor, Color.clear); + UGL.DrawDoughnut(vh, cenPos, radius, outsideRaidus, lineColor, ColorUtil.clearColor32); + if (polar.context.insideRadius > 0) + { + radius = polar.context.insideRadius; + outsideRaidus = radius + lineWidth * 2; + UGL.DrawDoughnut(vh, cenPos, radius, outsideRaidus, lineColor, ColorUtil.clearColor32); + } } } diff --git a/Runtime/Component/Axis/RadiusAxis/RadiusAxisHandler.cs b/Runtime/Component/Axis/RadiusAxis/RadiusAxisHandler.cs index bf840307..2eb27023 100644 --- a/Runtime/Component/Axis/RadiusAxis/RadiusAxisHandler.cs +++ b/Runtime/Component/Axis/RadiusAxis/RadiusAxisHandler.cs @@ -157,15 +157,18 @@ namespace XCharts.Runtime var tickWidth = radiusAxis.axisTick.GetWidth(chart.theme.axis.tickWidth); var tickLength = radiusAxis.axisTick.GetLength(chart.theme.axis.tickLength); var tickVetor = ChartHelper.GetVertialDire(dire) * tickLength; - for (int i = 0; i <= size; i++) + for (int i = 0; i < size; i++) { - var scaleWidth = AxisHelper.GetScaleWidth(radiusAxis, radius, i); + var scaleWidth = AxisHelper.GetScaleWidth(radiusAxis, radius, i + 1); var pos = ChartHelper.GetPos(cenPos, totalWidth + tickWidth, startAngle, true); if (radiusAxis.show && radiusAxis.splitLine.show) { - var outsideRaidus = totalWidth + radiusAxis.splitLine.GetWidth(chart.theme.axis.splitLineWidth) * 2; - var splitLineColor = radiusAxis.splitLine.GetColor(chart.theme.axis.splitLineColor); - UGL.DrawDoughnut(vh, cenPos, totalWidth, outsideRaidus, splitLineColor, Color.clear); + if (CanDrawSplitLine(angleAxis, i, size)) + { + var outsideRaidus = totalWidth + radiusAxis.splitLine.GetWidth(chart.theme.axis.splitLineWidth) * 2; + var splitLineColor = radiusAxis.splitLine.GetColor(chart.theme.axis.splitLineColor); + UGL.DrawDoughnut(vh, cenPos, totalWidth, outsideRaidus, splitLineColor, Color.clear); + } } if (radiusAxis.show && radiusAxis.axisTick.show) { @@ -186,5 +189,17 @@ namespace XCharts.Runtime UGL.DrawLine(vh, lineStartPos, lineEndPos, lineWidth, chart.theme.axis.lineColor); } } + + private bool CanDrawSplitLine(AngleAxis angleAxis, int i, int size) + { + if (angleAxis.axisLine.show) + { + return i != size - 1 && i != 0; + } + else + { + return true; + } + } } } \ No newline at end of file diff --git a/Runtime/Coord/Polar/PolarHelper.cs b/Runtime/Coord/Polar/PolarHelper.cs index 72260e41..8cfc7196 100644 --- a/Runtime/Coord/Polar/PolarHelper.cs +++ b/Runtime/Coord/Polar/PolarHelper.cs @@ -16,5 +16,18 @@ namespace XCharts.Runtime polar.context.outsideRadius = polar.radius[1] <= 1 ? minWidth * polar.radius[1] : polar.radius[1]; polar.context.radius = polar.context.outsideRadius - polar.context.insideRadius; } + + public static Vector3 UpdatePolarAngleAndPos(PolarCoord polar, AngleAxis angleAxis, RadiusAxis radiusAxis, SerieData serieData) + { + var value = serieData.GetData(0); + var angle = angleAxis.GetValueAngle(serieData.GetData(1)); + var radius = polar.context.insideRadius + radiusAxis.GetValueLength(value, polar.context.radius); + + angle = (angle + 360) % 360; + serieData.context.angle = angle; + serieData.context.position = ChartHelper.GetPos(polar.context.center, radius, angle, true); + + return serieData.context.position; + } } } \ No newline at end of file diff --git a/Runtime/Internal/BaseChart.Component.cs b/Runtime/Internal/BaseChart.Component.cs index fdf14c28..b989f2d9 100644 --- a/Runtime/Internal/BaseChart.Component.cs +++ b/Runtime/Internal/BaseChart.Component.cs @@ -443,6 +443,12 @@ namespace XCharts.Runtime internal bool GetSerieGridCoordAxis(Serie serie, out Axis axis, out Axis relativedAxis) { var yAxis = GetChartComponent(serie.yAxisIndex); + if (yAxis == null) + { + axis = null; + relativedAxis = null; + return false; + } var isY = yAxis.IsCategory(); if (isY) { diff --git a/Runtime/Internal/BaseChart.cs b/Runtime/Internal/BaseChart.cs index 3aa80d66..23cbca1e 100644 --- a/Runtime/Internal/BaseChart.cs +++ b/Runtime/Internal/BaseChart.cs @@ -579,23 +579,25 @@ namespace XCharts.Runtime serie.context.dataIndexs.Clear(); serie.context.dataIgnores.Clear(); serie.animation.context.isAllItemAnimationEnd = true; - if (!serie.context.pointerEnter) - serie.ResetInteract(); - - if (m_OnDrawSerieBefore != null) + if (serie.show && !serie.animation.HasFadeOut()) { - m_OnDrawSerieBefore.Invoke(vh, serie); - } - DrawPainterSerie(vh, serie); - if (i >= 0 && i < m_SerieHandlers.Count) - { - var handler = m_SerieHandlers[i]; - handler.DrawSerie(vh); - handler.RefreshLabelNextFrame(); - } - if (m_OnDrawSerieAfter != null) - { - m_OnDrawSerieAfter(vh, serie); + if (!serie.context.pointerEnter) + serie.ResetInteract(); + if (m_OnDrawSerieBefore != null) + { + m_OnDrawSerieBefore.Invoke(vh, serie); + } + DrawPainterSerie(vh, serie); + if (i >= 0 && i < m_SerieHandlers.Count) + { + var handler = m_SerieHandlers[i]; + handler.DrawSerie(vh); + handler.RefreshLabelNextFrame(); + } + if (m_OnDrawSerieAfter != null) + { + m_OnDrawSerieAfter(vh, serie); + } } serie.context.vertCount = vh.currentVertCount; } diff --git a/Runtime/Serie/Bar/Bar.cs b/Runtime/Serie/Bar/Bar.cs index c02e83cb..bd3c1031 100644 --- a/Runtime/Serie/Bar/Bar.cs +++ b/Runtime/Serie/Bar/Bar.cs @@ -3,7 +3,7 @@ namespace XCharts.Runtime [System.Serializable] [SerieHandler(typeof(BarHandler), true)] [SerieConvert(typeof(Line), typeof(Pie))] - [RequireChartComponent(typeof(GridCoord))] + [CoordOptions(typeof(GridCoord), typeof(PolarCoord))] [DefaultAnimation(AnimationType.BottomToTop)] [SerieExtraComponent(typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataExtraComponent(typeof(ItemStyle), typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] diff --git a/Runtime/Serie/Bar/BarHandler.PolarCoord.cs b/Runtime/Serie/Bar/BarHandler.PolarCoord.cs new file mode 100644 index 00000000..f44f0ee4 --- /dev/null +++ b/Runtime/Serie/Bar/BarHandler.PolarCoord.cs @@ -0,0 +1,183 @@ +using UnityEngine; +using UnityEngine.UI; +using XUGL; + +namespace XCharts.Runtime +{ + /// + /// For polar coord + /// + internal sealed partial class BarHandler + { + private PolarCoord m_SeriePolar; + + private void UpdateSeriePolarContext() + { + if (m_SeriePolar == null) + return; + + var needCheck = (chart.isPointerInChart && m_SeriePolar.IsPointerEnter()) || m_LegendEnter; + var lineWidth = 0f; + if (!needCheck) + { + if (m_LastCheckContextFlag != needCheck) + { + var needAnimation1 = false; + lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth); + m_LastCheckContextFlag = needCheck; + serie.context.pointerItemDataIndex = -1; + serie.context.pointerEnter = false; + serie.interact.SetValue(ref needAnimation1, lineWidth, false); + foreach (var serieData in serie.data) + { + var symbol = SerieHelper.GetSerieSymbol(serie, serieData); + var symbolSize = symbol.GetSize(serieData.data, chart.theme.serie.lineSymbolSize); + serieData.context.highlight = false; + serieData.interact.SetValue(ref needAnimation1, symbolSize); + } + if (needAnimation1) + { + if (SeriesHelper.IsStack(chart.series)) + chart.RefreshTopPainter(); + else + chart.RefreshPainter(serie); + } + } + return; + } + m_LastCheckContextFlag = needCheck; + var themeSymbolSize = chart.theme.serie.lineSymbolSize; + lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth); + + var needInteract = false; + if (m_LegendEnter) + { + serie.context.pointerEnter = true; + serie.interact.SetValue(ref needInteract, lineWidth, true, chart.theme.serie.selectedRate); + for (int i = 0; i < serie.dataCount; i++) + { + var serieData = serie.data[i]; + var size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize, SerieState.Emphasis); + serieData.context.highlight = true; + serieData.interact.SetValue(ref needInteract, size); + } + } + else + { + serie.context.pointerItemDataIndex = -1; + serie.context.pointerEnter = false; + var dir = chart.pointerPos - new Vector2(m_SeriePolar.context.center.x, m_SeriePolar.context.center.y); + var pointerAngle = ChartHelper.GetAngle360(Vector2.up, dir); + var pointerRadius = Vector2.Distance(chart.pointerPos, m_SeriePolar.context.center); + Color32 color, toColor; + for (int i = 0; i < serie.dataCount; i++) + { + var serieData = serie.data[i]; + if (pointerAngle >= serieData.context.startAngle && + pointerAngle < serieData.context.toAngle && + pointerRadius >= serieData.context.insideRadius && + pointerRadius < serieData.context.outsideRadius) + { + serie.context.pointerItemDataIndex = i; + serie.context.pointerEnter = true; + serieData.context.highlight = true; + } + else + { + serieData.context.highlight = false; + } + var state = SerieHelper.GetSerieState(serie, serieData, true); + SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, state); + serieData.interact.SetColor(ref needInteract, color, toColor); + } + } + if (needInteract) + { + if (SeriesHelper.IsStack(chart.series)) + chart.RefreshTopPainter(); + else + chart.RefreshPainter(serie); + } + } + + private void DrawPolarBar(VertexHelper vh, Serie serie) + { + var datas = serie.data; + if (datas.Count <= 0) + return; + + m_SeriePolar = chart.GetChartComponent(serie.polarIndex); + if (m_SeriePolar == null) + return; + + var m_AngleAxis = ComponentHelper.GetAngleAxis(chart.components, m_SeriePolar.index); + var m_RadiusAxis = ComponentHelper.GetRadiusAxis(chart.components, m_SeriePolar.index); + if (m_AngleAxis == null || m_RadiusAxis == null) + return; + + var startAngle = m_AngleAxis.context.startAngle; + var currDetailProgress = 0f; + var totalDetailProgress = datas.Count; + + serie.animation.InitProgress(currDetailProgress, totalDetailProgress); + + var isStack = SeriesHelper.IsStack(chart.series, serie.stack); + if (isStack) + SeriesHelper.UpdateStackDataList(chart.series, serie, null, m_StackSerieData); + + var barCount = chart.GetSerieBarRealCount(); + float categoryWidth = AxisHelper.GetDataWidth(m_AngleAxis, 360, datas.Count, null); + float barGap = chart.GetSerieBarGap(); + float totalBarWidth = chart.GetSerieTotalWidth(categoryWidth, barGap, barCount); + float barWidth = serie.GetBarWidth(categoryWidth, barCount); + float offset = (categoryWidth - totalBarWidth) * 0.5f; + //var serieReadIndex = chart.GetSerieIndexIfStack(serie); + //float gap = serie.barGap == -1 ? offset : offset + chart.GetSerieTotalGap(categoryWidth, barGap, serieReadIndex); + + var areaColor = ColorUtil.clearColor32; + var areaToColor = ColorUtil.clearColor32; + var interacting = false; + + for (int i = 0; i < datas.Count; i++) + { + if (serie.animation.CheckDetailBreak(i)) + break; + var serieData = datas[i]; + var value = serieData.GetData(1); + var start = startAngle + categoryWidth * i + offset; + var end = start + barWidth; + var itemStyle = SerieHelper.GetItemStyle(serie, serieData); + var borderWidth = itemStyle.borderWidth; + var borderColor = itemStyle.borderColor; + + serieData.context.startAngle = start; + serieData.context.toAngle = end; + + if (!serieData.interact.TryGetColor(ref areaColor, ref areaToColor, ref interacting)) + { + SerieHelper.GetItemColor(out areaColor, out areaToColor, serie, serieData, chart.theme); + serieData.interact.SetColor(ref interacting, areaColor, areaToColor); + } + + var inside = m_SeriePolar.context.insideRadius; + var outside = inside + m_RadiusAxis.GetValueLength(value, m_SeriePolar.context.radius); + var needRoundCap = serie.roundCap && inside > 0; + + serieData.context.insideRadius = inside; + serieData.context.outsideRadius = outside; + serieData.context.position = ChartHelper.GetPosition(m_SeriePolar.context.center, (inside + outside) / 2, outside); + + UGL.DrawDoughnut(vh, m_SeriePolar.context.center, inside, outside, areaColor, areaToColor, + ColorUtil.clearColor32, start, end, borderWidth, borderColor, serie.gap / 2, chart.settings.cicleSmoothness, + needRoundCap, true); + } + + if (!serie.animation.IsFinish()) + { + serie.animation.CheckProgress(totalDetailProgress); + serie.animation.CheckSymbol(serie.symbol.GetSize(null, chart.theme.serie.lineSymbolSize)); + chart.RefreshChart(); + } + } + } +} \ No newline at end of file diff --git a/Runtime/Serie/Bar/BarHandler.PolarCoord.cs.meta b/Runtime/Serie/Bar/BarHandler.PolarCoord.cs.meta new file mode 100644 index 00000000..30d890fb --- /dev/null +++ b/Runtime/Serie/Bar/BarHandler.PolarCoord.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 152848d4f7ed84b0491d277fd55b64ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Serie/Bar/BarHandler.cs b/Runtime/Serie/Bar/BarHandler.cs index 5b4558ff..8537a821 100644 --- a/Runtime/Serie/Bar/BarHandler.cs +++ b/Runtime/Serie/Bar/BarHandler.cs @@ -7,7 +7,7 @@ using XUGL; namespace XCharts.Runtime { [UnityEngine.Scripting.Preserve] - internal sealed class BarHandler : SerieHandler + internal sealed partial class BarHandler : SerieHandler { List> m_StackSerieData = new List>(); private GridCoord m_SerieGrid; @@ -16,7 +16,10 @@ namespace XCharts.Runtime public override void Update() { base.Update(); - UpdateSerieContext(); + if (serie.IsUseCoord()) + UpdateSerieGridContext(); + else if (serie.IsUseCoord()) + UpdateSeriePolarContext(); } public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category, @@ -29,7 +32,14 @@ namespace XCharts.Runtime public override void DrawSerie(VertexHelper vh) { - DrawBarSerie(vh, serie, serie.context.colorIndex); + if (serie.IsUseCoord()) + { + DrawPolarBar(vh, serie); + } + else if (serie.IsUseCoord()) + { + DrawBarSerie(vh, serie); + } } public override Vector3 GetSerieDataLabelPosition(SerieData serieData, LabelStyle label) @@ -57,7 +67,7 @@ namespace XCharts.Runtime } } - private void UpdateSerieContext() + private void UpdateSerieGridContext() { if (m_SerieGrid == null) return; @@ -119,7 +129,7 @@ namespace XCharts.Runtime } } - private void DrawBarSerie(VertexHelper vh, Bar serie, int colorIndex) + private void DrawBarSerie(VertexHelper vh, Bar serie) { if (!serie.show || serie.animation.HasFadeOut()) return; diff --git a/Runtime/Serie/Line/LineHandler.GridCoord.cs b/Runtime/Serie/Line/LineHandler.GridCoord.cs index b5cf3c92..8d7f76e0 100644 --- a/Runtime/Serie/Line/LineHandler.GridCoord.cs +++ b/Runtime/Serie/Line/LineHandler.GridCoord.cs @@ -248,8 +248,6 @@ namespace XCharts.Runtime private void DrawLineSerie(VertexHelper vh, Line serie) { - if (!serie.show) - return; if (serie.animation.HasFadeOut()) return; diff --git a/Runtime/Serie/Line/LineHandler.PolarCoord.cs b/Runtime/Serie/Line/LineHandler.PolarCoord.cs index 600dfe7e..3dedb776 100644 --- a/Runtime/Serie/Line/LineHandler.PolarCoord.cs +++ b/Runtime/Serie/Line/LineHandler.PolarCoord.cs @@ -111,12 +111,8 @@ namespace XCharts.Runtime return; var startAngle = m_AngleAxis.startAngle; - var radius = m_SeriePolar.context.outsideRadius; - - var min = m_RadiusAxis.context.minValue; - var max = m_RadiusAxis.context.maxValue; var firstSerieData = datas[0]; - var lp = GetPolarPos(m_SeriePolar, m_AngleAxis, firstSerieData, min, max, radius); + var lp = PolarHelper.UpdatePolarAngleAndPos(m_SeriePolar, m_AngleAxis, m_RadiusAxis, firstSerieData); var cp = Vector3.zero; var lineColor = SerieHelper.GetLineColor(serie, null, chart.theme, serie.index); var lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth); @@ -141,9 +137,9 @@ namespace XCharts.Runtime var serieData = datas[i]; - cp = GetPolarPos(m_SeriePolar, m_AngleAxis, datas[i], min, max, radius); + cp = PolarHelper.UpdatePolarAngleAndPos(m_SeriePolar, m_AngleAxis, m_RadiusAxis, datas[i]); var np = i == datas.Count - 1 ? cp : - GetPolarPos(m_SeriePolar, m_AngleAxis, datas[i + 1], min, max, radius); + PolarHelper.UpdatePolarAngleAndPos(m_SeriePolar, m_AngleAxis, m_RadiusAxis, datas[i + 1]); UGLHelper.GetLinePoints(lp, cp, np, lineWidth, ref ltp, ref lbp, @@ -227,29 +223,5 @@ namespace XCharts.Runtime } } } - - private Vector3 GetPolarPos(PolarCoord m_Polar, AngleAxis m_AngleAxis, SerieData serieData, double min, - double max, float polarRadius) - { - var angle = 0f; - - if (!m_AngleAxis.clockwise) - { - angle = m_AngleAxis.GetValueAngle((float) serieData.GetData(1)); - } - else - { - angle = m_AngleAxis.GetValueAngle((float) serieData.GetData(1)); - } - - var value = serieData.GetData(0); - var radius = (float) ((value - min) / (max - min) * polarRadius); - - angle = (angle + 360) % 360; - serieData.context.angle = angle; - serieData.context.position = ChartHelper.GetPos(m_Polar.context.center, radius, angle, true); - - return serieData.context.position; - } } } \ No newline at end of file