LineHandler.GridCoord.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. using System.Collections.Generic;
  2. using System.Text;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. using XUGL;
  6. namespace XCharts.Runtime
  7. {
  8. /// <summary>
  9. /// For grid coord
  10. /// </summary>
  11. internal sealed partial class LineHandler : SerieHandler<Line>
  12. {
  13. List<List<SerieData>> m_StackSerieData = new List<List<SerieData>>();
  14. private GridCoord m_SerieGrid;
  15. public override Vector3 GetSerieDataLabelOffset(SerieData serieData, LabelStyle label)
  16. {
  17. var invert = label.autoOffset &&
  18. SerieHelper.IsDownPoint(serie, serieData.index) &&
  19. (serie.areaStyle == null || !serie.areaStyle.show);
  20. if (invert)
  21. {
  22. var offset = label.GetOffset(serie.context.insideRadius);
  23. return new Vector3(offset.x, -offset.y, offset.z);
  24. }
  25. else
  26. {
  27. return label.GetOffset(serie.context.insideRadius);
  28. }
  29. }
  30. private void UpdateSerieGridContext()
  31. {
  32. if (m_SerieGrid == null)
  33. return;
  34. var needCheck = (chart.isPointerInChart && m_SerieGrid.IsPointerEnter()) || m_LegendEnter;
  35. if (!needCheck)
  36. {
  37. if (m_LastCheckContextFlag != needCheck)
  38. {
  39. m_LastCheckContextFlag = needCheck;
  40. serie.context.pointerItemDataIndex = -1;
  41. serie.context.pointerEnter = false;
  42. serie.highlight = false;
  43. serie.ResetInteract();
  44. foreach (var serieData in serie.data)
  45. serieData.context.highlight = false;
  46. if (SeriesHelper.IsStack(chart.series))
  47. chart.RefreshTopPainter();
  48. else
  49. chart.RefreshPainter(serie);
  50. }
  51. return;
  52. }
  53. m_LastCheckContextFlag = needCheck;
  54. var lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth);
  55. var themeSymbolSize = chart.theme.serie.lineSymbolSize;
  56. var needInteract = false;
  57. serie.ResetDataIndex();
  58. if (m_LegendEnter)
  59. {
  60. serie.context.pointerEnter = true;
  61. serie.interact.SetValue(ref needInteract, serie.animation.interaction.GetWidth(lineWidth));
  62. for (int i = 0; i < serie.dataCount; i++)
  63. {
  64. var serieData = serie.data[i];
  65. var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, SerieState.Emphasis);
  66. serieData.context.highlight = true;
  67. serieData.interact.SetValue(ref needInteract, size);
  68. }
  69. }
  70. else if (serie.context.isTriggerByAxis)
  71. {
  72. serie.context.pointerEnter = false;
  73. serie.interact.SetValue(ref needInteract, serie.animation.interaction.GetWidth(lineWidth));
  74. for (int i = 0; i < serie.dataCount; i++)
  75. {
  76. var serieData = serie.data[i];
  77. var highlight = i == serie.context.pointerItemDataIndex;
  78. serieData.context.highlight = highlight;
  79. var state = SerieHelper.GetSerieState(serie, serieData, true);
  80. var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, state);
  81. serieData.interact.SetValue(ref needInteract, size);
  82. if (highlight)
  83. {
  84. serie.context.pointerEnter = true;
  85. serie.context.pointerItemDataIndex = i;
  86. needInteract = true;
  87. }
  88. }
  89. }
  90. else
  91. {
  92. var lastIndex = serie.context.pointerItemDataIndex;
  93. serie.context.pointerItemDataIndex = -1;
  94. serie.context.pointerEnter = false;
  95. for (int i = 0; i < serie.dataCount; i++)
  96. {
  97. var serieData = serie.data[i];
  98. var dist = Vector3.Distance(chart.pointerPos, serieData.context.position);
  99. var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize);
  100. var highlight = dist <= size;
  101. serieData.context.highlight = highlight;
  102. var state = SerieHelper.GetSerieState(serie, serieData, true);
  103. size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, state);
  104. serieData.interact.SetValue(ref needInteract, size);
  105. if (highlight)
  106. {
  107. serie.context.pointerEnter = true;
  108. serie.context.pointerItemDataIndex = serieData.index;
  109. }
  110. }
  111. if (lastIndex != serie.context.pointerItemDataIndex)
  112. {
  113. needInteract = true;
  114. }
  115. if (serie.context.pointerItemDataIndex >= 0)
  116. serie.interact.SetValue(ref needInteract, serie.animation.interaction.GetWidth(lineWidth));
  117. else
  118. serie.interact.SetValue(ref needInteract, lineWidth);
  119. }
  120. if (needInteract)
  121. {
  122. if (SeriesHelper.IsStack(chart.series))
  123. chart.RefreshTopPainter();
  124. else
  125. chart.RefreshPainter(serie);
  126. }
  127. }
  128. private void DrawLinePoint(VertexHelper vh, Serie serie)
  129. {
  130. if (!serie.show || serie.IsPerformanceMode())
  131. return;
  132. if (m_SerieGrid == null)
  133. return;
  134. var count = serie.context.dataPoints.Count;
  135. var clip = SeriesHelper.IsAnyClipSerie(chart.series);
  136. var theme = chart.theme;
  137. var interacting = false;
  138. var lineArrow = serie.lineArrow;
  139. var visualMap = chart.GetVisualMapOfSerie(serie);
  140. var isVisualMapGradient = VisualMapHelper.IsNeedLineGradient(visualMap);
  141. var interactDuration = serie.animation.GetInteractionDuration();
  142. Axis axis;
  143. Axis relativedAxis;
  144. chart.GetSerieGridCoordAxis(serie, out axis, out relativedAxis);
  145. for (int i = 0; i < count; i++)
  146. {
  147. var index = serie.context.dataIndexs[i];
  148. var serieData = serie.GetSerieData(index);
  149. if (serieData == null)
  150. continue;
  151. if (serieData.context.isClip)
  152. continue;
  153. var state = SerieHelper.GetSerieState(serie, serieData, true);
  154. var symbol = SerieHelper.GetSerieSymbol(serie, serieData, state);
  155. if (!symbol.show || !symbol.ShowSymbol(index, count))
  156. continue;
  157. var pos = serie.context.dataPoints[i];
  158. if (lineArrow != null && lineArrow.show)
  159. {
  160. if (lineArrow.position == LineArrow.Position.Start && i == 0)
  161. continue;
  162. if (lineArrow.position == LineArrow.Position.End && i == count - 1)
  163. continue;
  164. }
  165. if (ChartHelper.IsIngore(pos))
  166. continue;
  167. var symbolSize = 0f;
  168. if (!serieData.interact.TryGetValue(ref symbolSize, ref interacting, interactDuration))
  169. {
  170. symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme.serie.lineSymbolSize, state);
  171. serieData.interact.SetValue(ref interacting, symbolSize);
  172. symbolSize = serie.animation.GetSysmbolSize(symbolSize);
  173. }
  174. float symbolBorder = 0f;
  175. float[] cornerRadius = null;
  176. Color32 symbolColor, symbolToColor, symbolEmptyColor, borderColor;
  177. SerieHelper.GetItemColor(out symbolColor, out symbolToColor, out symbolEmptyColor, serie, serieData, theme, serie.context.colorIndex);
  178. SerieHelper.GetSymbolInfo(out borderColor, out symbolBorder, out cornerRadius, serie, null, chart.theme, state);
  179. if (isVisualMapGradient)
  180. {
  181. symbolColor = VisualMapHelper.GetLineGradientColor(visualMap, pos, m_SerieGrid, axis, relativedAxis, symbolColor);
  182. symbolToColor = symbolColor;
  183. }
  184. chart.DrawClipSymbol(vh, symbol.type, symbolSize, symbolBorder, pos,
  185. symbolColor, symbolToColor, symbolEmptyColor, borderColor, symbol.gap, clip, cornerRadius, m_SerieGrid,
  186. i > 0 ? serie.context.dataPoints[i - 1] : m_SerieGrid.context.position);
  187. }
  188. if (interacting)
  189. {
  190. if (SeriesHelper.IsStack(chart.series))
  191. chart.RefreshTopPainter();
  192. else
  193. chart.RefreshPainter(serie);
  194. }
  195. }
  196. private void DrawLineArrow(VertexHelper vh, Serie serie)
  197. {
  198. if (!serie.show || serie.lineArrow == null || !serie.lineArrow.show)
  199. return;
  200. if (serie.context.dataPoints.Count < 2)
  201. return;
  202. var lineColor = SerieHelper.GetLineColor(serie, null, chart.theme, serie.context.colorIndex);
  203. var startPos = Vector3.zero;
  204. var arrowPos = Vector3.zero;
  205. var lineArrow = serie.lineArrow.arrow;
  206. var dataPoints = serie.context.drawPoints;
  207. switch (serie.lineArrow.position)
  208. {
  209. case LineArrow.Position.End:
  210. if (dataPoints.Count < 3)
  211. {
  212. startPos = dataPoints[dataPoints.Count - 2].position;
  213. arrowPos = dataPoints[dataPoints.Count - 1].position;
  214. }
  215. else
  216. {
  217. startPos = dataPoints[dataPoints.Count - 3].position;
  218. arrowPos = dataPoints[dataPoints.Count - 2].position;
  219. }
  220. UGL.DrawArrow(vh, startPos, arrowPos, lineArrow.width, lineArrow.height,
  221. lineArrow.offset, lineArrow.dent, lineArrow.GetColor(lineColor));
  222. break;
  223. case LineArrow.Position.Start:
  224. startPos = dataPoints[1].position;
  225. arrowPos = dataPoints[0].position;
  226. UGL.DrawArrow(vh, startPos, arrowPos, lineArrow.width, lineArrow.height,
  227. lineArrow.offset, lineArrow.dent, lineArrow.GetColor(lineColor));
  228. break;
  229. }
  230. }
  231. private void DrawLineSerie(VertexHelper vh, Line serie)
  232. {
  233. if (serie.animation.HasFadeOut())
  234. return;
  235. Axis axis;
  236. Axis relativedAxis;
  237. var isY = chart.GetSerieGridCoordAxis(serie, out axis, out relativedAxis);
  238. if (axis == null)
  239. return;
  240. if (relativedAxis == null)
  241. return;
  242. m_SerieGrid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
  243. if (m_SerieGrid == null)
  244. return;
  245. if (m_EndLabel != null && !m_SerieGrid.context.endLabelList.Contains(m_EndLabel))
  246. {
  247. m_SerieGrid.context.endLabelList.Add(m_EndLabel);
  248. }
  249. var visualMap = chart.GetVisualMapOfSerie(serie);
  250. var dataZoom = chart.GetDataZoomOfAxis(axis);
  251. var showData = serie.GetDataList(dataZoom);
  252. if (showData.Count <= 0)
  253. return;
  254. var axisLength = isY ? m_SerieGrid.context.height : m_SerieGrid.context.width;
  255. var axisRelativedLength = isY ? m_SerieGrid.context.width : m_SerieGrid.context.height;
  256. int maxCount = serie.maxShow > 0 ?
  257. (serie.maxShow > showData.Count ? showData.Count : serie.maxShow) :
  258. showData.Count;
  259. maxCount -= serie.context.dataZoomStartIndexOffset;
  260. var scaleWid = AxisHelper.GetDataWidth(axis, axisLength, maxCount, dataZoom);
  261. var scaleRelativedWid = AxisHelper.GetDataWidth(relativedAxis, axisRelativedLength, maxCount, dataZoom);
  262. int rate = LineHelper.GetDataAverageRate(serie, m_SerieGrid, maxCount, false);
  263. var totalAverage = serie.sampleAverage > 0 ?
  264. serie.sampleAverage :
  265. DataHelper.DataAverage(ref showData, serie.sampleType, serie.minShow, maxCount, rate);
  266. var dataChanging = false;
  267. var dataChangeDuration = serie.animation.GetChangeDuration();
  268. var unscaledTime = serie.animation.unscaledTime;
  269. var interacting = false;
  270. var lineWidth = LineHelper.GetLineWidth(ref interacting, serie, chart.theme.serie.lineWidth);
  271. axis.context.scaleWidth = scaleWid;
  272. serie.context.isHorizontal = isY;
  273. serie.containerIndex = m_SerieGrid.index;
  274. serie.containterInstanceId = m_SerieGrid.instanceId;
  275. Serie lastSerie = null;
  276. var isStack = SeriesHelper.IsStack<Line>(chart.series, serie.stack);
  277. if (isStack)
  278. {
  279. lastSerie = SeriesHelper.GetLastStackSerie(chart.series, serie);
  280. SeriesHelper.UpdateStackDataList(chart.series, serie, dataZoom, m_StackSerieData);
  281. }
  282. var lp = Vector3.zero;
  283. for (int i = serie.minShow; i < showData.Count; i += rate)
  284. {
  285. var serieData = showData[i];
  286. var realIndex = i - serie.context.dataZoomStartIndexOffset;
  287. var isIgnore = serie.IsIgnoreValue(serieData);
  288. if (isIgnore)
  289. {
  290. serieData.context.stackHeight = 0;
  291. serieData.context.position = Vector3.zero;
  292. if (serie.ignoreLineBreak && serie.context.dataIgnores.Count > 0)
  293. {
  294. serie.context.dataIgnores[serie.context.dataIgnores.Count - 1] = true;
  295. }
  296. }
  297. else
  298. {
  299. var np = Vector3.zero;
  300. var xValue = axis.IsCategory() ? realIndex : serieData.GetData(0, axis.inverse);
  301. var relativedValue = DataHelper.SampleValue(ref showData, serie.sampleType, rate, serie.minShow,
  302. maxCount, totalAverage, i, 0, dataChangeDuration, ref dataChanging, relativedAxis, unscaledTime);
  303. serieData.context.stackHeight = GetDataPoint(isY, axis, relativedAxis, m_SerieGrid, xValue, relativedValue,
  304. i, scaleWid, scaleRelativedWid, isStack, ref np);
  305. serieData.context.isClip = false;
  306. if (serie.clip && !m_SerieGrid.Contains(np))
  307. {
  308. //if (m_SerieGrid.BoundaryPoint(lp, np, ref np))
  309. {
  310. serieData.context.isClip = true;
  311. }
  312. }
  313. serie.context.dataIgnores.Add(false);
  314. serieData.context.position = np;
  315. serie.context.dataPoints.Add(np);
  316. serie.context.dataIndexs.Add(serieData.index);
  317. lp = np;
  318. }
  319. }
  320. if (dataChanging || interacting)
  321. chart.RefreshPainter(serie);
  322. if (serie.context.dataPoints.Count <= 0)
  323. return;
  324. serie.animation.InitProgress(serie.context.dataPoints, isY);
  325. VisualMapHelper.AutoSetLineMinMax(visualMap, serie, isY, axis, relativedAxis);
  326. LineHelper.UpdateSerieDrawPoints(serie, chart.settings, chart.theme, visualMap, lineWidth, isY, m_SerieGrid);
  327. LineHelper.DrawSerieLineArea(vh, serie, lastSerie, chart.theme, visualMap, isY, axis, relativedAxis, m_SerieGrid);
  328. LineHelper.DrawSerieLine(vh, chart.theme, serie, visualMap, m_SerieGrid, axis, relativedAxis, lineWidth);
  329. serie.context.vertCount = vh.currentVertCount;
  330. if (!serie.animation.IsFinish())
  331. {
  332. serie.animation.CheckProgress();
  333. serie.animation.CheckSymbol(serie.symbol.GetSize(null, chart.theme.serie.lineSymbolSize));
  334. chart.RefreshPainter(serie);
  335. }
  336. }
  337. private float GetDataPoint(bool isY, Axis axis, Axis relativedAxis, GridCoord grid, double xValue,
  338. double yValue, int i, float scaleWid, float scaleRelativedWid, bool isStack, ref Vector3 np)
  339. {
  340. float xPos, yPos;
  341. var gridXY = isY ? grid.context.x : grid.context.y;
  342. var valueHig = 0f;
  343. valueHig = AxisHelper.GetAxisValueDistance(grid, relativedAxis, scaleRelativedWid, yValue);
  344. valueHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, valueHig);
  345. if (isY)
  346. {
  347. xPos = gridXY + valueHig;
  348. yPos = AxisHelper.GetAxisValuePosition(grid, axis, scaleWid, xValue);
  349. if (isStack)
  350. {
  351. for (int n = 0; n < m_StackSerieData.Count - 1; n++)
  352. xPos += m_StackSerieData[n][i].context.stackHeight;
  353. }
  354. }
  355. else
  356. {
  357. yPos = gridXY + valueHig;
  358. xPos = AxisHelper.GetAxisValuePosition(grid, axis, scaleWid, xValue);
  359. if (isStack)
  360. {
  361. for (int n = 0; n < m_StackSerieData.Count - 1; n++)
  362. yPos += m_StackSerieData[n][i].context.stackHeight;
  363. }
  364. }
  365. np = new Vector3(xPos, yPos);
  366. return AxisHelper.GetAxisValueLength(grid, relativedAxis, scaleRelativedWid, yValue);
  367. }
  368. }
  369. }