MarkLineHandler.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.UI;
  4. namespace XCharts.Runtime
  5. {
  6. [UnityEngine.Scripting.Preserve]
  7. internal sealed class MarkLineHandler : MainComponentHandler<MarkLine>
  8. {
  9. private GameObject m_MarkLineLabelRoot;
  10. private bool m_RefreshLabel = false;
  11. public override void InitComponent()
  12. {
  13. m_MarkLineLabelRoot = ChartHelper.AddObject("markline", chart.transform, chart.chartMinAnchor,
  14. chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta);
  15. m_MarkLineLabelRoot.hideFlags = chart.chartHideFlags;
  16. ChartHelper.HideAllObject(m_MarkLineLabelRoot);
  17. InitMarkLine(component);
  18. }
  19. public override void DrawBase(VertexHelper vh)
  20. {
  21. if (!component.onTop)
  22. DrawMarkLine(vh, component);
  23. }
  24. public override void DrawUpper(VertexHelper vh)
  25. {
  26. if (component.onTop)
  27. DrawMarkLine(vh, component);
  28. }
  29. public override void Update()
  30. {
  31. if (m_RefreshLabel)
  32. {
  33. m_RefreshLabel = false;
  34. var serie = chart.GetSerie(component.serieIndex);
  35. if (!serie.show || !component.show) return;
  36. foreach (var data in component.data)
  37. {
  38. if (data.runtimeLabel != null)
  39. {
  40. var pos = MarkLineHelper.GetLabelPosition(data);
  41. data.runtimeLabel.SetActive(data.label.show && data.runtimeInGrid);
  42. data.runtimeLabel.SetPosition(pos);
  43. data.runtimeLabel.SetText(MarkLineHelper.GetFormatterContent(serie, data));
  44. }
  45. }
  46. }
  47. }
  48. private void InitMarkLine(MarkLine markLine)
  49. {
  50. var serie = chart.GetSerie(markLine.serieIndex);
  51. if (!serie.show || !markLine.show) return;
  52. ResetTempMarkLineGroupData(markLine);
  53. var serieColor = (Color)chart.GetItemColor(serie);
  54. if (m_TempGroupData.Count > 0)
  55. {
  56. foreach (var kv in m_TempGroupData)
  57. {
  58. if (kv.Value.Count >= 2)
  59. {
  60. var data = kv.Value[0];
  61. InitMarkLineLabel(serie, data, serieColor);
  62. }
  63. }
  64. }
  65. foreach (var data in markLine.data)
  66. {
  67. if (data.group != 0) continue;
  68. InitMarkLineLabel(serie, data, serieColor);
  69. }
  70. }
  71. private void InitMarkLineLabel(Serie serie, MarkLineData data, Color serieColor)
  72. {
  73. data.painter = chart.m_PainterUpper;
  74. data.refreshComponent = delegate ()
  75. {
  76. var textName = string.Format("markLine_{0}_{1}", component.index, data.index);
  77. var content = MarkLineHelper.GetFormatterContent(serie, data);
  78. var label = ChartHelper.AddChartLabel(textName, m_MarkLineLabelRoot.transform, data.label, chart.theme.axis,
  79. content, Color.clear, TextAnchor.MiddleCenter);
  80. var pos = MarkLineHelper.GetLabelPosition(data);
  81. label.SetIconActive(false);
  82. label.SetActive(data.label.show && data.runtimeInGrid);
  83. label.SetPosition(pos);
  84. data.runtimeLabel = label;
  85. };
  86. data.refreshComponent();
  87. }
  88. private Dictionary<int, List<MarkLineData>> m_TempGroupData = new Dictionary<int, List<MarkLineData>>();
  89. private void DrawMarkLine(VertexHelper vh, MarkLine markLine)
  90. {
  91. var serie = chart.GetSerie(markLine.serieIndex);
  92. if (!serie.show || !markLine.show) return;
  93. if (markLine.data.Count == 0) return;
  94. var yAxis = chart.GetChartComponent<YAxis>(serie.yAxisIndex);
  95. var xAxis = chart.GetChartComponent<XAxis>(serie.xAxisIndex);
  96. var grid = chart.GetChartComponent<GridCoord>(xAxis.gridIndex);
  97. var dataZoom = chart.GetDataZoomOfAxis(xAxis);
  98. var animation = markLine.animation;
  99. var showData = serie.GetDataList(dataZoom);
  100. var sp = Vector3.zero;
  101. var ep = Vector3.zero;
  102. var colorIndex = chart.GetLegendRealShowNameIndex(serie.serieName);
  103. var serieColor = SerieHelper.GetLineColor(serie, null, chart.theme, colorIndex, SerieState.Normal);
  104. animation.InitProgress(0, 1f);
  105. ResetTempMarkLineGroupData(markLine);
  106. if (m_TempGroupData.Count > 0)
  107. {
  108. foreach (var kv in m_TempGroupData)
  109. {
  110. if (kv.Value.Count >= 2)
  111. {
  112. sp = GetSinglePos(xAxis, yAxis, grid, serie, dataZoom, kv.Value[0], showData.Count);
  113. ep = GetSinglePos(xAxis, yAxis, grid, serie, dataZoom, kv.Value[1], showData.Count);
  114. kv.Value[0].runtimeStartPosition = sp;
  115. kv.Value[1].runtimeEndPosition = ep;
  116. DrawMakLineData(vh, kv.Value[0], animation, serie, grid, serieColor, sp, ep);
  117. }
  118. }
  119. }
  120. foreach (var data in markLine.data)
  121. {
  122. if (data.group != 0) continue;
  123. switch (data.type)
  124. {
  125. case MarkLineType.Min:
  126. data.runtimeValue = SerieHelper.GetMinData(serie, data.dimension, dataZoom);
  127. GetStartEndPos(yAxis, grid, data.runtimeValue, ref sp, ref ep);
  128. break;
  129. case MarkLineType.Max:
  130. data.runtimeValue = SerieHelper.GetMaxData(serie, data.dimension, dataZoom);
  131. GetStartEndPos(yAxis, grid, data.runtimeValue, ref sp, ref ep);
  132. break;
  133. case MarkLineType.Average:
  134. data.runtimeValue = SerieHelper.GetAverageData(serie, data.dimension, dataZoom);
  135. GetStartEndPos(yAxis, grid, data.runtimeValue, ref sp, ref ep);
  136. break;
  137. case MarkLineType.Median:
  138. data.runtimeValue = SerieHelper.GetMedianData(serie, data.dimension, dataZoom);
  139. GetStartEndPos(yAxis, grid, data.runtimeValue, ref sp, ref ep);
  140. break;
  141. case MarkLineType.None:
  142. if (data.xPosition != 0)
  143. {
  144. data.runtimeValue = data.xPosition;
  145. var pX = grid.context.x + data.xPosition;
  146. sp = new Vector3(pX, grid.context.y);
  147. ep = new Vector3(pX, grid.context.y + grid.context.height);
  148. }
  149. else if (data.yPosition != 0)
  150. {
  151. data.runtimeValue = data.yPosition;
  152. var pY = grid.context.y + data.yPosition;
  153. sp = new Vector3(grid.context.x, pY);
  154. ep = new Vector3(grid.context.x + grid.context.width, pY);
  155. }
  156. else if (data.yValue != 0 || (data.xValue == 0 && data.yValue == 0 && yAxis.IsValue()))
  157. {
  158. data.runtimeValue = data.yValue;
  159. if (yAxis.IsCategory())
  160. {
  161. var pY = AxisHelper.GetAxisPosition(grid, yAxis, data.yValue, showData.Count, dataZoom);
  162. sp = new Vector3(grid.context.x, pY);
  163. ep = new Vector3(grid.context.x + grid.context.width, pY);
  164. }
  165. else
  166. {
  167. GetStartEndPos(yAxis, grid, data.yValue, ref sp, ref ep);
  168. }
  169. }
  170. else
  171. {
  172. data.runtimeValue = data.xValue;
  173. if (xAxis.IsCategory())
  174. {
  175. var pX = AxisHelper.GetAxisPosition(grid, xAxis, data.xValue, showData.Count, dataZoom);
  176. sp = new Vector3(pX, grid.context.y);
  177. ep = new Vector3(pX, grid.context.y + grid.context.height);
  178. }
  179. else
  180. {
  181. GetStartEndPos(xAxis, grid, data.xValue, ref sp, ref ep);
  182. }
  183. }
  184. break;
  185. default:
  186. break;
  187. }
  188. data.runtimeStartPosition = sp;
  189. data.runtimeEndPosition = ep;
  190. DrawMakLineData(vh, data, animation, serie, grid, serieColor, sp, ep);
  191. }
  192. if (!animation.IsFinish())
  193. {
  194. animation.CheckProgress(1f);
  195. chart.RefreshTopPainter();
  196. }
  197. }
  198. private void ResetTempMarkLineGroupData(MarkLine markLine)
  199. {
  200. m_TempGroupData.Clear();
  201. for (int i = 0; i < markLine.data.Count; i++)
  202. {
  203. var data = markLine.data[i];
  204. data.index = i;
  205. if (data.group == 0) continue;
  206. if (!m_TempGroupData.ContainsKey(data.group))
  207. {
  208. m_TempGroupData[data.group] = new List<MarkLineData>();
  209. }
  210. m_TempGroupData[data.group].Add(data);
  211. }
  212. }
  213. private void DrawMakLineData(VertexHelper vh, MarkLineData data, AnimationStyle animation, Serie serie,
  214. GridCoord grid, Color32 serieColor, Vector3 sp, Vector3 ep)
  215. {
  216. if (!animation.IsFinish())
  217. ep = Vector3.Lerp(sp, ep, animation.GetCurrDetail());
  218. if ((!chart.IsInChart(sp) && !chart.IsInChart(ep)) ||
  219. (serie.clip && !grid.Contains(sp) && !grid.Contains(ep)))
  220. {
  221. data.runtimeInGrid = false;
  222. m_RefreshLabel = true;
  223. return;
  224. }
  225. data.runtimeCurrentEndPosition = ep;
  226. if (sp != Vector3.zero || ep != Vector3.zero)
  227. {
  228. data.runtimeInGrid = true;
  229. m_RefreshLabel = true;
  230. chart.ClampInChart(ref sp);
  231. chart.ClampInChart(ref ep);
  232. var theme = chart.theme.axis;
  233. var lineColor = ChartHelper.IsClearColor(data.lineStyle.color) ? serieColor : data.lineStyle.color;
  234. var lineWidth = data.lineStyle.width == 0 ? theme.lineWidth : data.lineStyle.width;
  235. ChartDrawer.DrawLineStyle(vh, data.lineStyle, sp, ep, lineWidth, LineStyle.Type.Dashed, lineColor, lineColor);
  236. if (data.startSymbol != null && data.startSymbol.show)
  237. {
  238. DrawMarkLineSymbol(vh, data.startSymbol, serie, grid, chart.theme, sp, sp, lineColor);
  239. }
  240. if (data.endSymbol != null && data.endSymbol.show)
  241. {
  242. DrawMarkLineSymbol(vh, data.endSymbol, serie, grid, chart.theme, ep, sp, lineColor);
  243. }
  244. }
  245. }
  246. private void DrawMarkLineSymbol(VertexHelper vh, SymbolStyle symbol, Serie serie, GridCoord grid, ThemeStyle theme,
  247. Vector3 pos, Vector3 startPos, Color32 lineColor)
  248. {
  249. float tickness = 0f;
  250. float[] cornerRadius = null;
  251. Color32 borderColor;
  252. SerieHelper.GetSymbolInfo(out borderColor, out tickness, out cornerRadius, serie, null, chart.theme);
  253. chart.DrawClipSymbol(vh, symbol.type, symbol.size, tickness, pos, lineColor, lineColor,
  254. ColorUtil.clearColor32, borderColor, symbol.gap, serie.clip, cornerRadius, grid, startPos);
  255. }
  256. private void GetStartEndPos(Axis xAxis, GridCoord grid, double value, ref Vector3 sp, ref Vector3 ep)
  257. {
  258. if (xAxis is YAxis)
  259. {
  260. var pY = AxisHelper.GetAxisPosition(grid, xAxis, value);
  261. sp = new Vector3(grid.context.x, pY);
  262. ep = new Vector3(grid.context.x + grid.context.width, pY);
  263. }
  264. else
  265. {
  266. var pX = AxisHelper.GetAxisPosition(grid, xAxis, value);
  267. sp = new Vector3(pX, grid.context.y);
  268. ep = new Vector3(pX, grid.context.y + grid.context.height);
  269. }
  270. }
  271. private float GetAxisPosition(GridCoord grid, Axis axis, DataZoom dataZoom, int dataCount, double value)
  272. {
  273. return AxisHelper.GetAxisPosition(grid, axis, value, dataCount, dataZoom);
  274. }
  275. private Vector3 GetSinglePos(Axis xAxis, Axis yAxis, GridCoord grid, Serie serie, DataZoom dataZoom, MarkLineData data,
  276. int serieDataCount)
  277. {
  278. switch (data.type)
  279. {
  280. case MarkLineType.Min:
  281. var serieData = SerieHelper.GetMinSerieData(serie, data.dimension, dataZoom);
  282. data.runtimeValue = serieData.GetData(data.dimension);
  283. var pX = GetAxisPosition(grid, xAxis, dataZoom, serieDataCount, serieData.index);
  284. var pY = GetAxisPosition(grid, yAxis, dataZoom, serieDataCount, data.runtimeValue);
  285. return new Vector3(pX, pY);
  286. case MarkLineType.Max:
  287. serieData = SerieHelper.GetMaxSerieData(serie, data.dimension, dataZoom);
  288. data.runtimeValue = serieData.GetData(data.dimension);
  289. pX = GetAxisPosition(grid, xAxis, dataZoom, serieDataCount, serieData.index);
  290. pY = GetAxisPosition(grid, yAxis, dataZoom, serieDataCount, data.runtimeValue);
  291. return new Vector3(pX, pY);
  292. case MarkLineType.None:
  293. if (data.zeroPosition)
  294. {
  295. data.runtimeValue = 0;
  296. return grid.context.position;
  297. }
  298. else
  299. {
  300. pX = data.xPosition != 0 ? grid.context.x + data.xPosition :
  301. GetAxisPosition(grid, xAxis, dataZoom, serieDataCount, data.xValue);
  302. pY = data.yPosition != 0 ? grid.context.y + data.yPosition :
  303. GetAxisPosition(grid, yAxis, dataZoom, serieDataCount, data.yValue);
  304. data.runtimeValue = data.yValue;
  305. return new Vector3(pX, pY);
  306. }
  307. default:
  308. return grid.context.position;
  309. }
  310. }
  311. }
  312. }