9 using System.Collections.Generic;
16 [AddComponentMenu(
"XCharts/PolarChart", 21)]
18 [RequireComponent(typeof(RectTransform))]
19 [DisallowMultipleComponent]
22 public Polar GetPolar(
int index)
24 if (index >= 0 && index < m_Polars.Count)
return m_Polars[index];
28 protected override void InitComponent()
31 if (m_Polars.Count == 0) m_Polars =
new List<Polar>() {
Polar.defaultPolar };
32 if (m_RadiusAxes.Count == 0) m_RadiusAxes =
new List<RadiusAxis>() {
RadiusAxis.defaultRadiusAxis };
33 if (m_AngleAxes.Count == 0) m_AngleAxes =
new List<AngleAxis>() {
AngleAxis.defaultAngleAxis };
44 protected override void Reset()
58 private void ResetValuePolar()
62 m_AngleAxes[0].min = 0;
63 m_AngleAxes[0].max = 360;
65 for (
int i = 0; i <= 360; i++)
67 var t = i / 180f * Mathf.PI;
68 var r = Mathf.Sin(2 * t) * Mathf.Cos(2 * t) * 2;
73 private void ResetCategoryPolar()
77 for (
int i = 0; i <= 13; i++)
79 m_AngleAxes[0].AddData(
"bar" + i);
80 AddData(0, UnityEngine.Random.Range(0, 10));
85 protected override void SetAllComponentDirty()
87 base.SetAllComponentDirty();
88 foreach (var axis
in m_RadiusAxes) axis.SetAllDirty();
89 foreach (var axis
in m_AngleAxes) axis.SetAllDirty();
93 protected override void OnSizeChanged()
96 foreach (var axis
in m_RadiusAxes) axis.SetAllDirty();
97 foreach (var axis
in m_AngleAxes) axis.SetAllDirty();
101 private void InitPolars()
103 for (
int i = 0; i < m_Polars.Count; i++)
105 m_Polars[i].index = i;
109 private void InitRadiusAxes()
111 for (
int i = 0; i < m_RadiusAxes.Count; i++)
121 var m_Polar = GetPolar(axis.index);
122 if (m_Polars ==
null)
return;
123 var m_AngleAxis = GetAngleAxis(m_Polar.index);
124 if (m_AngleAxis ==
null)
return;
125 PolarHelper.UpdatePolarCenter(m_Polar, m_ChartPosition, m_ChartWidth, m_ChartHeight);
126 axis.runtimeAxisLabelList.Clear();
127 var radius = m_Polar.runtimeRadius;
128 var objName =
"axis_radius" + axis.index;
129 var axisObj = ChartHelper.AddObject(objName, transform, graphAnchorMin,
131 axisObj.transform.localPosition = Vector3.zero;
133 axisObj.hideFlags = chartHideFlags;
134 ChartHelper.HideAllObject(axisObj);
136 var splitNumber = AxisHelper.GetSplitNumber(axis, radius,
null);
138 var startAngle = m_AngleAxis.runtimeStartAngle;
139 var cenPos = m_Polar.runtimeCenterPos;
140 var txtHig = textStyle.GetFontSize(m_Theme.axis) + 2;
141 var dire = ChartHelper.GetDire(startAngle,
true).normalized;
143 var tickVetor = ChartHelper.GetVertialDire(dire)
145 for (
int i = 0; i < splitNumber; i++)
147 var labelWidth = AxisHelper.GetScaleWidth(axis, radius, i,
null);
149 var isPercentStack = SeriesHelper.IsPercentStack(m_Series,
SerieType.Bar);
151 null, isPercentStack);
152 var label = ChartHelper.AddAxisLabelObject(splitNumber, i, objName + i, axisObj.transform,
new Vector2(0.5f, 0.5f),
153 new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f),
new Vector2(labelWidth, txtHig), axis,
theme.axis,
155 if (i == 0) axis.
axisLabel.SetRelatedText(label.label, labelWidth);
156 label.label.SetAlignment(textStyle.GetAlignment(TextAnchor.MiddleCenter));
157 label.SetText(labelName);
158 var pos = ChartHelper.GetPos(cenPos, totalWidth, startAngle,
true) + tickVetor;
159 label.SetPosition(pos);
160 AxisHelper.AdjustRadiusAxisLabelPos(label.label, pos, cenPos, txtHig, Vector3.zero);
161 axis.runtimeAxisLabelList.Add(label);
163 totalWidth += labelWidth;
167 Vector2 privot =
new Vector2(0.5f, 1);
169 var labelName = ChartCached.GetAxisTooltipLabel(objName);
170 GameObject labelObj = ChartHelper.AddTooltipLabel(labelName, labelParent, m_Theme, privot);
171 axis.SetTooltipLabel(labelObj);
177 private AngleAxis GetAngleAxis(
int polarIndex)
179 foreach (var axis
in m_AngleAxes)
181 if (axis.polarIndex == polarIndex)
return axis;
185 private RadiusAxis GetRadiusAxis(
int polarIndex)
187 foreach (var axis
in m_RadiusAxes)
189 if (axis.polarIndex == polarIndex)
return axis;
194 private void InitAngleAxes()
196 for (
int i = 0; i < m_AngleAxes.Count; i++)
204 private void InitAngleAxis(
AngleAxis axis)
207 if (m_Polars ==
null)
return;
208 PolarHelper.UpdatePolarCenter(m_Polar, m_ChartPosition, m_ChartWidth, m_ChartHeight);
209 var radius = m_Polar.runtimeRadius;
210 axis.runtimeAxisLabelList.Clear();
212 string objName =
"axis_angle" + axis.index;
213 var axisObj = ChartHelper.AddObject(objName, transform, graphAnchorMin,
215 axisObj.transform.localPosition = Vector3.zero;
216 axisObj.SetActive(axis.
show);
217 axisObj.hideFlags = chartHideFlags;
218 ChartHelper.HideAllObject(axisObj);
219 var splitNumber = AxisHelper.GetSplitNumber(axis, radius,
null);
220 var totalAngle = axis.runtimeStartAngle;
222 var cenPos = m_Polar.runtimeCenterPos;
226 var isPercentStack = SeriesHelper.IsPercentStack(m_Series,
SerieType.Bar);
227 for (
int i = 0; i < splitNumber; i++)
229 float scaleAngle = AxisHelper.GetScaleWidth(axis, total, i,
null);
232 null, isPercentStack);
233 var label = ChartHelper.AddAxisLabelObject(splitNumber, i, objName + i, axisObj.transform,
new Vector2(0.5f, 0.5f),
234 new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f),
new Vector2(scaleAngle, txtHig), axis,
235 theme.axis, labelName);
236 label.label.SetAlignment(axis.
axisLabel.
textStyle.GetAlignment(TextAnchor.MiddleCenter));
237 var pos = ChartHelper.GetPos(cenPos, radius + margin,
238 isCategory ? (totalAngle + scaleAngle / 2) : totalAngle,
true);
239 AxisHelper.AdjustCircleLabelPos(label, pos, cenPos, txtHig, Vector3.zero);
240 if (i == 0) axis.
axisLabel.SetRelatedText(label.label, scaleAngle);
241 axis.runtimeAxisLabelList.Add(label);
243 totalAngle += scaleAngle;
247 Vector2 privot =
new Vector2(0.5f, 0.5f);
249 GameObject labelObj = ChartHelper.AddTooltipLabel(ChartCached.GetAxisTooltipLabel(objName), labelParent,
250 m_Theme, privot, privot, privot,
new Vector2(10, txtHig));
251 axis.SetTooltipLabel(labelObj);
257 protected override void Update()
263 private void CheckMinMaxValue()
265 foreach (var axis
in m_RadiusAxes) UpdateAxisMinMaxValue(axis);
266 foreach (var axis
in m_AngleAxes) UpdateAxisMinMaxValue(axis);
269 private void UpdateAxisMinMaxValue(
Axis axis,
bool updateChart =
true)
272 double tempMinValue = 0;
273 double tempMaxValue = 0;
276 SeriesHelper.GetXMinMaxValue(m_Series,
null, axis.
polarIndex,
true, axis.
inverse, out tempMinValue,
277 out tempMaxValue,
true);
281 SeriesHelper.GetYMinMaxValue(m_Series,
null, axis.
polarIndex,
true, axis.
inverse, out tempMinValue,
282 out tempMaxValue,
true);
284 AxisHelper.AdjustMinMaxValue(axis, ref tempMinValue, ref tempMaxValue,
true);
287 m_IsPlayingAnimation =
true;
288 var needCheck = !m_IsPlayingAnimation && axis.runtimeLastCheckInverse == axis.
inverse;
289 axis.UpdateMinValue(tempMinValue, needCheck);
290 axis.UpdateMaxValue(tempMaxValue, needCheck);
293 axis.runtimeLastCheckInverse = axis.
inverse;
296 UpdateAxisLabelText(axis);
300 if (axis.IsValueChanging(500) && !m_IsPlayingAnimation)
302 UpdateAxisLabelText(axis);
307 protected void UpdateAxisLabelText(
Axis axis)
311 var isPercentStack = SeriesHelper.IsPercentStack(m_Series,
SerieType.Bar);
312 axis.UpdateLabelText(runtimeWidth,
null, isPercentStack, 500);
315 protected override void DrawPainterBase(VertexHelper vh)
317 base.DrawPainterBase(vh);
324 private void UpdateRuntimeValue()
326 foreach (var
polar in m_Polars)
327 PolarHelper.UpdatePolarCenter(
polar, m_ChartPosition, m_ChartWidth, m_ChartHeight);
328 foreach (var axis
in m_AngleAxes)
329 axis.runtimeStartAngle = 90 - axis.startAngle;
332 private void DrawPolar(VertexHelper vh)
334 UpdateRuntimeValue();
335 foreach (var
polar in m_Polars)
344 private void DrawRadiusAxis(VertexHelper vh)
349 if (
polar ==
null)
continue;
352 var startAngle =
angleAxis.runtimeStartAngle;
355 var size = AxisHelper.GetScaleNumber(
radiusAxis, radius,
null);
357 var dire = ChartHelper.GetDire(startAngle,
true).normalized;
360 var tickVetor = ChartHelper.GetVertialDire(dire) * tickLength;
361 for (
int i = 0; i < size - 1; i++)
363 var scaleWidth = AxisHelper.GetScaleWidth(
radiusAxis, radius, i);
364 var pos = ChartHelper.GetPos(cenPos, totalWidth, startAngle,
true);
369 UGL.DrawDoughnut(vh, cenPos, totalWidth, outsideRaidus, splitLineColor, Color.clear);
373 UGL.DrawLine(vh, pos, pos + tickVetor, tickWidth, m_Theme.axis.
lineColor);
375 totalWidth += scaleWidth;
382 UGL.DrawLine(vh, lineStartPos, lineEndPos, lineWidth, m_Theme.axis.
lineColor);
387 private void DrawAngleAxis(VertexHelper vh)
389 foreach (var m_AngleAxis
in m_AngleAxes)
391 var m_Polar = GetPolar(m_AngleAxis.polarIndex);
392 var radius = m_Polar.runtimeRadius;
393 var cenPos = m_Polar.runtimeCenterPos;
395 var size = AxisHelper.GetScaleNumber(m_AngleAxis, total,
null);
396 var currAngle = m_AngleAxis.runtimeStartAngle;
397 var tickWidth = m_AngleAxis.axisTick.GetWidth(m_Theme.angleAxis.
tickWidth);
398 var tickLength = m_AngleAxis.axisTick.GetLength(m_Theme.angleAxis.
tickLength);
399 for (
int i = 0; i < size; i++)
401 var scaleWidth = AxisHelper.GetScaleWidth(m_AngleAxis, total, i);
402 var pos = ChartHelper.GetPos(cenPos, radius, currAngle,
true);
403 if (m_AngleAxis.show && m_AngleAxis.splitLine.show)
405 var splitLineColor = m_AngleAxis.splitLine.GetColor(m_Theme.angleAxis.
splitLineColor);
406 var lineWidth = m_AngleAxis.splitLine.GetWidth(m_Theme.angleAxis.
splitLineWidth);
407 UGL.DrawLine(vh, cenPos, pos, lineWidth, splitLineColor);
409 if (m_AngleAxis.show && m_AngleAxis.axisTick.show)
411 var tickY = radius + tickLength;
412 var tickPos = ChartHelper.GetPos(cenPos, tickY, currAngle,
true);
413 UGL.DrawLine(vh, pos, tickPos, tickWidth, m_Theme.axis.
lineColor);
415 currAngle += scaleWidth;
417 if (m_AngleAxis.show && m_AngleAxis.axisLine.show)
419 var lineWidth = m_AngleAxis.axisLine.GetWidth(m_Theme.angleAxis.
lineWidth);
420 var outsideRaidus = radius + lineWidth * 2;
421 UGL.DrawDoughnut(vh, cenPos, radius, outsideRaidus, m_Theme.axis.
lineColor, Color.clear);
426 private void DrawSerie(VertexHelper vh)
428 for (
int i = 0; i < m_Series.
Count; i++)
432 if (!serie.show)
continue;
436 DrawPolarLine(vh, serie);
446 DrawPolarLineSymbol(vh);
449 private void DrawPolarLine(VertexHelper vh,
Serie serie)
452 if (m_Polar ==
null)
return;
453 var m_AngleAxis = GetAngleAxis(m_Polar.index);
454 var m_RadiusAxis = GetRadiusAxis(m_Polar.index);
455 if (m_AngleAxis ==
null || m_RadiusAxis ==
null)
return;
456 var startAngle = m_AngleAxis.runtimeStartAngle;
457 var radius = m_Polar.runtimeRadius;
458 var datas = serie.
data;
459 if (datas.Count <= 0)
return;
460 float dataChangeDuration = serie.
animation.GetUpdateAnimationDuration();
461 double min = m_RadiusAxis.GetCurrMinValue(dataChangeDuration);
462 double max = m_RadiusAxis.GetCurrMaxValue(dataChangeDuration);
463 var firstSerieData = datas[0];
464 var startPos = GetPolarPos(m_Polar, m_AngleAxis, firstSerieData, min, max, radius);
465 var nextPos = Vector3.zero;
466 var lineColor = SerieHelper.GetLineColor(serie, m_Theme, serie.
index, serie.
highlighted);
468 float currDetailProgress = 0;
469 float totalDetailProgress = datas.Count;
470 serie.
animation.InitProgress(serie.
dataPoints.Count, currDetailProgress, totalDetailProgress);
472 for (
int i = 1; i < datas.Count; i++)
474 if (serie.
animation.CheckDetailBreak(i))
break;
475 var serieData = datas[i];
476 nextPos = GetPolarPos(m_Polar, m_AngleAxis, datas[i], min, max, radius);
477 UGL.DrawLine(vh, startPos, nextPos, lineWidth, lineColor);
482 serie.
animation.CheckProgress(totalDetailProgress);
484 m_IsPlayingAnimation =
true;
489 private void DrawPolarBar(VertexHelper vh,
Serie serie)
493 private void DrawPolarLineSymbol(VertexHelper vh)
495 for (
int n = 0; n < m_Series.
Count; n++)
498 if (!serie.show)
continue;
499 if (serie.type !=
SerieType.Line)
continue;
501 for (
int i = 0; i < count; i++)
503 var serieData = serie.GetSerieData(i);
504 var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
505 if (ChartHelper.IsIngore(serieData.runtimePosition))
continue;
506 bool highlight = serieData.highlighted || serie.highlighted;
507 if ((!symbol.show || !symbol.ShowSymbol(i, count) || serie.IsPerformanceMode()) && !serieData.highlighted)
continue;
508 float symbolSize = highlight
509 ? symbol.GetSelectedSize(serieData.data, m_Theme.serie.lineSymbolSize)
510 : symbol.GetSize(serieData.data, m_Theme.serie.lineSymbolSize);
511 var symbolColor = SerieHelper.GetItemColor(serie, serieData, m_Theme, n, highlight);
512 var symbolToColor = SerieHelper.GetItemToColor(serie, serieData, m_Theme, n, highlight);
513 var backgroundColor = SerieHelper.GetItemBackgroundColor(serie, serieData, m_Theme, n, highlight,
false);
514 var symbolBorder = SerieHelper.GetSymbolBorder(serie, serieData, m_Theme, highlight);
515 var cornerRadius = SerieHelper.GetSymbolCornerRadius(serie, serieData, highlight);
516 symbolSize = serie.animation.GetSysmbolSize(symbolSize);
517 DrawSymbol(vh, symbol.type, symbolSize, symbolBorder, serieData.runtimePosition, symbolColor,
518 symbolToColor, backgroundColor, symbol.gap, cornerRadius);
523 protected override void DrawTooltip(VertexHelper vh)
526 var m_Polar = GetPolar(
tooltip.runtimePolarIndex);
527 var m_AngleAxis = GetAngleAxis(m_Polar.index);
528 var lineColor = TooltipHelper.GetLineColor(
tooltip, m_Theme);
531 var cenPos = m_Polar.runtimeCenterPos;
532 var radius = m_Polar.runtimeRadius;
533 var sp = m_Polar.runtimeCenterPos;
535 var ep = ChartHelper.GetPos(sp, radius, tooltipAngle,
true);
540 ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, sp, ep, lineColor);
541 var dist = Vector2.Distance(pointerPos, cenPos);
542 if (dist > radius) dist = radius;
544 UGL.DrawDoughnut(vh, cenPos, dist, outsideRaidus, lineColor, Color.clear);
547 ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, sp, ep, lineColor);
555 private Vector3 GetPolarPos(
Polar m_Polar,
AngleAxis m_AngleAxis,
SerieData serieData,
double min,
double max,
float polarRadius)
560 angle = m_AngleAxis.runtimeStartAngle - (float)serieData.GetData(1);
564 angle = m_AngleAxis.runtimeStartAngle + (float)serieData.GetData(1);
566 angle = (angle + 360) % 360;
567 var value = serieData.GetData(0);
568 var radius = (float)((value - min) / (max - min) * polarRadius);
569 serieData.runtimeAngle = angle;
570 serieData.runtimePosition = ChartHelper.GetPos(m_Polar.
runtimeCenterPos, radius, angle,
true);
571 return serieData.runtimePosition;
574 protected override void CheckTootipArea(Vector2 local,
bool isActivedOther)
576 if (isActivedOther)
return;
577 tooltip.runtimePolarIndex = GetPointerInPoloar(local);
578 if (
tooltip.runtimePolarIndex < 0)
585 var serie = m_Series.
GetSerie(kv.Key);
586 foreach (var dataIndex
in kv.Value)
593 foreach (var axis
in m_AngleAxes) axis.SetTooltipLabelActive(
false);
594 foreach (var axis
in m_RadiusAxes) axis.SetTooltipLabelActive(
false);
599 var m_Polar = GetPolar(
tooltip.runtimePolarIndex);
600 var m_AngleAxis = GetAngleAxis(m_Polar.index);
602 Vector2 dir = local -
new Vector2(m_Polar.runtimeCenterPos.x, m_Polar.runtimeCenterPos.y);
603 float angle = ChartHelper.GetAngle360(Vector2.up, dir);
605 foreach (var serie
in m_Series.
list)
610 bool refresh =
false;
611 var count = serie.data.Count;
612 SerieHelper.UpdateMinMaxData(serie, 1, -1);
613 var diff = (serie.runtimeDataMax - serie.runtimeDataMin) / (count - 1);
614 for (
int j = 0; j < count; j++)
616 var serieData = serie.
data[j];
617 var flag = Math.Abs(serieData.runtimeAngle - angle) < Math.Abs(diff / 2);
618 if (serieData.highlighted != flag)
622 serieData.highlighted = flag;
625 tooltip.
runtimeAngle = (serieData.runtimeAngle - m_AngleAxis.runtimeStartAngle + 360) % 360;
626 tooltip.AddSerieDataIndex(serie.index, j);
646 private int GetPointerInPoloar(Vector2 local)
648 for (
int i = 0; i < m_Polars.Count; i++)
650 var
polar = m_Polars[i];
663 var nextAngle = nextData.runtimeAngle;
664 var lastAngle = serieData.runtimeAngle;
666 if (nextAngle > 270 && lastAngle < 90)
668 diff = 360 - nextAngle + lastAngle;
672 diff = nextAngle - lastAngle;
674 return Mathf.Abs(diff);
677 protected override void UpdateTooltip()
679 base.UpdateTooltip();
680 var showTooltip =
tooltip.isAnySerieDataIndex();
683 var m_AngleAxis = GetAngleAxis(
tooltip.runtimePolarIndex);
684 var content = TooltipHelper.GetPolarFormatterContent(
tooltip,
this, m_AngleAxis);
685 TooltipHelper.SetContentAndPosition(
tooltip, content, chartRect);
686 UdpateTooltipLabel();
691 private void UdpateTooltipLabel()
694 var m_Polar = GetPolar(
tooltip.runtimePolarIndex);
695 if (m_Polar ==
null)
return;
696 var m_AngleAxis = GetAngleAxis(m_Polar.index);
697 var m_RadiusAxis = GetRadiusAxis(m_Polar.index);
698 var cenPos = m_Polar.runtimeCenterPos;
699 var radius = m_Polar.runtimeRadius;
700 m_AngleAxis.SetTooltipLabelActive(
true);
701 m_RadiusAxis.SetTooltipLabelActive(
true);
704 var ep = ChartHelper.GetPos(cenPos, radius + 5, tooltipAngle,
true);
705 m_AngleAxis.UpdateTooltipLabelPos(ep);
707 var dist = Vector2.Distance(pointerPos, cenPos);
708 if (dist > radius) dist = radius;
709 double min = m_RadiusAxis.runtimeMinValue;
710 double max = m_RadiusAxis.runtimeMaxValue;
711 var value = min + dist / radius * m_RadiusAxis.runtimeMinMaxRange;
712 m_RadiusAxis.UpdateTooptipLabelText(ChartCached.FloatToStr(value));
713 m_RadiusAxis.UpdateTooltipLabelPos(ChartHelper.GetPos(cenPos, dist, m_AngleAxis.runtimeStartAngle,
true));