LegendHandler.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. using System.Collections.Generic;
  2. using System.Linq;
  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 LegendHandler : MainComponentHandler<Legend>
  11. {
  12. private static readonly string s_LegendObjectName = "legend";
  13. private static readonly char[] s_NameSplit = new char[] { '_' };
  14. public override void InitComponent()
  15. {
  16. InitLegend(component);
  17. }
  18. public override void CheckComponent(System.Text.StringBuilder sb)
  19. {
  20. var legend = component;
  21. if (ChartHelper.IsColorAlphaZero(legend.labelStyle.textStyle.color))
  22. sb.AppendFormat("warning:legend{0}->textStyle->color alpha is 0\n", legend.index);
  23. var serieNameList = SeriesHelper.GetLegalSerieNameList(chart.series);
  24. if (serieNameList.Count == 0)
  25. sb.AppendFormat("warning:legend{0} need serie.serieName or serieData.name not empty\n", legend.index);
  26. foreach (var category in legend.data)
  27. {
  28. if (!serieNameList.Contains(category))
  29. {
  30. sb.AppendFormat("warning:legend{0} [{1}] is invalid, must be one of serie.serieName or serieData.name\n",
  31. legend.index, category);
  32. }
  33. }
  34. }
  35. public override void DrawTop(VertexHelper vh)
  36. {
  37. DrawLegend(vh);
  38. }
  39. public override void OnSerieDataUpdate(int serieIndex)
  40. {
  41. #pragma warning disable 0618
  42. if (FormatterHelper.NeedFormat(component.formatter) || FormatterHelper.NeedFormat(component.labelStyle.formatter))
  43. component.refreshComponent();
  44. #pragma warning restore 0618
  45. }
  46. private void InitLegend(Legend legend)
  47. {
  48. legend.painter = null;
  49. legend.refreshComponent = delegate ()
  50. {
  51. legend.OnChanged();
  52. var legendObject = ChartHelper.AddObject(s_LegendObjectName + legend.index, chart.transform, chart.chartMinAnchor,
  53. chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta);
  54. legend.gameObject = legendObject;
  55. legendObject.hideFlags = chart.chartHideFlags;
  56. //ChartHelper.DestoryGameObjectByMatch(legendObject.transform, "_");
  57. SeriesHelper.UpdateSerieNameList(chart, ref chart.m_LegendRealShowName);
  58. legend.context.background = ChartHelper.AddIcon("background", legendObject.transform, 0, 0);
  59. legend.context.background.transform.SetSiblingIndex(0);
  60. ChartHelper.SetBackground(legend.context.background, legend.background);
  61. List<string> datas;
  62. if (legend.show && legend.data.Count > 0)
  63. {
  64. datas = new List<string>();
  65. foreach (var data in legend.data)
  66. {
  67. if (chart.m_LegendRealShowName.Contains(data) || chart.IsSerieName(data))
  68. datas.Add(data);
  69. }
  70. }
  71. else
  72. {
  73. datas = chart.m_LegendRealShowName;
  74. }
  75. int totalLegend = 0;
  76. for (int i = 0; i < datas.Count; i++)
  77. {
  78. if (!SeriesHelper.IsLegalLegendName(datas[i])) continue;
  79. totalLegend++;
  80. }
  81. legend.RemoveButton();
  82. ChartHelper.HideAllObject(legendObject);
  83. if (!legend.show) return;
  84. var textLimitInitFlag = false;
  85. for (int i = 0; i < datas.Count; i++)
  86. {
  87. if (!SeriesHelper.IsLegalLegendName(datas[i])) continue;
  88. string legendName = datas[i];
  89. var legendContent = GetFormatterContent(legend, i, datas[i]);
  90. if (legend.textLimit.enable)
  91. legendContent = legend.textLimit.GetLimitContent(legendContent);
  92. var readIndex = chart.m_LegendRealShowName.IndexOf(datas[i]);
  93. var active = chart.IsActiveByLegend(datas[i]);
  94. var bgColor = LegendHelper.GetIconColor(chart, legend, readIndex, datas[i], active);
  95. bgColor.a = legend.itemOpacity;
  96. var item = LegendHelper.AddLegendItem(chart, legend, i, legendName, legendObject.transform, chart.theme,
  97. legendContent, bgColor, active, readIndex);
  98. legend.SetButton(legendName, item, totalLegend);
  99. if (!textLimitInitFlag && legend.textLimit.enable)
  100. {
  101. textLimitInitFlag = true;
  102. legend.textLimit.SetRelatedText(item.text, legend.itemWidth);
  103. }
  104. ChartHelper.ClearEventListener(item.button.gameObject);
  105. ChartHelper.AddEventListener(item.button.gameObject, EventTriggerType.PointerDown, (data) =>
  106. {
  107. if (data.selectedObject == null || legend.selectedMode == Legend.SelectedMode.None) return;
  108. var temp = data.selectedObject.name.Split(s_NameSplit, 2);
  109. string selectedName = temp[1];
  110. int clickedIndex = int.Parse(temp[0]);
  111. if (legend.selectedMode == Legend.SelectedMode.Multiple)
  112. {
  113. OnLegendButtonClick(legend, clickedIndex, selectedName, !chart.IsActiveByLegend(selectedName));
  114. }
  115. else
  116. {
  117. var btnList = legend.context.buttonList.Values.ToArray();
  118. if (btnList.Length == 1)
  119. {
  120. OnLegendButtonClick(legend, 0, selectedName, !chart.IsActiveByLegend(selectedName));
  121. }
  122. else
  123. {
  124. for (int n = 0; n < btnList.Length; n++)
  125. {
  126. temp = btnList[n].name.Split(s_NameSplit, 2);
  127. selectedName = btnList[n].legendName;
  128. var index = btnList[n].index;
  129. OnLegendButtonClick(legend, n, selectedName, index == clickedIndex ? true : false);
  130. }
  131. }
  132. }
  133. });
  134. ChartHelper.AddEventListener(item.button.gameObject, EventTriggerType.PointerEnter, (data) =>
  135. {
  136. if (item.button == null) return;
  137. var temp = item.button.name.Split(s_NameSplit, 2);
  138. string selectedName = temp[1];
  139. int index = int.Parse(temp[0]);
  140. OnLegendButtonEnter(legend, index, selectedName);
  141. });
  142. ChartHelper.AddEventListener(item.button.gameObject, EventTriggerType.PointerExit, (data) =>
  143. {
  144. if (item.button == null) return;
  145. var temp = item.button.name.Split(s_NameSplit, 2);
  146. string selectedName = temp[1];
  147. int index = int.Parse(temp[0]);
  148. OnLegendButtonExit(legend, index, selectedName);
  149. });
  150. }
  151. LegendHelper.ResetItemPosition(legend, chart.chartPosition, chart.chartWidth, chart.chartHeight);
  152. };
  153. legend.refreshComponent();
  154. }
  155. private string GetFormatterContent(Legend legend, int dataIndex, string category)
  156. {
  157. #pragma warning disable 0618
  158. if (string.IsNullOrEmpty(legend.formatter) && string.IsNullOrEmpty(legend.labelStyle.formatter))
  159. return category;
  160. else
  161. {
  162. var formatter = string.IsNullOrEmpty(legend.labelStyle.formatter) ? legend.formatter : legend.labelStyle.formatter;
  163. var content = formatter.Replace("{name}", category);
  164. content = content.Replace("{value}", category);
  165. var serie = chart.GetSerie(0);
  166. FormatterHelper.ReplaceContent(ref content, dataIndex, legend.labelStyle.numericFormatter, serie, chart, category);
  167. return content;
  168. }
  169. #pragma warning restore 0618
  170. }
  171. private void OnLegendButtonClick(Legend legend, int index, string legendName, bool show)
  172. {
  173. chart.OnLegendButtonClick(index, legendName, show);
  174. if (chart.onLegendClick != null)
  175. chart.onLegendClick(legend, index, legendName, show);
  176. }
  177. private void OnLegendButtonEnter(Legend legend, int index, string legendName)
  178. {
  179. chart.OnLegendButtonEnter(index, legendName);
  180. if (chart.onLegendEnter != null)
  181. chart.onLegendEnter(legend, index, legendName);
  182. }
  183. private void OnLegendButtonExit(Legend legend, int index, string legendName)
  184. {
  185. chart.OnLegendButtonExit(index, legendName);
  186. if (chart.onLegendExit != null)
  187. chart.onLegendExit(legend, index, legendName);
  188. }
  189. private void DrawLegend(VertexHelper vh)
  190. {
  191. if (chart.series.Count == 0) return;
  192. var legend = component;
  193. if (!legend.show) return;
  194. if (legend.iconType == Legend.Type.Custom) return;
  195. foreach (var kv in legend.context.buttonList)
  196. {
  197. var item = kv.Value;
  198. var rect = item.GetIconRect();
  199. var radius = Mathf.Min(rect.width, rect.height) / 2;
  200. var color = item.GetIconColor();
  201. var iconType = legend.iconType;
  202. if (legend.iconType == Legend.Type.Auto)
  203. {
  204. var serie = chart.GetSerie(item.legendName);
  205. if (serie != null)
  206. {
  207. if (serie is Line || serie is SimplifiedLine)
  208. {
  209. var sp = new Vector3(rect.center.x - rect.width / 2, rect.center.y);
  210. var ep = new Vector3(rect.center.x + rect.width / 2, rect.center.y);
  211. UGL.DrawLine(vh, sp, ep, chart.settings.legendIconLineWidth, color);
  212. if (!serie.symbol.show) continue;
  213. switch (serie.symbol.type)
  214. {
  215. case SymbolType.None:
  216. continue;
  217. case SymbolType.Circle:
  218. iconType = Legend.Type.Circle;
  219. break;
  220. case SymbolType.Diamond:
  221. iconType = Legend.Type.Diamond;
  222. break;
  223. case SymbolType.EmptyCircle:
  224. iconType = Legend.Type.EmptyCircle;
  225. break;
  226. case SymbolType.Rect:
  227. iconType = Legend.Type.Rect;
  228. break;
  229. case SymbolType.Triangle:
  230. iconType = Legend.Type.Triangle;
  231. break;
  232. }
  233. }
  234. else
  235. {
  236. iconType = Legend.Type.Rect;
  237. }
  238. }
  239. else
  240. {
  241. iconType = Legend.Type.Rect;
  242. }
  243. }
  244. switch (iconType)
  245. {
  246. case Legend.Type.Rect:
  247. var cornerRadius = chart.settings.legendIconCornerRadius;
  248. UGL.DrawRoundRectangle(vh, rect.center, rect.width, rect.height, color, color,
  249. 0, cornerRadius, false, 0.5f);
  250. break;
  251. case Legend.Type.Circle:
  252. UGL.DrawCricle(vh, rect.center, radius, color);
  253. break;
  254. case Legend.Type.Diamond:
  255. UGL.DrawDiamond(vh, rect.center, radius, color);
  256. break;
  257. case Legend.Type.EmptyCircle:
  258. var backgroundColor = chart.GetChartBackgroundColor();
  259. UGL.DrawEmptyCricle(vh, rect.center, radius, 2 * chart.settings.legendIconLineWidth,
  260. color, color, backgroundColor, 1f);
  261. break;
  262. case Legend.Type.Triangle:
  263. UGL.DrawTriangle(vh, rect.center, 1.2f * radius, color);
  264. break;
  265. case Legend.Type.Candlestick:
  266. UGL.DrawRoundRectangle(vh, rect.center, rect.width / 2, rect.height / 2, color, color,
  267. 0, null, false, 0.5f);
  268. UGL.DrawLine(vh, new Vector3(rect.center.x, rect.center.y - rect.height / 2),
  269. new Vector3(rect.center.x, rect.center.y + rect.height / 2), 1, color);
  270. break;
  271. }
  272. }
  273. }
  274. }
  275. }