Geen omschrijving
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BarHandler.cs 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.EventSystems;
  4. using UnityEngine.UI;
  5. using XUGL;
  6. namespace XCharts.Runtime
  7. {
  8. [UnityEngine.Scripting.Preserve]
  9. internal sealed partial class BarHandler : SerieHandler<Bar>
  10. {
  11. List<List<SerieData>> m_StackSerieData = new List<List<SerieData>>();
  12. private GridCoord m_SerieGrid;
  13. private float[] m_CapusleDefaultCornerRadius = new float[] { 1, 1, 1, 1 };
  14. public override void Update()
  15. {
  16. base.Update();
  17. if (serie.IsUseCoord<GridCoord>())
  18. UpdateSerieGridContext();
  19. else if (serie.IsUseCoord<PolarCoord>())
  20. UpdateSeriePolarContext();
  21. }
  22. public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category,
  23. string marker, string itemFormatter, string numericFormatter, string ignoreDataDefaultContent,
  24. ref List<SerieParams> paramList, ref string title)
  25. {
  26. UpdateCoordSerieParams(ref paramList, ref title, dataIndex, showCategory, category,
  27. marker, itemFormatter, numericFormatter, ignoreDataDefaultContent);
  28. }
  29. public override void DrawSerie(VertexHelper vh)
  30. {
  31. if (serie.IsUseCoord<PolarCoord>())
  32. {
  33. DrawPolarBar(vh, serie);
  34. }
  35. else if (serie.IsUseCoord<GridCoord>())
  36. {
  37. DrawBarSerie(vh, serie);
  38. }
  39. }
  40. public override Vector3 GetSerieDataLabelPosition(SerieData serieData, LabelStyle label)
  41. {
  42. if (serie.IsUseCoord<PolarCoord>())
  43. {
  44. switch (label.position)
  45. {
  46. case LabelStyle.Position.Bottom:
  47. var center = serieData.context.areaCenter;
  48. var angle = serieData.context.halfAngle;
  49. var radius = serieData.context.insideRadius;
  50. return ChartHelper.GetPosition(center, angle, radius);
  51. case LabelStyle.Position.Top:
  52. center = serieData.context.areaCenter;
  53. angle = serieData.context.halfAngle;
  54. radius = serieData.context.outsideRadius;
  55. return ChartHelper.GetPosition(center, angle, radius);
  56. default:
  57. return serieData.context.position;
  58. }
  59. }
  60. else
  61. {
  62. switch (label.position)
  63. {
  64. case LabelStyle.Position.Bottom:
  65. var center = serieData.context.rect.center;
  66. return new Vector3(center.x, center.y - serieData.context.rect.height / 2);
  67. case LabelStyle.Position.Center:
  68. case LabelStyle.Position.Inside:
  69. return serieData.context.rect.center;
  70. default:
  71. return serieData.context.position;
  72. }
  73. }
  74. }
  75. private void UpdateSerieGridContext()
  76. {
  77. if (m_SerieGrid == null)
  78. return;
  79. var needCheck = (chart.isPointerInChart && m_SerieGrid.IsPointerEnter() && !serie.placeHolder) || m_LegendEnter;
  80. var needInteract = false;
  81. if (!needCheck)
  82. {
  83. if (m_LastCheckContextFlag != needCheck)
  84. {
  85. m_LastCheckContextFlag = needCheck;
  86. serie.context.pointerItemDataIndex = -1;
  87. serie.context.pointerEnter = false;
  88. foreach (var serieData in serie.data)
  89. {
  90. serieData.context.highlight = false;
  91. serieData.interact.Reset();
  92. }
  93. chart.RefreshPainter(serie);
  94. }
  95. return;
  96. }
  97. m_LastCheckContextFlag = needCheck;
  98. Color32 color, toColor;
  99. if (m_LegendEnter)
  100. {
  101. serie.context.pointerEnter = true;
  102. foreach (var serieData in serie.data)
  103. {
  104. SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme);
  105. serieData.interact.SetColor(ref needInteract, color, toColor);
  106. }
  107. }
  108. else
  109. {
  110. serie.context.pointerItemDataIndex = -1;
  111. serie.context.pointerEnter = false;
  112. foreach (var serieData in serie.data)
  113. {
  114. if (serie.context.pointerAxisDataIndexs.Contains(serieData.index) ||
  115. serieData.context.rect.Contains(chart.pointerPos))
  116. {
  117. serie.context.pointerItemDataIndex = serieData.index;
  118. serie.context.pointerEnter = true;
  119. serieData.context.highlight = true;
  120. }
  121. else
  122. {
  123. serieData.context.highlight = false;
  124. }
  125. var state = SerieHelper.GetSerieState(serie, serieData, true);
  126. SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, state);
  127. serieData.interact.SetColor(ref needInteract, color, toColor);
  128. }
  129. }
  130. if (needInteract)
  131. {
  132. chart.RefreshPainter(serie);
  133. }
  134. }
  135. private void DrawBarSerie(VertexHelper vh, Bar serie)
  136. {
  137. if (!serie.show || serie.animation.HasFadeOut())
  138. return;
  139. Axis axis;
  140. Axis relativedAxis;
  141. var isY = chart.GetSerieGridCoordAxis(serie, out axis, out relativedAxis);
  142. if (axis == null)
  143. return;
  144. if (relativedAxis == null)
  145. return;
  146. m_SerieGrid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
  147. if (m_SerieGrid == null)
  148. return;
  149. var dataZoom = chart.GetDataZoomOfAxis(axis);
  150. var showData = serie.GetDataList(dataZoom);
  151. if (showData.Count <= 0)
  152. return;
  153. var axisLength = isY ? m_SerieGrid.context.height : m_SerieGrid.context.width;
  154. var relativedAxisLength = isY ? m_SerieGrid.context.width : m_SerieGrid.context.height;
  155. var axisXY = isY ? m_SerieGrid.context.y : m_SerieGrid.context.x;
  156. var isStack = SeriesHelper.IsStack<Bar>(chart.series, serie.stack);
  157. if (isStack)
  158. SeriesHelper.UpdateStackDataList(chart.series, serie, dataZoom, m_StackSerieData);
  159. var barCount = chart.GetSerieBarRealCount<Bar>();
  160. float categoryWidth = AxisHelper.GetDataWidth(axis, axisLength, showData.Count, dataZoom);
  161. float barGap = chart.GetSerieBarGap<Bar>();
  162. float totalBarWidth = chart.GetSerieTotalWidth<Bar>(categoryWidth, barGap, barCount);
  163. float barWidth = serie.GetBarWidth(categoryWidth, barCount);
  164. float offset = (categoryWidth - totalBarWidth) * 0.5f;
  165. var serieReadIndex = chart.GetSerieIndexIfStack<Bar>(serie);
  166. float gap = serie.barGap == -1 ? offset : offset + chart.GetSerieTotalGap<Bar>(categoryWidth, barGap, serieReadIndex);
  167. int maxCount = serie.maxShow > 0 ?
  168. (serie.maxShow > showData.Count ? showData.Count : serie.maxShow) :
  169. showData.Count;
  170. var isPercentStack = SeriesHelper.IsPercentStack<Bar>(chart.series, serie.stack);
  171. bool dataChanging = false;
  172. float dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
  173. double yMinValue = relativedAxis.context.minValue;
  174. double yMaxValue = relativedAxis.context.maxValue;
  175. var areaColor = ColorUtil.clearColor32;
  176. var areaToColor = ColorUtil.clearColor32;
  177. var interacting = false;
  178. serie.containerIndex = m_SerieGrid.index;
  179. serie.containterInstanceId = m_SerieGrid.instanceId;
  180. serie.animation.InitProgress(axisXY, axisXY + axisLength);
  181. for (int i = serie.minShow; i < maxCount; i++)
  182. {
  183. var serieData = showData[i];
  184. if (!serieData.show || serie.IsIgnoreValue(serieData))
  185. {
  186. serie.context.dataPoints.Add(Vector3.zero);
  187. serie.context.dataIndexs.Add(serieData.index);
  188. continue;
  189. }
  190. if (serieData.IsDataChanged())
  191. dataChanging = true;
  192. var state = SerieHelper.GetSerieState(serie, serieData);
  193. var itemStyle = SerieHelper.GetItemStyle(serie, serieData, state);
  194. var value = axis.IsCategory() ? i : serieData.GetData(0, axis.inverse);
  195. var relativedValue = serieData.GetCurrData(1, dataChangeDuration, relativedAxis.inverse, yMinValue, yMaxValue, serie.animation.unscaledTime);
  196. var borderWidth = relativedValue == 0 ? 0 : itemStyle.runtimeBorderWidth;
  197. var borderGap = relativedValue == 0 ? 0 : itemStyle.borderGap;
  198. var borderGapAndWidth = borderWidth + borderGap;
  199. var backgroundColor = itemStyle.backgroundColor;
  200. if (!serieData.interact.TryGetColor(ref areaColor, ref areaToColor, ref interacting))
  201. {
  202. SerieHelper.GetItemColor(out areaColor, out areaToColor, serie, serieData, chart.theme);
  203. serieData.interact.SetColor(ref interacting, areaColor, areaToColor);
  204. }
  205. var pX = 0f;
  206. var pY = 0f;
  207. UpdateXYPosition(m_SerieGrid, isY, axis, relativedAxis, i, categoryWidth, barWidth, isStack, value, ref pX, ref pY);
  208. var barHig = 0f;
  209. if (isPercentStack)
  210. {
  211. var valueTotal = chart.GetSerieSameStackTotalValue<Bar>(serie.stack, i);
  212. barHig = valueTotal != 0 ? (float)(relativedValue / valueTotal * relativedAxisLength) : 0;
  213. }
  214. else
  215. {
  216. barHig = AxisHelper.GetAxisValueLength(m_SerieGrid, relativedAxis, categoryWidth, relativedValue);
  217. }
  218. float currHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, barHig);
  219. Vector3 plb, plt, prt, prb, top;
  220. UpdateRectPosition(m_SerieGrid, isY, relativedValue, pX, pY, gap, borderWidth, barWidth, currHig,
  221. out plb, out plt, out prt, out prb, out top);
  222. serieData.context.stackHeight = barHig;
  223. serieData.context.position = top;
  224. serieData.context.rect = Rect.MinMaxRect(plb.x + borderGapAndWidth, plb.y + borderGapAndWidth,
  225. prt.x - borderGapAndWidth, prt.y - borderGapAndWidth);
  226. serieData.context.backgroundRect = isY ?
  227. Rect.MinMaxRect(m_SerieGrid.context.x, plb.y, m_SerieGrid.context.x + relativedAxisLength, prt.y) :
  228. Rect.MinMaxRect(plb.x, m_SerieGrid.context.y, prb.x, m_SerieGrid.context.y + relativedAxisLength);
  229. if (!serie.clip || (serie.clip && m_SerieGrid.Contains(top)))
  230. {
  231. serie.context.dataPoints.Add(top);
  232. serie.context.dataIndexs.Add(serieData.index);
  233. }
  234. else
  235. {
  236. continue;
  237. }
  238. if (serie.show && !serie.placeHolder)
  239. {
  240. switch (serie.barType)
  241. {
  242. case BarType.Normal:
  243. case BarType.Capsule:
  244. DrawNormalBar(vh, serie, serieData, itemStyle, backgroundColor, gap, barWidth,
  245. pX, pY, plb, plt, prt, prb, isY, m_SerieGrid, axis, areaColor, areaToColor, relativedValue);
  246. break;
  247. case BarType.Zebra:
  248. DrawZebraBar(vh, serie, serieData, itemStyle, backgroundColor, gap, barWidth,
  249. pX, pY, plb, plt, prt, prb, isY, m_SerieGrid, axis, areaColor, areaToColor);
  250. break;
  251. }
  252. }
  253. if (serie.animation.CheckDetailBreak(top, isY))
  254. {
  255. break;
  256. }
  257. }
  258. if (!serie.animation.IsFinish())
  259. {
  260. serie.animation.CheckProgress();
  261. chart.RefreshPainter(serie);
  262. }
  263. if (dataChanging || interacting)
  264. {
  265. chart.RefreshPainter(serie);
  266. }
  267. }
  268. private void UpdateXYPosition(GridCoord grid, bool isY, Axis axis, Axis relativedAxis, int i, float categoryWidth, float barWidth, bool isStack,
  269. double value, ref float pX, ref float pY)
  270. {
  271. if (isY)
  272. {
  273. if (axis.IsCategory())
  274. {
  275. pY = grid.context.y + i * categoryWidth + (axis.boundaryGap ? 0 : -categoryWidth * 0.5f);
  276. }
  277. else
  278. {
  279. if (axis.context.minMaxRange <= 0) pY = grid.context.y;
  280. else
  281. {
  282. var valueLen = (float)((value - axis.context.minValue) / axis.context.minMaxRange) * grid.context.height;
  283. pY = grid.context.y + valueLen - categoryWidth * 0.5f;
  284. }
  285. }
  286. pX = AxisHelper.GetAxisValuePosition(grid, relativedAxis, categoryWidth, 0);
  287. if (isStack)
  288. {
  289. for (int n = 0; n < m_StackSerieData.Count - 1; n++)
  290. pX += m_StackSerieData[n][i].context.stackHeight;
  291. }
  292. }
  293. else
  294. {
  295. if (axis.IsCategory())
  296. {
  297. pX = grid.context.x + i * categoryWidth + (axis.boundaryGap ? 0 : -categoryWidth * 0.5f);
  298. }
  299. else
  300. {
  301. if (axis.context.minMaxRange <= 0) pX = grid.context.x;
  302. else
  303. {
  304. var valueLen = (float)((value - axis.context.minValue) / axis.context.minMaxRange) * grid.context.width;
  305. pX = grid.context.x + valueLen - categoryWidth * 0.5f;
  306. }
  307. }
  308. pY = AxisHelper.GetAxisValuePosition(grid, relativedAxis, categoryWidth, 0);
  309. if (isStack)
  310. {
  311. for (int n = 0; n < m_StackSerieData.Count - 1; n++)
  312. pY += m_StackSerieData[n][i].context.stackHeight;
  313. }
  314. }
  315. }
  316. private void UpdateRectPosition(GridCoord grid, bool isY, double yValue, float pX, float pY, float gap, float borderWidth,
  317. float barWidth, float currHig,
  318. out Vector3 plb, out Vector3 plt, out Vector3 prt, out Vector3 prb, out Vector3 top)
  319. {
  320. if (isY)
  321. {
  322. if (yValue < 0)
  323. {
  324. plt = new Vector3(pX + currHig, pY + gap + barWidth);
  325. prt = new Vector3(pX, pY + gap + barWidth);
  326. prb = new Vector3(pX, pY + gap);
  327. plb = new Vector3(pX + currHig, pY + gap);
  328. }
  329. else
  330. {
  331. plt = new Vector3(pX, pY + gap + barWidth);
  332. prt = new Vector3(pX + currHig, pY + gap + barWidth);
  333. prb = new Vector3(pX + currHig, pY + gap);
  334. plb = new Vector3(pX, pY + gap);
  335. }
  336. top = new Vector3(pX + currHig, pY + gap + barWidth / 2);
  337. }
  338. else
  339. {
  340. if (yValue < 0)
  341. {
  342. plb = new Vector3(pX + gap, pY + currHig);
  343. plt = new Vector3(pX + gap, pY);
  344. prt = new Vector3(pX + gap + barWidth, pY);
  345. prb = new Vector3(pX + gap + barWidth, pY + currHig);
  346. }
  347. else
  348. {
  349. plb = new Vector3(pX + gap, pY);
  350. plt = new Vector3(pX + gap, pY + currHig);
  351. prt = new Vector3(pX + gap + barWidth, pY + currHig);
  352. prb = new Vector3(pX + gap + barWidth, pY);
  353. }
  354. top = new Vector3(pX + gap + barWidth / 2, pY + currHig);
  355. }
  356. if (serie.clip)
  357. {
  358. plb = chart.ClampInGrid(grid, plb);
  359. plt = chart.ClampInGrid(grid, plt);
  360. prt = chart.ClampInGrid(grid, prt);
  361. prb = chart.ClampInGrid(grid, prb);
  362. top = chart.ClampInGrid(grid, top);
  363. }
  364. }
  365. private void DrawNormalBar(VertexHelper vh, Serie serie, SerieData serieData, ItemStyle itemStyle, Color32 backgroundColor,
  366. float gap, float barWidth, float pX, float pY, Vector3 plb, Vector3 plt, Vector3 prt,
  367. Vector3 prb, bool isYAxis, GridCoord grid, Axis axis, Color32 areaColor, Color32 areaToColor, double value)
  368. {
  369. var borderWidth = itemStyle.runtimeBorderWidth;
  370. var cornerRadius = serie.barType == BarType.Capsule && !itemStyle.IsNeedCorner() ?
  371. m_CapusleDefaultCornerRadius :
  372. itemStyle.cornerRadius;
  373. var invert = value < 0;
  374. if (!ChartHelper.IsClearColor(backgroundColor))
  375. {
  376. UGL.DrawRoundRectangle(vh, serieData.context.backgroundRect, backgroundColor, backgroundColor, 0,
  377. cornerRadius, isYAxis, chart.settings.cicleSmoothness, invert);
  378. }
  379. UGL.DrawRoundRectangle(vh, serieData.context.rect, areaColor, areaToColor, 0,
  380. cornerRadius, isYAxis, chart.settings.cicleSmoothness, invert);
  381. if (serie.barType == BarType.Capsule)
  382. {
  383. UGL.DrawBorder(vh, serieData.context.backgroundRect, borderWidth, itemStyle.borderColor,
  384. 0, cornerRadius, isYAxis, chart.settings.cicleSmoothness, invert, -borderWidth);
  385. }
  386. else
  387. {
  388. UGL.DrawBorder(vh, serieData.context.rect, borderWidth, itemStyle.borderColor,
  389. 0, cornerRadius, isYAxis, chart.settings.cicleSmoothness, invert, itemStyle.borderGap);
  390. }
  391. }
  392. private void DrawZebraBar(VertexHelper vh, Serie serie, SerieData serieData, ItemStyle itemStyle, Color32 backgroundColor,
  393. float gap, float barWidth, float pX, float pY, Vector3 plb, Vector3 plt, Vector3 prt,
  394. Vector3 prb, bool isYAxis, GridCoord grid, Axis axis, Color32 barColor, Color32 barToColor)
  395. {
  396. if (!ChartHelper.IsClearColor(backgroundColor))
  397. {
  398. UGL.DrawRoundRectangle(vh, serieData.context.backgroundRect, backgroundColor, backgroundColor, 0,
  399. null, isYAxis, chart.settings.cicleSmoothness, false);
  400. }
  401. if (isYAxis)
  402. {
  403. plt = (plb + plt) / 2;
  404. prt = (prt + prb) / 2;
  405. chart.DrawClipZebraLine(vh, plt, prt, barWidth / 2, serie.barZebraWidth, serie.barZebraGap,
  406. barColor, barToColor, serie.clip, grid, grid.context.width);
  407. }
  408. else
  409. {
  410. plb = (prb + plb) / 2;
  411. plt = (plt + prt) / 2;
  412. chart.DrawClipZebraLine(vh, plb, plt, barWidth / 2, serie.barZebraWidth, serie.barZebraGap,
  413. barColor, barToColor, serie.clip, grid, grid.context.height);
  414. }
  415. }
  416. }
  417. }