AxisHandler.cs 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  1. using System;
  2. using UnityEngine;
  3. using UnityEngine.UI;
  4. using XCharts.Runtime;
  5. using XUGL;
  6. namespace XCharts
  7. {
  8. public abstract class AxisHandler<T> : MainComponentHandler
  9. where T : Axis
  10. {
  11. private static readonly string s_DefaultAxisName = "name";
  12. private double m_LastInterval = double.MinValue;
  13. private int m_LastSplitNumber = int.MinValue;
  14. public T component { get; internal set; }
  15. internal override void SetComponent(MainComponent component)
  16. {
  17. this.component = (T)component;
  18. }
  19. protected virtual Vector3 GetLabelPosition(float scaleWid, int i)
  20. {
  21. return Vector3.zero;
  22. }
  23. internal virtual float GetAxisLineXOrY()
  24. {
  25. return 0;
  26. }
  27. protected virtual Orient orient { get; set; }
  28. protected virtual void UpdatePointerValue(Axis axis)
  29. {
  30. var grid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
  31. if (grid == null)
  32. return;
  33. if (!grid.context.isPointerEnter)
  34. {
  35. axis.context.pointerValue = double.PositiveInfinity;
  36. }
  37. else
  38. {
  39. var lastPointerValue = axis.context.pointerValue;
  40. if (axis.IsCategory())
  41. {
  42. var dataZoom = chart.GetDataZoomOfAxis(axis);
  43. var dataCount = chart.series.Count > 0 ? chart.series[0].GetDataList(dataZoom).Count : 0;
  44. var local = chart.pointerPos;
  45. if (axis is YAxis)
  46. {
  47. float splitWid = AxisHelper.GetDataWidth(axis, grid.context.height, dataCount, dataZoom);
  48. for (int j = 0; j < axis.GetDataCount(dataZoom); j++)
  49. {
  50. float pY = grid.context.y + j * splitWid;
  51. if ((axis.boundaryGap && (local.y > pY && local.y <= pY + splitWid)) ||
  52. (!axis.boundaryGap && (local.y > pY - splitWid / 2 && local.y <= pY + splitWid / 2)))
  53. {
  54. axis.context.pointerValue = j;
  55. axis.context.pointerLabelPosition = axis.GetLabelObjectPosition(j);
  56. if (j != lastPointerValue)
  57. {
  58. if (chart.onAxisPointerValueChanged != null)
  59. chart.onAxisPointerValueChanged(axis, j);
  60. }
  61. break;
  62. }
  63. }
  64. }
  65. else
  66. {
  67. float splitWid = AxisHelper.GetDataWidth(axis, grid.context.width, dataCount, dataZoom);
  68. for (int j = 0; j < axis.GetDataCount(dataZoom); j++)
  69. {
  70. float pX = grid.context.x + j * splitWid;
  71. if ((axis.boundaryGap && (local.x > pX && local.x <= pX + splitWid)) ||
  72. (!axis.boundaryGap && (local.x > pX - splitWid / 2 && local.x <= pX + splitWid / 2)))
  73. {
  74. axis.context.pointerValue = j;
  75. axis.context.pointerLabelPosition = axis.GetLabelObjectPosition(j);
  76. if (j != lastPointerValue)
  77. {
  78. if (chart.onAxisPointerValueChanged != null)
  79. chart.onAxisPointerValueChanged(axis, j);
  80. }
  81. break;
  82. }
  83. }
  84. }
  85. }
  86. else
  87. {
  88. if (axis is YAxis)
  89. {
  90. var yRate = axis.context.minMaxRange / grid.context.height;
  91. var yValue = yRate * (chart.pointerPos.y - grid.context.y - axis.context.offset);
  92. if (axis.context.minValue > 0)
  93. yValue += axis.context.minValue;
  94. var labelX = axis.GetLabelObjectPosition(0).x;
  95. axis.context.pointerValue = yValue;
  96. axis.context.pointerLabelPosition = new Vector3(labelX, chart.pointerPos.y);
  97. if (yValue != lastPointerValue)
  98. {
  99. if (chart.onAxisPointerValueChanged != null)
  100. chart.onAxisPointerValueChanged(axis, yValue);
  101. }
  102. }
  103. else
  104. {
  105. double xValue;
  106. if (axis.IsLog())
  107. {
  108. var logBase = axis.logBase;
  109. var minLog = Math.Log(axis.context.minValue, logBase);
  110. var maxLog = Math.Log(axis.context.maxValue, logBase);
  111. var logRange = maxLog - minLog;
  112. var pointerLog = minLog + logRange * (chart.pointerPos.x - grid.context.x - axis.context.offset) / grid.context.width;
  113. xValue = Math.Pow(logBase, pointerLog);
  114. }
  115. else
  116. {
  117. var xRate = axis.context.minMaxRange / grid.context.width;
  118. xValue = xRate * (chart.pointerPos.x - grid.context.x - axis.context.offset);
  119. if (axis.context.minValue > 0)
  120. xValue += axis.context.minValue;
  121. }
  122. var labelY = axis.GetLabelObjectPosition(0).y;
  123. axis.context.pointerValue = xValue;
  124. axis.context.pointerLabelPosition = new Vector3(chart.pointerPos.x, labelY);
  125. if (xValue != lastPointerValue)
  126. {
  127. if (chart.onAxisPointerValueChanged != null)
  128. chart.onAxisPointerValueChanged(axis, xValue);
  129. }
  130. }
  131. }
  132. }
  133. }
  134. internal void UpdateAxisMinMaxValue(int axisIndex, Axis axis, bool updateChart = true)
  135. {
  136. if (!axis.show)
  137. return;
  138. if (axis.IsCategory())
  139. {
  140. axis.context.minValue = 0;
  141. axis.context.maxValue = SeriesHelper.GetMaxSerieDataCount(chart.series) - 1;
  142. axis.context.minMaxRange = axis.context.maxValue;
  143. return;
  144. }
  145. double tempMinValue;
  146. double tempMaxValue;
  147. axis.context.needAnimation = Application.isPlaying && axis.animation.show;
  148. chart.GetSeriesMinMaxValue(axis, axisIndex, out tempMinValue, out tempMaxValue);
  149. var dataZoom = chart.GetDataZoomOfAxis(axis);
  150. if (dataZoom != null && dataZoom.enable)
  151. {
  152. if (axis is XAxis)
  153. dataZoom.SetXAxisIndexValueInfo(axisIndex, ref tempMinValue, ref tempMaxValue);
  154. else
  155. dataZoom.SetYAxisIndexValueInfo(axisIndex, ref tempMinValue, ref tempMaxValue);
  156. }
  157. if (tempMinValue != axis.context.destMinValue ||
  158. tempMaxValue != axis.context.destMaxValue ||
  159. m_LastInterval != axis.interval ||
  160. m_LastSplitNumber != axis.splitNumber)
  161. {
  162. m_LastSplitNumber = axis.splitNumber;
  163. m_LastInterval = axis.interval;
  164. axis.UpdateMinMaxValue(tempMinValue, tempMaxValue, axis.context.needAnimation);
  165. axis.context.offset = 0;
  166. axis.context.lastCheckInverse = axis.inverse;
  167. UpdateAxisTickValueList(axis);
  168. if (tempMinValue != 0 || tempMaxValue != 0)
  169. {
  170. var grid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
  171. if (grid != null && axis is XAxis && axis.IsValue())
  172. {
  173. axis.UpdateZeroOffset(grid.context.width);
  174. }
  175. if (grid != null && axis is YAxis && axis.IsValue())
  176. {
  177. axis.UpdateZeroOffset(grid.context.height);
  178. }
  179. }
  180. if (updateChart)
  181. {
  182. UpdateAxisLabelText(axis);
  183. chart.RefreshChart();
  184. }
  185. }
  186. if (axis.context.needAnimation && (axis.context.minValue != axis.context.destMinValue || axis.context.maxValue != axis.context.destMaxValue))
  187. {
  188. var duration = axis.animation.duration == 0
  189. ? SeriesHelper.GetMinAnimationDuration(chart.series) / 1000f
  190. : axis.animation.duration / 1000f;
  191. var deltaTime = axis.animation.unscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
  192. var minDiff = axis.context.destMinValue - axis.context.lastMinValue;
  193. var maxDiff = axis.context.destMaxValue - axis.context.lastMaxValue;
  194. var minDelta = minDiff / duration * deltaTime;
  195. var maxDelta = maxDiff / duration * deltaTime;
  196. axis.context.minValue += minDelta;
  197. axis.context.maxValue += maxDelta;
  198. if ((minDiff > 0 && axis.context.minValue > axis.context.destMinValue)
  199. || (minDiff < 0 && axis.context.minValue < axis.context.destMinValue))
  200. {
  201. axis.context.minValue = axis.context.destMinValue;
  202. axis.context.lastMinValue = axis.context.destMinValue;
  203. }
  204. if ((maxDiff > 0 && axis.context.maxValue > axis.context.destMaxValue)
  205. || (maxDiff < 0 && axis.context.maxValue < axis.context.destMaxValue))
  206. {
  207. axis.context.maxValue = axis.context.destMaxValue;
  208. axis.context.lastMaxValue = axis.context.destMaxValue;
  209. }
  210. axis.context.minMaxRange = axis.context.maxValue - axis.context.minValue;
  211. UpdateAxisTickValueList(axis);
  212. UpdateAxisLabelText(axis);
  213. chart.RefreshChart();
  214. }
  215. }
  216. internal virtual void UpdateAxisLabelText(Axis axis)
  217. {
  218. var grid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
  219. if (grid == null || axis == null)
  220. return;
  221. float runtimeWidth = axis is XAxis ? grid.context.width : grid.context.height;
  222. var isPercentStack = SeriesHelper.IsPercentStack<Bar>(chart.series);
  223. var dataZoom = chart.GetDataZoomOfAxis(axis);
  224. axis.UpdateLabelText(runtimeWidth, dataZoom, isPercentStack);
  225. }
  226. internal void UpdateAxisTickValueList(Axis axis)
  227. {
  228. if (axis.IsTime())
  229. {
  230. var lastCount = axis.context.labelValueList.Count;
  231. axis.context.tickValue = DateTimeUtil.UpdateTimeAxisDateTimeList(axis.context.labelValueList,
  232. (int)axis.context.minValue, (int)axis.context.maxValue, axis.splitNumber);
  233. if (axis.context.labelValueList.Count != lastCount)
  234. axis.SetAllDirty();
  235. }
  236. else if (axis.IsValue())
  237. {
  238. var list = axis.context.labelValueList;
  239. var lastCount = list.Count;
  240. list.Clear();
  241. var range = axis.context.maxValue - axis.context.minValue;
  242. if (range <= 0)
  243. return;
  244. double tick = axis.interval;
  245. if (axis.interval == 0)
  246. {
  247. if (range >= double.MaxValue / 2)
  248. {
  249. tick = range / 4;
  250. }
  251. else if (axis.splitNumber > 0)
  252. {
  253. tick = range / axis.splitNumber;
  254. }
  255. else
  256. {
  257. var each = GetTick(range);
  258. tick = each;
  259. if (range / 4 % each == 0)
  260. tick = range / 4;
  261. else if (range / tick > 8)
  262. tick = 2 * each;
  263. else if (range / tick < 4)
  264. tick = each / 2;
  265. }
  266. }
  267. var value = 0d;
  268. axis.context.tickValue = tick;
  269. if (Mathf.Approximately((float)(axis.context.minValue % tick), 0))
  270. {
  271. value = axis.context.minValue;
  272. }
  273. else
  274. {
  275. list.Add(axis.context.minValue);
  276. value = Math.Ceiling(axis.context.minValue / tick) * tick;
  277. }
  278. var maxSplitNumber = chart.settings.axisMaxSplitNumber;
  279. while (value <= axis.context.maxValue)
  280. {
  281. list.Add(value);
  282. value += tick;
  283. if (maxSplitNumber > 0 && list.Count > maxSplitNumber)
  284. break;
  285. }
  286. if (!ChartHelper.IsEquals(axis.context.maxValue, list[list.Count - 1]))
  287. {
  288. list.Add(axis.context.maxValue);
  289. }
  290. if (lastCount != list.Count)
  291. {
  292. axis.SetAllDirty();
  293. }
  294. }
  295. }
  296. private static double GetTick(double max)
  297. {
  298. if (max <= 1) return max / 5;
  299. if (max > 1 && max < 10) return 1;
  300. var bigger = Math.Ceiling(Math.Abs(max));
  301. int n = 1;
  302. while (bigger / (Mathf.Pow(10, n)) > 10)
  303. {
  304. n++;
  305. }
  306. return Math.Pow(10, n);
  307. }
  308. internal void CheckValueLabelActive(Axis axis, int i, ChartLabel label, Vector3 pos)
  309. {
  310. if (!axis.show || !axis.axisLabel.show)
  311. {
  312. label.SetTextActive(false);
  313. return;
  314. }
  315. if (axis.IsValue())
  316. {
  317. if (orient == Orient.Horizonal)
  318. {
  319. if (i == 0)
  320. {
  321. var dist = GetLabelPosition(0, 1).x - pos.x;
  322. label.SetTextActive(axis.IsNeedShowLabel(i) && dist > label.text.GetPreferredWidth());
  323. }
  324. else if (i == axis.context.labelValueList.Count - 1)
  325. {
  326. var dist = pos.x - GetLabelPosition(0, i - 1).x;
  327. label.SetTextActive(axis.IsNeedShowLabel(i) && dist > label.text.GetPreferredWidth());
  328. }
  329. }
  330. else
  331. {
  332. if (i == 0)
  333. {
  334. var dist = GetLabelPosition(0, 1).y - pos.y;
  335. label.SetTextActive(axis.IsNeedShowLabel(i) && dist > label.text.GetPreferredHeight());
  336. }
  337. else if (i == axis.context.labelValueList.Count - 1)
  338. {
  339. var dist = pos.y - GetLabelPosition(0, i - 1).y;
  340. label.SetTextActive(axis.IsNeedShowLabel(i) && dist > label.text.GetPreferredHeight());
  341. }
  342. }
  343. }
  344. }
  345. protected void InitAxis(Axis relativedAxis, Orient orient,
  346. float axisStartX, float axisStartY, float axisLength, float relativedLength)
  347. {
  348. Axis axis = component;
  349. chart.InitAxisRuntimeData(axis);
  350. var objName = ChartCached.GetComponentObjectName(axis);
  351. var axisObj = ChartHelper.AddObject(objName,
  352. chart.transform,
  353. chart.chartMinAnchor,
  354. chart.chartMaxAnchor,
  355. chart.chartPivot,
  356. chart.chartSizeDelta);
  357. axisObj.SetActive(axis.show);
  358. axisObj.hideFlags = chart.chartHideFlags;
  359. ChartHelper.HideAllObject(axisObj);
  360. axis.gameObject = axisObj;
  361. axis.context.labelObjectList.Clear();
  362. if (!axis.show)
  363. return;
  364. var axisLabelTextStyle = axis.axisLabel.textStyle;
  365. var dataZoom = chart.GetDataZoomOfAxis(axis);
  366. var splitNumber = AxisHelper.GetScaleNumber(axis, axisLength, dataZoom);
  367. var totalWidth = 0f;
  368. var eachWidth = AxisHelper.GetEachWidth(axis, axisLength, dataZoom);
  369. var gapWidth = axis.boundaryGap ? eachWidth / 2 : 0;
  370. var textWidth = axis.axisLabel.width > 0 ?
  371. axis.axisLabel.width :
  372. (orient == Orient.Horizonal ?
  373. AxisHelper.GetScaleWidth(axis, axisLength, 0, dataZoom) :
  374. (axisStartX - chart.chartX)
  375. );
  376. var textHeight = axis.axisLabel.height > 0 ?
  377. axis.axisLabel.height :
  378. 20f;
  379. var isPercentStack = SeriesHelper.IsPercentStack<Bar>(chart.series);
  380. var inside = axis.axisLabel.inside;
  381. var defaultAlignment = orient == Orient.Horizonal ? TextAnchor.MiddleCenter :
  382. ((inside && axis.IsLeft()) || (!inside && axis.IsRight()) ?
  383. TextAnchor.MiddleLeft :
  384. TextAnchor.MiddleRight);
  385. if (axis.IsCategory() && axis.boundaryGap)
  386. splitNumber -= 1;
  387. axis.context.aligment = defaultAlignment;
  388. for (int i = 0; i < splitNumber; i++)
  389. {
  390. var labelWidth = AxisHelper.GetScaleWidth(axis, axisLength, i + 1, dataZoom);
  391. var labelName = AxisHelper.GetLabelName(axis, axisLength, i,
  392. axis.context.destMinValue,
  393. axis.context.destMaxValue,
  394. dataZoom, isPercentStack);
  395. var label = ChartHelper.AddAxisLabelObject(splitNumber, i,
  396. ChartCached.GetAxisLabelName(i),
  397. axisObj.transform,
  398. new Vector2(textWidth, textHeight),
  399. axis, chart.theme.axis, labelName,
  400. Color.clear,
  401. defaultAlignment,
  402. chart.theme.GetColor(i));
  403. if (i == 0)
  404. axis.axisLabel.SetRelatedText(label.text, labelWidth);
  405. var pos = GetLabelPosition(totalWidth + gapWidth, i);
  406. label.SetPosition(pos);
  407. CheckValueLabelActive(axis, i, label, pos);
  408. axis.context.labelObjectList.Add(label);
  409. totalWidth += labelWidth;
  410. }
  411. if (axis.axisName.show)
  412. {
  413. ChartLabel label = null;
  414. var relativedDist = (relativedAxis == null ? 0 : relativedAxis.context.offset);
  415. var zeroPos = new Vector3(axisStartX, axisStartY + relativedDist);
  416. var offset = axis.axisName.labelStyle.offset;
  417. var autoColor = axis.axisLine.GetColor(chart.theme.axis.lineColor);
  418. if (orient == Orient.Horizonal)
  419. {
  420. var grid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
  421. var posY = !axis.axisName.onZero && grid != null ? grid.context.y : GetAxisLineXOrY() + offset.y;
  422. switch (axis.axisName.labelStyle.position)
  423. {
  424. case LabelStyle.Position.Start:
  425. label = ChartHelper.AddChartLabel(s_DefaultAxisName, axisObj.transform, axis.axisName.labelStyle,
  426. chart.theme.axis, axis.axisName.name, autoColor, TextAnchor.MiddleRight);
  427. label.SetActive(axis.axisName.labelStyle.show);
  428. label.SetPosition(axis.position == Axis.AxisPosition.Top ?
  429. new Vector2(zeroPos.x - offset.x, axisStartY + relativedLength + offset.y + axis.offset) :
  430. new Vector2(zeroPos.x - offset.x, posY + offset.y));
  431. break;
  432. case LabelStyle.Position.Middle:
  433. label = ChartHelper.AddChartLabel(s_DefaultAxisName, axisObj.transform, axis.axisName.labelStyle,
  434. chart.theme.axis, axis.axisName.name, autoColor, TextAnchor.MiddleCenter);
  435. label.SetActive(axis.axisName.labelStyle.show);
  436. label.SetPosition(axis.position == Axis.AxisPosition.Top ?
  437. new Vector2(axisStartX + axisLength / 2 + offset.x, axisStartY + relativedLength - offset.y + axis.offset) :
  438. new Vector2(axisStartX + axisLength / 2 + offset.x, posY + offset.y));
  439. break;
  440. default:
  441. label = ChartHelper.AddChartLabel(s_DefaultAxisName, axisObj.transform, axis.axisName.labelStyle,
  442. chart.theme.axis, axis.axisName.name, autoColor, TextAnchor.MiddleLeft);
  443. label.SetActive(axis.axisName.labelStyle.show);
  444. label.SetPosition(axis.position == Axis.AxisPosition.Top ?
  445. new Vector2(axisStartX + axisLength + offset.x, axisStartY + relativedLength + offset.y + axis.offset) :
  446. new Vector2(axisStartX + axisLength + offset.x, posY + offset.y));
  447. break;
  448. }
  449. }
  450. else
  451. {
  452. var grid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
  453. var posX = !axis.axisName.onZero && grid != null ? grid.context.x : GetAxisLineXOrY() + offset.x;
  454. switch (axis.axisName.labelStyle.position)
  455. {
  456. case LabelStyle.Position.Start:
  457. label = ChartHelper.AddChartLabel(s_DefaultAxisName, axisObj.transform, axis.axisName.labelStyle,
  458. chart.theme.axis, axis.axisName.name, autoColor, TextAnchor.MiddleCenter);
  459. label.SetActive(axis.axisName.labelStyle.show);
  460. label.SetPosition(axis.position == Axis.AxisPosition.Right ?
  461. new Vector2(axisStartX + relativedLength + offset.x + axis.offset, axisStartY - offset.y) :
  462. new Vector2(posX + offset.x, axisStartY - offset.y));
  463. break;
  464. case LabelStyle.Position.Middle:
  465. label = ChartHelper.AddChartLabel(s_DefaultAxisName, axisObj.transform, axis.axisName.labelStyle,
  466. chart.theme.axis, axis.axisName.name, autoColor, TextAnchor.MiddleCenter);
  467. label.SetActive(axis.axisName.labelStyle.show);
  468. label.SetPosition(axis.position == Axis.AxisPosition.Right ?
  469. new Vector2(axisStartX + relativedLength - offset.x + axis.offset, axisStartY + axisLength / 2 + offset.y) :
  470. new Vector2(posX + offset.x, axisStartY + axisLength / 2 + offset.y));
  471. break;
  472. default:
  473. //LabelStyle.Position
  474. label = ChartHelper.AddChartLabel(s_DefaultAxisName, axisObj.transform, axis.axisName.labelStyle,
  475. chart.theme.axis, axis.axisName.name, autoColor, TextAnchor.MiddleCenter);
  476. label.SetActive(axis.axisName.labelStyle.show);
  477. label.SetPosition(axis.position == Axis.AxisPosition.Right ?
  478. new Vector2(axisStartX + relativedLength + offset.x + axis.offset, axisStartY + axisLength + offset.y) :
  479. new Vector2(posX + offset.x, axisStartY + axisLength + offset.y));
  480. break;
  481. }
  482. }
  483. }
  484. }
  485. internal static Vector3 GetLabelPosition(int i, Orient orient, Axis axis, Axis relativedAxis, AxisTheme theme,
  486. float scaleWid, float axisStartX, float axisStartY, float axisLength, float relativedLength)
  487. {
  488. var inside = axis.axisLabel.inside;
  489. var fontSize = axis.axisLabel.textStyle.GetFontSize(theme);
  490. var current = axis.offset;
  491. if (axis.IsTime() || axis.IsValue())
  492. {
  493. scaleWid = axis.context.minMaxRange != 0 ?
  494. axis.GetDistance(axis.GetLabelValue(i), axisLength) :
  495. 0;
  496. }
  497. if (orient == Orient.Horizonal)
  498. {
  499. if (axis.axisLabel.onZero && relativedAxis != null)
  500. axisStartY += relativedAxis.context.offset;
  501. if (axis.IsTop())
  502. axisStartY += relativedLength;
  503. if ((inside && axis.IsBottom()) || (!inside && axis.IsTop()))
  504. current += axisStartY + axis.axisLabel.distance + fontSize / 2;
  505. else
  506. current += axisStartY - axis.axisLabel.distance - fontSize / 2;
  507. return new Vector3(axisStartX + scaleWid, current) + axis.axisLabel.offset;
  508. }
  509. else
  510. {
  511. if (axis.axisLabel.onZero && relativedAxis != null)
  512. axisStartX += relativedAxis.context.offset;
  513. if (axis.IsRight())
  514. axisStartX += relativedLength;
  515. if ((inside && axis.IsLeft()) || (!inside && axis.IsRight()))
  516. current += axisStartX + axis.axisLabel.distance;
  517. else
  518. current += axisStartX - axis.axisLabel.distance;
  519. return new Vector3(current, axisStartY + scaleWid) + axis.axisLabel.offset;
  520. }
  521. }
  522. internal static void DrawAxisLine(VertexHelper vh, Axis axis, AxisTheme theme, Orient orient,
  523. float startX, float startY, float axisLength)
  524. {
  525. var inverse = axis.IsValue() && axis.inverse;
  526. var offset = AxisHelper.GetAxisLineArrowOffset(axis);
  527. var lineWidth = axis.axisLine.GetWidth(theme.lineWidth);
  528. var lineType = axis.axisLine.GetType(theme.lineType);
  529. var lineColor = axis.axisLine.GetColor(theme.lineColor);
  530. if (orient == Orient.Horizonal)
  531. {
  532. var left = new Vector3(startX - lineWidth - (inverse ? offset : 0), startY);
  533. var right = new Vector3(startX + axisLength + lineWidth + (!inverse ? offset : 0), startY);
  534. ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, left, right, lineColor);
  535. }
  536. else
  537. {
  538. var bottom = new Vector3(startX, startY - lineWidth - (inverse ? offset : 0));
  539. var top = new Vector3(startX, startY + axisLength + lineWidth + (!inverse ? offset : 0));
  540. ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, bottom, top, lineColor);
  541. }
  542. }
  543. internal static void DrawAxisTick(VertexHelper vh, Axis axis, AxisTheme theme, DataZoom dataZoom,
  544. Orient orient, float startX, float startY, float axisLength)
  545. {
  546. var lineWidth = axis.axisLine.GetWidth(theme.lineWidth);
  547. var tickLength = axis.axisTick.GetLength(theme.tickLength);
  548. if (AxisHelper.NeedShowSplit(axis))
  549. {
  550. var size = AxisHelper.GetScaleNumber(axis, axisLength, dataZoom);
  551. if (axis.IsTime())
  552. {
  553. size += 1;
  554. if (!ChartHelper.IsEquals(axis.GetLastLabelValue(), axis.context.maxValue))
  555. size += 1;
  556. }
  557. var tickWidth = axis.axisTick.GetWidth(theme.tickWidth);
  558. var tickColor = axis.axisTick.GetColor(theme.tickColor);
  559. var current = orient == Orient.Horizonal ? startX : startY;
  560. var maxAxisXY = current + axisLength;
  561. var lastTickX = current;
  562. var lastTickY = current;
  563. var minorTickSplitNumber = axis.minorTick.splitNumber <= 0 ? 5 : axis.minorTick.splitNumber;
  564. var minorTickDistance = axis.GetValueLength(axis.context.tickValue / minorTickSplitNumber, axisLength);
  565. var minorTickColor = axis.minorTick.GetColor(theme.tickColor);
  566. var minorTickWidth = axis.minorTick.GetWidth(theme.tickWidth);
  567. var minorTickLength = axis.minorTick.GetLength(theme.tickLength * 0.6f);
  568. var minorStartIndex = axis.IsTime() ? 0 : 1;
  569. var isLogAxis = axis.IsLog();
  570. for (int i = 0; i < size; i++)
  571. {
  572. var scaleWidth = AxisHelper.GetScaleWidth(axis, axisLength, i + 1, dataZoom);
  573. var hideTick = (i == 0 && (!axis.axisTick.showStartTick || axis.axisTick.alignWithLabel)) ||
  574. (i == size - 1 && !axis.axisTick.showEndTick);
  575. if (axis.axisTick.show)
  576. {
  577. if (orient == Orient.Horizonal)
  578. {
  579. float pX = axis.IsTime() ?
  580. (startX + axis.GetDistance(axis.GetLabelValue(i), axisLength)) :
  581. current;
  582. if (axis.boundaryGap && axis.axisTick.alignWithLabel)
  583. pX -= scaleWidth / 2;
  584. var sY = 0f;
  585. var eY = 0f;
  586. var mY = 0f;
  587. if ((axis.axisTick.inside && axis.IsBottom()) ||
  588. (!axis.axisTick.inside && axis.IsTop()))
  589. {
  590. sY = startY + lineWidth;
  591. eY = sY + tickLength;
  592. mY = sY + minorTickLength;
  593. }
  594. else
  595. {
  596. sY = startY - lineWidth;
  597. eY = sY - tickLength;
  598. mY = sY - minorTickLength;
  599. }
  600. if (!hideTick)
  601. UGL.DrawLine(vh, new Vector3(pX, sY), new Vector3(pX, eY), tickWidth, tickColor);
  602. if (axis.minorTick.show && i >= minorStartIndex && (minorTickDistance > 0 || isLogAxis))
  603. {
  604. if (isLogAxis)
  605. {
  606. var count = 0;
  607. var logRange = (axis.logBase - 1f);
  608. minorTickDistance = scaleWidth * axis.GetLogValue(1 + (count + 1) * logRange / minorTickSplitNumber);
  609. var tickTotal = lastTickX + minorTickDistance;
  610. while (tickTotal < current && count < minorTickSplitNumber - 1)
  611. {
  612. UGL.DrawLine(vh, new Vector3(tickTotal, sY), new Vector3(tickTotal, mY), minorTickWidth, minorTickColor);
  613. count++;
  614. minorTickDistance = scaleWidth * axis.GetLogValue(1 + (count + 1) * logRange / minorTickSplitNumber);
  615. tickTotal = lastTickX + minorTickDistance;
  616. }
  617. }
  618. else if (lastTickX <= axis.context.zeroX || (i == minorStartIndex && pX > axis.context.zeroX))
  619. {
  620. var tickTotal = pX - minorTickDistance;
  621. while (tickTotal > lastTickX)
  622. {
  623. UGL.DrawLine(vh, new Vector3(tickTotal, sY), new Vector3(tickTotal, mY), minorTickWidth, minorTickColor);
  624. tickTotal -= minorTickDistance;
  625. }
  626. }
  627. else
  628. {
  629. var tickTotal = lastTickX + minorTickDistance;
  630. while (tickTotal < pX)
  631. {
  632. UGL.DrawLine(vh, new Vector3(tickTotal, sY), new Vector3(tickTotal, mY), minorTickWidth, minorTickColor);
  633. tickTotal += minorTickDistance;
  634. }
  635. }
  636. if (i == size - 1)
  637. {
  638. var tickTotal = pX + minorTickDistance;
  639. while (tickTotal < maxAxisXY)
  640. {
  641. UGL.DrawLine(vh, new Vector3(tickTotal, sY), new Vector3(tickTotal, mY), minorTickWidth, minorTickColor);
  642. tickTotal += minorTickDistance;
  643. }
  644. }
  645. }
  646. lastTickX = pX;
  647. }
  648. else
  649. {
  650. float pY = axis.IsTime() ?
  651. (startY + axis.GetDistance(axis.GetLabelValue(i), axisLength)) :
  652. current;
  653. if (axis.boundaryGap && axis.axisTick.alignWithLabel)
  654. pY -= scaleWidth / 2;
  655. var sX = 0f;
  656. var eX = 0f;
  657. var mX = 0f;
  658. if ((axis.axisTick.inside && axis.IsLeft()) ||
  659. (!axis.axisTick.inside && axis.IsRight()))
  660. {
  661. sX = startX + lineWidth;
  662. eX = sX + tickLength;
  663. mX = sX + minorTickLength;
  664. }
  665. else
  666. {
  667. sX = startX - lineWidth;
  668. eX = sX - tickLength;
  669. mX = sX - minorTickLength;
  670. }
  671. if (!hideTick)
  672. UGL.DrawLine(vh, new Vector3(sX, pY), new Vector3(eX, pY), tickWidth, tickColor);
  673. if (axis.minorTick.show && i >= minorStartIndex && (minorTickDistance > 0 || isLogAxis))
  674. {
  675. if (isLogAxis)
  676. {
  677. var count = 0;
  678. var logRange = (axis.logBase - 1f);
  679. minorTickDistance = scaleWidth * axis.GetLogValue(1 + (count + 1) * logRange / minorTickSplitNumber);
  680. var tickTotal = lastTickY + minorTickDistance;
  681. while (tickTotal < current && count < minorTickSplitNumber - 1)
  682. {
  683. UGL.DrawLine(vh, new Vector3(sX, tickTotal), new Vector3(mX, tickTotal), minorTickWidth, minorTickColor);
  684. count++;
  685. minorTickDistance = scaleWidth * axis.GetLogValue(1 + (count + 1) * logRange / minorTickSplitNumber);
  686. tickTotal = lastTickY + minorTickDistance;
  687. }
  688. }
  689. else if (lastTickY <= axis.context.zeroY || (i == minorStartIndex && pY > axis.context.zeroY))
  690. {
  691. var tickTotal = pY - minorTickDistance;
  692. while (tickTotal > lastTickY)
  693. {
  694. UGL.DrawLine(vh, new Vector3(sX, tickTotal), new Vector3(mX, tickTotal), minorTickWidth, minorTickColor);
  695. tickTotal -= minorTickDistance;
  696. }
  697. }
  698. else
  699. {
  700. var tickTotal = lastTickY + minorTickDistance;
  701. while (tickTotal < pY)
  702. {
  703. UGL.DrawLine(vh, new Vector3(sX, tickTotal), new Vector3(mX, tickTotal), minorTickWidth, minorTickColor);
  704. tickTotal += minorTickDistance;
  705. }
  706. }
  707. if (i == size - 1)
  708. {
  709. var tickTotal = pY + minorTickDistance;
  710. while (tickTotal < maxAxisXY)
  711. {
  712. UGL.DrawLine(vh, new Vector3(sX, tickTotal), new Vector3(mX, tickTotal), minorTickWidth, minorTickColor);
  713. tickTotal += minorTickDistance;
  714. }
  715. }
  716. }
  717. lastTickY = pY;
  718. }
  719. }
  720. current += scaleWidth;
  721. }
  722. }
  723. if (axis.show && axis.axisLine.show && axis.axisLine.showArrow)
  724. {
  725. var lineY = startY + axis.offset;
  726. var inverse = axis.IsValue() && axis.inverse;
  727. var axisArrow = axis.axisLine.arrow;
  728. if (orient == Orient.Horizonal)
  729. {
  730. if (inverse)
  731. {
  732. var startPos = new Vector3(startX + axisLength, lineY);
  733. var arrowPos = new Vector3(startX, lineY);
  734. UGL.DrawArrow(vh, startPos, arrowPos, axisArrow.width, axisArrow.height,
  735. axisArrow.offset, axisArrow.dent,
  736. axisArrow.GetColor(axis.axisLine.GetColor(theme.lineColor)));
  737. }
  738. else
  739. {
  740. var arrowPosX = startX + axisLength + lineWidth;
  741. var startPos = new Vector3(startX, lineY);
  742. var arrowPos = new Vector3(arrowPosX, lineY);
  743. UGL.DrawArrow(vh, startPos, arrowPos, axisArrow.width, axisArrow.height,
  744. axisArrow.offset, axisArrow.dent,
  745. axisArrow.GetColor(axis.axisLine.GetColor(theme.lineColor)));
  746. }
  747. }
  748. else
  749. {
  750. if (inverse)
  751. {
  752. var startPos = new Vector3(startX, startY + axisLength);
  753. var arrowPos = new Vector3(startX, startY);
  754. UGL.DrawArrow(vh, startPos, arrowPos, axisArrow.width, axisArrow.height,
  755. axisArrow.offset, axisArrow.dent,
  756. axisArrow.GetColor(axis.axisLine.GetColor(theme.lineColor)));
  757. }
  758. else
  759. {
  760. var startPos = new Vector3(startX, startY);
  761. var arrowPos = new Vector3(startX, startY + axisLength + lineWidth);
  762. UGL.DrawArrow(vh, startPos, arrowPos, axisArrow.width, axisArrow.height,
  763. axisArrow.offset, axisArrow.dent,
  764. axisArrow.GetColor(axis.axisLine.GetColor(theme.lineColor)));
  765. }
  766. }
  767. }
  768. }
  769. protected void DrawAxisSplit(VertexHelper vh, AxisTheme theme, DataZoom dataZoom,
  770. Orient orient, float startX, float startY, float axisLength, float splitLength,
  771. Axis relativedAxis = null)
  772. {
  773. Axis axis = component;
  774. var axisLineWidth = axis.axisLine.GetWidth(theme.lineWidth);
  775. splitLength -= axisLineWidth;
  776. var lineColor = axis.splitLine.GetColor(theme.splitLineColor);
  777. var lineWidth = axis.splitLine.GetWidth(theme.lineWidth);
  778. var lineType = axis.splitLine.GetType(theme.splitLineType);
  779. var size = AxisHelper.GetScaleNumber(axis, axisLength, dataZoom);
  780. if (axis.IsTime())
  781. {
  782. size += 1;
  783. if (!ChartHelper.IsEquals(axis.GetLastLabelValue(), axis.context.maxValue))
  784. size += 1;
  785. }
  786. var current = orient == Orient.Horizonal ? startX : startY;
  787. var maxAxisXY = current + axisLength;
  788. var lastSplitX = 0f;
  789. var lastSplitY = 0f;
  790. var minorTickSplitNumber = axis.minorTick.splitNumber <= 0 ? 5 : axis.minorTick.splitNumber;
  791. var minorTickDistance = axis.GetValueLength(axis.context.tickValue / minorTickSplitNumber, axisLength);
  792. var minorSplitLineColor = axis.minorSplitLine.GetColor(theme.minorSplitLineColor);
  793. var minorLineWidth = axis.minorSplitLine.GetWidth(theme.lineWidth);
  794. var minorLineType = axis.minorSplitLine.GetType(theme.splitLineType);
  795. var minorStartIndex = axis.IsTime() ? 0 : 1;
  796. var isLogAxis = axis.IsLog();
  797. for (int i = 0; i < size; i++)
  798. {
  799. var scaleWidth = AxisHelper.GetScaleWidth(axis, axisLength, axis.IsTime() ? i : i + 1, dataZoom);
  800. if (axis.boundaryGap && axis.axisTick.alignWithLabel)
  801. current -= scaleWidth / 2;
  802. if (axis.splitArea.show && i <= size - 1)
  803. {
  804. if (orient == Orient.Horizonal)
  805. {
  806. UGL.DrawQuadrilateral(vh,
  807. new Vector2(current, startY),
  808. new Vector2(current, startY + splitLength),
  809. new Vector2(current + scaleWidth, startY + splitLength),
  810. new Vector2(current + scaleWidth, startY),
  811. axis.splitArea.GetColor(i, theme));
  812. }
  813. else
  814. {
  815. UGL.DrawQuadrilateral(vh,
  816. new Vector2(startX, current),
  817. new Vector2(startX + splitLength, current),
  818. new Vector2(startX + splitLength, current + scaleWidth),
  819. new Vector2(startX, current + scaleWidth),
  820. axis.splitArea.GetColor(i, theme));
  821. }
  822. }
  823. if (axis.splitLine.show)
  824. {
  825. if (axis.splitLine.NeedShow(i, size))
  826. {
  827. if (orient == Orient.Horizonal)
  828. {
  829. if (relativedAxis == null || !relativedAxis.axisLine.show || !MathUtil.Approximately(current, relativedAxis.context.x))
  830. {
  831. ChartDrawer.DrawLineStyle(vh,
  832. lineType,
  833. lineWidth,
  834. new Vector3(current, startY),
  835. new Vector3(current, startY + splitLength),
  836. lineColor);
  837. }
  838. if (axis.minorSplitLine.show && i >= minorStartIndex && (minorTickDistance > 0 || isLogAxis))
  839. {
  840. if (isLogAxis)
  841. {
  842. var count = 0;
  843. var logRange = axis.logBase - 1f;
  844. minorTickDistance = scaleWidth * axis.GetLogValue(1 + (count + 1) * logRange / minorTickSplitNumber);
  845. var tickTotal = lastSplitX + minorTickDistance;
  846. while (tickTotal < current && count < minorTickSplitNumber - 1)
  847. {
  848. ChartDrawer.DrawLineStyle(vh,
  849. minorLineType,
  850. minorLineWidth,
  851. new Vector3(tickTotal, startY),
  852. new Vector3(tickTotal, startY + splitLength),
  853. minorSplitLineColor);
  854. count++;
  855. minorTickDistance = scaleWidth * axis.GetLogValue(1 + (count + 1) * logRange / minorTickSplitNumber);
  856. tickTotal = lastSplitX + minorTickDistance;
  857. }
  858. }
  859. else if (lastSplitX <= axis.context.zeroX || (i == minorStartIndex && current > axis.context.zeroX))
  860. {
  861. var tickTotal = current - minorTickDistance;
  862. var count = 0;
  863. while (tickTotal > lastSplitX && count < minorTickSplitNumber - 1)
  864. {
  865. ChartDrawer.DrawLineStyle(vh,
  866. minorLineType,
  867. minorLineWidth,
  868. new Vector3(tickTotal, startY),
  869. new Vector3(tickTotal, startY + splitLength),
  870. minorSplitLineColor);
  871. count++;
  872. tickTotal -= minorTickDistance;
  873. }
  874. }
  875. else
  876. {
  877. var tickTotal = lastSplitX + minorTickDistance;
  878. var count = 0;
  879. while (tickTotal < current && count < minorTickSplitNumber - 1)
  880. {
  881. ChartDrawer.DrawLineStyle(vh,
  882. minorLineType,
  883. minorLineWidth,
  884. new Vector3(tickTotal, startY),
  885. new Vector3(tickTotal, startY + splitLength),
  886. minorSplitLineColor);
  887. count++;
  888. tickTotal += minorTickDistance;
  889. }
  890. }
  891. if (i == size - 1)
  892. {
  893. var tickTotal = current + minorTickDistance;
  894. var count = 0;
  895. while (tickTotal < maxAxisXY && count < minorTickSplitNumber - 1)
  896. {
  897. ChartDrawer.DrawLineStyle(vh,
  898. minorLineType,
  899. minorLineWidth,
  900. new Vector3(tickTotal, startY),
  901. new Vector3(tickTotal, startY + splitLength),
  902. minorSplitLineColor);
  903. count++;
  904. tickTotal += minorTickDistance;
  905. }
  906. }
  907. }
  908. lastSplitX = current;
  909. }
  910. else
  911. {
  912. if (relativedAxis == null || !relativedAxis.axisLine.show || !MathUtil.Approximately(current, relativedAxis.context.y))
  913. {
  914. ChartDrawer.DrawLineStyle(vh,
  915. lineType,
  916. lineWidth,
  917. new Vector3(startX, current),
  918. new Vector3(startX + splitLength, current),
  919. lineColor);
  920. }
  921. if (axis.minorSplitLine.show && i >= minorStartIndex && (minorTickDistance > 0 || isLogAxis))
  922. {
  923. if (isLogAxis)
  924. {
  925. var count = 0;
  926. var logRange = (axis.logBase - 1f);
  927. minorTickDistance = scaleWidth * axis.GetLogValue(1 + (count + 1) * logRange / minorTickSplitNumber);
  928. var tickTotal = lastSplitY + minorTickDistance;
  929. while (tickTotal < current && count < minorTickSplitNumber - 1)
  930. {
  931. ChartDrawer.DrawLineStyle(vh,
  932. minorLineType,
  933. minorLineWidth,
  934. new Vector3(startX, tickTotal),
  935. new Vector3(startX + splitLength, tickTotal),
  936. minorSplitLineColor);
  937. count++;
  938. minorTickDistance = scaleWidth * axis.GetLogValue(1 + (count + 1) * logRange / minorTickSplitNumber);
  939. tickTotal = lastSplitY + minorTickDistance;
  940. }
  941. }
  942. else if (lastSplitY <= axis.context.zeroY || (i == minorStartIndex && current > axis.context.zeroY))
  943. {
  944. var tickTotal = current - minorTickDistance;
  945. var count = 0;
  946. while (tickTotal > lastSplitY && count < minorTickSplitNumber - 1)
  947. {
  948. ChartDrawer.DrawLineStyle(vh,
  949. minorLineType,
  950. minorLineWidth,
  951. new Vector3(startX, tickTotal),
  952. new Vector3(startX + splitLength, tickTotal),
  953. minorSplitLineColor);
  954. count++;
  955. tickTotal -= minorTickDistance;
  956. }
  957. }
  958. else
  959. {
  960. var tickTotal = lastSplitY + minorTickDistance;
  961. var count = 0;
  962. while (tickTotal < current && count < minorTickSplitNumber - 1)
  963. {
  964. ChartDrawer.DrawLineStyle(vh,
  965. minorLineType,
  966. minorLineWidth,
  967. new Vector3(startX, tickTotal),
  968. new Vector3(startX + splitLength, tickTotal),
  969. minorSplitLineColor);
  970. count++;
  971. tickTotal += minorTickDistance;
  972. }
  973. }
  974. if (i == size - 1)
  975. {
  976. var tickTotal = current + minorTickDistance;
  977. var count = 0;
  978. while (tickTotal < maxAxisXY && count < minorTickSplitNumber - 1)
  979. {
  980. ChartDrawer.DrawLineStyle(vh,
  981. minorLineType,
  982. minorLineWidth,
  983. new Vector3(startX, tickTotal),
  984. new Vector3(startX + splitLength, tickTotal),
  985. minorSplitLineColor);
  986. count++;
  987. tickTotal += minorTickDistance;
  988. }
  989. }
  990. }
  991. lastSplitY = current;
  992. }
  993. }
  994. }
  995. current += scaleWidth;
  996. }
  997. }
  998. }
  999. }