UI update 02

This commit is contained in:
2026-06-30 21:21:30 +08:00
parent b2a1e307a4
commit f62f643cfc
1666 changed files with 211081 additions and 22799 deletions
@@ -0,0 +1,646 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace XCharts.Runtime
{
/// <summary>
/// Tooltip component.
/// ||提示框组件。
/// </summary>
[System.Serializable]
[ComponentHandler(typeof(TooltipHandler), true)]
public class Tooltip : MainComponent
{
/// <summary>
/// Indicator type.
/// ||指示器类型。
/// </summary>
public enum Type
{
/// <summary>
/// line indicator.
/// ||直线指示器
/// </summary>
Line,
/// <summary>
/// shadow crosshair indicator.
/// ||阴影指示器
/// </summary>
Shadow,
/// <summary>
/// no indicator displayed.
/// ||无指示器
/// </summary>
None,
/// <summary>
/// crosshair indicator, which is actually the shortcut of enable two axisPointers of two orthometric axes.
/// ||十字准星指示器。坐标轴显示Label和交叉线。
/// </summary>
Cross,
/// <summary>
/// Auto select indicator according to serie type.
/// ||根据serie的类型自动选择显示指示器。
/// </summary>
Auto
}
/// <summary>
/// Trigger strategy.
/// ||触发类型。
/// </summary>
public enum Trigger
{
/// <summary>
/// Triggered by data item, which is mainly used for charts that don't have a category axis like scatter charts or pie charts.
/// ||数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用。
/// </summary>
Item,
/// <summary>
/// Triggered by axes, which is mainly used for charts that have category axes, like bar charts or line charts.
/// ||坐标轴触发,主要在柱状图,折线图等会使用类目轴的图表中使用。
/// </summary>
Axis,
/// <summary>
/// Trigger nothing.
/// ||什么都不触发。
/// </summary>
None,
/// <summary>
/// Auto select trigger according to serie type.
/// ||根据serie的类型自动选择触发类型。
/// </summary>
Auto
}
/// <summary>
/// the condition of trigger tooltip.
/// ||触发条件。
/// </summary>
public enum TriggerOn
{
/// <summary>
/// Trigger when mouse move.
/// ||鼠标移动时触发。
/// </summary>
MouseMove,
/// <summary>
/// Trigger when mouse click.
/// ||鼠标点击时触发。
/// </summary>
Click,
}
/// <summary>
/// Position type.
/// ||坐标类型。
/// </summary>
public enum Position
{
/// <summary>
/// Auto. The mobile platform is displayed at the top, and the non-mobile platform follows the mouse position.
/// ||自适应。移动平台靠顶部显示,非移动平台跟随鼠标位置。
/// </summary>
Auto,
/// <summary>
/// Custom. Fully customize display position (x,y).
/// ||自定义。完全自定义显示位置(x,y)。
/// </summary>
Custom,
/// <summary>
/// Just fix the coordinate X. Y follows the mouse position.
/// ||只固定坐标X。Y跟随鼠标位置。
/// </summary>
FixedX,
/// <summary>
/// Just fix the coordinate Y. X follows the mouse position.
/// ||只固定坐标Y。X跟随鼠标位置。
FixedY
}
[SerializeField] private bool m_Show = true;
[SerializeField] private Type m_Type = Type.Auto;
[SerializeField] private Trigger m_Trigger = Trigger.Auto;
[SerializeField][Since("v3.11.0")] private TriggerOn m_TriggerOn = TriggerOn.MouseMove;
[SerializeField][Since("v3.3.0")] private Position m_Position = Position.Auto;
[SerializeField] private string m_ItemFormatter;
[SerializeField] private string m_TitleFormatter;
[SerializeField] private string m_Marker = "●";
[SerializeField] private float m_FixedWidth = 0;
[SerializeField] private float m_FixedHeight = 0;
[SerializeField] private float m_MinWidth = 0;
[SerializeField] private float m_MinHeight = 0;
[SerializeField] private string m_NumericFormatter = "";
[SerializeField] private int m_PaddingLeftRight = 10;
[SerializeField] private int m_PaddingTopBottom = 10;
[SerializeField] private bool m_IgnoreDataShow = false;
[SerializeField] private string m_IgnoreDataDefaultContent = "-";
[SerializeField] private bool m_ShowContent = true;
[SerializeField] private bool m_AlwayShowContent = false;
[SerializeField] private Vector2 m_Offset = new Vector2(18f, -25f);
[SerializeField] private Sprite m_BackgroundImage;
[SerializeField] private Image.Type m_BackgroundType = Image.Type.Simple;
[SerializeField] private Color m_BackgroundColor;
[SerializeField] private float m_BorderWidth = 2f;
[SerializeField] private float m_FixedX = 0f;
[SerializeField] private float m_FixedY = 0.7f;
[SerializeField] private float m_TitleHeight = 25f;
[SerializeField] private float m_ItemHeight = 25f;
[SerializeField] private Color32 m_BorderColor = new Color32(230, 230, 230, 255);
[SerializeField][Since("v3.14.0")] private List<float> m_ColumnGapWidths = new List<float>{15};
[SerializeField] private LineStyle m_LineStyle = new LineStyle(LineStyle.Type.None);
[SerializeField]
private LabelStyle m_TitleLabelStyle = new LabelStyle()
{
textStyle = new TextStyle() { alignment = TextAnchor.MiddleLeft }
};
[SerializeField]
private List<LabelStyle> m_ContentLabelStyles = new List<LabelStyle>()
{
new LabelStyle() { textPadding = new TextPadding(0, 5, 0, 0), textStyle = new TextStyle() { alignment = TextAnchor.MiddleCenter } },
new LabelStyle() { textPadding = new TextPadding(0, 20, 0, 0), textStyle = new TextStyle() { alignment = TextAnchor.MiddleLeft } },
new LabelStyle() { textPadding = new TextPadding(0, 0, 0, 0), textStyle = new TextStyle() { alignment = TextAnchor.MiddleRight } }
};
public TooltipContext context = new TooltipContext();
public TooltipView view;
/// <summary>
/// the callback of tooltip click index.
/// ||Tooltip为Click触发时,点击的X轴索引的回调。
/// </summary>
public System.Action<int> onClickIndex { get; set; }
/// <summary>
/// Whether to show the tooltip component.
/// ||是否显示提示框组件。
/// </summary>
public bool show
{
get { return m_Show; }
set { if (PropertyUtil.SetStruct(ref m_Show, value)) { SetAllDirty(); SetActive(value); } }
}
/// <summary>
/// Indicator type.
/// ||提示框指示器类型。
/// </summary>
public Type type
{
get { return m_Type; }
set { if (PropertyUtil.SetStruct(ref m_Type, value)) SetAllDirty(); }
}
/// <summary>
/// Type of triggering.
/// ||触发类型。
/// </summary>
public Trigger trigger
{
get { return m_Trigger; }
set { if (PropertyUtil.SetStruct(ref m_Trigger, value)) SetAllDirty(); }
}
/// <summary>
/// Condition of trigger tooltip.
/// ||触发条件。
/// </summary>
public TriggerOn triggerOn
{
get { return m_TriggerOn; }
set { if (PropertyUtil.SetStruct(ref m_TriggerOn, value)) SetAllDirty(); }
}
/// <summary>
/// Type of position.
/// ||显示位置类型。
/// </summary>
public Position position
{
get { return m_Position; }
set { if (PropertyUtil.SetStruct(ref m_Position, value)) SetAllDirty(); }
}
/// <summary>
/// String template formatter for tooltip title content. \n line wrapping is supported. The placeholder {i} can be set separately to indicate that title is ignored and not displayed.
/// Template variables are {.}, {a}, {b}, {c}, {d}, {e}, {f}, and {g}. <br />
/// {.} is the dot of the corresponding color of serie currently indicated or index 0. <br />
/// {a} is the series name name of serie currently indicated or index 0. <br />
/// {b} is the name of the serie data item serieData currently indicated or index 0, or the category value (such as the X-axis of a line chart). <br />
/// {c} is the value of the serie y-dimension (dimesion is 1) currently indicated or index is 0. <br />
/// {d} is the serie y-dimensional (dimesion 1) percentage value of the currently indicated or index 0, note without the % sign. <br />
/// {e} is the name of the serie data item serieData currently indicated or whose index is 0. <br />
/// {h} is the hexadecimal color value of serieData for the serie data item currently indicated or index 0. <br />
/// {f} is the sum of data. <br />
/// {g} indicates the total number of data. <br />
/// {y} is category value of y axis. <br />
/// {.1} represents a dot of the corresponding color with serie specified as index 1. <br />
/// The 1 in {a1}, {b1}, {c1} represents serie where index is specified as 1. <br />
/// {c1:2} represents the third data of the current indicator data item in serie with index 1 (one data item has multiple data, index 2 represents the third data). <br />
/// {c1:2-2} represents the third data of serie third data item with index 1 (that is, the number of data items must be specified when specifying the number of data items). <br />
/// {d1:2:f2} indicates that a format string with a single value is f2 (numericFormatter is used if no value is specified). <br />
/// {d:0.##} indicates that the format string with a value specified alone is 0.## # (for percentages, preserving a 2-digit significant number while avoiding the "100.00%" situation with f2). <br />
/// example: "{a}, {c}", "{a1}, {c1: f1}", "{a1}, {c1:0: f1}", "{a1}, {c1:1-1: f1}"
/// ||提示框标题内容的字符串模版格式器。支持用 \n 换行。可以单独设置占位符{i}表示忽略不显示title。
/// 模板变量有{.}、{a}、{b}、{c}、{d}、{e}、{f}、{g}。<br/>
/// {.}为当前所指示或index为0的serie的对应颜色的圆点。<br/>
/// {a}为当前所指示或index为0的serie的系列名name。<br/>
/// {b}为当前所指示或index为0的serie的数据项serieData的name,或者类目值(如折线图的X轴)。<br/>
/// {c}为当前所指示或index为0的serie的y维(dimesion为1)的数值。<br/>
/// {d}为当前所指示或index为0的serie的y维(dimesion为1)百分比值,注意不带%号。<br/>
/// {e}为当前所指示或index为0的serie的数据项serieData的name。<br/>
/// {h}为当前所指示或index为0的serie的数据项serieData的十六进制颜色值。<br/>
/// {f}为数据总和。<br/>
/// {g}为数据总个数。<br/>
/// {y}为value所对应的y轴的类目值。<br/>
/// {.1}表示指定index为1的serie对应颜色的圆点。<br/>
/// {a1}、{b1}、{c1}中的1表示指定index为1的serie。<br/>
/// {c1:2}表示索引为1的serie的当前指示数据项的第3个数据(一个数据项有多个数据,index为2表示第3个数据)。<br/>
/// {c1:2-2}表示索引为1的serie的第3个数据项的第3个数据(也就是要指定第几个数据项时必须要指定第几个数据)。<br/>
/// {d1:2:f2}表示单独指定了数值的格式化字符串为f2(不指定时用numericFormatter)。<br/>
/// {d:0.##} 表示单独指定了数值的格式化字符串为 0.## (用于百分比,保留2位有效数同时又能避免使用 f2 而出现的类似于"100.00%"的情况 )。<br/>
/// 示例:"{a}:{c}"、"{a1}:{c1:f1}"、"{a1}:{c1:0:f1}"、"{a1}:{c1:1-1:f1}"
/// </summary>
public string titleFormatter { get { return m_TitleFormatter; } set { m_TitleFormatter = value; } }
/// <summary>
/// a string template formatter for a single Serie or data item content. Support for wrapping lines with \n.
/// Template variables are {.}, {a}, {b}, {c}, {d}.<br/>
/// {.} is the dot of the corresponding color of a Serie that is currently indicated or whose index is 0.<br/>
/// {a} is the series name of the serie that is currently indicated or whose index is 0.<br/>
/// {b} is the name of the data item serieData that is currently indicated or whose index is 0, or a category value (such as the X-axis of a line chart).<br/>
/// {c} is the value of a Y-dimension (dimesion is 1) from a Serie that is currently indicated or whose index is 0.<br/>
/// {d} is the percentage value of Y-dimensions (dimesion is 1) from serie that is currently indicated or whose index is 0, with no % sign.<br/>
/// {e} is the name of the data item serieData that is currently indicated or whose index is 0.<br/>
/// {f} is sum of data.<br/>
/// {y} is category value of y axis.<br/>
/// {.1} represents a dot from serie corresponding color that specifies index as 1.<br/>
/// 1 in {a1}, {b1}, {c1} represents a serie that specifies an index of 1.<br/>
/// {c1:2} represents the third data from serie's current indication data item indexed to 1 (a data item has multiple data, index 2 represents the third data).<br/>
/// {c1:2-2} represents the third data item from serie's third data item indexed to 1 (i.e., which data item must be specified to specify).<br/>
/// {d1:2: F2} indicates that a formatted string with a value specified separately is F2 (numericFormatter is used when numericFormatter is not specified).<br/>
/// {d:0.##} indicates that a formatted string with a value specified separately is 0.## (used for percentage, reserved 2 valid digits while avoiding the situation similar to "100.00%" when using f2 ).<br/>
/// Example: "{a}, {c}", "{a1}, {c1: f1}", "{a1}, {c1:0: f1}", "{a1} : {c1:1-1: f1}"<br/>
/// ||提示框单个serie或数据项内容的字符串模版格式器。支持用 \n 换行。用|来表示多个列的分隔。
/// 模板变量有{.}、{a}、{b}、{c}、{d}、{e}、{f}、{g}。<br/>
/// {i}或-表示忽略当前项。
/// {.}为当前所指示的serie或数据项的对应颜色的圆点。<br/>
/// {a}为当前所指示的serie或数据项的系列名name。<br/>
/// {b}为当前所指示的serie或数据项的数据项serieData的name,或者类目值(如折线图的X轴)。<br/>
/// {c}为当前所指示的serie或数据项的y维(dimesion为1)的数值。<br/>
/// {d}为当前所指示的serie或数据项的y维(dimesion为1)百分比值,注意不带%号。<br/>
/// {e}为当前所指示的serie或数据项的数据项serieData的name。<br/>
/// {f}为当前所指示的serie的默认维度的数据总和。<br/>
/// {g}为当前所指示的serie的数据总个数。<br/>
/// {h}为当前所指示的serie的十六进制颜色值。<br/>
/// {y}为当前所指示的serie的y轴的类目值。<br/>
/// {c0}表示当前数据项维度为0的数据。<br/>
/// {c1}表示当前数据项维度为1的数据。<br/>
/// {d3}表示维度3的数据的百分比。它的分母是默认维度(一般是1维度)数据。<br/>
/// |表示多个列的分隔。<br/>
/// 示例:"{i}", "{.}|{a}|{c}", "{.}|{b}|{c2:f2}", "{.}|{b}|{y}"
/// </summary>
public string itemFormatter { get { return m_ItemFormatter; } set { m_ItemFormatter = value; } }
/// <summary>
/// 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 />
/// 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 />
/// Date format: Starts with `date`, which is used to format DateTime. Common date formats are:
/// yyyy year, MM month, dd day, HH hour, mm minute, ss second, fff millisecond. For example: date:yyyy-MM-dd HH:mm:ss<br />
/// Time format: Starts with `time`, which is used to format TimeSpan. Common time formats are:
/// d day, HH hour, mm minute, ss second, fffffff fractional part.
/// Only the version of Unity2018 or later can support formatting, and the characters inside should be escaped.
/// For example: time:HH\:mm\:ss<br />
/// number format reference: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings<br/>
/// date format reference: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings<br/>
/// Note: The date and time formats are only supported by 'v3.12.0' or later.<br/>
/// ||标准数字和日期格式字符串。用于将Double数值或DateTime日期格式化显示为字符串。numericFormatter用来作为Double.ToString()或DateTime.ToString()的参数。<br/>
/// 数字格式使用Axx的形式:A是格式说明符的单字符,支持C货币、D十进制、E指数、F定点数、G常规、N数字、P百分比、R往返、X十六进制的。xx是精度说明,从0-99。如:F1, E2<br/>
/// 日期格式:以`date`开头,用来格式化DateTime,常见格式有:yyyy年,MM月,dd日,HH时,mm分,ss秒,fff毫秒。如:date:yyyy-MM-dd HH:mm:ss<br/>
/// 时间格式:以`time`开头,用来格式化TimeSpan,常见格式有:d日,HH时,mm分,ss秒,fffffff小数部分。
/// 需要Unity2018以上版本才支持格式化,并且里面的字符要转义。如:time:d\.HH\:mm\:ss<br/>
/// 数值格式化参考:https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/standard-numeric-format-strings <br/>
/// 日期格式化参考:https://learn.microsoft.com/zh-cn/dotnet/standard/base-types/standard-date-and-time-format-strings <br/>
/// 时间格式化参考:https://learn.microsoft.com/zh-cn/dotnet/standard/base-types/standard-timespan-format-strings <br/>
/// 注意:date和time格式需要`v3.12.0`以上版本才支持。
/// </summary>
public string numericFormatter
{
get { return m_NumericFormatter; }
set { if (PropertyUtil.SetClass(ref m_NumericFormatter, value)) SetComponentDirty(); }
}
/// <summary>
/// the marker of serie.
/// ||serie的符号标志。
/// </summary>
public string marker { get { return m_Marker; } set { m_Marker = value; } }
/// <summary>
/// Fixed width. Higher priority than minWidth.
/// ||固定宽度。比 minWidth 优先。
/// </summary>
public float fixedWidth { get { return m_FixedWidth; } set { m_FixedWidth = value; } }
/// <summary>
/// Fixed height. Higher priority than minHeight.
/// ||固定高度。比 minHeight 优先。
/// </summary>
public float fixedHeight { get { return m_FixedHeight; } set { m_FixedHeight = value; } }
/// <summary>
/// Minimum width. If fixedWidth has a value, get fixedWidth first.
/// ||最小宽度。如若 fixedWidth 设有值,优先取 fixedWidth。
/// </summary>
public float minWidth { get { return m_MinWidth; } set { m_MinWidth = value; } }
/// <summary>
/// Minimum height. If fixedHeight has a value, take priority over fixedHeight.
/// ||最小高度。如若 fixedHeight 设有值,优先取 fixedHeight。
/// </summary>
public float minHeight { get { return m_MinHeight; } set { m_MinHeight = value; } }
/// <summary>
/// the text padding of left and right. defaut:5.
/// ||左右边距。
/// </summary>
public int paddingLeftRight { get { return m_PaddingLeftRight; } set { m_PaddingLeftRight = value; } }
/// <summary>
/// the text padding of top and bottom. defaut:5.
/// ||上下边距。
/// </summary>
public int paddingTopBottom { get { return m_PaddingTopBottom; } set { m_PaddingTopBottom = value; } }
/// <summary>
/// Whether to show ignored data on tooltip.
/// ||是否显示忽略数据在tooltip上。
/// </summary>
public bool ignoreDataShow { get { return m_IgnoreDataShow; } set { m_IgnoreDataShow = value; } }
/// <summary>
/// The default display character information for ignored data.
/// ||被忽略数据的默认显示字符信息。如果设置为空,则表示完全不显示忽略数据。
/// </summary>
public string ignoreDataDefaultContent { get { return m_IgnoreDataDefaultContent; } set { m_IgnoreDataDefaultContent = value; } }
/// <summary>
/// The background image of tooltip.
/// ||提示框的背景图片。
/// </summary>
public Sprite backgroundImage { get { return m_BackgroundImage; } set { m_BackgroundImage = value; SetComponentDirty(); } }
/// <summary>
/// The background type of tooltip.
/// ||提示框的背景图片显示类型。
/// </summary>
public Image.Type backgroundType { get { return m_BackgroundType; } set { m_BackgroundType = value; SetComponentDirty(); } }
/// <summary>
/// The background color of tooltip.
/// ||提示框的背景颜色。
/// </summary>
public Color backgroundColor { get { return m_BackgroundColor; } set { m_BackgroundColor = value; SetComponentDirty(); } }
/// <summary>
/// Whether to trigger after always display.
/// ||是否触发后一直显示提示框浮层。
/// </summary>
public bool alwayShowContent { get { return m_AlwayShowContent; } set { m_AlwayShowContent = value; } }
/// <summary>
/// Whether to show the tooltip floating layer, whose default value is true.
/// It should be configurated to be false, if you only need tooltip to trigger the event or show the axisPointer without content.
/// ||是否显示提示框浮层,默认显示。只需tooltip触发事件或显示axisPointer而不需要显示内容时可配置该项为false。
/// </summary>
public bool showContent { get { return m_ShowContent; } set { m_ShowContent = value; } }
/// <summary>
/// The position offset of tooltip relative to the mouse position.
/// ||提示框相对于鼠标位置的偏移。
/// </summary>
public Vector2 offset { get { return m_Offset; } set { m_Offset = value; } }
/// <summary>
/// the width of tooltip border.
/// ||边框线宽。
/// </summary>
public float borderWidth
{
get { return m_BorderWidth; }
set { if (PropertyUtil.SetStruct(ref m_BorderWidth, value)) SetVerticesDirty(); }
}
/// <summary>
/// the color of tooltip border.
/// ||边框颜色。
/// </summary>
public Color32 borderColor
{
get { return m_BorderColor; }
set { if (PropertyUtil.SetColor(ref m_BorderColor, value)) SetVerticesDirty(); }
}
/// <summary>
/// the x positionn of fixedX.
/// ||固定X位置的坐标。
/// </summary>
public float fixedX
{
get { return m_FixedX; }
set { if (PropertyUtil.SetStruct(ref m_FixedX, value)) SetVerticesDirty(); }
}
/// <summary>
/// the y position of fixedY.
/// ||固定Y位置的坐标。
/// </summary>
public float fixedY
{
get { return m_FixedY; }
set { if (PropertyUtil.SetStruct(ref m_FixedY, value)) SetVerticesDirty(); }
}
/// <summary>
/// height of title text.
/// ||标题文本的高。
/// </summary>
public float titleHeight
{
get { return m_TitleHeight; }
set { if (PropertyUtil.SetStruct(ref m_TitleHeight, value)) SetComponentDirty(); }
}
/// <summary>
/// height of content text.
/// ||数据项文本的高。
/// </summary>
public float itemHeight
{
get { return m_ItemHeight; }
set { if (PropertyUtil.SetStruct(ref m_ItemHeight, value)) SetComponentDirty(); }
}
/// <summary>
/// the column gap width of content. When there is only one column, it only represents the gap width of the second column.
/// ||内容部分的列间距。当只有一列时,只表示第二列的间距。
/// </summary>
public List<float> columnGapWidths
{
get { return m_ColumnGapWidths; }
set { if (value != null) { m_ColumnGapWidths = value; SetComponentDirty(); } }
}
/// <summary>
/// the textstyle of title.
/// ||标题的文本样式。
/// </summary>
public LabelStyle titleLabelStyle
{
get { return m_TitleLabelStyle; }
set { if (value != null) { m_TitleLabelStyle = value; SetComponentDirty(); } }
}
/// <summary>
/// the column text style list of content. The first represents the text style of the first column, and so on.
/// ||内容部分的列文本样式列表。第一个表示第一列的文本样式,以此类推。
/// </summary>
public List<LabelStyle> contentLabelStyles
{
get { return m_ContentLabelStyles; }
set { if (value != null) { m_ContentLabelStyles = value; SetComponentDirty(); } }
}
/// <summary>
/// the line style of indicator line.
/// ||指示线样式。
/// </summary>
public LineStyle lineStyle
{
get { return m_LineStyle; }
set { if (value != null) m_LineStyle = value; SetComponentDirty(); }
}
/// <summary>
/// 组件是否需要刷新
/// </summary>
public override bool componentDirty
{
get { return m_ComponentDirty || lineStyle.componentDirty; }
}
public override void ClearComponentDirty()
{
base.ClearComponentDirty();
lineStyle.ClearComponentDirty();
}
/// <summary>
/// 当前提示框所指示的Serie索引(目前只对散点图有效)。
/// </summary>
public Dictionary<int, List<int>> runtimeSerieIndex = new Dictionary<int, List<int>>();
/// <summary>
/// The data index currently indicated by Tooltip.
/// ||当前提示框所指示的数据项索引。
/// </summary>
public List<int> runtimeDataIndex { get { return m_RuntimeDateIndex; } internal set { m_RuntimeDateIndex = value; } }
private List<int> m_RuntimeDateIndex = new List<int>() { -1, -1 };
/// <summary>
/// Keep Tooltiop displayed at the top.
/// ||保持Tooltiop显示在最顶上
/// </summary>
public void KeepTop()
{
gameObject.transform.SetAsLastSibling();
}
public override void ClearData()
{
ClearValue();
}
/// <summary>
/// 清除提示框指示数据
/// </summary>
internal void ClearValue()
{
for (int i = 0; i < runtimeDataIndex.Count; i++) runtimeDataIndex[i] = -1;
}
/// <summary>
/// 提示框是否显示
/// </summary>
/// <returns></returns>
public bool IsActive()
{
return gameObject != null && gameObject.activeInHierarchy;
}
/// <summary>
/// 设置Tooltip组件是否显示
/// </summary>
/// <param name="flag"></param>
public void SetActive(bool flag)
{
if (gameObject && gameObject.activeInHierarchy != flag)
{
gameObject.SetActive(alwayShowContent ? true : flag);
}
SetContentActive(flag);
}
/// <summary>
/// 设置文本框是否显示
/// </summary>
/// <param name="flag"></param>
public void SetContentActive(bool flag)
{
if (view == null)
return;
view.SetActive(alwayShowContent ? true : flag);
}
/// <summary>
/// 当前提示框是否选中数据项
/// </summary>
/// <returns></returns>
public bool IsSelected()
{
foreach (var index in runtimeDataIndex)
if (index >= 0) return true;
return false;
}
/// <summary>
/// 指定索引的数据项是否被提示框选中
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public bool IsSelected(int index)
{
foreach (var temp in runtimeDataIndex)
if (temp == index) return true;
return false;
}
public void ClearSerieDataIndex()
{
foreach (var kv in runtimeSerieIndex)
{
kv.Value.Clear();
}
}
public void AddSerieDataIndex(int serieIndex, int dataIndex)
{
if (!runtimeSerieIndex.ContainsKey(serieIndex))
{
runtimeSerieIndex[serieIndex] = new List<int>();
}
runtimeSerieIndex[serieIndex].Add(dataIndex);
}
public bool isAnySerieDataIndex()
{
foreach (var kv in runtimeSerieIndex)
{
if (kv.Value.Count > 0) return true;
}
return false;
}
public bool IsTriggerItem()
{
return trigger == Trigger.Auto ? context.trigger == Trigger.Item : trigger == Trigger.Item;
}
public bool IsTriggerAxis()
{
return trigger == Trigger.Auto ? context.trigger == Trigger.Axis : trigger == Trigger.Axis;
}
public LabelStyle GetContentLabelStyle(int index)
{
if (m_ContentLabelStyles.Count == 0)
return null;
if (index < 0)
index = 0;
else if (index > m_ContentLabelStyles.Count - 1)
index = m_ContentLabelStyles.Count - 1;
return m_ContentLabelStyles[index];
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dff3b0d6d38ee49838f054d30ab9b733
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts.Runtime
{
public class TooltipData
{
public string title;
public List<SerieParams> param = new List<SerieParams>();
}
public class TooltipContext
{
public Vector2 pointer;
public float width;
public float height;
public float angle;
public int xAxisClickIndex = -1;
public Tooltip.Type type;
public Tooltip.Trigger trigger;
public TooltipData data = new TooltipData();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7324ce36c9b2c475bb18abd6618b107c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,893 @@
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using XUGL;
namespace XCharts.Runtime
{
[UnityEngine.Scripting.Preserve]
internal sealed class TooltipHandler : MainComponentHandler<Tooltip>
{
private Dictionary<string, ChartLabel> m_IndicatorLabels = new Dictionary<string, ChartLabel>();
private GameObject m_LabelRoot;
private ISerieContainer m_PointerContainer;
public override void InitComponent()
{
InitTooltip(component);
}
public override void BeforceSerieUpdate()
{
UpdateTooltipData(component);
}
public override void Update()
{
UpdateTooltip(component);
UpdateTooltipIndicatorLabelText(component);
if (component.view != null)
component.view.Update();
}
public override void DrawUpper(VertexHelper vh)
{
DrawTooltipIndicator(vh, component);
}
public override void OnPointerExit(PointerEventData eventData)
{
base.OnPointerExit(eventData);
if (chart.isTriggerOnClick)
{
component.context.xAxisClickIndex = -1;
}
}
private void InitTooltip(Tooltip tooltip)
{
tooltip.painter = chart.m_PainterUpper;
tooltip.refreshComponent = delegate ()
{
var objName = ChartCached.GetComponentObjectName(tooltip);
tooltip.gameObject = ChartHelper.AddObject(objName, chart.transform, chart.chartMinAnchor,
chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta, -1, chart.childrenNodeNames);
var tooltipObject = tooltip.gameObject;
tooltipObject.transform.localPosition = Vector3.zero;
tooltipObject.hideFlags = chart.chartHideFlags;
var parent = tooltipObject.transform;
ChartHelper.HideAllObject(tooltipObject.transform);
tooltip.view = TooltipView.CreateView(tooltip, chart.theme, parent);
tooltip.SetActive(false);
m_LabelRoot = ChartHelper.AddObject("label", tooltip.gameObject.transform, chart.chartMinAnchor,
chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta);
m_LabelRoot.transform.SetSiblingIndex(0);
ChartHelper.HideAllObject(m_LabelRoot);
m_IndicatorLabels.Clear();
foreach (var com in chart.components)
{
if (com is Axis)
{
var axis = com as Axis;
var aligment = (com is AngleAxis) ? TextAnchor.MiddleCenter : axis.context.aligment;
var labelName = ChartCached.GetComponentObjectName(axis);
var item = ChartHelper.AddTooltipIndicatorLabel(component, labelName, m_LabelRoot.transform,
chart.theme, aligment, axis.indicatorLabel);
item.SetActive(false);
m_IndicatorLabels[labelName] = item;
}
}
chart.isTriggerOnClick = tooltip.triggerOn == Tooltip.TriggerOn.Click;
};
tooltip.refreshComponent();
}
private ChartLabel GetIndicatorLabel(Axis axis)
{
if (m_LabelRoot == null) return null;
var key = ChartCached.GetComponentObjectName(axis);
if (m_IndicatorLabels.ContainsKey(key))
{
return m_IndicatorLabels[key];
}
else
{
var item = ChartHelper.AddTooltipIndicatorLabel(component, key, m_LabelRoot.transform,
chart.theme, TextAnchor.MiddleCenter, axis.indicatorLabel);
m_IndicatorLabels[key] = item;
return item;
}
}
private void UpdateTooltipData(Tooltip tooltip)
{
m_ShowTooltip = false;
if (tooltip.trigger == Tooltip.Trigger.None) return;
chart.isTriggerOnClick = tooltip.triggerOn == Tooltip.TriggerOn.Click;
if ((tooltip.show && chart.isPointerInChart) &&
((tooltip.triggerOn == Tooltip.TriggerOn.Click && chart.isPointerClick) ||
(tooltip.triggerOn == Tooltip.TriggerOn.MouseMove))
)
{
for (int i = chart.series.Count - 1; i >= 0; i--)
{
var serie = chart.series[i];
if (!(serie is INeedSerieContainer))
{
m_ShowTooltip = true;
m_ContainerSeries = null;
return;
}
}
m_ContainerSeries = ListPool<Serie>.Get();
UpdatePointerContainerAndSeriesAndTooltip(tooltip, ref m_ContainerSeries);
if (m_ContainerSeries.Count > 0)
{
m_ShowTooltip = true;
return;
}
}
if (!m_ShowTooltip && tooltip.IsActive())
{
tooltip.ClearValue();
tooltip.SetActive(false);
component.context.xAxisClickIndex = -1;
chart.pointerClickEventData = null;
}
}
private bool m_ShowTooltip;
private List<Serie> m_ContainerSeries;
private void UpdateTooltip(Tooltip tooltip)
{
if (!m_ShowTooltip)
{
if (m_ContainerSeries != null)
{
ListPool<Serie>.Release(m_ContainerSeries);
m_ContainerSeries = null;
}
return;
}
var anyTrigger = false;
for (int i = chart.series.Count - 1; i >= 0; i--)
{
var serie = chart.series[i];
if (!(serie is INeedSerieContainer))
{
if (SetSerieTooltip(tooltip, serie))
{
anyTrigger = true;
chart.RefreshTopPainter();
break;
}
}
}
if (!anyTrigger && m_ContainerSeries == null)
{
m_ContainerSeries = ListPool<Serie>.Get();
UpdatePointerContainerAndSeriesAndTooltip(tooltip, ref m_ContainerSeries);
}
if (m_ContainerSeries != null)
{
if (!SetSerieTooltip(tooltip, m_ContainerSeries))
m_ShowTooltip = false;
else
anyTrigger = true;
ListPool<Serie>.Release(m_ContainerSeries);
m_ContainerSeries = null;
}
if (!m_ShowTooltip || !anyTrigger)
{
if (tooltip.context.type == Tooltip.Type.Cross && m_PointerContainer != null && m_PointerContainer.IsPointerEnter())
{
m_ShowTooltip = true;
tooltip.SetActive(true);
tooltip.SetContentActive(false);
}
else
{
m_ShowTooltip = false;
tooltip.SetActive(false);
chart.pointerClickEventData = null;
}
}
else
{
chart.RefreshUpperPainter();
}
}
private void UpdateTooltipIndicatorLabelText(Tooltip tooltip)
{
if (!tooltip.show) return;
if (tooltip.context.type == Tooltip.Type.None) return;
if (m_PointerContainer != null)
{
if (tooltip.context.type == Tooltip.Type.Cross)
{
if (m_PointerContainer is GridCoord)
{
var grid = m_PointerContainer as GridCoord;
ChartHelper.HideAllObject(m_LabelRoot);
foreach (var component in chart.components)
{
if (component is XAxis || component is YAxis)
{
var axis = component as Axis;
if (axis.gridIndex == grid.index)
{
var label = GetIndicatorLabel(axis);
SetTooltipIndicatorLabel(tooltip, axis, label);
}
}
}
}
else if (m_PointerContainer is PolarCoord)
{
var polar = m_PointerContainer as PolarCoord;
ChartHelper.HideAllObject(m_LabelRoot);
foreach (var component in chart.components)
{
if (component is AngleAxis || component is RadiusAxis)
{
var axis = component as Axis;
if (axis.polarIndex == polar.index)
{
var label = GetIndicatorLabel(axis);
SetTooltipIndicatorLabel(tooltip, axis, label);
}
}
}
}
}
}
}
private void SetTooltipIndicatorLabel(Tooltip tooltip, Axis axis, ChartLabel label)
{
if (label == null) return;
if (double.IsNaN(axis.context.pointerValue)) return;
if (!axis.show || !axis.indicatorLabel.show)
{
label.SetActive(false, false);
return;
}
label.SetActive(true, true);
label.SetTextActive(true);
label.SetPosition(axis.context.pointerLabelPosition + axis.indicatorLabel.offset);
if (axis.IsCategory())
{
var index = (int)axis.context.pointerValue;
var dataZoom = chart.GetDataZoomOfAxis(axis);
var category = axis.GetData(index, dataZoom);
label.SetText(axis.indicatorLabel.GetFormatterContent(index, 0, category));
}
else if (axis.IsTime())
{
label.SetText(axis.indicatorLabel.GetFormatterDateTime(0, 0, axis.context.pointerValue, axis.context.minValue, axis.context.maxValue, !chart.useUtc));
}
else
{
label.SetText(axis.indicatorLabel.GetFormatterContent(0, 0, axis.context.pointerValue, axis.context.minValue, axis.context.maxValue, axis.IsLog()));
}
var textColor = axis.axisLabel.textStyle.GetColor(chart.theme.axis.textColor);
if (ChartHelper.IsClearColor(axis.indicatorLabel.background.color))
label.color = textColor;
else
label.color = axis.indicatorLabel.background.color;
if (ChartHelper.IsClearColor(axis.indicatorLabel.textStyle.color))
label.SetTextColor(Color.white);
else
label.SetTextColor(axis.indicatorLabel.textStyle.color);
}
private void UpdatePointerContainerAndSeriesAndTooltip(Tooltip tooltip, ref List<Serie> list)
{
list.Clear();
m_PointerContainer = null;
var updateTooltipTypeAndTrigger = false;
for (int i = chart.components.Count - 1; i >= 0; i--)
{
var component = chart.components[i];
if (component is ISerieContainer)
{
var container = component as ISerieContainer;
if (container.IsPointerEnter())
{
foreach (var serie in chart.series)
{
if (serie is INeedSerieContainer &&
(serie as INeedSerieContainer).containterInstanceId == component.instanceId &&
!serie.placeHolder)
{
if (!updateTooltipTypeAndTrigger)
{
updateTooltipTypeAndTrigger = true;
tooltip.context.type = tooltip.type == Tooltip.Type.Auto ?
serie.context.tooltipType : tooltip.type;
tooltip.context.trigger = tooltip.trigger == Tooltip.Trigger.Auto ?
serie.context.tooltipTrigger : tooltip.trigger;
}
var isTriggerAxis = tooltip.IsTriggerAxis();
var inchart = true;
if (container is GridCoord)
{
var xAxis = chart.GetChartComponent<XAxis>(serie.xAxisIndex);
var yAxis = chart.GetChartComponent<YAxis>(serie.yAxisIndex);
inchart = UpdateAxisPointerDataIndex(serie, xAxis, yAxis, container as GridCoord, isTriggerAxis);
}
else if (container is PolarCoord)
{
var m_AngleAxis = ComponentHelper.GetAngleAxis(chart.components, container.index);
tooltip.context.angle = (float)m_AngleAxis.context.pointerValue;
}
if (inchart)
{
list.Add(serie);
if (!isTriggerAxis)
{
chart.RefreshTopPainter();
}
}
}
}
m_PointerContainer = container;
}
}
}
}
private bool UpdateAxisPointerDataIndex(Serie serie, XAxis xAxis, YAxis yAxis, GridCoord grid, bool isTriggerAxis)
{
serie.context.pointerAxisDataIndexs.Clear();
if (xAxis == null || yAxis == null) return false;
var flag = true;
if (serie is Heatmap)
{
GetSerieDataByXYAxis(serie, xAxis, yAxis);
}
else if (yAxis.IsCategory() && !xAxis.IsCategory())
{
if (isTriggerAxis)
{
var index = serie.context.dataZoomStartIndex + (int)yAxis.context.pointerValue;
if (serie.useSortData) index = yAxis.context.sortedDataIndices[index];
serie.context.pointerEnter = true;
serie.context.pointerAxisDataIndexs.Add(index);
serie.context.pointerItemDataIndex = index;
yAxis.context.axisTooltipValue = index;
}
}
else if (yAxis.IsTime())
{
serie.context.pointerEnter = true;
if (isTriggerAxis)
GetSerieDataIndexByAxis(serie, yAxis, grid);
else
GetSerieDataIndexByItem(serie, yAxis, grid);
}
else if (xAxis.IsCategory())
{
if (isTriggerAxis)
{
var index = serie.context.dataZoomStartIndex + (int)xAxis.context.pointerValue;
if (serie.useSortData) index = xAxis.context.sortedDataIndices[index];
if (chart.isTriggerOnClick)
{
if (serie.insertDataToHead)
index = index + (serie.context.totalDataIndex - serie.context.clickTotalDataIndex);
else if (serie.context.totalDataIndex >= serie.dataCount)
index = index - (serie.context.totalDataIndex - serie.context.clickTotalDataIndex);
if (index < 0 || index >= serie.dataCount)
{
index = -1;
flag = false;
}
}
if (component.context.xAxisClickIndex != index)
{
component.context.xAxisClickIndex = index;
if (component.onClickIndex != null)
{
component.onClickIndex(index);
}
}
serie.context.pointerEnter = true;
serie.context.pointerAxisDataIndexs.Add(index);
serie.context.pointerItemDataIndex = index;
xAxis.context.axisTooltipValue = index;
}
}
else
{
if (isTriggerAxis)
{
serie.context.pointerEnter = true;
GetSerieDataIndexByAxis(serie, xAxis, grid);
}
else
{
GetSerieDataIndexByItem(serie, xAxis, grid);
}
}
return flag;
}
private void GetSerieDataByXYAxis(Serie serie, Axis xAxis, Axis yAxis)
{
var xAxisIndex = AxisHelper.GetAxisValueSplitIndex(xAxis, xAxis.context.pointerValue, false);
var yAxisIndex = AxisHelper.GetAxisValueSplitIndex(yAxis, yAxis.context.pointerValue, false);
serie.context.pointerItemDataIndex = -1;
if (serie is Heatmap)
{
var heatmap = serie as Heatmap;
if (heatmap.heatmapType == HeatmapType.Count)
{
serie.context.pointerItemDataIndex = HeatmapHandler.GetGridKey(xAxisIndex, yAxisIndex);
return;
}
}
foreach (var serieData in serie.data)
{
var x = AxisHelper.GetAxisValueSplitIndex(xAxis, serieData.GetData(0), true);
var y = AxisHelper.GetAxisValueSplitIndex(yAxis, serieData.GetData(1), true);
if (xAxisIndex == x && y == yAxisIndex)
{
serie.context.pointerItemDataIndex = serieData.index;
break;
}
}
}
private void GetSerieDataIndexByAxis(Serie serie, Axis axis, GridCoord grid, int dimension = 0)
{
var currValue = 0d;
var lastValue = 0d;
var nextValue = 0d;
var axisValue = axis.context.pointerValue;
var isTimeAxis = axis.IsTime();
var dataCount = serie.dataCount;
var themeSymbolSize = chart.theme.serie.scatterSymbolSize;
var data = serie.data;
if (!isTimeAxis)// || serie.useSortData)
{
serie.context.sortedData.Clear();
for (int i = 0; i < dataCount; i++)
{
var serieData = serie.data[i];
serie.context.sortedData.Add(serieData);
}
serie.context.sortedData.Sort(delegate (SerieData a, SerieData b)
{
return a.GetData(dimension).CompareTo(b.GetData(dimension));
});
data = serie.context.sortedData;
}
serie.context.pointerAxisDataIndexs.Clear();
for (int i = 0; i < dataCount; i++)
{
var serieData = data[i];
currValue = serieData.GetData(dimension);
if (i == 0)
{
if (i + 1 < dataCount)
{
nextValue = data[i + 1].GetData(dimension);
if (axisValue <= currValue + (nextValue - currValue) / 2)
{
serie.context.pointerAxisDataIndexs.Add(serieData.index);
break;
}
}
else
{
var diff = axis.context.tickValue * 0.5f;
if (axisValue >= currValue - diff && axisValue <= currValue + diff)
{
serie.context.pointerAxisDataIndexs.Add(serieData.index);
break;
}
}
}
else if (i == dataCount - 1)
{
if (axisValue > lastValue + (currValue - lastValue) / 2)
{
serie.context.pointerAxisDataIndexs.Add(serieData.index);
break;
}
}
else if (i + 1 < dataCount)
{
nextValue = data[i + 1].GetData(dimension);
if (axisValue > (currValue - (currValue - lastValue) / 2) && axisValue <= currValue + (nextValue - currValue) / 2)
{
serie.context.pointerAxisDataIndexs.Add(serieData.index);
break;
}
}
lastValue = currValue;
}
if (serie.context.pointerAxisDataIndexs.Count > 0)
{
var index = serie.context.pointerAxisDataIndexs[0];
serie.context.pointerItemDataIndex = index;
axis.context.axisTooltipValue = serie.GetSerieData(index).GetData(dimension);
}
else
{
serie.context.pointerItemDataIndex = -1;
axis.context.axisTooltipValue = 0;
}
}
private void GetSerieDataIndexByItem(Serie serie, Axis axis, GridCoord grid, int dimension = 0)
{
if (serie.context.pointerItemDataIndex >= 0)
{
axis.context.axisTooltipValue = serie.GetSerieData(serie.context.pointerItemDataIndex).GetData(dimension);
}
else if (component.type == Tooltip.Type.Cross)
{
axis.context.axisTooltipValue = axis.context.pointerValue;
}
else
{
axis.context.axisTooltipValue = 0;
}
}
private bool SetSerieTooltip(Tooltip tooltip, Serie serie)
{
if (serie.context.pointerItemDataIndex < 0) return false;
tooltip.context.type = tooltip.type == Tooltip.Type.Auto ? serie.context.tooltipType : tooltip.type;
tooltip.context.trigger = tooltip.trigger == Tooltip.Trigger.Auto ? serie.context.tooltipTrigger : tooltip.trigger;
if (tooltip.context.trigger == Tooltip.Trigger.None) return false;
tooltip.context.data.param.Clear();
tooltip.context.data.title = serie.serieName;
tooltip.context.pointer = GetTooltipPointerPos();
serie.handler.UpdateTooltipSerieParams(serie.context.pointerItemDataIndex, false, null,
tooltip.marker, tooltip.itemFormatter, tooltip.numericFormatter, tooltip.ignoreDataDefaultContent,
ref tooltip.context.data.param,
ref tooltip.context.data.title);
TooltipHelper.ResetTooltipParamsByItemFormatter(tooltip, chart);
tooltip.SetActive(m_ShowTooltip);
tooltip.view.Refresh();
TooltipHelper.LimitInRect(chart, tooltip, chart.chartRect);
return true;
}
private Vector2 GetTooltipPointerPos()
{
if (chart.isTriggerOnClick && chart.isPointerClick)
return chart.clickPos;
else
return chart.pointerPos;
}
private bool SetSerieTooltip(Tooltip tooltip, List<Serie> series)
{
if (tooltip.context.trigger == Tooltip.Trigger.None)
return false;
if (series.Count <= 0)
return false;
string category = null;
var showCategory = false;
var isTriggerByAxis = false;
var isTriggerByItem = tooltip.context.trigger == Tooltip.Trigger.Item;
var dataIndex = -1;
var timestamp = -1;
double axisRange = 0;
tooltip.context.data.param.Clear();
tooltip.context.pointer = GetTooltipPointerPos();
if (m_PointerContainer is GridCoord)
{
GetAxisCategory(m_PointerContainer.index, ref dataIndex, ref category, ref timestamp, ref axisRange);
if (tooltip.context.trigger == Tooltip.Trigger.Axis)
{
isTriggerByAxis = true;
if (series.Count <= 1)
{
showCategory = true;
tooltip.context.data.title = series[0].serieName;
}
else
{
tooltip.context.data.title = category;
}
}
else if (tooltip.context.trigger == Tooltip.Trigger.Item)
{
isTriggerByItem = true;
showCategory = series.Count <= 1;
}
}
var triggerSerieCount = 0;
for (int i = 0; i < series.Count; i++)
{
var serie = series[i];
if (!serie.show) continue;
if (isTriggerByItem && serie.context.pointerItemDataIndex < 0) continue;
triggerSerieCount++;
serie.context.isTriggerByAxis = isTriggerByAxis;
if (isTriggerByAxis && dataIndex >= 0 && serie.context.pointerItemDataIndex < 0)
serie.context.pointerItemDataIndex = dataIndex;
if (timestamp >= 0)
{
showCategory = false;
var serieData = serie.GetSerieData(serie.context.pointerItemDataIndex);
if (serieData != null)
{
var value = (int)serieData.GetData(0);
if (string.IsNullOrEmpty(tooltip.titleLabelStyle.numericFormatter))
tooltip.context.data.title = DateTimeUtil.GetDefaultDateTimeString(value, axisRange, !chart.useUtc);
else
{
var dateTime = DateTimeUtil.GetDateTime(value, !chart.useUtc);
try
{
tooltip.context.data.title = dateTime.ToString(tooltip.titleLabelStyle.numericFormatter);
}
catch
{
tooltip.context.data.title = DateTimeUtil.GetDefaultDateTimeString(value, axisRange, !chart.useUtc);
}
}
}
}
serie.handler.UpdateTooltipSerieParams(dataIndex, showCategory, category,
tooltip.marker, tooltip.itemFormatter, tooltip.numericFormatter,
tooltip.ignoreDataDefaultContent,
ref tooltip.context.data.param,
ref tooltip.context.data.title);
}
if (triggerSerieCount <= 0)
{
return false;
}
TooltipHelper.ResetTooltipParamsByItemFormatter(tooltip, chart);
if (tooltip.context.data.param.Count > 0 || !string.IsNullOrEmpty(tooltip.context.data.title))
{
tooltip.SetActive(m_ShowTooltip);
if (tooltip.view != null)
tooltip.view.Refresh();
TooltipHelper.LimitInRect(chart, tooltip, chart.chartRect);
return true;
}
return false;
}
private bool GetAxisCategory(int gridIndex, ref int dataIndex, ref string category, ref int timestamp, ref double axisRange)
{
foreach (var component in chart.components)
{
if (component is Axis)
{
var axis = component as Axis;
if (axis.gridIndex == gridIndex)
{
if (axis.IsCategory())
{
dataIndex = double.IsNaN(axis.context.pointerValue)
? axis.context.dataZoomStartIndex
: (int)axis.context.axisTooltipValue;
category = axis.GetData(dataIndex);
return true;
}
else if (axis.IsTime())
{
timestamp = (int)axis.context.pointerValue;
axisRange = axis.context.minMaxRange;
}
}
}
}
return false;
}
private void DrawTooltipIndicator(VertexHelper vh, Tooltip tooltip)
{
if (!tooltip.show) return;
if (tooltip.context.type == Tooltip.Type.None) return;
if (!IsAnySerieNeedTooltip()) return;
if (m_PointerContainer is GridCoord)
{
var grid = m_PointerContainer as GridCoord;
if (!grid.context.isPointerEnter) return;
if (IsYCategoryOfGrid(grid.index))
DrawYAxisIndicator(vh, tooltip, grid);
else
DrawXAxisIndicator(vh, tooltip, grid);
}
else if (m_PointerContainer is PolarCoord)
{
DrawPolarIndicator(vh, tooltip, m_PointerContainer as PolarCoord);
}
}
private bool IsYCategoryOfGrid(int gridIndex)
{
foreach (var component in chart.GetChartComponents<YAxis>())
{
var yAxis = component as YAxis;
if (yAxis.gridIndex == gridIndex && !yAxis.IsCategory()) return false;
}
foreach (var component in chart.GetChartComponents<XAxis>())
{
var xAxis = component as XAxis;
if (xAxis.gridIndex == gridIndex && xAxis.IsCategory()) return false;
}
return true;
}
private void DrawXAxisIndicator(VertexHelper vh, Tooltip tooltip, GridCoord grid)
{
if (!tooltip.lineStyle.show) return;
var xAxes = chart.GetChartComponents<XAxis>();
var lineType = tooltip.lineStyle.GetType(chart.theme.tooltip.lineType);
var lineWidth = tooltip.lineStyle.GetWidth(chart.theme.tooltip.lineWidth);
foreach (var component in xAxes)
{
var xAxis = component as XAxis;
if (xAxis.gridIndex == grid.index)
{
if (double.IsInfinity(xAxis.context.pointerValue))
continue;
var dataZoom = chart.GetDataZoomOfAxis(xAxis);
int dataCount = chart.series.Count > 0 ? chart.series[0].GetDataList(dataZoom).Count : 0;
float splitWidth = AxisHelper.GetDataWidth(xAxis, grid.context.width, dataCount, dataZoom);
switch (tooltip.context.type)
{
case Tooltip.Type.Cross:
case Tooltip.Type.Line:
float pX = grid.context.x;
pX += xAxis.IsCategory() ?
(float)(xAxis.context.pointerValue * splitWidth + (xAxis.boundaryGap ? splitWidth / 2 : 0)) :
xAxis.GetDistance(xAxis.context.axisTooltipValue, grid.context.width);
if (pX < grid.context.x)
break;
Vector2 sp = new Vector2(pX, grid.context.y);
Vector2 ep = new Vector2(pX, grid.context.y + grid.context.height);
var lineColor = TooltipHelper.GetLineColor(tooltip, chart.theme.tooltip.lineColor);
ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, sp, ep, lineColor);
if (tooltip.context.type == Tooltip.Type.Cross)
{
sp = new Vector2(grid.context.x, chart.pointerPos.y);
ep = new Vector2(grid.context.x + grid.context.width, chart.pointerPos.y);
ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, sp, ep, lineColor);
}
break;
case Tooltip.Type.Shadow:
if (xAxis.IsCategory() && !double.IsInfinity(xAxis.context.pointerValue))
{
float tooltipSplitWid = splitWidth < 1 ? 1 : splitWidth;
pX = (float)(grid.context.x + splitWidth * xAxis.context.pointerValue -
(xAxis.boundaryGap ? 0 : splitWidth / 2));
if (pX < grid.context.x)
break;
float pY = grid.context.y + grid.context.height;
Vector3 p1 = chart.ClampInGrid(grid, new Vector3(pX, grid.context.y));
Vector3 p2 = chart.ClampInGrid(grid, new Vector3(pX, pY));
Vector3 p3 = chart.ClampInGrid(grid, new Vector3(pX + tooltipSplitWid, pY));
Vector3 p4 = chart.ClampInGrid(grid, new Vector3(pX + tooltipSplitWid, grid.context.y));
var areaColor = TooltipHelper.GetLineColor(tooltip, chart.theme.tooltip.areaColor);
UGL.DrawQuadrilateral(vh, p1, p2, p3, p4, areaColor);
}
break;
}
}
}
}
private bool IsAnySerieNeedTooltip()
{
foreach (var serie in chart.series)
{
if (serie.context.pointerEnter) return true;
}
return false;
}
private void DrawYAxisIndicator(VertexHelper vh, Tooltip tooltip, GridCoord grid)
{
var yAxes = chart.GetChartComponents<YAxis>();
var lineType = tooltip.lineStyle.GetType(chart.theme.tooltip.lineType);
var lineWidth = tooltip.lineStyle.GetWidth(chart.theme.tooltip.lineWidth);
foreach (var component in yAxes)
{
var yAxis = component as YAxis;
if (yAxis.gridIndex == grid.index)
{
if (double.IsInfinity(yAxis.context.pointerValue))
continue;
var dataZoom = chart.GetDataZoomOfAxis(yAxis);
int dataCount = chart.series.Count > 0 ? chart.series[0].GetDataList(dataZoom).Count : 0;
float splitWidth = AxisHelper.GetDataWidth(yAxis, grid.context.height, dataCount, dataZoom);
switch (tooltip.context.type)
{
case Tooltip.Type.Cross:
case Tooltip.Type.Line:
float pY = (float)(grid.context.y + yAxis.context.pointerValue * splitWidth +
(yAxis.boundaryGap ? splitWidth / 2 : 0));
if (pY < grid.context.y)
break;
Vector2 sp = new Vector2(grid.context.x, pY);
Vector2 ep = new Vector2(grid.context.x + grid.context.width, pY);
var lineColor = TooltipHelper.GetLineColor(tooltip, chart.theme.tooltip.lineColor);
ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, sp, ep, lineColor);
if (tooltip.context.type == Tooltip.Type.Cross)
{
sp = new Vector2(chart.pointerPos.x, grid.context.y);
ep = new Vector2(chart.pointerPos.x, grid.context.y + grid.context.height);
ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, sp, ep, lineColor);
}
break;
case Tooltip.Type.Shadow:
if (yAxis.IsCategory())
{
float tooltipSplitWid = splitWidth < 1 ? 1 : splitWidth;
float pX = grid.context.x + grid.context.width;
pY = (float)(grid.context.y + splitWidth * yAxis.context.pointerValue -
(yAxis.boundaryGap ? 0 : splitWidth / 2));
if (pY < grid.context.y)
break;
Vector3 p1 = new Vector3(grid.context.x, pY);
Vector3 p2 = new Vector3(grid.context.x, pY + tooltipSplitWid);
Vector3 p3 = new Vector3(pX, pY + tooltipSplitWid);
Vector3 p4 = new Vector3(pX, pY);
UGL.DrawQuadrilateral(vh, p1, p2, p3, p4, chart.theme.tooltip.areaColor);
}
break;
}
}
}
}
private void DrawPolarIndicator(VertexHelper vh, Tooltip tooltip, PolarCoord m_Polar)
{
if (tooltip.context.angle < 0) return;
var theme = chart.theme;
var m_AngleAxis = ComponentHelper.GetAngleAxis(chart.components, m_Polar.index);
var lineColor = TooltipHelper.GetLineColor(tooltip, theme.tooltip.lineColor);
var lineType = tooltip.lineStyle.GetType(theme.tooltip.lineType);
var lineWidth = tooltip.lineStyle.GetWidth(theme.tooltip.lineWidth);
var cenPos = m_Polar.context.center;
var radius = m_Polar.context.outsideRadius;
var tooltipAngle = m_AngleAxis.GetValueAngle(tooltip.context.angle);
var sp = ChartHelper.GetPos(m_Polar.context.center, m_Polar.context.insideRadius, tooltipAngle, true);
var ep = ChartHelper.GetPos(m_Polar.context.center, m_Polar.context.outsideRadius, tooltipAngle, true);
switch (tooltip.context.type)
{
case Tooltip.Type.Cross:
ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, sp, ep, lineColor);
var dist = Vector2.Distance(chart.pointerPos, cenPos);
if (dist > radius) dist = radius;
var outsideRaidus = dist + tooltip.lineStyle.GetWidth(theme.tooltip.lineWidth) * 2;
UGL.DrawDoughnut(vh, cenPos, dist, outsideRaidus, lineColor, Color.clear);
break;
case Tooltip.Type.Line:
ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, sp, ep, lineColor);
break;
case Tooltip.Type.Shadow:
UGL.DrawSector(vh, cenPos, radius, lineColor, tooltipAngle - 2, tooltipAngle + 2, chart.settings.cicleSmoothness);
break;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7d25a5b5e3d6f45b8a06b94e33792087
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,156 @@
using System;
using UnityEngine;
namespace XCharts.Runtime
{
public static class TooltipHelper
{
internal static void ResetTooltipParamsByItemFormatter(Tooltip tooltip, BaseChart chart)
{
if (!string.IsNullOrEmpty(tooltip.titleFormatter))
{
if (IsIgnoreFormatter(tooltip.titleFormatter))
{
tooltip.context.data.title = string.Empty;
}
else
{
tooltip.context.data.title = tooltip.titleFormatter;
var numericFormatter = string.IsNullOrEmpty(tooltip.titleLabelStyle.numericFormatter)
? tooltip.numericFormatter : tooltip.titleLabelStyle.numericFormatter;
FormatterHelper.ReplaceContent(ref tooltip.context.data.title, -1, numericFormatter, null, chart);
}
}
for (int i = tooltip.context.data.param.Count - 1; i >= 0; i--)
{
var param = tooltip.context.data.param[i];
if (IsIgnoreFormatter(param.itemFormatter))
{
tooltip.context.data.param.RemoveAt(i);
}
}
foreach (var param in tooltip.context.data.param)
{
if (!string.IsNullOrEmpty(param.itemFormatter))
{
param.columns.Clear();
var content = param.itemFormatter;
FormatterHelper.ReplaceSerieLabelContent(ref content,
param.numericFormatter,
param.dataCount,
param.value,
param.total,
param.serieName,
param.category,
param.serieData.name,
param.color,
param.serieData,
chart,
param.serieIndex);
foreach (var item in content.Split('|'))
{
param.columns.Add(item);
}
}
}
}
public static bool IsIgnoreFormatter(string itemFormatter)
{
return "-".Equals(itemFormatter) || "{i}".Equals(itemFormatter, StringComparison.CurrentCultureIgnoreCase);
}
public static void LimitInRect(BaseChart chart, Tooltip tooltip, Rect chartRect)
{
if (tooltip.view == null)
return;
var pos = tooltip.view.GetTargetPos();
if (pos.x + tooltip.context.width > chartRect.x + chartRect.width)
{
pos.x = tooltip.context.pointer.x - tooltip.context.width - tooltip.offset.x;
}
else if (pos.x < chartRect.x)
{
pos.x = tooltip.context.pointer.x - tooltip.context.width + Mathf.Abs(tooltip.offset.x);
}
if (pos.y - tooltip.context.height < chartRect.y)
{
pos.y = chartRect.y + tooltip.context.height;
}
if (pos.y > chartRect.y + chartRect.height)
pos.y = chartRect.y + chartRect.height;
var screenGap = 10;
var screenPos = chart.LocalPointToScreenPoint(pos);
if (screenPos.x < screenGap)
pos.x += Mathf.Abs(screenPos.x) + screenGap;
if (screenPos.x + tooltip.context.width > Screen.width - screenGap)
pos.x -= Mathf.Abs(screenPos.x + tooltip.context.width - Screen.width) + screenGap;
if (screenPos.y < tooltip.context.height + screenGap)
pos.y += Mathf.Abs(screenPos.y - tooltip.context.height) + screenGap;
if (screenPos.y > Screen.height - screenGap)
pos.y -= Mathf.Abs(screenPos.y - Screen.height) + screenGap;
UpdateContentPos(tooltip, pos, chartRect);
}
/// <summary>
/// 更新文本框位置
/// </summary>
/// <param name="pos"></param>
private static void UpdateContentPos(Tooltip tooltip, Vector2 pos, Rect chartRect)
{
if (tooltip.view != null)
{
var width = chartRect.width;
var height = chartRect.height;
switch (tooltip.position)
{
case Tooltip.Position.Auto:
#if UNITY_ANDROID || UNITY_IOS
if (tooltip.fixedY == 0) pos.y = chartRect.x + ChartHelper.GetActualValue(0.7f, height);
else pos.y = chartRect.y + ChartHelper.GetActualValue(tooltip.fixedY, height);
#endif
break;
case Tooltip.Position.Custom:
pos = new Vector2(chartRect.x, chartRect.y);
pos.x += ChartHelper.GetActualValue(tooltip.fixedX, width);
pos.y += ChartHelper.GetActualValue(tooltip.fixedY, height);
break;
case Tooltip.Position.FixedX:
pos = new Vector2(chartRect.x, pos.y);
pos.x += ChartHelper.GetActualValue(tooltip.fixedX, width);
break;
case Tooltip.Position.FixedY:
pos = new Vector2(pos.x, chartRect.y);
pos.y += ChartHelper.GetActualValue(tooltip.fixedY, height);
break;
}
tooltip.view.UpdatePosition(pos);
}
}
public static string GetItemNumericFormatter(Tooltip tooltip, Serie serie, SerieData serieData)
{
var itemStyle = SerieHelper.GetItemStyle(serie, serieData);
if (!string.IsNullOrEmpty(itemStyle.numericFormatter)) return itemStyle.numericFormatter;
else return tooltip.numericFormatter;
}
public static Color32 GetLineColor(Tooltip tooltip, Color32 defaultColor)
{
var lineStyle = tooltip.lineStyle;
if (!ChartHelper.IsClearColor(lineStyle.color))
{
return lineStyle.GetColor();
}
else
{
var color = defaultColor;
ChartHelper.SetColorOpacity(ref color, lineStyle.opacity);
return color;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 184e190de6da6486b8b4d333a302477a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,301 @@
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts.Runtime
{
public class TooltipViewItem
{
public GameObject gameObject;
public List<ChartLabel> columns = new List<ChartLabel>();
}
public class TooltipView
{
private static Vector2 anchorMax = new Vector2(0, 1);
private static Vector2 anchorMin = new Vector2(0, 1);
private static Vector2 pivot = new Vector2(0, 1);
private static Vector2 v2_0_05 = new Vector2(0, 0.5f);
public Tooltip tooltip;
public ComponentTheme theme;
public GameObject gameObject;
public Transform transform;
public Image background;
public Outline border;
public VerticalLayoutGroup layout;
public ChartLabel title;
private List<TooltipViewItem> m_Items = new List<TooltipViewItem>();
private List<float> m_ColumnMaxWidth = new List<float>();
private bool m_Active = false;
private Vector3 m_TargetPos;
private Vector3 m_CurrentVelocity;
public void Update()
{
if (!m_Active)
return;
transform.localPosition = Vector3.SmoothDamp(transform.localPosition, m_TargetPos, ref m_CurrentVelocity, 0.08f);
}
public Vector3 GetCurrentPos()
{
return transform.localPosition;
}
public Vector3 GetTargetPos()
{
return m_TargetPos;
}
public void UpdatePosition(Vector3 pos)
{
m_TargetPos = pos;
}
public void SetActive(bool flag)
{
m_Active = flag && tooltip.showContent;
ChartHelper.SetActive(gameObject, m_Active);
if (!flag)
{
m_ColumnMaxWidth.Clear();
foreach (var item in m_Items)
item.gameObject.SetActive(false);
}
}
public void Refresh()
{
if (tooltip == null) return;
var data = tooltip.context.data;
var ignoreColumn = string.IsNullOrEmpty(tooltip.ignoreDataDefaultContent);
var titleActive = !string.IsNullOrEmpty(data.title);
ChartHelper.SetActive(title, titleActive);
title.SetText(data.title);
for (int i = 0; i < data.param.Count; i++)
{
var item = GetItem(i);
var param = data.param[i];
if (param.columns.Count <= 0 || (ignoreColumn && param.ignore))
{
item.gameObject.SetActive(false);
continue;
}
item.gameObject.SetActive(true);
for (int j = 0; j < param.columns.Count; j++)
{
var column = GetItemColumn(item, j, j == 0 && IsSecondaryMark(param, param.columns[j]));
column.SetActive(true);
column.SetText(param.columns[j]);
if (j == 0)
{
var labelStyle = tooltip.GetContentLabelStyle(j);
if (labelStyle != null && ChartHelper.IsClearColor(labelStyle.textStyle.color))
column.text.SetColor(param.color);
}
if (j >= m_ColumnMaxWidth.Count)
m_ColumnMaxWidth.Add(0);
var columnWidth = column.text.GetPreferredWidth() + GetTooltipColumnGapWidth(tooltip, j);
if (m_ColumnMaxWidth[j] < columnWidth)
m_ColumnMaxWidth[j] = columnWidth;
}
for (int j = param.columns.Count; j < item.columns.Count; j++)
{
item.columns[j].SetActive(false);
}
}
for (int i = data.param.Count; i < m_Items.Count; i++)
{
m_Items[i].gameObject.SetActive(false);
}
ResetSize();
UpdatePosition(tooltip.context.pointer + tooltip.offset);
tooltip.gameObject.transform.SetAsLastSibling();
}
private static float GetTooltipColumnGapWidth(Tooltip tooltip, int index)
{
if (tooltip == null || tooltip.columnGapWidths.Count == 0) return 0;
if (tooltip.columnGapWidths.Count == 1) return index == 1 ? tooltip.columnGapWidths[0] : 0;
if (index < tooltip.columnGapWidths.Count)
{
return tooltip.columnGapWidths[index];
}
return 0;
}
private static bool IsSecondaryMark(SerieParams sp, string mark)
{
return sp.isSecondaryMark && mark == sp.marker;
}
private void ResetSize()
{
var maxHig = 0f;
var maxWid = 0f;
if (tooltip.fixedWidth > 0)
{
maxWid = tooltip.fixedWidth;
}
else
{
maxWid = TotalMaxWidth();
var titleWid = title.GetTextWidth();
if (maxWid < titleWid)
maxWid = titleWid;
}
if (tooltip.fixedHeight > 0)
{
maxHig = tooltip.fixedHeight;
}
else
{
if (!string.IsNullOrEmpty(title.text.GetText()))
maxHig += tooltip.titleHeight;
maxHig += tooltip.itemHeight * tooltip.context.data.param.Count;
maxHig += tooltip.paddingTopBottom * 2;
}
if (tooltip.minWidth > 0 && maxWid < tooltip.minWidth)
maxWid = tooltip.minWidth;
if (tooltip.minHeight > 0 && maxHig < tooltip.minHeight)
maxHig = tooltip.minHeight;
for (int i = 0; i < m_Items.Count; i++)
{
var item = m_Items[i];
item.gameObject.GetComponent<RectTransform>().sizeDelta = new Vector2(maxWid, tooltip.itemHeight);
var xPos = 0f;
for (int j = 0; j < m_ColumnMaxWidth.Count; j++)
{
if (j >= item.columns.Count) break;
var deltaX = j == m_ColumnMaxWidth.Count - 1 ? maxWid - xPos : m_ColumnMaxWidth[j];
item.columns[j].text.SetSizeDelta(new Vector2(deltaX, tooltip.itemHeight));
item.columns[j].SetSize(deltaX, tooltip.itemHeight);
item.columns[j].SetRectPosition(new Vector3(xPos, 0));
xPos += m_ColumnMaxWidth[j];
}
}
tooltip.context.width = maxWid + tooltip.paddingLeftRight * 2;
tooltip.context.height = maxHig;
background.GetComponent<RectTransform>().sizeDelta = new Vector2(tooltip.context.width, tooltip.context.height);
}
private float TotalMaxWidth()
{
var total = 0f;
foreach (var max in m_ColumnMaxWidth)
total += max;
return total;
}
private TooltipViewItem GetItem(int i)
{
if (i < 0) i = 0;
if (i < m_Items.Count)
{
return m_Items[i];
}
else
{
var item = CreateViewItem(i, gameObject.transform, tooltip, theme);
m_Items.Add(item);
return item;
}
}
private ChartLabel GetItemColumn(TooltipViewItem item, int i, bool isSecondaryMark = false)
{
if (i < 0) i = 0;
ChartLabel column;
if (i < item.columns.Count)
{
column = item.columns[i];
}
else
{
column = CreateViewItemColumn(i, item.gameObject.transform, tooltip, theme);
item.columns.Add(column);
}
if (isSecondaryMark)
{
column.text.text.fontSize = (int)(tooltip.GetContentLabelStyle(i).textStyle.fontSize * 0.6f);
}
return column;
}
public static TooltipView CreateView(Tooltip tooltip, ThemeStyle theme, Transform parent)
{
var view = new TooltipView();
view.tooltip = tooltip;
view.theme = theme.tooltip;
view.gameObject = ChartHelper.AddObject("view", parent, anchorMin, anchorMax, pivot, Vector3.zero);
view.gameObject.transform.localPosition = Vector3.zero;
view.transform = view.gameObject.transform;
view.background = ChartHelper.EnsureComponent<Image>(view.gameObject);
view.background.sprite = tooltip.backgroundImage;
view.background.type = tooltip.backgroundType;
view.background.color = ChartHelper.IsClearColor(tooltip.backgroundColor) ?
Color.white : tooltip.backgroundColor;
view.border = ChartHelper.EnsureComponent<Outline>(view.gameObject);
view.border.enabled = tooltip.borderWidth > 0;
view.border.useGraphicAlpha = false;
view.border.effectColor = tooltip.borderColor;
view.border.effectDistance = new Vector2(tooltip.borderWidth, -tooltip.borderWidth);
view.layout = ChartHelper.EnsureComponent<VerticalLayoutGroup>(view.gameObject);
view.layout.childControlHeight = false;
view.layout.childControlWidth = false;
view.layout.childForceExpandHeight = false;
view.layout.childForceExpandWidth = false;
view.layout.padding = new RectOffset(tooltip.paddingLeftRight,
tooltip.paddingLeftRight,
tooltip.paddingTopBottom,
tooltip.paddingTopBottom);
view.title = ChartHelper.AddChartLabel("title", view.gameObject.transform, tooltip.titleLabelStyle, theme.tooltip,
"", Color.clear, TextAnchor.MiddleLeft);
view.title.gameObject.SetActive(true);
var item = CreateViewItem(0, view.gameObject.transform, tooltip, theme.tooltip);
view.m_Items.Add(item);
view.Refresh();
return view;
}
private static TooltipViewItem CreateViewItem(int i, Transform parent, Tooltip tooltip, ComponentTheme theme)
{
GameObject item1 = ChartHelper.AddObject("item" + i, parent, anchorMin, anchorMax, v2_0_05, Vector3.zero);
var item = new TooltipViewItem();
item.gameObject = item1;
item.columns.Add(CreateViewItemColumn(0, item1.transform, tooltip, theme));
item.columns.Add(CreateViewItemColumn(1, item1.transform, tooltip, theme));
item.columns.Add(CreateViewItemColumn(2, item1.transform, tooltip, theme));
return item;
}
private static ChartLabel CreateViewItemColumn(int i, Transform parent, Tooltip tooltip, ComponentTheme theme)
{
var labelStyle = tooltip.GetContentLabelStyle(i);
labelStyle.textStyle.autoAlign = false;
var label = ChartHelper.AddChartLabel("column" + i, parent, labelStyle, theme,
"", Color.clear, TextAnchor.MiddleLeft, true);
return label;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 20bbaf6c402824f5d8abcaf1cee57865
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: