DrawSerieGauge.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /************************************************/
  2. /* */
  3. /* Copyright (c) 2018 - 2021 monitor1394 */
  4. /* https://github.com/monitor1394 */
  5. /* */
  6. /************************************************/
  7. using UnityEngine;
  8. using UnityEngine.UI;
  9. using UnityEngine.EventSystems;
  10. using XUGL;
  11. using System.Collections.Generic;
  12. namespace XCharts
  13. {
  14. internal class DrawSerieGauge : IDrawSerie
  15. {
  16. public BaseChart chart;
  17. private static readonly string s_SerieLabelObjectName = "label";
  18. private static readonly string s_AxisLabelObjectName = "axis_label";
  19. private bool m_UpdateTitleText = false;
  20. private bool m_UpdateLabelText = false;
  21. private Dictionary<int, int> m_LastSplitNumber = new Dictionary<int, int>();
  22. public DrawSerieGauge(BaseChart chart)
  23. {
  24. this.chart = chart;
  25. }
  26. public void InitComponent()
  27. {
  28. InitAxisLabel();
  29. }
  30. public void CheckComponent()
  31. {
  32. }
  33. public void Update()
  34. {
  35. if (m_UpdateTitleText)
  36. {
  37. m_UpdateTitleText = false;
  38. foreach (var serie in chart.series.list)
  39. {
  40. if (serie.type == SerieType.Gauge)
  41. {
  42. TitleStyleHelper.UpdateTitleText(serie);
  43. }
  44. }
  45. }
  46. if (m_UpdateLabelText)
  47. {
  48. m_UpdateLabelText = false;
  49. foreach (var serie in chart.series.list)
  50. {
  51. if (serie.type == SerieType.Gauge)
  52. {
  53. SerieLabelHelper.SetGaugeLabelText(serie);
  54. UpdateAxisLabel(serie);
  55. }
  56. }
  57. }
  58. foreach (var serie in chart.series.list)
  59. {
  60. if (serie.type == SerieType.Gauge)
  61. {
  62. if (!m_LastSplitNumber.TryGetValue(serie.index, out var lastSplitNumber))
  63. {
  64. m_LastSplitNumber[serie.index] = lastSplitNumber;
  65. }
  66. else if (serie.splitNumber != lastSplitNumber)
  67. {
  68. m_LastSplitNumber[serie.index] = serie.splitNumber;
  69. InitAxisLabel();
  70. }
  71. }
  72. }
  73. }
  74. public void DrawBase(VertexHelper vh)
  75. {
  76. }
  77. public void DrawSerie(VertexHelper vh, Serie serie)
  78. {
  79. if (serie.type != SerieType.Gauge) return;
  80. DrawGauge(vh, serie);
  81. }
  82. public void RefreshLabel()
  83. {
  84. }
  85. public bool CheckTootipArea(Vector2 local)
  86. {
  87. if (!chart.series.Contains(SerieType.Gauge)) return false;
  88. var serie = GetPointerInSerieIndex(chart.series, local);
  89. if (serie != null)
  90. {
  91. chart.tooltip.runtimeDataIndex.Clear();
  92. chart.tooltip.runtimeDataIndex.Add(serie.index);
  93. chart.tooltip.UpdateContentPos(local + chart.tooltip.offset);
  94. UpdateTooltip();
  95. return true;
  96. }
  97. else if (chart.tooltip.IsActive())
  98. {
  99. chart.tooltip.SetActive(false);
  100. chart.RefreshChart();
  101. }
  102. return false;
  103. }
  104. public bool OnLegendButtonClick(int index, string legendName, bool show)
  105. {
  106. return false;
  107. }
  108. public bool OnLegendButtonEnter(int index, string legendName)
  109. {
  110. return false;
  111. }
  112. public bool OnLegendButtonExit(int index, string legendName)
  113. {
  114. return false;
  115. }
  116. public void OnPointerDown(PointerEventData eventData)
  117. {
  118. }
  119. private void InitAxisLabel()
  120. {
  121. if (!SeriesHelper.ContainsSerie(chart.series, SerieType.Gauge)) return;
  122. var labelObject = ChartHelper.AddObject(s_AxisLabelObjectName, chart.transform, chart.chartMinAnchor,
  123. chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta);
  124. labelObject.hideFlags = chart.chartHideFlags;
  125. SerieLabelPool.ReleaseAll(labelObject.transform);
  126. for (int i = 0; i < chart.series.Count; i++)
  127. {
  128. var serie = chart.series.list[i];
  129. if (serie.type != SerieType.Gauge) continue;
  130. var serieLabel = serie.gaugeAxis.axisLabel;
  131. var count = serie.splitNumber > 36 ? 36 : (serie.splitNumber + 1);
  132. var startAngle = serie.startAngle;
  133. var textColor = serieLabel.textStyle.GetColor(chart.theme.gauge.textColor);
  134. serie.gaugeAxis.ClearLabelObject();
  135. SerieHelper.UpdateCenter(serie, chart.chartPosition, chart.chartWidth, chart.chartHeight);
  136. for (int j = 0; j < count; j++)
  137. {
  138. var textName = ChartCached.GetSerieLabelName(s_SerieLabelObjectName, i, j);
  139. var labelObj = SerieLabelPool.Get(textName, labelObject.transform, serieLabel, textColor, 100, 100, chart.theme);
  140. var iconImage = labelObj.transform.Find("Icon").GetComponent<Image>();
  141. var isAutoSize = serieLabel.backgroundWidth == 0 || serieLabel.backgroundHeight == 0;
  142. var item = new ChartLabel();
  143. item.SetLabel(labelObj, isAutoSize, serieLabel.paddingLeftRight, serieLabel.paddingTopBottom);
  144. item.SetIcon(iconImage);
  145. item.SetIconActive(false);
  146. serie.gaugeAxis.AddLabelObject(item);
  147. }
  148. UpdateAxisLabel(serie);
  149. }
  150. }
  151. private void UpdateAxisLabel()
  152. {
  153. foreach (var serie in chart.series.list)
  154. {
  155. if (serie.type == SerieType.Gauge)
  156. {
  157. UpdateAxisLabel(serie);
  158. }
  159. }
  160. }
  161. private void UpdateAxisLabel(Serie serie)
  162. {
  163. var show = serie.gaugeAxis.show && serie.gaugeAxis.axisLabel.show;
  164. serie.gaugeAxis.SetLabelObjectActive(show);
  165. if (!show)
  166. {
  167. return;
  168. }
  169. var count = serie.splitNumber > 36 ? 36 : serie.splitNumber;
  170. var startAngle = serie.startAngle;
  171. var totalAngle = serie.endAngle - serie.startAngle;
  172. var totalValue = serie.max - serie.min;
  173. var diffAngle = totalAngle / count;
  174. var diffValue = totalValue / count;
  175. var radius = serie.runtimeInsideRadius - serie.gaugeAxis.axisLabel.margin;
  176. var serieData = serie.GetSerieData(0);
  177. var customLabelText = serie.gaugeAxis.axisLabelText;
  178. for (int j = 0; j <= count; j++)
  179. {
  180. var angle = serie.startAngle + j * diffAngle;
  181. var value = serie.min + j * diffValue;
  182. var pos = ChartHelper.GetPosition(serie.runtimeCenterPos, angle, radius);
  183. var text = customLabelText != null && j < customLabelText.Count ? customLabelText[j] :
  184. SerieLabelHelper.GetFormatterContent(serie, serieData, value, totalValue,
  185. serie.gaugeAxis.axisLabel, Color.clear);
  186. serie.gaugeAxis.SetLabelObjectText(j, text);
  187. serie.gaugeAxis.SetLabelObjectPosition(j, pos + serie.gaugeAxis.axisLabel.offset);
  188. }
  189. }
  190. private void DrawGauge(VertexHelper vh, Serie serie)
  191. {
  192. SerieHelper.UpdateCenter(serie, chart.chartPosition, chart.chartWidth, chart.chartHeight);
  193. var destAngle = GetCurrAngle(serie, true);
  194. serie.animation.InitProgress(0, serie.startAngle, destAngle);
  195. var currAngle = serie.animation.IsFinish() ? GetCurrAngle(serie, false) : serie.animation.GetCurrDetail();
  196. DrawProgressBar(vh, serie, (float)currAngle);
  197. DrawStageColor(vh, serie);
  198. DrawLineStyle(vh, serie);
  199. DrawAxisTick(vh, serie);
  200. DrawPointer(vh, serie, (float)currAngle);
  201. TitleStyleHelper.CheckTitle(serie, ref chart.m_ReinitTitle, ref m_UpdateTitleText);
  202. SerieLabelHelper.CheckLabel(serie, ref chart.m_ReinitLabel, ref m_UpdateLabelText);
  203. CheckAnimation(serie);
  204. if (!serie.animation.IsFinish())
  205. {
  206. serie.animation.CheckProgress(destAngle - serie.startAngle);
  207. chart.RefreshPainter(serie);
  208. }
  209. else if (NeedRefresh(serie))
  210. {
  211. chart.RefreshPainter(serie);
  212. }
  213. }
  214. private void DrawProgressBar(VertexHelper vh, Serie serie, float currAngle)
  215. {
  216. if (serie.gaugeType != GaugeType.ProgressBar) return;
  217. if (!serie.gaugeAxis.show || !serie.gaugeAxis.axisLine.show) return;
  218. var color = serie.gaugeAxis.GetAxisLineColor(chart.theme, serie.index);
  219. var backgroundColor = serie.gaugeAxis.GetAxisLineBackgroundColor(chart.theme, serie.index);
  220. var lineWidth = serie.gaugeAxis.axisLine.GetWidth(chart.theme.gauge.lineWidth);
  221. var outsideRadius = serie.runtimeInsideRadius + lineWidth;
  222. var borderWidth = serie.itemStyle.borderWidth;
  223. var borderColor = serie.itemStyle.borderColor;
  224. UGL.DrawDoughnut(vh, serie.runtimeCenterPos, serie.runtimeInsideRadius, outsideRadius,
  225. backgroundColor, backgroundColor, Color.clear, serie.startAngle, serie.endAngle, 0, Color.clear,
  226. 0, chart.settings.cicleSmoothness, serie.roundCap);
  227. UGL.DrawDoughnut(vh, serie.runtimeCenterPos, serie.runtimeInsideRadius, outsideRadius,
  228. color, color, Color.clear, serie.startAngle, currAngle, 0, Color.clear,
  229. 0, chart.settings.cicleSmoothness, serie.roundCap);
  230. }
  231. private void DrawStageColor(VertexHelper vh, Serie serie)
  232. {
  233. if (serie.gaugeType != GaugeType.Pointer) return;
  234. if (!serie.gaugeAxis.show || !serie.gaugeAxis.axisLine.show) return;
  235. var totalAngle = serie.endAngle - serie.startAngle;
  236. var tempStartAngle = serie.startAngle;
  237. var tempEndAngle = serie.startAngle;
  238. var lineWidth = serie.gaugeAxis.axisLine.GetWidth(chart.theme.gauge.lineWidth);
  239. var outsideRadius = serie.runtimeInsideRadius + lineWidth;
  240. serie.gaugeAxis.runtimeStageAngle.Clear();
  241. for (int i = 0; i < serie.gaugeAxis.axisLine.stageColor.Count; i++)
  242. {
  243. var stageColor = serie.gaugeAxis.axisLine.stageColor[i];
  244. tempEndAngle = serie.startAngle + totalAngle * stageColor.percent;
  245. serie.gaugeAxis.runtimeStageAngle.Add(tempEndAngle);
  246. UGL.DrawDoughnut(vh, serie.runtimeCenterPos, serie.runtimeInsideRadius, outsideRadius,
  247. stageColor.color, stageColor.color, Color.clear, tempStartAngle, tempEndAngle, 0, Color.clear,
  248. 0, chart.settings.cicleSmoothness);
  249. tempStartAngle = tempEndAngle;
  250. }
  251. }
  252. private void DrawPointer(VertexHelper vh, Serie serie, float currAngle)
  253. {
  254. if (!serie.gaugePointer.show) return;
  255. var pointerColor = serie.gaugeAxis.GetPointerColor(chart.theme, serie.index, currAngle, serie.itemStyle);
  256. var pointerToColor = !ChartHelper.IsClearColor(serie.itemStyle.toColor) ? serie.itemStyle.toColor : pointerColor;
  257. var len = serie.gaugePointer.length < 1 && serie.gaugePointer.length > -1 ?
  258. serie.runtimeInsideRadius * serie.gaugePointer.length :
  259. serie.gaugePointer.length;
  260. var p1 = ChartHelper.GetPosition(serie.runtimeCenterPos, currAngle, len);
  261. var p2 = ChartHelper.GetPosition(serie.runtimeCenterPos, currAngle + 180, serie.gaugePointer.width);
  262. var p3 = ChartHelper.GetPosition(serie.runtimeCenterPos, currAngle - 90, serie.gaugePointer.width / 2);
  263. var p4 = ChartHelper.GetPosition(serie.runtimeCenterPos, currAngle + 90, serie.gaugePointer.width / 2);
  264. UGL.DrawTriangle(vh, p2, p3, p1, pointerColor, pointerColor, pointerToColor);
  265. UGL.DrawTriangle(vh, p4, p2, p1, pointerColor, pointerColor, pointerToColor);
  266. }
  267. private void DrawLineStyle(VertexHelper vh, Serie serie)
  268. {
  269. if (serie.gaugeType != GaugeType.Pointer) return;
  270. if (!serie.gaugeAxis.show || !serie.gaugeAxis.splitLine.show) return;
  271. if (serie.splitNumber <= 0) return;
  272. var splitLine = serie.gaugeAxis.splitLine;
  273. var totalAngle = serie.endAngle - serie.startAngle;
  274. var diffAngle = totalAngle / serie.splitNumber;
  275. var lineWidth = serie.gaugeAxis.axisLine.GetWidth(chart.theme.gauge.lineWidth);
  276. var splitLineWidth = splitLine.GetWidth(chart.theme.gauge.splitLineWidth);
  277. var splitLineLength = splitLine.GetLength(chart.theme.gauge.splitLineLength);
  278. var outsideRadius = serie.runtimeInsideRadius + lineWidth;
  279. var insideRadius = outsideRadius - splitLineLength;
  280. for (int i = 0; i < serie.splitNumber + 1; i++)
  281. {
  282. var angle = serie.startAngle + i * diffAngle;
  283. var lineColor = serie.gaugeAxis.GetSplitLineColor(chart.theme.gauge.splitLineColor, serie.index, angle);
  284. var p1 = ChartHelper.GetPosition(serie.runtimeCenterPos, angle, insideRadius);
  285. var p2 = ChartHelper.GetPosition(serie.runtimeCenterPos, angle, outsideRadius);
  286. UGL.DrawLine(vh, p1, p2, splitLineWidth, lineColor);
  287. }
  288. }
  289. private void DrawAxisTick(VertexHelper vh, Serie serie)
  290. {
  291. if (serie.gaugeType != GaugeType.Pointer) return;
  292. if (!serie.gaugeAxis.show || !serie.gaugeAxis.axisTick.show) return;
  293. if (serie.splitNumber <= 0) return;
  294. var axisTick = serie.gaugeAxis.axisTick;
  295. var totalAngle = serie.endAngle - serie.startAngle;
  296. var diffAngle = totalAngle / serie.splitNumber;
  297. var lineWidth = serie.gaugeAxis.axisLine.GetWidth(chart.theme.gauge.lineWidth);
  298. var tickWidth = axisTick.GetWidth(chart.theme.gauge.tickWidth);
  299. var tickLength = axisTick.GetLength(chart.theme.gauge.tickLength);
  300. var outsideRadius = serie.runtimeInsideRadius + lineWidth;
  301. var insideRadius = outsideRadius - (tickLength < 1 ? lineWidth * tickLength : tickLength);
  302. for (int i = 0; i < serie.splitNumber; i++)
  303. {
  304. for (int j = 1; j < axisTick.splitNumber; j++)
  305. {
  306. var angle = serie.startAngle + i * diffAngle + j * (diffAngle / axisTick.splitNumber);
  307. var lineColor = serie.gaugeAxis.GetSplitLineColor(chart.theme.gauge.tickColor, serie.index, angle);
  308. var p1 = ChartHelper.GetPosition(serie.runtimeCenterPos, angle, insideRadius);
  309. var p2 = ChartHelper.GetPosition(serie.runtimeCenterPos, angle, outsideRadius);
  310. UGL.DrawLine(vh, p1, p2, tickWidth, lineColor);
  311. }
  312. }
  313. }
  314. private float GetCurrAngle(Serie serie, bool dest)
  315. {
  316. if (serie.animation.HasFadeOut())
  317. {
  318. return (float)serie.animation.GetCurrDetail();
  319. }
  320. float rangeValue = serie.max - serie.min;
  321. float rangeAngle = serie.endAngle - serie.startAngle;
  322. double value = 0;
  323. float angle = serie.startAngle;
  324. if (serie.dataCount > 0)
  325. {
  326. var serieData = serie.data[0];
  327. serieData.labelPosition = serie.runtimeCenterPos + serie.label.offset;
  328. value = dest ? serieData.GetData(1)
  329. : serieData.GetCurrData(1, serie.animation.GetUpdateAnimationDuration());
  330. value = MathUtil.Clamp(value, serie.min, serie.max);
  331. }
  332. if (rangeValue > 0)
  333. {
  334. angle += rangeAngle * (float)(value - serie.min) / rangeValue;
  335. }
  336. return angle;
  337. }
  338. private void CheckAnimation(Serie serie)
  339. {
  340. var serieData = serie.GetSerieData(0);
  341. if (serieData != null)
  342. {
  343. var value = serieData.GetCurrData(1, serie.animation.GetUpdateAnimationDuration());
  344. var data = serieData.GetData(1);
  345. if (value != data) chart.RefreshPainter(serie);
  346. }
  347. }
  348. private bool NeedRefresh(Serie serie)
  349. {
  350. if (serie.type == SerieType.Gauge)
  351. {
  352. var serieData = serie.GetSerieData(0);
  353. if (serieData != null)
  354. {
  355. var destValue = serieData.GetData(1);
  356. var currValue = serieData.GetCurrData(1, serie.animation.GetUpdateAnimationDuration());
  357. return destValue != currValue;
  358. }
  359. }
  360. return false;
  361. }
  362. private Serie GetPointerInSerieIndex(Series series, Vector2 local)
  363. {
  364. foreach (var serie in series.list)
  365. {
  366. if (serie.type != SerieType.Gauge) continue;
  367. if (!serie.gaugePointer.show) continue;
  368. var len = serie.gaugePointer.length < 1 && serie.gaugePointer.length > -1
  369. ? serie.runtimeInsideRadius * serie.gaugePointer.length
  370. : serie.gaugePointer.length;
  371. if (Vector3.Distance(local, serie.runtimeCenterPos) > len) continue;
  372. var currAngle = (float)(serie.animation.IsFinish() ? GetCurrAngle(serie, false) : serie.animation.GetCurrDetail());
  373. var p1 = ChartHelper.GetPosition(serie.runtimeCenterPos, currAngle, len);
  374. var p2 = ChartHelper.GetPosition(serie.runtimeCenterPos, currAngle + 180, serie.gaugePointer.width);
  375. var p3 = ChartHelper.GetPosition(serie.runtimeCenterPos, currAngle - 90, serie.gaugePointer.width / 2);
  376. var p4 = ChartHelper.GetPosition(serie.runtimeCenterPos, currAngle + 90, serie.gaugePointer.width / 2);
  377. if (ChartHelper.IsPointInQuadrilateral(local, p1, p3, p2, p4))
  378. {
  379. return serie;
  380. }
  381. }
  382. return null;
  383. }
  384. private void UpdateTooltip()
  385. {
  386. int index = chart.tooltip.runtimeDataIndex[0];
  387. if (index < 0)
  388. {
  389. chart.tooltip.SetActive(false);
  390. return;
  391. }
  392. var content = TooltipHelper.GetFormatterContent(chart.tooltip, index, chart);
  393. TooltipHelper.SetContentAndPosition(chart.tooltip, content.TrimStart(), chart.chartRect);
  394. chart.tooltip.SetActive(true);
  395. }
  396. }
  397. }