using System; using UnityEngine; namespace XCharts.Runtime { /// /// Text label of chart, to explain some data information about graphic item like value, name and so on. /// ||图形上的文本标签,可用于说明图形的一些数据信息,比如值,名称等。 /// [System.Serializable] public class LabelStyle : ChildComponent, ISerieComponent, ISerieDataComponent { /// /// The position of label. /// ||标签的位置。 /// public enum Position { Default, /// /// Outside of sectors of pie chart, which relates to corresponding sector through visual guide line. /// ||饼图扇区外侧,通过视觉引导线连到相应的扇区。 /// Outside, /// /// Inside the sectors of pie chart. /// ||饼图扇区内部。 /// Inside, /// /// In the center of pie chart. /// ||在饼图中心位置。 /// Center, /// /// top of symbol. /// ||图形标志的顶部。 /// Top, /// /// the bottom of symbol. /// ||图形标志的底部。 /// Bottom, /// /// the left of symbol. /// ||图形标志的左边。 /// Left, /// /// the right of symbol. /// ||图形标志的右边。 /// Right, /// /// the start of line. /// ||线的起始点。 /// Start, /// /// the middle of line. /// ||线的中点。 /// Middle, /// /// the end of line. /// ||线的结束点。 /// End } [SerializeField] protected bool m_Show = true; [SerializeField] Position m_Position = Position.Default; [SerializeField] protected bool m_AutoOffset = false; [SerializeField] protected Vector3 m_Offset; [SerializeField] protected float m_Rotate; [SerializeField][Since("v3.6.0")] protected bool m_AutoRotate = false; [SerializeField] protected float m_Distance; [SerializeField] protected string m_Formatter; [SerializeField] protected string m_NumericFormatter = ""; [SerializeField] protected float m_Width = 0; [SerializeField] protected float m_Height = 0; [SerializeField] protected IconStyle m_Icon = new IconStyle(); [SerializeField] protected ImageStyle m_Background = new ImageStyle(); [SerializeField] protected TextPadding m_TextPadding = new TextPadding(); [SerializeField] protected TextStyle m_TextStyle = new TextStyle(); protected LabelFormatterFunction m_FormatterFunction; public void Reset() { m_Show = false; m_Position = Position.Default; m_Offset = Vector3.zero; m_Distance = 0; m_Rotate = 0; m_Width = 0; m_Height = 0; m_NumericFormatter = ""; m_AutoOffset = false; } /// /// Whether the label is showed. /// ||是否显示文本标签。 /// public bool show { get { return m_Show; } set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetAllDirty(); } } /// /// The position of label. /// ||标签的位置。 /// public Position position { get { return m_Position; } set { if (PropertyUtil.SetStruct(ref m_Position, value)) SetAllDirty(); } } /// /// label content string template formatter. \n line wrapping is supported. Formatters for some components will not take effect.
/// Template placeholder have the following, some of which apply only to fixed components:
/// `{.}` : indicates the dot mark.
/// `{a}` : indicates the series name.
/// `{b}` : category value of x axis or data name.
/// `{c}` : data value.
/// `{d}` : percentage.
/// `{e}` : indicates the data name.
/// `{f}` : data sum.
/// `{g}` : indicates the total number of data.
/// `{h}` : hexadecimal color value.
/// `{y}` : category value of y axis.
/// `{value}` : The value of the axis or legend.
/// The following placeholder apply to `UITable` components:
/// `{name}` : indicates the row name of the table.
/// `{index}` : indicates the row number of the table.
/// The following placeholder apply to `UIStatistc` components:
/// `{title}` : title text.
/// `{dd}` : day.
/// `{hh}` : hours.
/// `{mm}` : minutes.
/// `{ss}` : second.
/// `{fff}` : milliseconds.
/// `{d}` : day.
/// `{h}` : hours.
/// `{m}` : minutes.
/// `{s}` : second.
/// `{f}` : milliseconds.
/// Example :{b}:{c}
/// ||标签内容字符串模版格式器。支持用 \n 换行。部分组件的格式器会不生效。
/// 模板通配符有以下这些,部分只适用于固定的组件:
/// `{.}`:圆点标记。
/// `{a}`:系列名。
/// `{b}`:X轴类目名或数据名。
/// `{c}`:数据值。
/// `{d}`:百分比。
/// `{e}`:数据名。
/// `{f}`:数据和。
/// `{g}`:数据总个数。
/// `{h}`:十六进制颜色值。
/// `{y}`:Y轴的类目名。
/// `{value}`:坐标轴或图例的值。
/// 以下通配符适用UITable组件:
/// `{name}`: 表格的行名。
/// `{index}`:表格的行号。
/// 以下通配符适用UIStatistc组件:
/// `{title}`:标题文本。
/// `{dd}`:天。
/// `{hh}`:小时。
/// `{mm}`:分钟。
/// `{ss}`:秒。
/// `{fff}`:毫秒。
/// `{d}`:天。
/// `{h}`:小时。
/// `{m}`:分钟。
/// `{s}`:秒。
/// `{f}`:毫秒。
/// 示例:“{b}:{c}” ///
public string formatter { get { return m_Formatter; } set { if (PropertyUtil.SetClass(ref m_Formatter, value)) SetComponentDirty(); } } /// /// 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()`.
/// 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
/// 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
/// number format reference: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings
/// date format reference: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings
/// ||标准数字和日期格式字符串。用于将Double数值或DateTime日期格式化显示为字符串。numericFormatter用来作为Double.ToString()或DateTime.ToString()的参数。
/// 数字格式使用Axx的形式:A是格式说明符的单字符,支持C货币、D十进制、E指数、F定点数、G常规、N数字、P百分比、R往返、X十六进制的。xx是精度说明,从0-99。如:F1, E2
/// 日期格式常见的格式:yyyy年,MM月,dd日,HH时,mm分,ss秒,fff毫秒。如:yyyy-MM-dd HH:mm:ss
/// 数值格式化参考:https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/standard-numeric-format-strings
/// 日期格式化参考:https://learn.microsoft.com/zh-cn/dotnet/standard/base-types/standard-date-and-time-format-strings ///
public string numericFormatter { get { return m_NumericFormatter; } set { if (PropertyUtil.SetClass(ref m_NumericFormatter, value)) SetComponentDirty(); } } /// /// offset to the host graphic element. /// ||距离图形元素的偏移 /// public Vector3 offset { get { return m_Offset; } set { if (PropertyUtil.SetStruct(ref m_Offset, value)) SetAllDirty(); } } /// /// Rotation of label. /// ||文本的旋转。 /// public float rotate { get { return m_Rotate; } set { if (PropertyUtil.SetStruct(ref m_Rotate, value)) SetComponentDirty(); } } /// /// auto rotate of label. /// ||是否自动旋转。 /// public bool autoRotate { get { return m_AutoRotate; } set { if (PropertyUtil.SetStruct(ref m_AutoRotate, value)) SetComponentDirty(); } } /// /// the distance of label to axis line. /// ||距离轴线的距离。 /// public float distance { get { return m_Distance; } set { if (PropertyUtil.SetStruct(ref m_Distance, value)) SetAllDirty(); } } /// /// the width of label. If set as default value 0, it means than the label width auto set as the text width. /// ||标签的宽度。一般不用指定,不指定时则自动是文字的宽度。 /// public float width { get { return m_Width; } set { if (PropertyUtil.SetStruct(ref m_Width, value)) SetComponentDirty(); } } /// /// the height of label. If set as default value 0, it means than the label height auto set as the text height. /// ||标签的高度。一般不用指定,不指定时则自动是文字的高度。 /// public float height { get { return m_Height; } set { if (PropertyUtil.SetStruct(ref m_Height, value)) SetComponentDirty(); } } /// /// the text padding of label. /// ||文本的边距。 /// public TextPadding textPadding { get { return m_TextPadding; } set { if (PropertyUtil.SetClass(ref m_TextPadding, value)) SetComponentDirty(); } } /// /// 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. /// ||是否开启自动偏移。当开启时,Y的偏移会自动判断曲线的开口来决定向上还是向下偏移。 /// public bool autoOffset { get { return m_AutoOffset; } set { if (PropertyUtil.SetStruct(ref m_AutoOffset, value)) SetAllDirty(); } } /// /// the sytle of background. /// ||背景图样式。 /// public ImageStyle background { get { return m_Background; } set { if (PropertyUtil.SetClass(ref m_Background, value)) SetAllDirty(); } } /// /// the sytle of icon. /// ||图标样式。 /// public IconStyle icon { get { return m_Icon; } set { if (PropertyUtil.SetClass(ref m_Icon, value)) SetAllDirty(); } } /// /// the sytle of text. /// ||文本样式。 /// public TextStyle textStyle { get { return m_TextStyle; } set { if (PropertyUtil.SetClass(ref m_TextStyle, value)) SetAllDirty(); } } /// /// the formatter function of label, which supports string template and callback function. /// ||标签的文本格式化函数,支持字符串模版和回调函数。 /// public LabelFormatterFunction formatterFunction { get { return m_FormatterFunction; } set { m_FormatterFunction = value; } } /// /// whether the label is inside. /// ||是否在内部。 /// public bool IsInside() { return m_Position == Position.Inside || m_Position == Position.Center; } public bool IsDefaultPosition(Position position) { return m_Position == Position.Default || m_Position == position; } public bool IsAutoSize() { return width == 0 && height == 0; } public Vector3 GetOffset(float radius) { var x = ChartHelper.GetActualValue(m_Offset.x, radius); var y = ChartHelper.GetActualValue(m_Offset.y, radius); var z = ChartHelper.GetActualValue(m_Offset.z, radius); return new Vector3(x, y, z); } public Color GetColor(Color defaultColor) { if (ChartHelper.IsClearColor(textStyle.color)) { return IsInside() ? Color.black : defaultColor; } else { return textStyle.color; } } public virtual LabelStyle Clone() { var label = new LabelStyle(); label.m_Show = m_Show; label.m_Position = m_Position; label.m_Offset = m_Offset; label.m_Rotate = m_Rotate; label.m_Distance = m_Distance; label.m_Formatter = m_Formatter; label.m_Width = m_Width; label.m_Height = m_Height; label.m_NumericFormatter = m_NumericFormatter; label.m_AutoOffset = m_AutoOffset; label.m_Icon.Copy(m_Icon); label.m_Background.Copy(m_Background); label.m_TextPadding = m_TextPadding; label.m_TextStyle.Copy(m_TextStyle); return label; } public virtual void Copy(LabelStyle label) { m_Show = label.m_Show; m_Position = label.m_Position; m_Offset = label.m_Offset; m_Rotate = label.m_Rotate; m_Distance = label.m_Distance; m_Formatter = label.m_Formatter; m_Width = label.m_Width; m_Height = label.m_Height; m_NumericFormatter = label.m_NumericFormatter; m_AutoOffset = label.m_AutoOffset; m_Icon.Copy(label.m_Icon); m_Background.Copy(label.m_Background); m_TextPadding = label.m_TextPadding; m_TextStyle.Copy(label.m_TextStyle); } public virtual string GetFormatterContent(int labelIndex, string category) { if (string.IsNullOrEmpty(category)) return GetFormatterFunctionContent(labelIndex, category, category); if (string.IsNullOrEmpty(m_Formatter)) { return GetFormatterFunctionContent(labelIndex, category, category); } else { var content = m_Formatter; FormatterHelper.ReplaceAxisLabelContent(ref content, category); return GetFormatterFunctionContent(labelIndex, category, category); } } public virtual string GetFormatterContent(int labelIndex, double value, double minValue, double maxValue, bool isLog = false) { var newNumericFormatter = numericFormatter; if (value == 0) { newNumericFormatter = "f0"; } else if (string.IsNullOrEmpty(newNumericFormatter) && !isLog) { if (Math.Abs(maxValue) >= Math.Abs(minValue)) { newNumericFormatter = MathUtil.IsInteger(maxValue) ? "0.#" : "f" + MathUtil.GetPrecision(maxValue); } else { newNumericFormatter = MathUtil.IsInteger(minValue) ? "0.#" : "f" + MathUtil.GetPrecision(minValue); } } if (string.IsNullOrEmpty(m_Formatter)) { if (isLog) { return GetFormatterFunctionContent(labelIndex, value, ChartCached.NumberToStr(value, newNumericFormatter)); } if (minValue >= -1 && minValue <= 1 && maxValue >= -1 && maxValue <= 1) { int minAcc = MathUtil.GetPrecision(minValue); int maxAcc = MathUtil.GetPrecision(maxValue); int curAcc = MathUtil.GetPrecision(value); int acc = Mathf.Max(Mathf.Max(minAcc, maxAcc), curAcc); return GetFormatterFunctionContent(labelIndex, value, ChartCached.FloatToStr(value, newNumericFormatter, acc)); } return GetFormatterFunctionContent(labelIndex, value, ChartCached.NumberToStr(value, newNumericFormatter)); } else { var content = m_Formatter; FormatterHelper.ReplaceAxisLabelContent(ref content, newNumericFormatter, value); return GetFormatterFunctionContent(labelIndex, value, content); } } public string GetFormatterDateTime(int labelIndex, double value, double minValue, double maxValue) { var timestamp = (int)value; var dateTime = DateTimeUtil.GetDateTime(timestamp); var dateString = string.Empty; if (string.IsNullOrEmpty(numericFormatter) || numericFormatter.Equals("f2")) { dateString = DateTimeUtil.GetDateTimeFormatString(dateTime, maxValue - minValue); } else { try { dateString = dateTime.ToString(numericFormatter); } catch { XLog.Warning("not support datetime formatter:" + numericFormatter); } } if (!string.IsNullOrEmpty(m_Formatter)) { var content = m_Formatter; FormatterHelper.ReplaceAxisLabelContent(ref content, dateString); return GetFormatterFunctionContent(labelIndex, value, content); } else { return GetFormatterFunctionContent(labelIndex, value, dateString); } } protected string GetFormatterFunctionContent(int labelIndex, string category, string currentContent) { return m_FormatterFunction == null ? currentContent : m_FormatterFunction(labelIndex, labelIndex, category, currentContent); } protected string GetFormatterFunctionContent(int labelIndex, double value, string currentContent) { return m_FormatterFunction == null ? currentContent : m_FormatterFunction(labelIndex, value, null, currentContent); } } }