설명 없음
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AxisHandler.cs 46KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958
  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.NaN;
  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. var xRate = axis.context.minMaxRange / grid.context.width;
  106. var xValue = xRate * (chart.pointerPos.x - grid.context.x - axis.context.offset);
  107. if (axis.context.minValue > 0)
  108. xValue += axis.context.minValue;
  109. var labelY = axis.GetLabelObjectPosition(0).y;
  110. axis.context.pointerValue = xValue;
  111. axis.context.pointerLabelPosition = new Vector3(chart.pointerPos.x, labelY);
  112. if (xValue != lastPointerValue)
  113. {
  114. if (chart.onAxisPointerValueChanged != null)
  115. chart.onAxisPointerValueChanged(axis, xValue);
  116. }
  117. }
  118. }
  119. }
  120. }
  121. internal void UpdateAxisMinMaxValue(int axisIndex, Axis axis, bool updateChart = true)
  122. {
  123. if (!axis.show)
  124. return;
  125. if (axis.IsCategory())
  126. {
  127. axis.context.minValue = 0;
  128. axis.context.maxValue = SeriesHelper.GetMaxSerieDataCount(chart.series) - 1;
  129. axis.context.minMaxRange = axis.context.maxValue;
  130. return;
  131. }
  132. double tempMinValue = 0;
  133. double tempMaxValue = 0;
  134. chart.GetSeriesMinMaxValue(axis, axisIndex, out tempMinValue, out tempMaxValue);
  135. var dataZoom = chart.GetDataZoomOfAxis(axis);
  136. if (dataZoom != null && dataZoom.enable)
  137. {
  138. if (axis is XAxis)
  139. dataZoom.SetXAxisIndexValueInfo(axisIndex, ref tempMinValue, ref tempMaxValue);
  140. else
  141. dataZoom.SetYAxisIndexValueInfo(axisIndex, ref tempMinValue, ref tempMaxValue);
  142. }
  143. if (tempMinValue != axis.context.minValue ||
  144. tempMaxValue != axis.context.maxValue ||
  145. m_LastInterval != axis.interval ||
  146. m_LastSplitNumber != axis.splitNumber)
  147. {
  148. m_LastSplitNumber = axis.splitNumber;
  149. m_LastInterval = axis.interval;
  150. axis.UpdateMinMaxValue(tempMinValue, tempMaxValue);
  151. axis.context.offset = 0;
  152. axis.context.lastCheckInverse = axis.inverse;
  153. UpdateAxisTickValueList(axis);
  154. if (tempMinValue != 0 || tempMaxValue != 0)
  155. {
  156. var grid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
  157. if (grid != null && axis is XAxis && axis.IsValue())
  158. {
  159. axis.UpdateZeroOffset(grid.context.width);
  160. }
  161. if (grid != null && axis is YAxis && axis.IsValue())
  162. {
  163. axis.UpdateZeroOffset(grid.context.height);
  164. }
  165. }
  166. if (updateChart)
  167. {
  168. UpdateAxisLabelText(axis);
  169. chart.RefreshChart();
  170. }
  171. }
  172. }
  173. internal virtual void UpdateAxisLabelText(Axis axis)
  174. {
  175. var grid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
  176. if (grid == null || axis == null)
  177. return;
  178. float runtimeWidth = axis is XAxis ? grid.context.width : grid.context.height;
  179. var isPercentStack = SeriesHelper.IsPercentStack<Bar>(chart.series);
  180. var dataZoom = chart.GetDataZoomOfAxis(axis);
  181. axis.UpdateLabelText(runtimeWidth, dataZoom, isPercentStack);
  182. }
  183. internal void UpdateAxisTickValueList(Axis axis)
  184. {
  185. if (axis.IsTime())
  186. {
  187. var lastCount = axis.context.labelValueList.Count;
  188. axis.context.tickValue = DateTimeUtil.UpdateTimeAxisDateTimeList(axis.context.labelValueList,
  189. (int) axis.context.minValue, (int) axis.context.maxValue, axis.splitNumber);
  190. if (axis.context.labelValueList.Count != lastCount)
  191. axis.SetAllDirty();
  192. }
  193. else if (axis.IsValue())
  194. {
  195. var list = axis.context.labelValueList;
  196. var lastCount = list.Count;
  197. list.Clear();
  198. var range = axis.context.maxValue - axis.context.minValue;
  199. if (range <= 0)
  200. return;
  201. double tick = axis.interval;
  202. if (axis.interval == 0)
  203. {
  204. if (axis.splitNumber > 0)
  205. {
  206. tick = range / axis.splitNumber;
  207. }
  208. else
  209. {
  210. var each = GetTick(range);
  211. tick = each;
  212. if (range / 4 % each == 0)
  213. tick = range / 4;
  214. else if (range / tick > 8)
  215. tick = 2 * each;
  216. else if (range / tick < 4)
  217. tick = each / 2;
  218. }
  219. }
  220. var value = 0d;
  221. axis.context.tickValue = tick;
  222. if (Mathf.Approximately((float) (axis.context.minValue % tick), 0))
  223. {
  224. value = axis.context.minValue;
  225. }
  226. else
  227. {
  228. list.Add(axis.context.minValue);
  229. value = Math.Ceiling(axis.context.minValue / tick) * tick;
  230. }
  231. var maxSplitNumber = chart.settings.axisMaxSplitNumber;
  232. while (value <= axis.context.maxValue)
  233. {
  234. list.Add(value);
  235. value += tick;
  236. if (maxSplitNumber > 0 && list.Count > maxSplitNumber)
  237. break;
  238. }
  239. if (!ChartHelper.IsEquals(axis.context.maxValue, list[list.Count - 1]))
  240. {
  241. list.Add(axis.context.maxValue);
  242. }
  243. if (lastCount != list.Count)
  244. {
  245. axis.SetAllDirty();
  246. }
  247. }
  248. }
  249. private static double GetTick(double max)
  250. {
  251. if (max <= 1) return max / 5;
  252. if (max > 1 && max < 10) return 1;
  253. var bigger = Math.Ceiling(Math.Abs(max));
  254. int n = 1;
  255. while (bigger / (Mathf.Pow(10, n)) > 10)
  256. {
  257. n++;
  258. }
  259. return Math.Pow(10, n);
  260. }
  261. internal void CheckValueLabelActive(Axis axis, int i, ChartLabel label, Vector3 pos)
  262. {
  263. if (!axis.show || !axis.axisLabel.show)
  264. {
  265. label.SetTextActive(false);
  266. return;
  267. }
  268. if (axis.IsValue())
  269. {
  270. if (orient == Orient.Horizonal)
  271. {
  272. if (i == 0)
  273. {
  274. var dist = GetLabelPosition(0, 1).x - pos.x;
  275. label.SetTextActive(axis.IsNeedShowLabel(i) && dist > label.text.GetPreferredWidth());
  276. }
  277. else if (i == axis.context.labelValueList.Count - 1)
  278. {
  279. var dist = pos.x - GetLabelPosition(0, i - 1).x;
  280. label.SetTextActive(axis.IsNeedShowLabel(i) && dist > label.text.GetPreferredWidth());
  281. }
  282. }
  283. else
  284. {
  285. if (i == 0)
  286. {
  287. var dist = GetLabelPosition(0, 1).y - pos.y;
  288. label.SetTextActive(axis.IsNeedShowLabel(i) && dist > label.text.GetPreferredHeight());
  289. }
  290. else if (i == axis.context.labelValueList.Count - 1)
  291. {
  292. var dist = pos.y - GetLabelPosition(0, i - 1).y;
  293. label.SetTextActive(axis.IsNeedShowLabel(i) && dist > label.text.GetPreferredHeight());
  294. }
  295. }
  296. }
  297. }
  298. protected void InitAxis(Axis relativedAxis, Orient orient,
  299. float axisStartX, float axisStartY, float axisLength, float relativedLength)
  300. {
  301. Axis axis = component;
  302. chart.InitAxisRuntimeData(axis);
  303. var objName = ChartCached.GetComponentObjectName(axis);
  304. var axisObj = ChartHelper.AddObject(objName,
  305. chart.transform,
  306. chart.chartMinAnchor,
  307. chart.chartMaxAnchor,
  308. chart.chartPivot,
  309. chart.chartSizeDelta);
  310. axisObj.SetActive(axis.show);
  311. axisObj.hideFlags = chart.chartHideFlags;
  312. ChartHelper.HideAllObject(axisObj);
  313. axis.gameObject = axisObj;
  314. axis.context.labelObjectList.Clear();
  315. if (!axis.show)
  316. return;
  317. var axisLabelTextStyle = axis.axisLabel.textStyle;
  318. var dataZoom = chart.GetDataZoomOfAxis(axis);
  319. var splitNumber = AxisHelper.GetScaleNumber(axis, axisLength, dataZoom);
  320. var totalWidth = 0f;
  321. var eachWidth = AxisHelper.GetEachWidth(axis, axisLength, dataZoom);
  322. var gapWidth = axis.boundaryGap ? eachWidth / 2 : 0;
  323. var textWidth = axis.axisLabel.width > 0 ?
  324. axis.axisLabel.width :
  325. (orient == Orient.Horizonal ?
  326. AxisHelper.GetScaleWidth(axis, axisLength, 0, dataZoom) :
  327. (axisStartX - chart.chartX)
  328. );
  329. var textHeight = axis.axisLabel.height > 0 ?
  330. axis.axisLabel.height :
  331. 20f;
  332. var isPercentStack = SeriesHelper.IsPercentStack<Bar>(chart.series);
  333. var inside = axis.axisLabel.inside;
  334. var defaultAlignment = orient == Orient.Horizonal ? TextAnchor.MiddleCenter :
  335. ((inside && axis.IsLeft()) || (!inside && axis.IsRight()) ?
  336. TextAnchor.MiddleLeft :
  337. TextAnchor.MiddleRight);
  338. if (axis.IsCategory() && axis.boundaryGap)
  339. splitNumber -= 1;
  340. axis.context.aligment = defaultAlignment;
  341. for (int i = 0; i < splitNumber; i++)
  342. {
  343. var labelWidth = AxisHelper.GetScaleWidth(axis, axisLength, i + 1, dataZoom);
  344. var labelName = AxisHelper.GetLabelName(axis, axisLength, i,
  345. axis.context.minValue,
  346. axis.context.maxValue,
  347. dataZoom, isPercentStack);
  348. var label = ChartHelper.AddAxisLabelObject(splitNumber, i,
  349. ChartCached.GetAxisLabelName(i),
  350. axisObj.transform,
  351. new Vector2(textWidth, textHeight),
  352. axis, chart.theme.axis, labelName,
  353. Color.clear,
  354. defaultAlignment);
  355. if (i == 0)
  356. axis.axisLabel.SetRelatedText(label.text, labelWidth);
  357. var pos = GetLabelPosition(totalWidth + gapWidth, i);
  358. label.SetPosition(pos);
  359. CheckValueLabelActive(axis, i, label, pos);
  360. axis.context.labelObjectList.Add(label);
  361. totalWidth += labelWidth;
  362. }
  363. if (axis.axisName.show)
  364. {
  365. ChartLabel label = null;
  366. var relativedDist = (relativedAxis == null ? 0 : relativedAxis.context.offset);
  367. var zeroPos = new Vector3(axisStartX, axisStartY + relativedDist);
  368. var offset = axis.axisName.labelStyle.offset;
  369. var autoColor = axis.axisLine.GetColor(chart.theme.axis.lineColor);
  370. if (orient == Orient.Horizonal)
  371. {
  372. var grid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
  373. var posY = !axis.axisName.onZero && grid != null? grid.context.y : GetAxisLineXOrY() + offset.y;
  374. switch (axis.axisName.labelStyle.position)
  375. {
  376. case LabelStyle.Position.Start:
  377. label = ChartHelper.AddChartLabel(s_DefaultAxisName, axisObj.transform, axis.axisName.labelStyle,
  378. chart.theme.axis, axis.axisName.name, autoColor, TextAnchor.MiddleRight);
  379. label.SetActive(axis.axisName.labelStyle.show);
  380. label.SetPosition(axis.position == Axis.AxisPosition.Top ?
  381. new Vector2(zeroPos.x - offset.x, axisStartY + relativedLength + offset.y + axis.offset) :
  382. new Vector2(zeroPos.x - offset.x, posY + offset.y));
  383. break;
  384. case LabelStyle.Position.Middle:
  385. label = ChartHelper.AddChartLabel(s_DefaultAxisName, axisObj.transform, axis.axisName.labelStyle,
  386. chart.theme.axis, axis.axisName.name, autoColor, TextAnchor.MiddleCenter);
  387. label.SetActive(axis.axisName.labelStyle.show);
  388. label.SetPosition(axis.position == Axis.AxisPosition.Top ?
  389. new Vector2(axisStartX + axisLength / 2 + offset.x, axisStartY + relativedLength - offset.y + axis.offset) :
  390. new Vector2(axisStartX + axisLength / 2 + offset.x, posY + offset.y));
  391. break;
  392. default:
  393. label = ChartHelper.AddChartLabel(s_DefaultAxisName, axisObj.transform, axis.axisName.labelStyle,
  394. chart.theme.axis, axis.axisName.name, autoColor, TextAnchor.MiddleLeft);
  395. label.SetActive(axis.axisName.labelStyle.show);
  396. label.SetPosition(axis.position == Axis.AxisPosition.Top ?
  397. new Vector2(axisStartX + axisLength + offset.x, axisStartY + relativedLength + offset.y + axis.offset) :
  398. new Vector2(axisStartX + axisLength + offset.x, posY + offset.y));
  399. break;
  400. }
  401. }
  402. else
  403. {
  404. var grid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
  405. var posX = !axis.axisName.onZero && grid != null? grid.context.x : GetAxisLineXOrY() + offset.x;
  406. switch (axis.axisName.labelStyle.position)
  407. {
  408. case LabelStyle.Position.Start:
  409. label = ChartHelper.AddChartLabel(s_DefaultAxisName, axisObj.transform, axis.axisName.labelStyle,
  410. chart.theme.axis, axis.axisName.name, autoColor, TextAnchor.MiddleCenter);
  411. label.SetActive(axis.axisName.labelStyle.show);
  412. label.SetPosition(axis.position == Axis.AxisPosition.Right ?
  413. new Vector2(axisStartX + relativedLength + offset.x + axis.offset, axisStartY - offset.y) :
  414. new Vector2(posX + offset.x, axisStartY - offset.y));
  415. break;
  416. case LabelStyle.Position.Middle:
  417. label = ChartHelper.AddChartLabel(s_DefaultAxisName, axisObj.transform, axis.axisName.labelStyle,
  418. chart.theme.axis, axis.axisName.name, autoColor, TextAnchor.MiddleCenter);
  419. label.SetActive(axis.axisName.labelStyle.show);
  420. label.SetPosition(axis.position == Axis.AxisPosition.Right ?
  421. new Vector2(axisStartX + relativedLength - offset.x + axis.offset, axisStartY + axisLength / 2 + offset.y) :
  422. new Vector2(posX + offset.x, axisStartY + axisLength / 2 + offset.y));
  423. break;
  424. default:
  425. //LabelStyle.Position
  426. label = ChartHelper.AddChartLabel(s_DefaultAxisName, axisObj.transform, axis.axisName.labelStyle,
  427. chart.theme.axis, axis.axisName.name, autoColor, TextAnchor.MiddleCenter);
  428. label.SetActive(axis.axisName.labelStyle.show);
  429. label.SetPosition(axis.position == Axis.AxisPosition.Right ?
  430. new Vector2(axisStartX + relativedLength + offset.x + axis.offset, axisStartY + axisLength + offset.y) :
  431. new Vector2(posX + offset.x, axisStartY + axisLength + offset.y));
  432. break;
  433. }
  434. }
  435. }
  436. }
  437. internal static Vector3 GetLabelPosition(int i, Orient orient, Axis axis, Axis relativedAxis, AxisTheme theme,
  438. float scaleWid, float axisStartX, float axisStartY, float axisLength, float relativedLength)
  439. {
  440. var inside = axis.axisLabel.inside;
  441. var fontSize = axis.axisLabel.textStyle.GetFontSize(theme);
  442. var current = axis.offset;
  443. if (axis.IsTime() || axis.IsValue())
  444. {
  445. scaleWid = axis.context.minMaxRange != 0 ?
  446. axis.GetDistance(axis.GetLabelValue(i), axisLength) :
  447. 0;
  448. }
  449. if (orient == Orient.Horizonal)
  450. {
  451. if (axis.axisLabel.onZero && relativedAxis != null)
  452. axisStartY += relativedAxis.context.offset;
  453. if (axis.IsTop())
  454. axisStartY += relativedLength;
  455. if ((inside && axis.IsBottom()) || (!inside && axis.IsTop()))
  456. current += axisStartY + axis.axisLabel.distance + fontSize / 2;
  457. else
  458. current += axisStartY - axis.axisLabel.distance - fontSize / 2;
  459. return new Vector3(axisStartX + scaleWid, current) + axis.axisLabel.offset;
  460. }
  461. else
  462. {
  463. if (axis.axisLabel.onZero && relativedAxis != null)
  464. axisStartX += relativedAxis.context.offset;
  465. if (axis.IsRight())
  466. axisStartX += relativedLength;
  467. if ((inside && axis.IsLeft()) || (!inside && axis.IsRight()))
  468. current += axisStartX + axis.axisLabel.distance;
  469. else
  470. current += axisStartX - axis.axisLabel.distance;
  471. return new Vector3(current, axisStartY + scaleWid) + axis.axisLabel.offset;
  472. }
  473. }
  474. internal static void DrawAxisLine(VertexHelper vh, Axis axis, AxisTheme theme, Orient orient,
  475. float startX, float startY, float axisLength)
  476. {
  477. var inverse = axis.IsValue() && axis.inverse;
  478. var offset = AxisHelper.GetAxisLineArrowOffset(axis);
  479. var lineWidth = axis.axisLine.GetWidth(theme.lineWidth);
  480. var lineType = axis.axisLine.GetType(theme.lineType);
  481. var lineColor = axis.axisLine.GetColor(theme.lineColor);
  482. if (orient == Orient.Horizonal)
  483. {
  484. var left = new Vector3(startX - lineWidth - (inverse ? offset : 0), startY);
  485. var right = new Vector3(startX + axisLength + lineWidth + (!inverse ? offset : 0), startY);
  486. ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, left, right, lineColor);
  487. }
  488. else
  489. {
  490. var bottom = new Vector3(startX, startY - lineWidth - (inverse ? offset : 0));
  491. var top = new Vector3(startX, startY + axisLength + lineWidth + (!inverse ? offset : 0));
  492. ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, bottom, top, lineColor);
  493. }
  494. }
  495. internal static void DrawAxisTick(VertexHelper vh, Axis axis, AxisTheme theme, DataZoom dataZoom,
  496. Orient orient, float startX, float startY, float axisLength)
  497. {
  498. var lineWidth = axis.axisLine.GetWidth(theme.lineWidth);
  499. var tickLength = axis.axisTick.GetLength(theme.tickLength);
  500. if (AxisHelper.NeedShowSplit(axis))
  501. {
  502. var size = AxisHelper.GetScaleNumber(axis, axisLength, dataZoom);
  503. if (axis.IsTime())
  504. {
  505. size += 1;
  506. if (!ChartHelper.IsEquals(axis.GetLastLabelValue(), axis.context.maxValue))
  507. size += 1;
  508. }
  509. var tickWidth = axis.axisTick.GetWidth(theme.tickWidth);
  510. var tickColor = axis.axisTick.GetColor(theme.tickColor);
  511. var current = orient == Orient.Horizonal ? startX : startY;
  512. var maxAxisXY = current + axisLength;
  513. var lastTickX = current;
  514. var lastTickY = current;
  515. var minorTickSplitNumber = axis.minorTick.splitNumber <= 0 ? 5 : axis.minorTick.splitNumber;
  516. var minorTickDistance = axis.GetValueLength(axis.context.tickValue / minorTickSplitNumber, axisLength);
  517. var minorTickColor = axis.minorTick.GetColor(theme.tickColor);
  518. var minorTickWidth = axis.minorTick.GetWidth(theme.tickWidth);
  519. var minorTickLength = axis.minorTick.GetLength(theme.tickLength * 0.6f);
  520. var minorStartIndex = axis.IsTime() ? 0 : 1;
  521. for (int i = 0; i < size; i++)
  522. {
  523. var scaleWidth = AxisHelper.GetScaleWidth(axis, axisLength, i + 1, dataZoom);
  524. var hideTick = (i == 0 && (!axis.axisTick.showStartTick || axis.axisTick.alignWithLabel)) ||
  525. (i == size - 1 && !axis.axisTick.showEndTick);
  526. if (axis.axisTick.show)
  527. {
  528. if (orient == Orient.Horizonal)
  529. {
  530. float pX = axis.IsTime() ?
  531. (startX + axis.GetDistance(axis.GetLabelValue(i), axisLength)) :
  532. current;
  533. if (axis.boundaryGap && axis.axisTick.alignWithLabel)
  534. pX -= scaleWidth / 2;
  535. var sY = 0f;
  536. var eY = 0f;
  537. var mY = 0f;
  538. if ((axis.axisTick.inside && axis.IsBottom()) ||
  539. (!axis.axisTick.inside && axis.IsTop()))
  540. {
  541. sY = startY + lineWidth;
  542. eY = sY + tickLength;
  543. mY = sY + minorTickLength;
  544. }
  545. else
  546. {
  547. sY = startY - lineWidth;
  548. eY = sY - tickLength;
  549. mY = sY - minorTickLength;
  550. }
  551. if (!hideTick)
  552. UGL.DrawLine(vh, new Vector3(pX, sY), new Vector3(pX, eY), tickWidth, tickColor);
  553. if (axis.minorTick.show && i >= minorStartIndex && minorTickDistance > 0)
  554. {
  555. if (lastTickX <= axis.context.zeroX || (i == minorStartIndex && pX > axis.context.zeroX))
  556. {
  557. var tickTotal = pX - minorTickDistance;
  558. while (tickTotal > lastTickX)
  559. {
  560. UGL.DrawLine(vh, new Vector3(tickTotal, sY), new Vector3(tickTotal, mY), minorTickWidth, minorTickColor);
  561. tickTotal -= minorTickDistance;
  562. }
  563. }
  564. else
  565. {
  566. var tickTotal = lastTickX + minorTickDistance;
  567. while (tickTotal < pX)
  568. {
  569. UGL.DrawLine(vh, new Vector3(tickTotal, sY), new Vector3(tickTotal, mY), minorTickWidth, minorTickColor);
  570. tickTotal += minorTickDistance;
  571. }
  572. }
  573. if (i == size - 1)
  574. {
  575. var tickTotal = pX + minorTickDistance;
  576. while (tickTotal < maxAxisXY)
  577. {
  578. UGL.DrawLine(vh, new Vector3(tickTotal, sY), new Vector3(tickTotal, mY), minorTickWidth, minorTickColor);
  579. tickTotal += minorTickDistance;
  580. }
  581. }
  582. }
  583. lastTickX = pX;
  584. }
  585. else
  586. {
  587. float pY = axis.IsTime() ?
  588. (startY + axis.GetDistance(axis.GetLabelValue(i), axisLength)) :
  589. current;
  590. if (axis.boundaryGap && axis.axisTick.alignWithLabel)
  591. pY -= scaleWidth / 2;
  592. var sX = 0f;
  593. var eX = 0f;
  594. var mX = 0f;
  595. if ((axis.axisTick.inside && axis.IsLeft()) ||
  596. (!axis.axisTick.inside && axis.IsRight()))
  597. {
  598. sX = startX + lineWidth;
  599. eX = sX + tickLength;
  600. mX = sX + minorTickLength;
  601. }
  602. else
  603. {
  604. sX = startX - lineWidth;
  605. eX = sX - tickLength;
  606. mX = sX - minorTickLength;
  607. }
  608. if (!hideTick)
  609. UGL.DrawLine(vh, new Vector3(sX, pY), new Vector3(eX, pY), tickWidth, tickColor);
  610. if (axis.minorTick.show && i >= minorStartIndex && minorTickDistance > 0)
  611. {
  612. if (lastTickY <= axis.context.zeroY || (i == minorStartIndex && pY > axis.context.zeroY))
  613. {
  614. var tickTotal = pY - minorTickDistance;
  615. while (tickTotal > lastTickY)
  616. {
  617. UGL.DrawLine(vh, new Vector3(sX, tickTotal), new Vector3(mX, tickTotal), minorTickWidth, minorTickColor);
  618. tickTotal -= minorTickDistance;
  619. }
  620. }
  621. else
  622. {
  623. var tickTotal = lastTickY + minorTickDistance;
  624. while (tickTotal < pY)
  625. {
  626. UGL.DrawLine(vh, new Vector3(sX, tickTotal), new Vector3(mX, tickTotal), minorTickWidth, minorTickColor);
  627. tickTotal += minorTickDistance;
  628. }
  629. }
  630. if (i == size - 1)
  631. {
  632. var tickTotal = pY + minorTickDistance;
  633. while (tickTotal < maxAxisXY)
  634. {
  635. UGL.DrawLine(vh, new Vector3(sX, tickTotal), new Vector3(mX, tickTotal), minorTickWidth, minorTickColor);
  636. tickTotal += minorTickDistance;
  637. }
  638. }
  639. }
  640. lastTickY = pY;
  641. }
  642. }
  643. current += scaleWidth;
  644. }
  645. }
  646. if (axis.show && axis.axisLine.show && axis.axisLine.showArrow)
  647. {
  648. var lineY = startY + axis.offset;
  649. var inverse = axis.IsValue() && axis.inverse;
  650. var axisArrow = axis.axisLine.arrow;
  651. if (orient == Orient.Horizonal)
  652. {
  653. if (inverse)
  654. {
  655. var startPos = new Vector3(startX + axisLength, lineY);
  656. var arrowPos = new Vector3(startX, lineY);
  657. UGL.DrawArrow(vh, startPos, arrowPos, axisArrow.width, axisArrow.height,
  658. axisArrow.offset, axisArrow.dent,
  659. axisArrow.GetColor(axis.axisLine.GetColor(theme.lineColor)));
  660. }
  661. else
  662. {
  663. var arrowPosX = startX + axisLength + lineWidth;
  664. var startPos = new Vector3(startX, lineY);
  665. var arrowPos = new Vector3(arrowPosX, lineY);
  666. UGL.DrawArrow(vh, startPos, arrowPos, axisArrow.width, axisArrow.height,
  667. axisArrow.offset, axisArrow.dent,
  668. axisArrow.GetColor(axis.axisLine.GetColor(theme.lineColor)));
  669. }
  670. }
  671. else
  672. {
  673. if (inverse)
  674. {
  675. var startPos = new Vector3(startX, startY + axisLength);
  676. var arrowPos = new Vector3(startX, startY);
  677. UGL.DrawArrow(vh, startPos, arrowPos, axisArrow.width, axisArrow.height,
  678. axisArrow.offset, axisArrow.dent,
  679. axisArrow.GetColor(axis.axisLine.GetColor(theme.lineColor)));
  680. }
  681. else
  682. {
  683. var startPos = new Vector3(startX, startY);
  684. var arrowPos = new Vector3(startX, startY + axisLength + lineWidth);
  685. UGL.DrawArrow(vh, startPos, arrowPos, axisArrow.width, axisArrow.height,
  686. axisArrow.offset, axisArrow.dent,
  687. axisArrow.GetColor(axis.axisLine.GetColor(theme.lineColor)));
  688. }
  689. }
  690. }
  691. }
  692. protected void DrawAxisSplit(VertexHelper vh, AxisTheme theme, DataZoom dataZoom,
  693. Orient orient, float startX, float startY, float axisLength, float splitLength,
  694. Axis relativedAxis = null)
  695. {
  696. Axis axis = component;
  697. var axisLineWidth = axis.axisLine.GetWidth(theme.lineWidth);
  698. splitLength -= axisLineWidth;
  699. var lineColor = axis.splitLine.GetColor(theme.splitLineColor);
  700. var lineWidth = axis.splitLine.GetWidth(theme.lineWidth);
  701. var lineType = axis.splitLine.GetType(theme.splitLineType);
  702. var size = AxisHelper.GetScaleNumber(axis, axisLength, dataZoom);
  703. if (axis.IsTime())
  704. {
  705. size += 1;
  706. if (!ChartHelper.IsEquals(axis.GetLastLabelValue(), axis.context.maxValue))
  707. size += 1;
  708. }
  709. var current = orient == Orient.Horizonal ? startX : startY;
  710. var maxAxisXY = current + axisLength;
  711. var lastSplitX = 0f;
  712. var lastSplitY = 0f;
  713. var minorTickSplitNumber = axis.minorTick.splitNumber <= 0 ? 5 : axis.minorTick.splitNumber;
  714. var minorTickDistance = axis.GetValueLength(axis.context.tickValue / minorTickSplitNumber, axisLength);
  715. var minorSplitLineColor = axis.minorSplitLine.GetColor(theme.minorSplitLineColor);
  716. var minorLineWidth = axis.minorSplitLine.GetWidth(theme.lineWidth);
  717. var minorLineType = axis.minorSplitLine.GetType(theme.splitLineType);
  718. var minorStartIndex = axis.IsTime() ? 0 : 1;
  719. for (int i = 0; i < size; i++)
  720. {
  721. var scaleWidth = AxisHelper.GetScaleWidth(axis, axisLength, axis.IsTime() ? i : i + 1, dataZoom);
  722. if (axis.boundaryGap && axis.axisTick.alignWithLabel)
  723. current -= scaleWidth / 2;
  724. if (axis.splitArea.show && i <= size - 1)
  725. {
  726. if (orient == Orient.Horizonal)
  727. {
  728. UGL.DrawQuadrilateral(vh,
  729. new Vector2(current, startY),
  730. new Vector2(current, startY + splitLength),
  731. new Vector2(current + scaleWidth, startY + splitLength),
  732. new Vector2(current + scaleWidth, startY),
  733. axis.splitArea.GetColor(i, theme));
  734. }
  735. else
  736. {
  737. UGL.DrawQuadrilateral(vh,
  738. new Vector2(startX, current),
  739. new Vector2(startX + splitLength, current),
  740. new Vector2(startX + splitLength, current + scaleWidth),
  741. new Vector2(startX, current + scaleWidth),
  742. axis.splitArea.GetColor(i, theme));
  743. }
  744. }
  745. if (axis.splitLine.show)
  746. {
  747. if (axis.splitLine.NeedShow(i, size))
  748. {
  749. if (orient == Orient.Horizonal)
  750. {
  751. if (relativedAxis == null || !relativedAxis.axisLine.show || !MathUtil.Approximately(current, relativedAxis.context.x))
  752. {
  753. ChartDrawer.DrawLineStyle(vh,
  754. lineType,
  755. lineWidth,
  756. new Vector3(current, startY),
  757. new Vector3(current, startY + splitLength),
  758. lineColor);
  759. }
  760. if (axis.minorSplitLine.show && i >= minorStartIndex && minorTickDistance > 0)
  761. {
  762. if (lastSplitX <= axis.context.zeroX || (i == minorStartIndex && current > axis.context.zeroX))
  763. {
  764. var tickTotal = current - minorTickDistance;
  765. var count = 0;
  766. while (tickTotal > lastSplitX && count < minorTickSplitNumber - 1)
  767. {
  768. ChartDrawer.DrawLineStyle(vh,
  769. minorLineType,
  770. minorLineWidth,
  771. new Vector3(tickTotal, startY),
  772. new Vector3(tickTotal, startY + splitLength),
  773. minorSplitLineColor);
  774. count++;
  775. tickTotal -= minorTickDistance;
  776. }
  777. }
  778. else
  779. {
  780. var tickTotal = lastSplitX + minorTickDistance;
  781. var count = 0;
  782. while (tickTotal < current && count < minorTickSplitNumber - 1)
  783. {
  784. ChartDrawer.DrawLineStyle(vh,
  785. minorLineType,
  786. minorLineWidth,
  787. new Vector3(tickTotal, startY),
  788. new Vector3(tickTotal, startY + splitLength),
  789. minorSplitLineColor);
  790. count++;
  791. tickTotal += minorTickDistance;
  792. }
  793. }
  794. if (i == size - 1)
  795. {
  796. var tickTotal = current + minorTickDistance;
  797. var count = 0;
  798. while (tickTotal < maxAxisXY && count < minorTickSplitNumber - 1)
  799. {
  800. ChartDrawer.DrawLineStyle(vh,
  801. minorLineType,
  802. minorLineWidth,
  803. new Vector3(tickTotal, startY),
  804. new Vector3(tickTotal, startY + splitLength),
  805. minorSplitLineColor);
  806. count++;
  807. tickTotal += minorTickDistance;
  808. }
  809. }
  810. }
  811. lastSplitX = current;
  812. }
  813. else
  814. {
  815. if (relativedAxis == null || !relativedAxis.axisLine.show || !MathUtil.Approximately(current, relativedAxis.context.y))
  816. {
  817. ChartDrawer.DrawLineStyle(vh,
  818. lineType,
  819. lineWidth,
  820. new Vector3(startX, current),
  821. new Vector3(startX + splitLength, current),
  822. lineColor);
  823. }
  824. if (axis.minorSplitLine.show && i >= minorStartIndex && minorTickDistance > 0)
  825. {
  826. if (lastSplitY <= axis.context.zeroY || (i == minorStartIndex && current > axis.context.zeroY))
  827. {
  828. var tickTotal = current - minorTickDistance;
  829. var count = 0;
  830. while (tickTotal > lastSplitY && count < minorTickSplitNumber - 1)
  831. {
  832. ChartDrawer.DrawLineStyle(vh,
  833. minorLineType,
  834. minorLineWidth,
  835. new Vector3(startX, tickTotal),
  836. new Vector3(startX + splitLength, tickTotal),
  837. minorSplitLineColor);
  838. count++;
  839. tickTotal -= minorTickDistance;
  840. }
  841. }
  842. else
  843. {
  844. var tickTotal = lastSplitY + minorTickDistance;
  845. var count = 0;
  846. while (tickTotal < current && count < minorTickSplitNumber - 1)
  847. {
  848. ChartDrawer.DrawLineStyle(vh,
  849. minorLineType,
  850. minorLineWidth,
  851. new Vector3(startX, tickTotal),
  852. new Vector3(startX + splitLength, tickTotal),
  853. minorSplitLineColor);
  854. count++;
  855. tickTotal += minorTickDistance;
  856. }
  857. }
  858. if (i == size - 1)
  859. {
  860. var tickTotal = current + minorTickDistance;
  861. var count = 0;
  862. while (tickTotal < maxAxisXY && count < minorTickSplitNumber - 1)
  863. {
  864. ChartDrawer.DrawLineStyle(vh,
  865. minorLineType,
  866. minorLineWidth,
  867. new Vector3(startX, tickTotal),
  868. new Vector3(startX + splitLength, tickTotal),
  869. minorSplitLineColor);
  870. count++;
  871. tickTotal += minorTickDistance;
  872. }
  873. }
  874. }
  875. lastSplitY = current;
  876. }
  877. }
  878. }
  879. current += scaleWidth;
  880. }
  881. }
  882. }
  883. }