Нет описания
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

RingHandler.cs 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. using System.Collections.Generic;
  2. using System.Text;
  3. using UnityEngine;
  4. using UnityEngine.EventSystems;
  5. using UnityEngine.UI;
  6. using XUGL;
  7. namespace XCharts.Runtime
  8. {
  9. [UnityEngine.Scripting.Preserve]
  10. internal sealed class RingHandler : SerieHandler<Ring>
  11. {
  12. public override int defaultDimension { get { return 0; } }
  13. public override void Update()
  14. {
  15. base.Update();
  16. }
  17. public override void UpdateSerieContext()
  18. {
  19. var needCheck = chart.isPointerInChart || m_LegendEnter;
  20. var needInteract = false;
  21. if (!needCheck)
  22. {
  23. if (m_LastCheckContextFlag != needCheck)
  24. {
  25. m_LastCheckContextFlag = needCheck;
  26. serie.context.pointerItemDataIndex = -1;
  27. serie.context.pointerEnter = false;
  28. foreach (var serieData in serie.data)
  29. {
  30. serieData.context.highlight = false;
  31. }
  32. chart.RefreshPainter(serie);
  33. }
  34. return;
  35. }
  36. m_LastCheckContextFlag = needCheck;
  37. if (m_LegendEnter)
  38. {
  39. serie.context.pointerEnter = true;
  40. foreach (var serieData in serie.data)
  41. {
  42. serieData.context.highlight = true;
  43. }
  44. }
  45. else
  46. {
  47. serie.context.pointerEnter = false;
  48. serie.context.pointerItemDataIndex = -1;
  49. var ringIndex = GetRingIndex(chart.pointerPos);
  50. foreach (var serieData in serie.data)
  51. {
  52. if (!needInteract && ringIndex == serieData.index)
  53. {
  54. serie.context.pointerEnter = true;
  55. serie.context.pointerItemDataIndex = ringIndex;
  56. serieData.context.highlight = true;
  57. needInteract = true;
  58. }
  59. else
  60. {
  61. serieData.context.highlight = false;
  62. }
  63. }
  64. }
  65. if (needInteract)
  66. {
  67. chart.RefreshPainter(serie);
  68. }
  69. }
  70. public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category,
  71. string marker, string itemFormatter, string numericFormatter, string ignoreDataDefaultContent,
  72. ref List<SerieParams> paramList, ref string title)
  73. {
  74. if (dataIndex < 0)
  75. dataIndex = serie.context.pointerItemDataIndex;
  76. if (dataIndex < 0)
  77. return;
  78. var serieData = serie.GetSerieData(dataIndex);
  79. if (serieData == null)
  80. return;
  81. Color32 color, toColor;
  82. SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, dataIndex);
  83. var param = serie.context.param;
  84. param.serieName = serie.serieName;
  85. param.serieIndex = serie.index;
  86. param.category = category;
  87. param.dimension = defaultDimension;
  88. param.serieData = serieData;
  89. param.dataCount = serie.dataCount;
  90. param.value = serieData.GetData(0);
  91. param.total = serieData.GetData(1);
  92. param.color = color;
  93. param.marker = SerieHelper.GetItemMarker(serie, serieData, marker);
  94. param.itemFormatter = SerieHelper.GetItemFormatter(serie, serieData, itemFormatter);
  95. param.numericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter);;
  96. param.columns.Clear();
  97. param.columns.Add(param.marker);
  98. param.columns.Add(serieData.name);
  99. param.columns.Add(ChartCached.NumberToStr(param.value, param.numericFormatter));
  100. paramList.Add(param);
  101. }
  102. public override Vector3 GetSerieDataLabelPosition(SerieData serieData, LabelStyle label)
  103. {
  104. var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData);
  105. var centerRadius = (serieData.context.outsideRadius + serieData.context.insideRadius) / 2;
  106. var startAngle = serieData.context.startAngle;
  107. var toAngle = serieData.context.toAngle;
  108. switch (label.position)
  109. {
  110. case LabelStyle.Position.Bottom:
  111. case LabelStyle.Position.Start:
  112. var px1 = Mathf.Sin(startAngle * Mathf.Deg2Rad) * centerRadius;
  113. var py1 = Mathf.Cos(startAngle * Mathf.Deg2Rad) * centerRadius;
  114. var xDiff = serie.clockwise ? -label.distance : label.distance;
  115. if (labelLine != null && labelLine.show)
  116. {
  117. serieData.context.labelLinePosition = serie.context.center + new Vector3(px1, py1) + labelLine.GetStartSymbolOffset();
  118. serieData.context.labelPosition = GetLabelLineEndPosition(serie, serieData, labelLine) + new Vector3(xDiff, 0);
  119. }
  120. else
  121. {
  122. serieData.context.labelLinePosition = serie.context.center + new Vector3(px1 + xDiff, py1);
  123. serieData.context.labelPosition = serieData.context.labelLinePosition;
  124. }
  125. break;
  126. case LabelStyle.Position.Top:
  127. case LabelStyle.Position.End:
  128. startAngle += serie.clockwise ? -label.distance : label.distance;
  129. toAngle += serie.clockwise ? label.distance : -label.distance;
  130. var px2 = Mathf.Sin(toAngle * Mathf.Deg2Rad) * centerRadius;
  131. var py2 = Mathf.Cos(toAngle * Mathf.Deg2Rad) * centerRadius;
  132. if (labelLine != null && labelLine.show)
  133. {
  134. serieData.context.labelLinePosition = serie.context.center + new Vector3(px2, py2) + labelLine.GetStartSymbolOffset();
  135. serieData.context.labelPosition = GetLabelLineEndPosition(serie, serieData, labelLine);
  136. }
  137. else
  138. {
  139. serieData.context.labelLinePosition = serie.context.center + new Vector3(px2, py2);
  140. serieData.context.labelPosition = serieData.context.labelLinePosition;
  141. }
  142. break;
  143. default: //LabelStyle.Position.Center
  144. serieData.context.labelLinePosition = serie.context.center + label.offset;
  145. serieData.context.labelPosition = serieData.context.labelLinePosition;
  146. break;
  147. }
  148. return serieData.context.labelPosition;
  149. }
  150. private Vector3 GetLabelLineEndPosition(Serie serie, SerieData serieData, LabelLine labelLine)
  151. {
  152. var isRight = !serie.clockwise;
  153. var dire = isRight ? Vector3.right : Vector3.left;
  154. var rad = Mathf.Deg2Rad * (isRight ? labelLine.lineAngle : 180 - labelLine.lineAngle);
  155. var lineLength1 = ChartHelper.GetActualValue(labelLine.lineLength1, serie.context.outsideRadius);
  156. var lineLength2 = ChartHelper.GetActualValue(labelLine.lineLength2, serie.context.outsideRadius);
  157. var pos1 = serieData.context.labelLinePosition;
  158. var pos2 = pos1 + new Vector3(Mathf.Cos(rad) * lineLength1, Mathf.Sin(rad) * lineLength1);
  159. var pos5 = pos2 + dire * lineLength2;
  160. return pos5 + labelLine.GetEndSymbolOffset();
  161. }
  162. public override void DrawSerie(VertexHelper vh)
  163. {
  164. if (!serie.show || serie.animation.HasFadeOut()) return;
  165. var data = serie.data;
  166. serie.animation.InitProgress(serie.startAngle, serie.startAngle + 360);
  167. SerieHelper.UpdateCenter(serie, chart.chartPosition, chart.chartWidth, chart.chartHeight);
  168. var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
  169. var unscaledTime = serie.animation.unscaledTime;
  170. var ringWidth = serie.context.outsideRadius - serie.context.insideRadius;
  171. var dataChanging = false;
  172. for (int j = 0; j < data.Count; j++)
  173. {
  174. var serieData = data[j];
  175. if (!serieData.show) continue;
  176. if (serieData.IsDataChanged()) dataChanging = true;
  177. var value = serieData.GetFirstData(unscaledTime, dataChangeDuration);
  178. var max = serieData.GetLastData();
  179. var degree = (float) (360 * value / max);
  180. var startDegree = GetStartAngle(serie);
  181. var toDegree = GetToAngle(serie, degree);
  182. var itemStyle = SerieHelper.GetItemStyle(serie, serieData);
  183. var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName);
  184. Color32 itemColor, itemToColor;
  185. SerieHelper.GetItemColor(out itemColor, out itemToColor, serie, serieData, chart.theme, colorIndex);
  186. var outsideRadius = serie.context.outsideRadius - j * (ringWidth + serie.gap);
  187. var insideRadius = outsideRadius - ringWidth;
  188. var borderWidth = itemStyle.borderWidth;
  189. var borderColor = itemStyle.borderColor;
  190. var roundCap = serie.roundCap && insideRadius > 0;
  191. serieData.context.startAngle = startDegree;
  192. serieData.context.toAngle = toDegree;
  193. serieData.context.insideRadius = insideRadius;
  194. serieData.context.outsideRadius = serieData.radius > 0 ? serieData.radius : outsideRadius;
  195. DrawBackground(vh, serie, serieData, j, insideRadius, outsideRadius);
  196. UGL.DrawDoughnut(vh, serie.context.center, insideRadius, outsideRadius, itemColor, itemToColor,
  197. Color.clear, startDegree, toDegree, borderWidth, borderColor, 0, chart.settings.cicleSmoothness,
  198. roundCap, serie.clockwise);
  199. DrawCenter(vh, serie, serieData, insideRadius, j == data.Count - 1);
  200. var serieLabel = SerieHelper.GetSerieLabel(serie, serieData);
  201. if (SerieLabelHelper.CanShowLabel(serie, serieData, serieLabel, 0))
  202. {
  203. DrawRingLabelLine(vh, serie, serieData, itemColor);
  204. }
  205. }
  206. if (!serie.animation.IsFinish())
  207. {
  208. serie.animation.CheckProgress(360);
  209. chart.RefreshChart();
  210. }
  211. if (dataChanging)
  212. {
  213. chart.RefreshChart();
  214. }
  215. }
  216. public override void OnLegendButtonClick(int index, string legendName, bool show)
  217. {
  218. if (!serie.IsLegendName(legendName))
  219. return;
  220. LegendHelper.CheckDataShow(serie, legendName, show);
  221. chart.UpdateLegendColor(legendName, show);
  222. chart.RefreshPainter(serie);
  223. }
  224. public override void OnLegendButtonEnter(int index, string legendName)
  225. {
  226. if (!serie.IsLegendName(legendName))
  227. return;
  228. LegendHelper.CheckDataHighlighted(serie, legendName, true);
  229. chart.RefreshPainter(serie);
  230. }
  231. public override void OnLegendButtonExit(int index, string legendName)
  232. {
  233. if (!serie.IsLegendName(legendName))
  234. return;
  235. LegendHelper.CheckDataHighlighted(serie, legendName, false);
  236. chart.RefreshPainter(serie);
  237. }
  238. public override void OnPointerDown(PointerEventData eventData) { }
  239. private float GetStartAngle(Serie serie)
  240. {
  241. return serie.clockwise ? serie.startAngle : 360 - serie.startAngle;
  242. }
  243. private float GetToAngle(Serie serie, float angle)
  244. {
  245. var toAngle = angle + serie.startAngle;
  246. if (!serie.clockwise)
  247. {
  248. toAngle = 360 - angle - serie.startAngle;
  249. }
  250. if (!serie.animation.IsFinish())
  251. {
  252. var currAngle = serie.animation.GetCurrDetail();
  253. if (serie.clockwise)
  254. {
  255. toAngle = toAngle > currAngle ? currAngle : toAngle;
  256. }
  257. else
  258. {
  259. toAngle = toAngle < 360 - currAngle ? 360 - currAngle : toAngle;
  260. }
  261. }
  262. return toAngle;
  263. }
  264. private void DrawCenter(VertexHelper vh, Serie serie, SerieData serieData, float insideRadius, bool last)
  265. {
  266. var itemStyle = SerieHelper.GetItemStyle(serie, serieData);
  267. if (!ChartHelper.IsClearColor(itemStyle.centerColor) && last)
  268. {
  269. var radius = insideRadius - itemStyle.centerGap;
  270. var smoothness = chart.settings.cicleSmoothness;
  271. UGL.DrawCricle(vh, serie.context.center, radius, itemStyle.centerColor, smoothness);
  272. }
  273. }
  274. private void DrawBackground(VertexHelper vh, Serie serie, SerieData serieData, int index, float insideRadius, float outsideRadius)
  275. {
  276. var itemStyle = SerieHelper.GetItemStyle(serie, serieData);
  277. var backgroundColor = itemStyle.backgroundColor;
  278. if (ChartHelper.IsClearColor(backgroundColor))
  279. {
  280. backgroundColor = chart.theme.GetColor(index);
  281. backgroundColor.a = 50;
  282. }
  283. if (itemStyle.backgroundWidth != 0)
  284. {
  285. var centerRadius = (outsideRadius + insideRadius) / 2;
  286. var inradius = centerRadius - itemStyle.backgroundWidth / 2;
  287. var outradius = centerRadius + itemStyle.backgroundWidth / 2;
  288. UGL.DrawDoughnut(vh, serie.context.center, inradius,
  289. outradius, backgroundColor, Color.clear, chart.settings.cicleSmoothness);
  290. }
  291. else
  292. {
  293. UGL.DrawDoughnut(vh, serie.context.center, insideRadius,
  294. outsideRadius, backgroundColor, Color.clear, chart.settings.cicleSmoothness);
  295. }
  296. }
  297. private void DrawBorder(VertexHelper vh, Serie serie, SerieData serieData, float insideRadius, float outsideRadius)
  298. {
  299. var itemStyle = SerieHelper.GetItemStyle(serie, serieData);
  300. if (itemStyle.show && itemStyle.borderWidth > 0 && !ChartHelper.IsClearColor(itemStyle.borderColor))
  301. {
  302. UGL.DrawDoughnut(vh, serie.context.center, outsideRadius,
  303. outsideRadius + itemStyle.borderWidth, itemStyle.borderColor,
  304. Color.clear, chart.settings.cicleSmoothness);
  305. UGL.DrawDoughnut(vh, serie.context.center, insideRadius,
  306. insideRadius + itemStyle.borderWidth, itemStyle.borderColor,
  307. Color.clear, chart.settings.cicleSmoothness);
  308. }
  309. }
  310. private int GetRingIndex(Vector2 local)
  311. {
  312. var dist = Vector2.Distance(local, serie.context.center);
  313. if (dist > serie.context.outsideRadius) return -1;
  314. Vector2 dir = local - new Vector2(serie.context.center.x, serie.context.center.y);
  315. float angle = VectorAngle(Vector2.up, dir);
  316. for (int i = 0; i < serie.data.Count; i++)
  317. {
  318. var serieData = serie.data[i];
  319. if (dist >= serieData.context.insideRadius &&
  320. dist <= serieData.context.outsideRadius &&
  321. IsInAngle(serieData, angle, serie.clockwise))
  322. {
  323. return i;
  324. }
  325. }
  326. return -1;
  327. }
  328. private bool IsInAngle(SerieData serieData, float angle, bool clockwise)
  329. {
  330. if (clockwise)
  331. return angle >= serieData.context.startAngle && angle <= serieData.context.toAngle;
  332. else
  333. return angle >= serieData.context.toAngle && angle <= serieData.context.startAngle;
  334. }
  335. private float VectorAngle(Vector2 from, Vector2 to)
  336. {
  337. float angle;
  338. Vector3 cross = Vector3.Cross(from, to);
  339. angle = Vector2.Angle(from, to);
  340. angle = cross.z > 0 ? -angle : angle;
  341. angle = (angle + 360) % 360;
  342. return angle;
  343. }
  344. private void DrawRingLabelLine(VertexHelper vh, Serie serie, SerieData serieData, Color32 defaltColor)
  345. {
  346. var serieLabel = SerieHelper.GetSerieLabel(serie, serieData);
  347. var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData);
  348. if (serieLabel != null && serieLabel.show &&
  349. labelLine != null && labelLine.show)
  350. {
  351. var color = ChartHelper.IsClearColor(labelLine.lineColor) ?
  352. ChartHelper.GetHighlightColor(defaltColor, 0.9f) :
  353. labelLine.lineColor;
  354. var isRight = !serie.clockwise;
  355. var dire = isRight ? Vector3.right : Vector3.left;
  356. var rad = Mathf.Deg2Rad * (isRight ? labelLine.lineAngle : 180 - labelLine.lineAngle);
  357. var lineLength1 = ChartHelper.GetActualValue(labelLine.lineLength1, serie.context.outsideRadius);
  358. var lineLength2 = ChartHelper.GetActualValue(labelLine.lineLength2, serie.context.outsideRadius);
  359. var pos1 = serieData.context.labelLinePosition;
  360. var pos2 = pos1 + new Vector3(Mathf.Cos(rad) * lineLength1, Mathf.Sin(rad) * lineLength1);
  361. var pos5 = pos2 + dire * lineLength2 + labelLine.GetEndSymbolOffset();
  362. serieData.context.labelPosition = pos5;
  363. switch (labelLine.lineType)
  364. {
  365. case LabelLine.LineType.BrokenLine:
  366. UGL.DrawLine(vh, pos1, pos2, pos5, labelLine.lineWidth, color);
  367. break;
  368. case LabelLine.LineType.Curves:
  369. UGL.DrawCurves(vh, pos1, pos5, pos1, pos2, labelLine.lineWidth, color,
  370. chart.settings.lineSmoothness, UGL.Direction.XAxis);
  371. break;
  372. case LabelLine.LineType.HorizontalLine:
  373. pos5 = pos1 + dire * (lineLength1 + lineLength2);
  374. serieData.context.labelPosition = pos5;
  375. UGL.DrawLine(vh, pos1, pos5, labelLine.lineWidth, color);
  376. break;
  377. }
  378. DrawLabelLineSymbol(vh, labelLine, pos1, pos5, color);
  379. }
  380. }
  381. }
  382. }