LabelStyle.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. using System;
  2. using UnityEngine;
  3. namespace XCharts.Runtime
  4. {
  5. /// <summary>
  6. /// Text label of chart, to explain some data information about graphic item like value, name and so on.
  7. /// ||图形上的文本标签,可用于说明图形的一些数据信息,比如值,名称等。
  8. /// </summary>
  9. [System.Serializable]
  10. public class LabelStyle : ChildComponent, ISerieComponent, ISerieDataComponent
  11. {
  12. /// <summary>
  13. /// The position of label.
  14. /// ||标签的位置。
  15. /// </summary>
  16. public enum Position
  17. {
  18. Default,
  19. /// <summary>
  20. /// Outside of sectors of pie chart, which relates to corresponding sector through visual guide line.
  21. /// ||饼图扇区外侧,通过视觉引导线连到相应的扇区。
  22. /// </summary>
  23. Outside,
  24. /// <summary>
  25. /// Inside the sectors of pie chart.
  26. /// ||饼图扇区内部。
  27. /// </summary>
  28. Inside,
  29. /// <summary>
  30. /// In the center of pie chart.
  31. /// ||在饼图中心位置。
  32. /// </summary>
  33. Center,
  34. /// <summary>
  35. /// top of symbol.
  36. /// ||图形标志的顶部。
  37. /// </summary>
  38. Top,
  39. /// <summary>
  40. /// the bottom of symbol.
  41. /// ||图形标志的底部。
  42. /// </summary>
  43. Bottom,
  44. /// <summary>
  45. /// the left of symbol.
  46. /// ||图形标志的左边。
  47. /// </summary>
  48. Left,
  49. /// <summary>
  50. /// the right of symbol.
  51. /// ||图形标志的右边。
  52. /// </summary>
  53. Right,
  54. /// <summary>
  55. /// the start of line.
  56. /// ||线的起始点。
  57. /// </summary>
  58. Start,
  59. /// <summary>
  60. /// the middle of line.
  61. /// ||线的中点。
  62. /// </summary>
  63. Middle,
  64. /// <summary>
  65. /// the end of line.
  66. /// ||线的结束点。
  67. /// </summary>
  68. End
  69. }
  70. [SerializeField] protected bool m_Show = true;
  71. [SerializeField] Position m_Position = Position.Default;
  72. [SerializeField] protected bool m_AutoOffset = false;
  73. [SerializeField] protected Vector3 m_Offset;
  74. [SerializeField] protected float m_Rotate;
  75. [SerializeField][Since("v3.6.0")] protected bool m_AutoRotate = false;
  76. [SerializeField] protected float m_Distance;
  77. [SerializeField] protected string m_Formatter;
  78. [SerializeField] protected string m_NumericFormatter = "";
  79. [SerializeField] protected float m_Width = 0;
  80. [SerializeField] protected float m_Height = 0;
  81. [SerializeField] protected IconStyle m_Icon = new IconStyle();
  82. [SerializeField] protected ImageStyle m_Background = new ImageStyle();
  83. [SerializeField] protected TextPadding m_TextPadding = new TextPadding();
  84. [SerializeField] protected TextStyle m_TextStyle = new TextStyle();
  85. protected LabelFormatterFunction m_FormatterFunction;
  86. public void Reset()
  87. {
  88. m_Show = false;
  89. m_Position = Position.Default;
  90. m_Offset = Vector3.zero;
  91. m_Distance = 0;
  92. m_Rotate = 0;
  93. m_Width = 0;
  94. m_Height = 0;
  95. m_NumericFormatter = "";
  96. m_AutoOffset = false;
  97. }
  98. /// <summary>
  99. /// Whether the label is showed.
  100. /// ||是否显示文本标签。
  101. /// </summary>
  102. public bool show
  103. {
  104. get { return m_Show; }
  105. set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetAllDirty(); }
  106. }
  107. /// <summary>
  108. /// The position of label.
  109. /// ||标签的位置。
  110. /// </summary>
  111. public Position position
  112. {
  113. get { return m_Position; }
  114. set { if (PropertyUtil.SetStruct(ref m_Position, value)) SetAllDirty(); }
  115. }
  116. /// <summary>
  117. /// label content string template formatter. \n line wrapping is supported. Formatters for some components will not take effect. <br />
  118. /// Template placeholder have the following, some of which apply only to fixed components: <br />
  119. /// `{.}` : indicates the dot mark. <br />
  120. /// `{a}` : indicates the series name. <br />
  121. /// `{b}` : category value of x axis or data name. <br />
  122. /// `{c}` : data value. <br />
  123. /// `{d}` : percentage. <br />
  124. /// `{e}` : indicates the data name. <br />
  125. /// `{f}` : data sum. <br />
  126. /// `{g}` : indicates the total number of data. <br />
  127. /// `{h}` : hexadecimal color value. <br />
  128. /// `{y}` : category value of y axis. <br />
  129. /// `{value}` : The value of the axis or legend. <br />
  130. /// The following placeholder apply to `UITable` components: <br />
  131. /// `{name}` : indicates the row name of the table. <br />
  132. /// `{index}` : indicates the row number of the table. <br />
  133. /// The following placeholder apply to `UIStatistc` components: <br />
  134. /// `{title}` : title text. <br />
  135. /// `{dd}` : day. <br />
  136. /// `{hh}` : hours. <br />
  137. /// `{mm}` : minutes. <br />
  138. /// `{ss}` : second. <br />
  139. /// `{fff}` : milliseconds. <br />
  140. /// `{d}` : day. <br />
  141. /// `{h}` : hours. <br />
  142. /// `{m}` : minutes. <br />
  143. /// `{s}` : second. <br />
  144. /// `{f}` : milliseconds. <br />
  145. /// Example :{b}:{c}<br />
  146. /// ||标签内容字符串模版格式器。支持用 \n 换行。部分组件的格式器会不生效。<br/>
  147. /// 模板通配符有以下这些,部分只适用于固定的组件:<br/>
  148. /// `{.}`:圆点标记。<br/>
  149. /// `{a}`:系列名。<br/>
  150. /// `{b}`:X轴类目名或数据名。<br/>
  151. /// `{c}`:数据值。<br/>
  152. /// `{d}`:百分比。<br/>
  153. /// `{e}`:数据名。<br/>
  154. /// `{f}`:数据和。<br/>
  155. /// `{g}`:数据总个数。<br/>
  156. /// `{h}`:十六进制颜色值。<br/>
  157. /// `{y}`:Y轴的类目名。<br/>
  158. /// `{value}`:坐标轴或图例的值。<br/>
  159. /// 以下通配符适用UITable组件:<br/>
  160. /// `{name}`: 表格的行名。<br/>
  161. /// `{index}`:表格的行号。<br/>
  162. /// 以下通配符适用UIStatistc组件:<br/>
  163. /// `{title}`:标题文本。<br/>
  164. /// `{dd}`:天。<br/>
  165. /// `{hh}`:小时。<br/>
  166. /// `{mm}`:分钟。<br/>
  167. /// `{ss}`:秒。<br/>
  168. /// `{fff}`:毫秒。<br/>
  169. /// `{d}`:天。<br/>
  170. /// `{h}`:小时。<br/>
  171. /// `{m}`:分钟。<br/>
  172. /// `{s}`:秒。<br/>
  173. /// `{f}`:毫秒。<br/>
  174. /// 示例:“{b}:{c}”
  175. /// </summary>
  176. public string formatter
  177. {
  178. get { return m_Formatter; }
  179. set { if (PropertyUtil.SetClass(ref m_Formatter, value)) SetComponentDirty(); }
  180. }
  181. /// <summary>
  182. /// Standard number and date format string. Used to format a Double value or a DateTime date as a string. numericFormatter is used as an argument to either `Double.ToString ()` or `DateTime.ToString()`. <br />
  183. /// The number format uses the Axx format: A is a single-character format specifier that supports C currency, D decimal, E exponent, F fixed-point number, G regular, N digit, P percentage, R round trip, and X hexadecimal. xx is precision specification, from 0-99. E.g. F1, E2<br />
  184. /// Date format Common date formats are: yyyy year, MM month, dd day, HH hour, mm minute, ss second, fff millisecond. For example: yyyy-MM-dd HH:mm:ss<br />
  185. /// number format reference: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings<br/>
  186. /// date format reference: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings<br/>
  187. /// ||标准数字和日期格式字符串。用于将Double数值或DateTime日期格式化显示为字符串。numericFormatter用来作为Double.ToString()或DateTime.ToString()的参数。<br/>
  188. /// 数字格式使用Axx的形式:A是格式说明符的单字符,支持C货币、D十进制、E指数、F定点数、G常规、N数字、P百分比、R往返、X十六进制的。xx是精度说明,从0-99。如:F1, E2<br/>
  189. /// 日期格式常见的格式:yyyy年,MM月,dd日,HH时,mm分,ss秒,fff毫秒。如:yyyy-MM-dd HH:mm:ss<br/>
  190. /// 数值格式化参考:https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/standard-numeric-format-strings <br/>
  191. /// 日期格式化参考:https://learn.microsoft.com/zh-cn/dotnet/standard/base-types/standard-date-and-time-format-strings
  192. /// </summary>
  193. public string numericFormatter
  194. {
  195. get { return m_NumericFormatter; }
  196. set { if (PropertyUtil.SetClass(ref m_NumericFormatter, value)) SetComponentDirty(); }
  197. }
  198. /// <summary>
  199. /// offset to the host graphic element.
  200. /// ||距离图形元素的偏移
  201. /// </summary>
  202. public Vector3 offset
  203. {
  204. get { return m_Offset; }
  205. set { if (PropertyUtil.SetStruct(ref m_Offset, value)) SetAllDirty(); }
  206. }
  207. /// <summary>
  208. /// Rotation of label.
  209. /// ||文本的旋转。
  210. /// </summary>
  211. public float rotate
  212. {
  213. get { return m_Rotate; }
  214. set { if (PropertyUtil.SetStruct(ref m_Rotate, value)) SetComponentDirty(); }
  215. }
  216. /// <summary>
  217. /// auto rotate of label.
  218. /// ||是否自动旋转。
  219. /// </summary>
  220. public bool autoRotate
  221. {
  222. get { return m_AutoRotate; }
  223. set { if (PropertyUtil.SetStruct(ref m_AutoRotate, value)) SetComponentDirty(); }
  224. }
  225. /// <summary>
  226. /// the distance of label to axis line.
  227. /// ||距离轴线的距离。
  228. /// </summary>
  229. public float distance
  230. {
  231. get { return m_Distance; }
  232. set { if (PropertyUtil.SetStruct(ref m_Distance, value)) SetAllDirty(); }
  233. }
  234. /// <summary>
  235. /// the width of label. If set as default value 0, it means than the label width auto set as the text width.
  236. /// ||标签的宽度。一般不用指定,不指定时则自动是文字的宽度。
  237. /// </summary>
  238. public float width
  239. {
  240. get { return m_Width; }
  241. set { if (PropertyUtil.SetStruct(ref m_Width, value)) SetComponentDirty(); }
  242. }
  243. /// <summary>
  244. /// the height of label. If set as default value 0, it means than the label height auto set as the text height.
  245. /// ||标签的高度。一般不用指定,不指定时则自动是文字的高度。
  246. /// </summary>
  247. public float height
  248. {
  249. get { return m_Height; }
  250. set { if (PropertyUtil.SetStruct(ref m_Height, value)) SetComponentDirty(); }
  251. }
  252. /// <summary>
  253. /// the text padding of label.
  254. /// ||文本的边距。
  255. /// </summary>
  256. public TextPadding textPadding
  257. {
  258. get { return m_TextPadding; }
  259. set { if (PropertyUtil.SetClass(ref m_TextPadding, value)) SetComponentDirty(); }
  260. }
  261. /// <summary>
  262. /// Whether to automatically offset. When turned on, the Y offset will automatically determine the opening of the curve to determine whether to offset up or down.
  263. /// ||是否开启自动偏移。当开启时,Y的偏移会自动判断曲线的开口来决定向上还是向下偏移。
  264. /// </summary>
  265. public bool autoOffset
  266. {
  267. get { return m_AutoOffset; }
  268. set { if (PropertyUtil.SetStruct(ref m_AutoOffset, value)) SetAllDirty(); }
  269. }
  270. /// <summary>
  271. /// the sytle of background.
  272. /// ||背景图样式。
  273. /// </summary>
  274. public ImageStyle background
  275. {
  276. get { return m_Background; }
  277. set { if (PropertyUtil.SetClass(ref m_Background, value)) SetAllDirty(); }
  278. }
  279. /// <summary>
  280. /// the sytle of icon.
  281. /// ||图标样式。
  282. /// </summary>
  283. public IconStyle icon
  284. {
  285. get { return m_Icon; }
  286. set { if (PropertyUtil.SetClass(ref m_Icon, value)) SetAllDirty(); }
  287. }
  288. /// <summary>
  289. /// the sytle of text.
  290. /// ||文本样式。
  291. /// </summary>
  292. public TextStyle textStyle
  293. {
  294. get { return m_TextStyle; }
  295. set { if (PropertyUtil.SetClass(ref m_TextStyle, value)) SetAllDirty(); }
  296. }
  297. /// <summary>
  298. /// the formatter function of label, which supports string template and callback function.
  299. /// ||标签的文本格式化函数,支持字符串模版和回调函数。
  300. /// </summary>
  301. public LabelFormatterFunction formatterFunction
  302. {
  303. get { return m_FormatterFunction; }
  304. set { m_FormatterFunction = value; }
  305. }
  306. /// <summary>
  307. /// whether the label is inside.
  308. /// ||是否在内部。
  309. /// </summary>
  310. public bool IsInside()
  311. {
  312. return m_Position == Position.Inside || m_Position == Position.Center;
  313. }
  314. public bool IsDefaultPosition(Position position)
  315. {
  316. return m_Position == Position.Default || m_Position == position;
  317. }
  318. public bool IsAutoSize()
  319. {
  320. return width == 0 && height == 0;
  321. }
  322. public Vector3 GetOffset(float radius)
  323. {
  324. var x = ChartHelper.GetActualValue(m_Offset.x, radius);
  325. var y = ChartHelper.GetActualValue(m_Offset.y, radius);
  326. var z = ChartHelper.GetActualValue(m_Offset.z, radius);
  327. return new Vector3(x, y, z);
  328. }
  329. public Color GetColor(Color defaultColor)
  330. {
  331. if (ChartHelper.IsClearColor(textStyle.color))
  332. {
  333. return IsInside() ? Color.black : defaultColor;
  334. }
  335. else
  336. {
  337. return textStyle.color;
  338. }
  339. }
  340. public virtual LabelStyle Clone()
  341. {
  342. var label = new LabelStyle();
  343. label.m_Show = m_Show;
  344. label.m_Position = m_Position;
  345. label.m_Offset = m_Offset;
  346. label.m_Rotate = m_Rotate;
  347. label.m_Distance = m_Distance;
  348. label.m_Formatter = m_Formatter;
  349. label.m_Width = m_Width;
  350. label.m_Height = m_Height;
  351. label.m_NumericFormatter = m_NumericFormatter;
  352. label.m_AutoOffset = m_AutoOffset;
  353. label.m_Icon.Copy(m_Icon);
  354. label.m_Background.Copy(m_Background);
  355. label.m_TextPadding = m_TextPadding;
  356. label.m_TextStyle.Copy(m_TextStyle);
  357. return label;
  358. }
  359. public virtual void Copy(LabelStyle label)
  360. {
  361. m_Show = label.m_Show;
  362. m_Position = label.m_Position;
  363. m_Offset = label.m_Offset;
  364. m_Rotate = label.m_Rotate;
  365. m_Distance = label.m_Distance;
  366. m_Formatter = label.m_Formatter;
  367. m_Width = label.m_Width;
  368. m_Height = label.m_Height;
  369. m_NumericFormatter = label.m_NumericFormatter;
  370. m_AutoOffset = label.m_AutoOffset;
  371. m_Icon.Copy(label.m_Icon);
  372. m_Background.Copy(label.m_Background);
  373. m_TextPadding = label.m_TextPadding;
  374. m_TextStyle.Copy(label.m_TextStyle);
  375. }
  376. public virtual string GetFormatterContent(int labelIndex, string category)
  377. {
  378. if (string.IsNullOrEmpty(category))
  379. return GetFormatterFunctionContent(labelIndex, category, category);
  380. if (string.IsNullOrEmpty(m_Formatter))
  381. {
  382. return GetFormatterFunctionContent(labelIndex, category, category);
  383. }
  384. else
  385. {
  386. var content = m_Formatter;
  387. FormatterHelper.ReplaceAxisLabelContent(ref content, category);
  388. return GetFormatterFunctionContent(labelIndex, category, category);
  389. }
  390. }
  391. public virtual string GetFormatterContent(int labelIndex, double value, double minValue, double maxValue, bool isLog = false)
  392. {
  393. var newNumericFormatter = numericFormatter;
  394. if (value == 0)
  395. {
  396. newNumericFormatter = "f0";
  397. }
  398. else if (string.IsNullOrEmpty(newNumericFormatter) && !isLog)
  399. {
  400. if (Math.Abs(maxValue) >= Math.Abs(minValue))
  401. {
  402. newNumericFormatter = MathUtil.IsInteger(maxValue) ? "0.#" : "f" + MathUtil.GetPrecision(maxValue);
  403. }
  404. else
  405. {
  406. newNumericFormatter = MathUtil.IsInteger(minValue) ? "0.#" : "f" + MathUtil.GetPrecision(minValue);
  407. }
  408. }
  409. if (string.IsNullOrEmpty(m_Formatter))
  410. {
  411. if (isLog)
  412. {
  413. return GetFormatterFunctionContent(labelIndex, value, ChartCached.NumberToStr(value, newNumericFormatter));
  414. }
  415. if (minValue >= -1 && minValue <= 1 && maxValue >= -1 && maxValue <= 1)
  416. {
  417. int minAcc = MathUtil.GetPrecision(minValue);
  418. int maxAcc = MathUtil.GetPrecision(maxValue);
  419. int curAcc = MathUtil.GetPrecision(value);
  420. int acc = Mathf.Max(Mathf.Max(minAcc, maxAcc), curAcc);
  421. return GetFormatterFunctionContent(labelIndex, value, ChartCached.FloatToStr(value, newNumericFormatter, acc));
  422. }
  423. return GetFormatterFunctionContent(labelIndex, value, ChartCached.NumberToStr(value, newNumericFormatter));
  424. }
  425. else
  426. {
  427. var content = m_Formatter;
  428. FormatterHelper.ReplaceAxisLabelContent(ref content, newNumericFormatter, value);
  429. return GetFormatterFunctionContent(labelIndex, value, content);
  430. }
  431. }
  432. public string GetFormatterDateTime(int labelIndex, double value, double minValue, double maxValue)
  433. {
  434. var timestamp = (int)value;
  435. var dateTime = DateTimeUtil.GetDateTime(timestamp);
  436. var dateString = string.Empty;
  437. if (string.IsNullOrEmpty(numericFormatter) || numericFormatter.Equals("f2"))
  438. {
  439. dateString = DateTimeUtil.GetDateTimeFormatString(dateTime, maxValue - minValue);
  440. }
  441. else
  442. {
  443. try
  444. {
  445. dateString = dateTime.ToString(numericFormatter);
  446. }
  447. catch
  448. {
  449. XLog.Warning("not support datetime formatter:" + numericFormatter);
  450. }
  451. }
  452. if (!string.IsNullOrEmpty(m_Formatter))
  453. {
  454. var content = m_Formatter;
  455. FormatterHelper.ReplaceAxisLabelContent(ref content, dateString);
  456. return GetFormatterFunctionContent(labelIndex, value, content);
  457. }
  458. else
  459. {
  460. return GetFormatterFunctionContent(labelIndex, value, dateString);
  461. }
  462. }
  463. protected string GetFormatterFunctionContent(int labelIndex, string category, string currentContent)
  464. {
  465. return m_FormatterFunction == null ? currentContent :
  466. m_FormatterFunction(labelIndex, labelIndex, category, currentContent);
  467. }
  468. protected string GetFormatterFunctionContent(int labelIndex, double value, string currentContent)
  469. {
  470. return m_FormatterFunction == null ? currentContent :
  471. m_FormatterFunction(labelIndex, value, null, currentContent);
  472. }
  473. }
  474. }