diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c4407c1..50d5b749 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ ## master +* (2022.09.20) 增加`PolarChart`对`Heatmap`热力图的支持 * (2022.09.19) 增加`PolarChart`对多柱图和堆叠柱图的支持 * (2022.09.16) 增加`PolarChart`对`Bar`柱图的支持 * (2022.09.14) 增加`PolarCoord`可通过`radius`设置环形极坐标的支持 diff --git a/Editor/Series/BarEditor.cs b/Editor/Series/BarEditor.cs index beb6ecea..1a078531 100644 --- a/Editor/Series/BarEditor.cs +++ b/Editor/Series/BarEditor.cs @@ -19,13 +19,20 @@ namespace XCharts.Editor PropertyField("m_YAxisIndex"); } PropertyField("m_BarType"); - PropertyField("m_BarPercentStack"); PropertyField("m_BarWidth"); PropertyField("m_BarGap"); - if (serie.barType == BarType.Zebra) + if (serie.IsUseCoord()) { - PropertyField("m_BarZebraWidth"); - PropertyField("m_BarZebraGap"); + PropertyField("m_RoundCap"); + } + else + { + PropertyField("m_BarPercentStack"); + if (serie.barType == BarType.Zebra) + { + PropertyField("m_BarZebraWidth"); + PropertyField("m_BarZebraGap"); + } } PropertyField("m_Clip"); PropertyFiledMore(() => diff --git a/Editor/Series/HeatmapEditor.cs b/Editor/Series/HeatmapEditor.cs index f525541e..c4eaa9cb 100644 --- a/Editor/Series/HeatmapEditor.cs +++ b/Editor/Series/HeatmapEditor.cs @@ -7,6 +7,15 @@ namespace XCharts.Editor { public override void OnCustomInspectorGUI() { + if (serie.IsUseCoord()) + { + PropertyField("m_PolarIndex"); + } + else + { + PropertyField("m_XAxisIndex"); + PropertyField("m_YAxisIndex"); + } PropertyField("m_HeatmapType"); PropertyField("m_Ignore"); PropertyField("m_IgnoreValue"); diff --git a/Runtime/Component/Legend/LegendHandler.cs b/Runtime/Component/Legend/LegendHandler.cs index ab3df818..52951bd8 100644 --- a/Runtime/Component/Legend/LegendHandler.cs +++ b/Runtime/Component/Legend/LegendHandler.cs @@ -225,6 +225,10 @@ namespace XCharts.Runtime break; } } + else + { + iconType = Legend.Type.Rect; + } } else { diff --git a/Runtime/Serie/Bar/BarHandler.PolarCoord.cs b/Runtime/Serie/Bar/BarHandler.PolarCoord.cs index f4688f57..f2c860ec 100644 --- a/Runtime/Serie/Bar/BarHandler.PolarCoord.cs +++ b/Runtime/Serie/Bar/BarHandler.PolarCoord.cs @@ -175,7 +175,7 @@ namespace XCharts.Runtime for (int n = 0; n < m_StackSerieData.Count - 1; n++) start += m_StackSerieData[n][i].context.stackHeight; } - end = startAngle + m_AngleAxis.GetValueLength(angleValue, 360); + end = start + m_AngleAxis.GetValueLength(angleValue, 360); serieData.context.stackHeight = end - start; inside = m_SeriePolar.context.insideRadius + categoryWidth * (float) radiusValue + gap; outside = inside + barWidth; diff --git a/Runtime/Serie/Heatmap/Heatmap.cs b/Runtime/Serie/Heatmap/Heatmap.cs index a40b745d..91b79855 100644 --- a/Runtime/Serie/Heatmap/Heatmap.cs +++ b/Runtime/Serie/Heatmap/Heatmap.cs @@ -24,6 +24,7 @@ namespace XCharts.Runtime [SerieHandler(typeof(HeatmapHandler), true)] [DefaultAnimation(AnimationType.LeftToRight)] [RequireChartComponent(typeof(VisualMap))] + [CoordOptions(typeof(GridCoord), typeof(PolarCoord))] [SerieExtraComponent(typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataExtraComponent(typeof(ItemStyle), typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataExtraField()] diff --git a/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs b/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs new file mode 100644 index 00000000..c2ed3ffc --- /dev/null +++ b/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs @@ -0,0 +1,202 @@ +using UnityEngine; +using UnityEngine.UI; +using XUGL; + +namespace XCharts.Runtime +{ + /// + /// For polar coord + /// + internal sealed partial class HeatmapHandler + { + 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 DrawPolarHeatmap(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 visualMap = chart.GetVisualMapOfSerie(serie); + + var startAngle = m_AngleAxis.context.startAngle; + var currDetailProgress = 0f; + var totalDetailProgress = datas.Count; + + var xCount = AxisHelper.GetTotalSplitGridNum(m_RadiusAxis); + var yCount = AxisHelper.GetTotalSplitGridNum(m_AngleAxis); + var xWidth = m_SeriePolar.context.radius / xCount; + var yWidth = 360 / yCount; + + serie.animation.InitProgress(currDetailProgress, totalDetailProgress); + + var dimension = VisualMapHelper.GetDimension(visualMap, defaultDimension); + if (visualMap.autoMinMax) + { + double maxValue, minValue; + SerieHelper.GetMinMaxData(serie, dimension, out minValue, out maxValue); + VisualMapHelper.SetMinMax(visualMap, minValue, maxValue); + } + var rangeMin = visualMap.rangeMin; + var rangeMax = visualMap.rangeMax; + var color = chart.theme.GetColor(serie.index); + + float start, end; + float inside, outside; + double value, radiusValue, angleValue; + for (int i = 0; i < datas.Count; i++) + { + if (serie.animation.CheckDetailBreak(i)) + break; + var serieData = datas[i]; + var itemStyle = SerieHelper.GetItemStyle(serie, serieData); + var borderWidth = itemStyle.borderWidth; + var borderColor = itemStyle.borderColor; + + radiusValue = serieData.GetData(0); + angleValue = serieData.GetData(1); + value = serieData.GetData(2); + + var xIndex = AxisHelper.GetAxisValueSplitIndex(m_RadiusAxis, radiusValue, xCount); + var yIndex = AxisHelper.GetAxisValueSplitIndex(m_AngleAxis, angleValue, yCount); + + start = startAngle + yIndex * yWidth; + end = start + yWidth; + + inside = m_SeriePolar.context.insideRadius + xIndex * xWidth; + outside = inside + xWidth; + + serieData.context.startAngle = start; + serieData.context.toAngle = end; + serieData.context.halfAngle = (start + end) / 2; + serieData.context.insideRadius = inside; + serieData.context.outsideRadius = outside; + + if ((value < rangeMin && rangeMin != visualMap.min) || + (value > rangeMax && rangeMax != visualMap.max)) + { + continue; + } + if (!visualMap.IsInSelectedValue(value)) continue; + color = visualMap.GetColor(value); + if (serieData.context.highlight) + color = ChartHelper.GetHighlightColor(color); + + var needRoundCap = serie.roundCap && inside > 0; + + serieData.context.insideRadius = inside; + serieData.context.outsideRadius = outside; + serieData.context.areaCenter = m_SeriePolar.context.center; + serieData.context.position = ChartHelper.GetPosition(m_SeriePolar.context.center, (start + end) / 2, (inside + outside) / 2); + + UGL.DrawDoughnut(vh, m_SeriePolar.context.center, inside, outside, color, color, + 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/Heatmap/HeatmapHandler.PolarCoord.cs.meta b/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs.meta new file mode 100644 index 00000000..e9f8a398 --- /dev/null +++ b/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: baaa1d070b88a4b9bb7d1eed341041e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Serie/Heatmap/HeatmapHandler.cs b/Runtime/Serie/Heatmap/HeatmapHandler.cs index 648b37e1..b3bf9ba4 100644 --- a/Runtime/Serie/Heatmap/HeatmapHandler.cs +++ b/Runtime/Serie/Heatmap/HeatmapHandler.cs @@ -6,7 +6,7 @@ using XUGL; namespace XCharts.Runtime { [UnityEngine.Scripting.Preserve] - internal sealed class HeatmapHandler : SerieHandler + internal sealed partial class HeatmapHandler : SerieHandler { private GridCoord m_SerieGrid; private Dictionary m_CountDict = new Dictionary(); @@ -27,7 +27,10 @@ namespace XCharts.Runtime public override void Update() { base.Update(); - UpdateSerieContext(); + if (serie.IsUseCoord()) + UpdateSerieContext(); + else if (serie.IsUseCoord()) + UpdateSeriePolarContext(); } public override void DrawSerie(VertexHelper vh) @@ -35,7 +38,16 @@ namespace XCharts.Runtime if (serie.heatmapType == HeatmapType.Count) DrawCountHeatmapSerie(vh, serie); else - DrawDataHeatmapSerie(vh, serie); + { + if (serie.IsUseCoord()) + { + DrawPolarHeatmap(vh, serie); + } + else if (serie.IsUseCoord()) + { + DrawDataHeatmapSerie(vh, serie); + } + } } public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category, @@ -416,7 +428,7 @@ namespace XCharts.Runtime var pos = new Vector3(zeroX + (i + 0.5f) * xWidth, zeroY + (j + 0.5f) * yWidth); - + var rectWid = 0f; var rectHig = 0f; if (isRectSymbol)