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

HeatmapHandler.cs 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.UI;
  4. using XUGL;
  5. namespace XCharts.Runtime
  6. {
  7. [UnityEngine.Scripting.Preserve]
  8. internal sealed partial class HeatmapHandler : SerieHandler<Heatmap>
  9. {
  10. private GridCoord m_SerieGrid;
  11. private Dictionary<int, int> m_CountDict = new Dictionary<int, int>();
  12. public override int defaultDimension { get { return 2; } }
  13. public static int GetGridKey(int x, int y)
  14. {
  15. return x * 100000 + y;
  16. }
  17. public static void GetGridXYByKey(int key, out int x, out int y)
  18. {
  19. x = key / 100000;
  20. y = key % 100000;
  21. }
  22. public override void Update()
  23. {
  24. base.Update();
  25. }
  26. public override void DrawSerie(VertexHelper vh)
  27. {
  28. if (serie.heatmapType == HeatmapType.Count)
  29. DrawCountHeatmapSerie(vh, serie);
  30. else
  31. {
  32. if (serie.IsUseCoord<PolarCoord>())
  33. {
  34. DrawPolarHeatmap(vh, serie);
  35. }
  36. else if (serie.IsUseCoord<GridCoord>())
  37. {
  38. DrawDataHeatmapSerie(vh, serie);
  39. }
  40. }
  41. }
  42. public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category,
  43. string marker, string itemFormatter, string numericFormatter, string ignoreDataDefaultContent,
  44. ref List<SerieParams> paramList, ref string title)
  45. {
  46. dataIndex = serie.context.pointerItemDataIndex;
  47. if (serie.heatmapType == HeatmapType.Count)
  48. {
  49. int value;
  50. if (!m_CountDict.TryGetValue(dataIndex, out value)) return;
  51. var visualMap = chart.GetVisualMapOfSerie(serie);
  52. var dimension = VisualMapHelper.GetDimension(visualMap, defaultDimension);
  53. title = serie.serieName;
  54. var param = serie.context.param;
  55. param.serieName = serie.serieName;
  56. param.serieIndex = serie.index;
  57. param.dimension = dimension;
  58. param.dataCount = serie.dataCount;
  59. param.serieData = null;
  60. param.color = visualMap.GetColor(value);
  61. param.marker = SerieHelper.GetItemMarker(serie, null, marker);
  62. param.itemFormatter = SerieHelper.GetItemFormatter(serie, null, itemFormatter);
  63. param.numericFormatter = SerieHelper.GetNumericFormatter(serie, null, numericFormatter);
  64. param.columns.Clear();
  65. param.columns.Add(param.marker);
  66. param.columns.Add("count");
  67. param.columns.Add(ChartCached.NumberToStr(value, param.numericFormatter));
  68. paramList.Add(param);
  69. }
  70. else
  71. {
  72. if (dataIndex < 0)
  73. return;
  74. var serieData = serie.GetSerieData(dataIndex);
  75. if (serieData == null)
  76. return;
  77. var visualMap = chart.GetVisualMapOfSerie(serie);
  78. var dimension = VisualMapHelper.GetDimension(visualMap, defaultDimension);
  79. if (string.IsNullOrEmpty(category))
  80. {
  81. var xAxis = chart.GetChartComponent<XAxis>(serie.xAxisIndex);
  82. if (xAxis != null)
  83. category = xAxis.GetData((int)serieData.GetData(0));
  84. }
  85. title = serie.serieName;
  86. var param = serie.context.param;
  87. param.serieName = serie.serieName;
  88. param.serieIndex = serie.index;
  89. param.dimension = dimension;
  90. param.dataCount = serie.dataCount;
  91. param.serieData = serieData;
  92. param.color = serieData.context.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(category);
  99. param.columns.Add(ChartCached.NumberToStr(serieData.GetData(dimension), param.numericFormatter));
  100. paramList.Add(param);
  101. }
  102. }
  103. public override void UpdateSerieContext()
  104. {
  105. if (serie.IsUseCoord<GridCoord>())
  106. UpdateSerieGridContext();
  107. else if (serie.IsUseCoord<PolarCoord>())
  108. UpdateSeriePolarContext();
  109. }
  110. private void UpdateSerieGridContext()
  111. {
  112. if (m_SerieGrid == null)
  113. return;
  114. var needCheck = (chart.isPointerInChart && m_SerieGrid.IsPointerEnter()) || m_LegendEnter;
  115. var needInteract = false;
  116. if (!needCheck)
  117. {
  118. if (m_LastCheckContextFlag != needCheck)
  119. {
  120. m_LastCheckContextFlag = needCheck;
  121. serie.context.pointerItemDataIndex = -1;
  122. serie.context.pointerEnter = false;
  123. foreach (var serieData in serie.data)
  124. {
  125. serieData.context.highlight = false;
  126. }
  127. chart.RefreshPainter(serie);
  128. }
  129. return;
  130. }
  131. if (serie.heatmapType == HeatmapType.Count)
  132. return;
  133. m_LastCheckContextFlag = needCheck;
  134. if (m_LegendEnter)
  135. {
  136. serie.context.pointerEnter = true;
  137. foreach (var serieData in serie.data)
  138. {
  139. serieData.context.highlight = true;
  140. }
  141. }
  142. else
  143. {
  144. serie.context.pointerItemDataIndex = -1;
  145. serie.context.pointerEnter = false;
  146. foreach (var serieData in serie.data)
  147. {
  148. if (!needInteract && serieData.context.rect.Contains(chart.pointerPos))
  149. {
  150. serie.context.pointerItemDataIndex = serieData.index;
  151. serie.context.pointerEnter = true;
  152. serieData.context.highlight = true;
  153. needInteract = true;
  154. }
  155. else
  156. {
  157. serieData.context.highlight = false;
  158. }
  159. }
  160. }
  161. if (needInteract)
  162. {
  163. chart.RefreshPainter(serie);
  164. }
  165. }
  166. private void DrawDataHeatmapSerie(VertexHelper vh, Heatmap serie)
  167. {
  168. if (!serie.show || serie.animation.HasFadeOut()) return;
  169. XAxis xAxis;
  170. YAxis yAxis;
  171. if (!chart.TryGetChartComponent<XAxis>(out xAxis, serie.xAxisIndex)) return;
  172. if (!chart.TryGetChartComponent<YAxis>(out yAxis, serie.yAxisIndex)) return;
  173. m_SerieGrid = chart.GetChartComponent<GridCoord>(xAxis.gridIndex);
  174. xAxis.boundaryGap = true;
  175. yAxis.boundaryGap = true;
  176. var visualMap = chart.GetVisualMapOfSerie(serie);
  177. var emphasisStyle = serie.emphasisStyle;
  178. var xCount = AxisHelper.GetTotalSplitGridNum(xAxis);
  179. var yCount = AxisHelper.GetTotalSplitGridNum(yAxis);
  180. var xWidth = m_SerieGrid.context.width / xCount;
  181. var yWidth = m_SerieGrid.context.height / yCount;
  182. var zeroX = m_SerieGrid.context.x;
  183. var zeroY = m_SerieGrid.context.y;
  184. var borderWidth = serie.itemStyle.show ? serie.itemStyle.borderWidth : 0;
  185. var splitWid = xWidth - 2 * borderWidth;
  186. var splitHig = yWidth - 2 * borderWidth;
  187. var defaultSymbolSize = Mathf.Min(splitWid, splitHig) * 0.25f;
  188. serie.animation.InitProgress(0, xCount);
  189. var animationIndex = serie.animation.GetCurrIndex();
  190. var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
  191. var unscaledTime = serie.animation.unscaledTime;
  192. var dataChanging = false;
  193. serie.containerIndex = m_SerieGrid.index;
  194. serie.containterInstanceId = m_SerieGrid.instanceId;
  195. var dimension = VisualMapHelper.GetDimension(visualMap, defaultDimension);
  196. if (visualMap.autoMinMax)
  197. {
  198. double maxValue, minValue;
  199. SerieHelper.GetMinMaxData(serie, dimension, out minValue, out maxValue);
  200. VisualMapHelper.SetMinMax(visualMap, minValue, maxValue);
  201. }
  202. var rangeMin = visualMap.rangeMin;
  203. var rangeMax = visualMap.rangeMax;
  204. var color = chart.theme.GetColor(serie.index);
  205. float symbolBorder = 0f;
  206. float[] cornerRadius = null;
  207. Color32 borderColor;
  208. for (int n = 0; n < serie.dataCount; n++)
  209. {
  210. var serieData = serie.data[n];
  211. var xValue = serieData.GetData(0);
  212. var yValue = serieData.GetData(1);
  213. var i = AxisHelper.GetAxisValueSplitIndex(xAxis, xValue, xCount);
  214. var j = AxisHelper.GetAxisValueSplitIndex(yAxis, yValue, yCount);
  215. if (serie.IsIgnoreValue(serieData, dimension))
  216. {
  217. serie.context.dataPoints.Add(Vector3.zero);
  218. serie.context.dataIndexs.Add(serieData.index);
  219. continue;
  220. }
  221. var state = SerieHelper.GetSerieState(serie, serieData, true);
  222. var symbol = SerieHelper.GetSerieSymbol(serie, serieData, state);
  223. var isRectSymbol = symbol.type == SymbolType.Rect;
  224. SerieHelper.GetSymbolInfo(out borderColor, out symbolBorder, out cornerRadius, serie, serieData, chart.theme, state);
  225. var value = serieData.GetCurrData(dimension, dataChangeDuration, yAxis.inverse,
  226. yAxis.context.minValue, yAxis.context.maxValue, unscaledTime);
  227. if (serieData.IsDataChanged()) dataChanging = true;
  228. var pos = new Vector3(zeroX + (i + 0.5f) * xWidth,
  229. zeroY + (j + 0.5f) * yWidth);
  230. serie.context.dataPoints.Add(pos);
  231. serie.context.dataIndexs.Add(serieData.index);
  232. serieData.context.position = pos;
  233. serieData.context.canShowLabel = false;
  234. if ((value < rangeMin && rangeMin != visualMap.min) ||
  235. (value > rangeMax && rangeMax != visualMap.max))
  236. {
  237. continue;
  238. }
  239. if (!visualMap.IsInSelectedValue(value)) continue;
  240. if (animationIndex >= 0 && i > animationIndex) continue;
  241. color = visualMap.GetColor(value);
  242. if (serieData.context.highlight)
  243. color = ChartHelper.GetHighlightColor(color);
  244. serieData.context.canShowLabel = true;
  245. serieData.context.color = color;
  246. var highlight = (serieData.context.highlight) ||
  247. visualMap.context.pointerIndex > 0;
  248. var rectWid = 0f;
  249. var rectHig = 0f;
  250. if (isRectSymbol)
  251. {
  252. if (symbol.size == 0 && symbol.sizeType == SymbolSizeType.Custom)
  253. {
  254. rectWid = splitWid;
  255. rectHig = splitHig;
  256. }
  257. else
  258. {
  259. var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, defaultSymbolSize, state);
  260. rectWid = symbolSize;
  261. rectHig = symbolSize;
  262. }
  263. serieData.context.rect = new Rect(pos.x - rectWid / 2, pos.y - rectHig / 2, rectWid, rectHig);
  264. UGL.DrawRectangle(vh, serieData.context.rect, color);
  265. if (borderWidth > 0 && !ChartHelper.IsClearColor(borderColor))
  266. {
  267. UGL.DrawBorder(vh, pos, rectWid, rectHig, borderWidth, borderColor, borderColor);
  268. }
  269. }
  270. else
  271. {
  272. var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, defaultSymbolSize, state);
  273. var emptyColor = SerieHelper.GetItemBackgroundColor(serie, serieData, chart.theme, serie.context.colorIndex, state);
  274. serieData.context.rect = new Rect(pos.x - symbolSize / 2, pos.y - symbolSize / 2, symbolSize, symbolSize);
  275. chart.DrawSymbol(vh, symbol.type, symbolSize, symbolBorder, pos,
  276. color, color, emptyColor, borderColor, symbol.gap, cornerRadius);
  277. }
  278. if (visualMap.hoverLink && highlight && emphasisStyle != null &&
  279. emphasisStyle.itemStyle.borderWidth > 0)
  280. {
  281. var emphasisItemStyle = emphasisStyle.itemStyle;
  282. var emphasisBorderWidth = emphasisItemStyle.borderWidth;
  283. var emphasisBorderColor = emphasisItemStyle.opacity > 0 ?
  284. emphasisItemStyle.borderColor : ChartConst.clearColor32;
  285. var emphasisBorderToColor = emphasisItemStyle.opacity > 0 ?
  286. emphasisItemStyle.borderToColor : ChartConst.clearColor32;
  287. UGL.DrawBorder(vh, pos, rectWid, rectHig, emphasisBorderWidth, emphasisBorderColor,
  288. emphasisBorderToColor);
  289. }
  290. }
  291. if (!serie.animation.IsFinish())
  292. {
  293. serie.animation.CheckProgress(xCount);
  294. chart.RefreshPainter(serie);
  295. }
  296. if (dataChanging)
  297. {
  298. chart.RefreshPainter(serie);
  299. }
  300. }
  301. private void DrawCountHeatmapSerie(VertexHelper vh, Heatmap serie)
  302. {
  303. if (!serie.show || serie.animation.HasFadeOut()) return;
  304. XAxis xAxis;
  305. YAxis yAxis;
  306. if (!chart.TryGetChartComponent<XAxis>(out xAxis, serie.xAxisIndex)) return;
  307. if (!chart.TryGetChartComponent<YAxis>(out yAxis, serie.yAxisIndex)) return;
  308. m_SerieGrid = chart.GetChartComponent<GridCoord>(xAxis.gridIndex);
  309. xAxis.boundaryGap = true;
  310. yAxis.boundaryGap = true;
  311. var visualMap = chart.GetVisualMapOfSerie(serie);
  312. var emphasisStyle = serie.emphasisStyle;
  313. var xCount = AxisHelper.GetTotalSplitGridNum(xAxis);
  314. var yCount = AxisHelper.GetTotalSplitGridNum(yAxis);
  315. var xWidth = m_SerieGrid.context.width / xCount;
  316. var yWidth = m_SerieGrid.context.height / yCount;
  317. var zeroX = m_SerieGrid.context.x;
  318. var zeroY = m_SerieGrid.context.y;
  319. var borderWidth = serie.itemStyle.show ? serie.itemStyle.borderWidth : 0;
  320. var splitWid = xWidth - 2 * borderWidth;
  321. var splitHig = yWidth - 2 * borderWidth;
  322. var defaultSymbolSize = Mathf.Min(splitWid, splitHig) * 0.25f;
  323. serie.animation.InitProgress(0, xCount);
  324. var animationIndex = serie.animation.GetCurrIndex();
  325. var dataChanging = false;
  326. serie.containerIndex = m_SerieGrid.index;
  327. serie.containterInstanceId = m_SerieGrid.instanceId;
  328. m_CountDict.Clear();
  329. double minCount = 0, maxCount = 0;
  330. foreach (var serieData in serie.data)
  331. {
  332. var xValue = serieData.GetData(0);
  333. var yValue = serieData.GetData(1);
  334. var i = AxisHelper.GetAxisValueSplitIndex(xAxis, xValue, xCount);
  335. var j = AxisHelper.GetAxisValueSplitIndex(yAxis, yValue, yCount);
  336. var key = GetGridKey(i, j);
  337. var count = 0;
  338. if (!m_CountDict.TryGetValue(key, out count))
  339. count = 1;
  340. else
  341. count++;
  342. if (count > maxCount)
  343. maxCount = count;
  344. m_CountDict[key] = count;
  345. }
  346. if (visualMap.autoMinMax)
  347. {
  348. VisualMapHelper.SetMinMax(visualMap, minCount, maxCount);
  349. }
  350. var rangeMin = visualMap.rangeMin;
  351. var rangeMax = visualMap.rangeMax;
  352. int highlightX = -1;
  353. int highlightY = -1;
  354. if (serie.context.pointerItemDataIndex > 0)
  355. {
  356. if (m_CountDict.ContainsKey(serie.context.pointerItemDataIndex))
  357. {
  358. GetGridXYByKey(serie.context.pointerItemDataIndex, out highlightX, out highlightY);
  359. }
  360. }
  361. var state = SerieHelper.GetSerieState(serie, null, true);
  362. var symbol = SerieHelper.GetSerieSymbol(serie, null, state);
  363. var symbolSize = SerieHelper.GetSysmbolSize(serie, null, chart.theme, defaultSymbolSize, state);
  364. var isRectSymbol = symbol.type == SymbolType.Rect;
  365. float symbolBorder = 0f;
  366. float[] cornerRadius = null;
  367. Color32 color, toColor, emptyColor, borderColor;
  368. SerieHelper.GetItemColor(out color, out toColor, out emptyColor, serie, null, chart.theme, serie.context.colorIndex, state);
  369. SerieHelper.GetSymbolInfo(out borderColor, out symbolBorder, out cornerRadius, serie, null, chart.theme, state);
  370. foreach (var kv in m_CountDict)
  371. {
  372. int i, j;
  373. GetGridXYByKey(kv.Key, out i, out j);
  374. var value = kv.Value;
  375. if (serie.IsIgnoreValue(value))
  376. {
  377. continue;
  378. }
  379. if ((value < rangeMin && rangeMin != visualMap.min) ||
  380. (value > rangeMax && rangeMax != visualMap.max))
  381. {
  382. continue;
  383. }
  384. if (!visualMap.IsInSelectedValue(value))
  385. continue;
  386. if (animationIndex >= 0 && i > animationIndex)
  387. continue;
  388. var highlight = i == highlightX && j == highlightY;
  389. color = visualMap.GetColor(value);
  390. if (highlight)
  391. color = ChartHelper.GetHighlightColor(color);
  392. var pos = new Vector3(zeroX + (i + 0.5f) * xWidth,
  393. zeroY + (j + 0.5f) * yWidth);
  394. var rectWid = 0f;
  395. var rectHig = 0f;
  396. if (isRectSymbol)
  397. {
  398. if (symbol.size == 0 && symbol.sizeType == SymbolSizeType.Custom)
  399. {
  400. rectWid = splitWid;
  401. rectHig = splitHig;
  402. }
  403. else
  404. {
  405. rectWid = symbolSize;
  406. rectHig = symbolSize;
  407. }
  408. var rect = new Rect(pos.x - rectWid / 2, pos.y - rectHig / 2, rectWid, rectHig);
  409. UGL.DrawRectangle(vh, rect, color);
  410. if (borderWidth > 0 && !ChartHelper.IsClearColor(borderColor))
  411. {
  412. UGL.DrawBorder(vh, pos, rectWid, rectHig, borderWidth, borderColor, borderColor);
  413. }
  414. }
  415. else
  416. {
  417. chart.DrawSymbol(vh, symbol.type, symbolSize, symbolBorder, pos,
  418. color, color, emptyColor, borderColor, symbol.gap, cornerRadius);
  419. }
  420. if (visualMap.hoverLink && highlight && emphasisStyle != null &&
  421. emphasisStyle.itemStyle.borderWidth > 0)
  422. {
  423. var emphasisItemStyle = emphasisStyle.itemStyle;
  424. var emphasisBorderWidth = emphasisItemStyle.borderWidth;
  425. var emphasisBorderColor = emphasisItemStyle.opacity > 0 ?
  426. emphasisItemStyle.borderColor : ChartConst.clearColor32;
  427. var emphasisBorderToColor = emphasisItemStyle.opacity > 0 ?
  428. emphasisItemStyle.borderToColor : ChartConst.clearColor32;
  429. UGL.DrawBorder(vh, pos, rectWid, rectHig, emphasisBorderWidth, emphasisBorderColor,
  430. emphasisBorderToColor);
  431. }
  432. }
  433. if (!serie.animation.IsFinish())
  434. {
  435. serie.animation.CheckProgress(xCount);
  436. chart.RefreshPainter(serie);
  437. }
  438. if (dataChanging)
  439. {
  440. chart.RefreshPainter(serie);
  441. }
  442. }
  443. }
  444. }