UI update 02
This commit is contained in:
@@ -0,0 +1,468 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace XCharts.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Legend component.The legend component shows different sets of tags, colors, and names.
|
||||
/// You can control which series are not displayed by clicking on the legend.
|
||||
/// ||图例组件。
|
||||
/// 图例组件展现了不同系列的标记,颜色和名字。可以通过点击图例控制哪些系列不显示。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
[ComponentHandler(typeof(LegendHandler), true)]
|
||||
public class Legend : MainComponent, IPropertyChanged
|
||||
{
|
||||
public enum Type
|
||||
{
|
||||
/// <summary>
|
||||
/// 自动匹配。
|
||||
/// </summary>
|
||||
Auto,
|
||||
/// <summary>
|
||||
/// 自定义图标。
|
||||
/// </summary>
|
||||
Custom,
|
||||
/// <summary>
|
||||
/// 空心圆。
|
||||
/// </summary>
|
||||
EmptyCircle,
|
||||
/// <summary>
|
||||
/// 圆形。
|
||||
/// </summary>
|
||||
Circle,
|
||||
/// <summary>
|
||||
/// 正方形。可通过Setting的legendIconCornerRadius参数调整圆角。
|
||||
/// </summary>
|
||||
Rect,
|
||||
/// <summary>
|
||||
/// 三角形。
|
||||
/// </summary>
|
||||
Triangle,
|
||||
/// <summary>
|
||||
/// 菱形。
|
||||
/// </summary>
|
||||
Diamond,
|
||||
/// <summary>
|
||||
/// 烛台(可用于K线图)。
|
||||
/// </summary>
|
||||
Candlestick,
|
||||
}
|
||||
/// <summary>
|
||||
/// Selected mode of legend, which controls whether series can be toggled displaying by clicking legends.
|
||||
/// ||图例选择的模式,控制是否可以通过点击图例改变系列的显示状态。默认开启图例选择,可以设成 None 关闭。
|
||||
/// </summary>
|
||||
public enum SelectedMode
|
||||
{
|
||||
/// <summary>
|
||||
/// 多选。
|
||||
/// </summary>
|
||||
Multiple,
|
||||
/// <summary>
|
||||
/// 单选。
|
||||
/// </summary>
|
||||
Single,
|
||||
/// <summary>
|
||||
/// 无法选择。
|
||||
/// </summary>
|
||||
None
|
||||
}
|
||||
|
||||
[SerializeField] private bool m_Show = true;
|
||||
[SerializeField] private Type m_IconType = Type.Auto;
|
||||
[SerializeField] private SelectedMode m_SelectedMode = SelectedMode.Multiple;
|
||||
[SerializeField] private Orient m_Orient = Orient.Horizonal;
|
||||
[SerializeField] private Location m_Location = new Location() { align = Location.Align.TopCenter, top = 0.125f };
|
||||
[SerializeField] private float m_ItemWidth = 25.0f;
|
||||
[SerializeField] private float m_ItemHeight = 12.0f;
|
||||
[SerializeField] private float m_ItemGap = 10f;
|
||||
[SerializeField] private bool m_ItemAutoColor = true;
|
||||
[SerializeField] private float m_ItemOpacity = 1;
|
||||
[SerializeField][Since("v3.15.0")] private float m_ItemInactiveOpacity = 1;
|
||||
[SerializeField] private string m_Formatter;
|
||||
[SerializeField] private LabelStyle m_LabelStyle = new LabelStyle();
|
||||
[SerializeField][Since("v3.10.0")] private TextLimit m_TextLimit = new TextLimit();
|
||||
[SerializeField] private List<string> m_Data = new List<string>();
|
||||
[SerializeField] private List<Sprite> m_Icons = new List<Sprite>();
|
||||
[SerializeField] private List<Color> m_Colors = new List<Color>();
|
||||
[SerializeField][Since("v3.1.0")] protected ImageStyle m_Background = new ImageStyle() { show = false };
|
||||
[SerializeField][Since("v3.1.0")] protected Padding m_Padding = new Padding();
|
||||
[SerializeField][Since("v3.6.0")] private List<Vector3> m_Positions = new List<Vector3>();
|
||||
|
||||
public LegendContext context = new LegendContext();
|
||||
|
||||
/// <summary>
|
||||
/// Whether to show legend component.
|
||||
/// ||是否显示图例组件。
|
||||
/// </summary>
|
||||
public bool show
|
||||
{
|
||||
get { return m_Show; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetComponentDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// Type of legend.
|
||||
/// ||图例类型。
|
||||
/// </summary>
|
||||
public Type iconType
|
||||
{
|
||||
get { return m_IconType; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_IconType, value)) SetAllDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// Selected mode of legend, which controls whether series can be toggled displaying by clicking legends.
|
||||
/// ||选择模式。控制是否可以通过点击图例改变系列的显示状态。默认开启图例选择,可以设成 None 关闭。
|
||||
/// </summary>
|
||||
public SelectedMode selectedMode
|
||||
{
|
||||
get { return m_SelectedMode; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_SelectedMode, value)) SetComponentDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// Specify whether the layout of legend component is horizontal or vertical.
|
||||
/// ||布局方式是横还是竖。
|
||||
/// </summary>
|
||||
public Orient orient
|
||||
{
|
||||
get { return m_Orient; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_Orient, value)) SetComponentDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The location of legend.
|
||||
/// ||图例显示的位置。
|
||||
/// </summary>
|
||||
public Location location
|
||||
{
|
||||
get { return m_Location; }
|
||||
set { if (PropertyUtil.SetClass(ref m_Location, value)) SetComponentDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// Image width of legend symbol.
|
||||
/// ||图例标记的图形宽度。
|
||||
/// </summary>
|
||||
public float itemWidth
|
||||
{
|
||||
get { return m_ItemWidth; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_ItemWidth, value)) SetComponentDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// Image height of legend symbol.
|
||||
/// ||图例标记的图形高度。
|
||||
/// </summary>
|
||||
public float itemHeight
|
||||
{
|
||||
get { return m_ItemHeight; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_ItemHeight, value)) SetComponentDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The distance between each legend, horizontal distance in horizontal layout, and vertical distance in vertical layout.
|
||||
/// ||图例每项之间的间隔。横向布局时为水平间隔,纵向布局时为纵向间隔。
|
||||
/// </summary>
|
||||
public float itemGap
|
||||
{
|
||||
get { return m_ItemGap; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_ItemGap, value)) SetComponentDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// Whether the legend symbol matches the color automatically.
|
||||
/// ||图例标记的图形是否自动匹配颜色。
|
||||
/// </summary>
|
||||
public bool itemAutoColor
|
||||
{
|
||||
get { return m_ItemAutoColor; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_ItemAutoColor, value)) SetComponentDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// the opacity of item color.
|
||||
/// ||图例标记的图形的颜色透明度。
|
||||
/// </summary>
|
||||
public float itemOpacity
|
||||
{
|
||||
get { return m_ItemOpacity; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_ItemOpacity, value)) SetComponentDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// the opacity of item color when item is inactive.
|
||||
/// ||图例标记的图形在非激活状态下的颜色透明度。
|
||||
/// </summary>
|
||||
public float itemInactiveOpacity
|
||||
{
|
||||
get { return m_ItemInactiveOpacity; }
|
||||
set { if (PropertyUtil.SetStruct(ref m_ItemInactiveOpacity, value)) SetComponentDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// No longer used, the use of LabelStyle.formatter instead.
|
||||
/// ||不再使用,使用LabelStyle.formatter代替。
|
||||
/// </summary>
|
||||
[Obsolete("Use LabelStyle.formatter instead.", false)]
|
||||
public string formatter
|
||||
{
|
||||
get { return m_Formatter; }
|
||||
set { if (PropertyUtil.SetClass(ref m_Formatter, value)) SetComponentDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// the style of text.
|
||||
/// ||文本样式。
|
||||
/// </summary>
|
||||
public LabelStyle labelStyle
|
||||
{
|
||||
get { return m_LabelStyle; }
|
||||
set { if (PropertyUtil.SetClass(ref m_LabelStyle, value)) SetComponentDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// the limit of text.
|
||||
/// ||文本限制。
|
||||
/// </summary>
|
||||
public TextLimit textLimit
|
||||
{
|
||||
get { return m_TextLimit; }
|
||||
set { if (value != null) { m_TextLimit = value; SetComponentDirty(); } }
|
||||
}
|
||||
/// <summary>
|
||||
/// the sytle of background.
|
||||
/// ||背景图样式。
|
||||
/// </summary>
|
||||
public ImageStyle background
|
||||
{
|
||||
get { return m_Background; }
|
||||
set { if (PropertyUtil.SetClass(ref m_Background, value)) SetAllDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// the paddinng of item and background.
|
||||
/// ||图例标记和背景的间距。
|
||||
/// </summary>
|
||||
public Padding padding
|
||||
{
|
||||
get { return m_Padding; }
|
||||
set { if (PropertyUtil.SetClass(ref m_Padding, value)) SetAllDirty(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// Data array of legend. An array item is usually a name representing string. (If it is a pie chart,
|
||||
/// it could also be the name of a single data in the pie chart) of a series.
|
||||
/// If data is not specified, it will be auto collected from series.
|
||||
/// ||图例的数据数组。数组项通常为一个字符串,每一项代表一个系列的 name(如果是饼图,也可以是饼图单个数据的 name)。
|
||||
/// 如果 data 没有被指定,会自动从当前系列中获取。指定data时里面的数据项和serie匹配时才会生效。
|
||||
/// </summary>
|
||||
public List<string> data
|
||||
{
|
||||
get { return m_Data; }
|
||||
set { if (value != null) { m_Data = value; SetComponentDirty(); } }
|
||||
}
|
||||
/// <summary>
|
||||
/// 自定义的图例标记图形。
|
||||
/// </summary>
|
||||
public List<Sprite> icons
|
||||
{
|
||||
get { return m_Icons; }
|
||||
set { if (value != null) { m_Icons = value; SetComponentDirty(); } }
|
||||
}
|
||||
/// <summary>
|
||||
/// the colors of legend item.
|
||||
/// ||图例标记的颜色列表。
|
||||
/// </summary>
|
||||
public List<Color> colors
|
||||
{
|
||||
get { return m_Colors; }
|
||||
set { if (value != null) { m_Colors = value; SetAllDirty(); } }
|
||||
}
|
||||
/// <summary>
|
||||
/// the custom positions of legend item.
|
||||
/// ||图例标记的自定义位置列表。
|
||||
/// </summary>
|
||||
public List<Vector3> positions
|
||||
{
|
||||
get { return m_Positions; }
|
||||
set { if (value != null) { m_Positions = value; SetAllDirty(); } }
|
||||
}
|
||||
/// <summary>
|
||||
/// 图表是否需要刷新(图例组件不需要刷新图表)
|
||||
/// </summary>
|
||||
public override bool vertsDirty { get { return false; } }
|
||||
/// <summary>
|
||||
/// 组件是否需要刷新
|
||||
/// </summary>
|
||||
public override bool componentDirty
|
||||
{
|
||||
get { return m_ComponentDirty || location.componentDirty || labelStyle.componentDirty || textLimit.componentDirty; }
|
||||
}
|
||||
|
||||
public override void ClearComponentDirty()
|
||||
{
|
||||
base.ClearComponentDirty();
|
||||
location.ClearComponentDirty();
|
||||
labelStyle.ClearComponentDirty();
|
||||
textLimit.ClearComponentDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear legend data.
|
||||
/// ||清空。
|
||||
/// </summary>
|
||||
public override void ClearData()
|
||||
{
|
||||
m_Data.Clear();
|
||||
SetComponentDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether include in legend data by the specified name.
|
||||
/// ||是否包括由指定名字的图例
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public bool ContainsData(string name)
|
||||
{
|
||||
return m_Data.Contains(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the legend with the specified name.
|
||||
/// ||移除指定名字的图例。
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
public void RemoveData(string name)
|
||||
{
|
||||
if (m_Data.Contains(name))
|
||||
{
|
||||
m_Data.Remove(name);
|
||||
SetComponentDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add legend data.
|
||||
/// ||添加图例。
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
public void AddData(string name)
|
||||
{
|
||||
if (!m_Data.Contains(name) && !string.IsNullOrEmpty(name))
|
||||
{
|
||||
m_Data.Add(name);
|
||||
SetComponentDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the legend for the specified index.
|
||||
/// ||获得指定索引的图例。
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public string GetData(int index)
|
||||
{
|
||||
if (index >= 0 && index < m_Data.Count)
|
||||
{
|
||||
return m_Data[index];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the specified legend.
|
||||
/// ||获得指定图例的索引。
|
||||
/// </summary>
|
||||
/// <param name="legendName"></param>
|
||||
/// <returns></returns>
|
||||
public int GetIndex(string legendName)
|
||||
{
|
||||
return m_Data.IndexOf(legendName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all legend buttons.
|
||||
/// ||移除所有图例按钮。
|
||||
/// </summary>
|
||||
public void RemoveButton()
|
||||
{
|
||||
context.buttonList.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bind buttons to legends.
|
||||
/// ||给图例绑定按钮。
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="btn"></param>
|
||||
/// <param name="total"></param>
|
||||
public void SetButton(string name, LegendItem item, int total)
|
||||
{
|
||||
context.buttonList[name] = item;
|
||||
int index = context.buttonList.Values.Count;
|
||||
item.SetIconActive(iconType == Type.Custom);
|
||||
item.SetActive(show);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the legend button color.
|
||||
/// ||更新图例按钮颜色。
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="color"></param>
|
||||
public void UpdateButtonColor(string name, Color color)
|
||||
{
|
||||
if (context.buttonList.ContainsKey(name))
|
||||
{
|
||||
context.buttonList[name].SetIconColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the text color of legend.
|
||||
/// ||更新图例文字颜色。
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="color"></param>
|
||||
public void UpdateContentColor(string name, Color color)
|
||||
{
|
||||
if (context.buttonList.ContainsKey(name))
|
||||
{
|
||||
context.buttonList[name].SetContentColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the legend button for the specified index.
|
||||
/// ||获得指定索引的图例按钮。
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public Sprite GetIcon(int index)
|
||||
{
|
||||
if (index >= 0 && index < m_Icons.Count)
|
||||
{
|
||||
return m_Icons[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Color GetColor(int index)
|
||||
{
|
||||
if (index >= 0 && index < m_Colors.Count)
|
||||
return m_Colors[index];
|
||||
else
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
public Vector3 GetPosition(int index, Vector3 defaultPos)
|
||||
{
|
||||
if (index >= 0 && index < m_Positions.Count)
|
||||
return m_Positions[index];
|
||||
else
|
||||
return defaultPos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback handling when parameters change.
|
||||
/// ||参数变更时的回调处理。
|
||||
/// </summary>
|
||||
public void OnChanged()
|
||||
{
|
||||
m_Location.OnChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c53210fe487d047b6a51bacc0d3e7a71
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace XCharts.Runtime
|
||||
{
|
||||
|
||||
public class LegendContext : MainComponentContext
|
||||
{
|
||||
/// <summary>
|
||||
/// 运行时图例的总宽度
|
||||
/// </summary>
|
||||
public float width { get; internal set; }
|
||||
/// <summary>
|
||||
/// 运行时图例的总高度
|
||||
/// </summary>
|
||||
public float height { get; internal set; }
|
||||
public Vector2 center { get; internal set; }
|
||||
/// <summary>
|
||||
/// the button list of legend.
|
||||
/// ||图例按钮列表。
|
||||
/// </summary>
|
||||
internal Dictionary<string, LegendItem> buttonList = new Dictionary<string, LegendItem>();
|
||||
/// <summary>
|
||||
/// 多列时每列的宽度
|
||||
/// </summary>
|
||||
internal Dictionary<int, float> eachWidthDict = new Dictionary<int, float>();
|
||||
/// <summary>
|
||||
/// 单列高度
|
||||
/// </summary>
|
||||
internal float eachHeight { get; set; }
|
||||
public Image background { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c62c17c9d5b2b4a0fb260103c3ceb5ac
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,288 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
using XUGL;
|
||||
|
||||
namespace XCharts.Runtime
|
||||
{
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
internal sealed class LegendHandler : MainComponentHandler<Legend>
|
||||
{
|
||||
private static readonly string s_LegendObjectName = "legend";
|
||||
private static readonly char[] s_NameSplit = new char[] { '_' };
|
||||
|
||||
public override void InitComponent()
|
||||
{
|
||||
InitLegend(component);
|
||||
}
|
||||
|
||||
public override void CheckComponent(System.Text.StringBuilder sb)
|
||||
{
|
||||
var legend = component;
|
||||
if (ChartHelper.IsColorAlphaZero(legend.labelStyle.textStyle.color))
|
||||
sb.AppendFormat("warning:legend{0}->textStyle->color alpha is 0\n", legend.index);
|
||||
var serieNameList = SeriesHelper.GetLegalSerieNameList(chart.series);
|
||||
if (serieNameList.Count == 0)
|
||||
sb.AppendFormat("warning:legend{0} need serie.serieName or serieData.name not empty\n", legend.index);
|
||||
foreach (var category in legend.data)
|
||||
{
|
||||
if (!serieNameList.Contains(category))
|
||||
{
|
||||
sb.AppendFormat("warning:legend{0} [{1}] is invalid, must be one of serie.serieName or serieData.name\n",
|
||||
legend.index, category);
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void DrawTop(VertexHelper vh)
|
||||
{
|
||||
DrawLegend(vh);
|
||||
}
|
||||
|
||||
public override void OnSerieDataUpdate(int serieIndex)
|
||||
{
|
||||
#pragma warning disable 0618
|
||||
if (FormatterHelper.NeedFormat(component.formatter) || FormatterHelper.NeedFormat(component.labelStyle.formatter))
|
||||
component.refreshComponent();
|
||||
#pragma warning restore 0618
|
||||
}
|
||||
|
||||
private void InitLegend(Legend legend)
|
||||
{
|
||||
legend.painter = null;
|
||||
legend.refreshComponent = delegate ()
|
||||
{
|
||||
legend.OnChanged();
|
||||
var legendObject = ChartHelper.AddObject(s_LegendObjectName + legend.index, chart.transform, chart.chartMinAnchor,
|
||||
chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta, -1, chart.childrenNodeNames);
|
||||
legend.gameObject = legendObject;
|
||||
legendObject.hideFlags = chart.chartHideFlags;
|
||||
//ChartHelper.DestoryGameObjectByMatch(legendObject.transform, "_");
|
||||
SeriesHelper.UpdateSerieNameList(chart, ref chart.m_LegendRealShowName);
|
||||
legend.context.background = ChartHelper.AddIcon("background", legendObject.transform, 0, 0);
|
||||
legend.context.background.transform.SetSiblingIndex(0);
|
||||
ChartHelper.SetBackground(legend.context.background, legend.background);
|
||||
List<string> datas;
|
||||
if (legend.show && legend.data.Count > 0)
|
||||
{
|
||||
datas = new List<string>();
|
||||
foreach (var data in legend.data)
|
||||
{
|
||||
if (chart.m_LegendRealShowName.Contains(data) || chart.IsSerieName(data))
|
||||
datas.Add(data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
datas = chart.m_LegendRealShowName;
|
||||
}
|
||||
int totalLegend = 0;
|
||||
for (int i = 0; i < datas.Count; i++)
|
||||
{
|
||||
if (!SeriesHelper.IsLegalLegendName(datas[i])) continue;
|
||||
totalLegend++;
|
||||
}
|
||||
legend.RemoveButton();
|
||||
ChartHelper.HideAllObject(legendObject);
|
||||
if (!legend.show) return;
|
||||
var textLimitInitFlag = false;
|
||||
var isAnySerieColorByData = SeriesHelper.IsAnyColorByDataSerie(chart.series);
|
||||
for (int i = 0; i < datas.Count; i++)
|
||||
{
|
||||
if (!SeriesHelper.IsLegalLegendName(datas[i])) continue;
|
||||
string legendName = datas[i];
|
||||
var serieIndex = isAnySerieColorByData ? 0 : i;
|
||||
var dataIndex = isAnySerieColorByData ? i : 0;
|
||||
var legendContent = GetFormatterContent(legend, dataIndex, datas[i], serieIndex);
|
||||
if (legend.textLimit.enable)
|
||||
legendContent = legend.textLimit.GetLimitContent(legendContent);
|
||||
var readIndex = chart.m_LegendRealShowName.IndexOf(datas[i]);
|
||||
var active = chart.IsActiveByLegend(datas[i]);
|
||||
var bgColor = LegendHelper.GetIconColor(chart, legend, readIndex, datas[i], active);
|
||||
bgColor.a = active ? legend.itemOpacity : legend.itemInactiveOpacity;
|
||||
var item = LegendHelper.AddLegendItem(chart, legend, i, legendName, legendObject.transform, chart.theme,
|
||||
legendContent, bgColor, active, readIndex);
|
||||
legend.SetButton(legendName, item, totalLegend);
|
||||
if (!textLimitInitFlag && legend.textLimit.enable)
|
||||
{
|
||||
textLimitInitFlag = true;
|
||||
legend.textLimit.SetRelatedText(item.text, legend.itemWidth);
|
||||
}
|
||||
ChartHelper.ClearEventListener(item.button.gameObject);
|
||||
ChartHelper.AddEventListener(item.button.gameObject, EventTriggerType.PointerDown, (data) =>
|
||||
{
|
||||
if (data.selectedObject == null || legend.selectedMode == Legend.SelectedMode.None) return;
|
||||
var temp = data.selectedObject.name.Split(s_NameSplit, 2);
|
||||
string selectedName = temp[1];
|
||||
int clickedIndex = int.Parse(temp[0]);
|
||||
if (legend.selectedMode == Legend.SelectedMode.Multiple)
|
||||
{
|
||||
OnLegendButtonClick(legend, clickedIndex, selectedName, !chart.IsActiveByLegend(selectedName));
|
||||
}
|
||||
else
|
||||
{
|
||||
var btnList = legend.context.buttonList.Values.ToArray();
|
||||
if (btnList.Length == 1)
|
||||
{
|
||||
OnLegendButtonClick(legend, 0, selectedName, !chart.IsActiveByLegend(selectedName));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int n = 0; n < btnList.Length; n++)
|
||||
{
|
||||
temp = btnList[n].name.Split(s_NameSplit, 2);
|
||||
selectedName = btnList[n].legendName;
|
||||
var index = btnList[n].index;
|
||||
OnLegendButtonClick(legend, n, selectedName, index == clickedIndex ? true : false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
ChartHelper.AddEventListener(item.button.gameObject, EventTriggerType.PointerEnter, (data) =>
|
||||
{
|
||||
if (item.button == null) return;
|
||||
var temp = item.button.name.Split(s_NameSplit, 2);
|
||||
string selectedName = temp[1];
|
||||
int index = int.Parse(temp[0]);
|
||||
OnLegendButtonEnter(legend, index, selectedName);
|
||||
});
|
||||
ChartHelper.AddEventListener(item.button.gameObject, EventTriggerType.PointerExit, (data) =>
|
||||
{
|
||||
if (item.button == null) return;
|
||||
var temp = item.button.name.Split(s_NameSplit, 2);
|
||||
string selectedName = temp[1];
|
||||
int index = int.Parse(temp[0]);
|
||||
OnLegendButtonExit(legend, index, selectedName);
|
||||
});
|
||||
}
|
||||
LegendHelper.ResetItemPosition(legend, chart.chartPosition, chart.chartWidth, chart.chartHeight);
|
||||
};
|
||||
legend.refreshComponent();
|
||||
}
|
||||
|
||||
private string GetFormatterContent(Legend legend, int dataIndex, string category, int serieIndex)
|
||||
{
|
||||
#pragma warning disable 0618
|
||||
if (string.IsNullOrEmpty(legend.formatter) && string.IsNullOrEmpty(legend.labelStyle.formatter))
|
||||
return category;
|
||||
else
|
||||
{
|
||||
var formatter = string.IsNullOrEmpty(legend.labelStyle.formatter) ? legend.formatter : legend.labelStyle.formatter;
|
||||
var content = formatter.Replace("{name}", category);
|
||||
content = content.Replace("{value}", category);
|
||||
var serie = chart.GetSerie(serieIndex);
|
||||
FormatterHelper.ReplaceContent(ref content, dataIndex, legend.labelStyle.numericFormatter, serie, chart, category);
|
||||
return content;
|
||||
}
|
||||
#pragma warning restore 0618
|
||||
}
|
||||
|
||||
private void OnLegendButtonClick(Legend legend, int index, string legendName, bool show)
|
||||
{
|
||||
chart.OnLegendButtonClick(index, legendName, show);
|
||||
if (chart.onLegendClick != null)
|
||||
chart.onLegendClick(legend, index, legendName, show);
|
||||
}
|
||||
|
||||
private void OnLegendButtonEnter(Legend legend, int index, string legendName)
|
||||
{
|
||||
chart.OnLegendButtonEnter(index, legendName);
|
||||
if (chart.onLegendEnter != null)
|
||||
chart.onLegendEnter(legend, index, legendName);
|
||||
}
|
||||
|
||||
private void OnLegendButtonExit(Legend legend, int index, string legendName)
|
||||
{
|
||||
chart.OnLegendButtonExit(index, legendName);
|
||||
if (chart.onLegendExit != null)
|
||||
chart.onLegendExit(legend, index, legendName);
|
||||
}
|
||||
|
||||
private void DrawLegend(VertexHelper vh)
|
||||
{
|
||||
if (chart.series.Count == 0) return;
|
||||
var legend = component;
|
||||
if (!legend.show) return;
|
||||
if (legend.iconType == Legend.Type.Custom) return;
|
||||
foreach (var kv in legend.context.buttonList)
|
||||
{
|
||||
var item = kv.Value;
|
||||
var rect = item.GetIconRect();
|
||||
var radius = Mathf.Min(rect.width, rect.height) / 2;
|
||||
var color = item.GetIconColor();
|
||||
var iconType = legend.iconType;
|
||||
if (legend.iconType == Legend.Type.Auto)
|
||||
{
|
||||
var serie = chart.GetSerie(item.legendName);
|
||||
if (serie != null)
|
||||
{
|
||||
if (serie is Line || serie is SimplifiedLine)
|
||||
{
|
||||
var sp = new Vector3(rect.center.x - rect.width / 2, rect.center.y);
|
||||
var ep = new Vector3(rect.center.x + rect.width / 2, rect.center.y);
|
||||
UGL.DrawLine(vh, sp, ep, chart.settings.legendIconLineWidth, color);
|
||||
if (!serie.symbol.show) continue;
|
||||
switch (serie.symbol.type)
|
||||
{
|
||||
case SymbolType.None:
|
||||
continue;
|
||||
case SymbolType.Circle:
|
||||
iconType = Legend.Type.Circle;
|
||||
break;
|
||||
case SymbolType.Diamond:
|
||||
iconType = Legend.Type.Diamond;
|
||||
break;
|
||||
case SymbolType.EmptyCircle:
|
||||
iconType = Legend.Type.EmptyCircle;
|
||||
break;
|
||||
case SymbolType.Rect:
|
||||
iconType = Legend.Type.Rect;
|
||||
break;
|
||||
case SymbolType.Triangle:
|
||||
iconType = Legend.Type.Triangle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iconType = Legend.Type.Rect;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iconType = Legend.Type.Rect;
|
||||
}
|
||||
}
|
||||
switch (iconType)
|
||||
{
|
||||
case Legend.Type.Rect:
|
||||
var cornerRadius = chart.settings.legendIconCornerRadius;
|
||||
UGL.DrawRoundRectangle(vh, rect.center, rect.width, rect.height, color, color,
|
||||
0, cornerRadius, false, 0.5f);
|
||||
break;
|
||||
case Legend.Type.Circle:
|
||||
UGL.DrawCricle(vh, rect.center, radius, color);
|
||||
break;
|
||||
case Legend.Type.Diamond:
|
||||
UGL.DrawDiamond(vh, rect.center, radius, color);
|
||||
break;
|
||||
case Legend.Type.EmptyCircle:
|
||||
var backgroundColor = chart.GetChartBackgroundColor();
|
||||
UGL.DrawEmptyCricle(vh, rect.center, radius, 2 * chart.settings.legendIconLineWidth,
|
||||
color, color, backgroundColor, 1f);
|
||||
break;
|
||||
case Legend.Type.Triangle:
|
||||
UGL.DrawTriangle(vh, rect.center, 1.2f * radius, color);
|
||||
break;
|
||||
case Legend.Type.Candlestick:
|
||||
UGL.DrawRoundRectangle(vh, rect.center, rect.width / 2, rect.height / 2, color, color,
|
||||
0, null, false, 0.5f);
|
||||
UGL.DrawLine(vh, new Vector3(rect.center.x, rect.center.y - rect.height / 2),
|
||||
new Vector3(rect.center.x, rect.center.y + rect.height / 2), 1, color);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d05c7e75b9d3c4a839099bf152752af1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,311 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace XCharts.Runtime
|
||||
{
|
||||
public static class LegendHelper
|
||||
{
|
||||
public static Color GetContentColor(BaseChart chart, int legendIndex, string legendName, Legend legend, ThemeStyle theme, bool active)
|
||||
{
|
||||
var textStyle = legend.labelStyle.textStyle;
|
||||
if (active)
|
||||
{
|
||||
if (legend.labelStyle.textStyle.autoColor)
|
||||
return SeriesHelper.GetNameColor(chart, legendIndex, legendName);
|
||||
else
|
||||
return !ChartHelper.IsClearColor(textStyle.color) ? textStyle.color : theme.legend.textColor;
|
||||
}
|
||||
else return theme.legend.inactiveColor;
|
||||
}
|
||||
|
||||
public static Color GetIconColor(BaseChart chart, Legend legend, int readIndex, string legendName, bool active)
|
||||
{
|
||||
if (active)
|
||||
{
|
||||
if (legend.itemAutoColor)
|
||||
{
|
||||
return SeriesHelper.GetNameColor(chart, readIndex, legendName);
|
||||
}
|
||||
else
|
||||
return legend.GetColor(readIndex);
|
||||
}
|
||||
else return chart.theme.legend.inactiveColor;
|
||||
}
|
||||
|
||||
public static LegendItem AddLegendItem(BaseChart chart, Legend legend, int i, string legendName, Transform parent,
|
||||
ThemeStyle theme, string content, Color itemColor, bool active, int legendIndex)
|
||||
{
|
||||
var objName = i + "_" + legendName;
|
||||
var anchorMin = new Vector2(0, 0.5f);
|
||||
var anchorMax = new Vector2(0, 0.5f);
|
||||
var pivot = new Vector2(0, 0.5f);
|
||||
var sizeDelta = new Vector2(100, 30);
|
||||
var iconSizeDelta = new Vector2(legend.itemWidth, legend.itemHeight);
|
||||
var textStyle = legend.labelStyle.textStyle;
|
||||
var contentColor = GetContentColor(chart, legendIndex, legendName, legend, theme, active);
|
||||
|
||||
var objAnchorMin = new Vector2(0, 1);
|
||||
var objAnchorMax = new Vector2(0, 1);
|
||||
var objPivot = new Vector2(0, 1);
|
||||
var btnObj = ChartHelper.AddObject(objName, parent, objAnchorMin, objAnchorMax, objPivot, sizeDelta, -1, chart.childrenNodeNames);
|
||||
var iconObj = ChartHelper.AddObject("icon", btnObj.transform, anchorMin, anchorMax, pivot, iconSizeDelta);
|
||||
var img = ChartHelper.EnsureComponent<Image>(btnObj);
|
||||
img.color = Color.clear;
|
||||
img.raycastTarget = true;
|
||||
ChartHelper.EnsureComponent<Button>(btnObj);
|
||||
ChartHelper.EnsureComponent<Image>(iconObj);
|
||||
|
||||
var label = ChartHelper.AddChartLabel("content", btnObj.transform, legend.labelStyle, theme.legend,
|
||||
content, contentColor, TextAnchor.MiddleLeft);
|
||||
label.SetActive(true, true);
|
||||
|
||||
var item = new LegendItem();
|
||||
item.index = i;
|
||||
item.name = objName;
|
||||
item.legendName = legendName;
|
||||
item.SetObject(btnObj);
|
||||
item.SetIconSize(legend.itemWidth, legend.itemHeight);
|
||||
item.SetIconColor(itemColor);
|
||||
item.SetIconImage(legend.GetIcon(i));
|
||||
item.SetContentPosition(legend.labelStyle.offset);
|
||||
item.SetContent(content);
|
||||
//item.SetBackground(legend.background);
|
||||
return item;
|
||||
}
|
||||
|
||||
public static void SetLegendBackground(Legend legend, ImageStyle style)
|
||||
{
|
||||
var background = legend.context.background;
|
||||
if (background == null) return;
|
||||
ChartHelper.SetActive(background, style.show);
|
||||
if (!style.show) return;
|
||||
var rect = background.gameObject.GetComponent<RectTransform>();
|
||||
rect.localPosition = legend.context.center;
|
||||
rect.sizeDelta = new Vector2(legend.context.width, legend.context.height);
|
||||
ChartHelper.SetBackground(background, style);
|
||||
}
|
||||
|
||||
public static void ResetItemPosition(Legend legend, Vector3 chartPos, float chartWidth, float chartHeight)
|
||||
{
|
||||
legend.location.UpdateRuntimeData(chartWidth, chartHeight);
|
||||
var startX = 0f;
|
||||
var startY = 0f;
|
||||
var legendMaxWidth = chartWidth - legend.location.runtimeLeft - legend.location.runtimeRight;
|
||||
var legendMaxHeight = chartHeight - legend.location.runtimeTop - legend.location.runtimeBottom;
|
||||
UpdateLegendWidthAndHeight(legend, legendMaxWidth, legendMaxHeight);
|
||||
var legendRuntimeWidth = legend.context.width;
|
||||
var legendRuntimeHeight = legend.context.height;
|
||||
var isVertical = legend.orient == Orient.Vertical;
|
||||
switch (legend.location.align)
|
||||
{
|
||||
case Location.Align.TopCenter:
|
||||
startX = chartPos.x + chartWidth / 2 - legendRuntimeWidth / 2;
|
||||
startY = chartPos.y + chartHeight - legend.location.runtimeTop;
|
||||
break;
|
||||
case Location.Align.TopLeft:
|
||||
startX = chartPos.x + legend.location.runtimeLeft;
|
||||
startY = chartPos.y + chartHeight - legend.location.runtimeTop;
|
||||
break;
|
||||
case Location.Align.TopRight:
|
||||
startX = chartPos.x + chartWidth - legendRuntimeWidth - legend.location.runtimeRight;
|
||||
startY = chartPos.y + chartHeight - legend.location.runtimeTop;
|
||||
break;
|
||||
case Location.Align.Center:
|
||||
startX = chartPos.x + chartWidth / 2 - legendRuntimeWidth / 2;
|
||||
startY = chartPos.y + chartHeight / 2 + legendRuntimeHeight / 2;
|
||||
break;
|
||||
case Location.Align.CenterLeft:
|
||||
startX = chartPos.x + legend.location.runtimeLeft;
|
||||
startY = chartPos.y + chartHeight / 2 + legendRuntimeHeight / 2;
|
||||
break;
|
||||
case Location.Align.CenterRight:
|
||||
startX = chartPos.x + chartWidth - legendRuntimeWidth - legend.location.runtimeRight;
|
||||
startY = chartPos.y + chartHeight / 2 + legendRuntimeHeight / 2;
|
||||
break;
|
||||
case Location.Align.BottomCenter:
|
||||
startX = chartPos.x + chartWidth / 2 - legendRuntimeWidth / 2;
|
||||
startY = chartPos.y + legendRuntimeHeight + legend.location.runtimeBottom;
|
||||
break;
|
||||
case Location.Align.BottomLeft:
|
||||
startX = chartPos.x + legend.location.runtimeLeft;
|
||||
startY = chartPos.y + legendRuntimeHeight + legend.location.runtimeBottom;
|
||||
break;
|
||||
case Location.Align.BottomRight:
|
||||
startX = chartPos.x + chartWidth - legendRuntimeWidth - legend.location.runtimeRight;
|
||||
startY = chartPos.y + legendRuntimeHeight + legend.location.runtimeBottom;
|
||||
break;
|
||||
}
|
||||
if (!legend.padding.show)
|
||||
{
|
||||
legend.context.center = new Vector2(startX + legend.context.width / 2, startY - legend.context.height / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
legend.context.center = new Vector2(startX + legend.context.width / 2 - legend.padding.left,
|
||||
startY - legend.context.height / 2 + legend.padding.top);
|
||||
}
|
||||
|
||||
if (isVertical) SetVerticalItemPosition(legend, legendMaxHeight, startX, startY);
|
||||
else SetHorizonalItemPosition(legend, legendMaxWidth, startX, startY);
|
||||
SetLegendBackground(legend, legend.background);
|
||||
}
|
||||
|
||||
private static void SetVerticalItemPosition(Legend legend, float legendMaxHeight, float startX, float startY)
|
||||
{
|
||||
var currHeight = 0f;
|
||||
var offsetX = 0f;
|
||||
var row = 0;
|
||||
var index = 0;
|
||||
foreach (var kv in legend.context.buttonList)
|
||||
{
|
||||
var item = kv.Value;
|
||||
if (currHeight + item.height > legendMaxHeight)
|
||||
{
|
||||
currHeight = 0;
|
||||
offsetX += legend.context.eachWidthDict[row];
|
||||
row++;
|
||||
}
|
||||
item.SetPosition(legend.GetPosition(index++, new Vector3(startX + offsetX, startY - currHeight)));
|
||||
currHeight += item.height + legend.itemGap;
|
||||
}
|
||||
}
|
||||
private static void SetHorizonalItemPosition(Legend legend, float legendMaxWidth, float startX, float startY)
|
||||
{
|
||||
var currWidth = 0f;
|
||||
var offsetY = 0f;
|
||||
var index = 0;
|
||||
foreach (var kv in legend.context.buttonList)
|
||||
{
|
||||
var item = kv.Value;
|
||||
if (currWidth + item.width > legendMaxWidth)
|
||||
{
|
||||
currWidth = 0;
|
||||
offsetY += legend.context.eachHeight;
|
||||
}
|
||||
item.SetPosition(legend.GetPosition(index++, new Vector3(startX + currWidth, startY - offsetY)));
|
||||
currWidth += item.width + legend.itemGap;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateLegendWidthAndHeight(Legend legend, float maxWidth, float maxHeight)
|
||||
{
|
||||
var width = 0f;
|
||||
var height = 0f;
|
||||
var realHeight = 0f;
|
||||
var realWidth = 0f;
|
||||
legend.context.eachWidthDict.Clear();
|
||||
legend.context.eachHeight = 0;
|
||||
if (legend.orient == Orient.Horizonal)
|
||||
{
|
||||
foreach (var kv in legend.context.buttonList)
|
||||
{
|
||||
if (width + kv.Value.width > maxWidth)
|
||||
{
|
||||
realWidth = width - legend.itemGap;
|
||||
realHeight += height + legend.itemGap;
|
||||
if (legend.context.eachHeight < height + legend.itemGap)
|
||||
{
|
||||
legend.context.eachHeight = height + legend.itemGap;
|
||||
}
|
||||
height = 0;
|
||||
width = 0;
|
||||
}
|
||||
width += kv.Value.width + legend.itemGap;
|
||||
if (kv.Value.height > height)
|
||||
height = kv.Value.height;
|
||||
}
|
||||
width -= legend.itemGap;
|
||||
legend.context.height = realHeight + height;
|
||||
legend.context.width = realWidth > 0 ? realWidth : width;
|
||||
}
|
||||
else
|
||||
{
|
||||
var row = 0;
|
||||
foreach (var kv in legend.context.buttonList)
|
||||
{
|
||||
if (height + kv.Value.height > maxHeight)
|
||||
{
|
||||
realHeight = height - legend.itemGap;
|
||||
realWidth += width + legend.itemGap;
|
||||
legend.context.eachWidthDict[row] = width + legend.itemGap;
|
||||
row++;
|
||||
height = 0;
|
||||
width = 0;
|
||||
}
|
||||
height += kv.Value.height + legend.itemGap;
|
||||
if (kv.Value.width > width)
|
||||
width = kv.Value.width;
|
||||
}
|
||||
height -= legend.itemGap;
|
||||
legend.context.height = realHeight > 0 ? realHeight : height;
|
||||
legend.context.width = realWidth + width;
|
||||
}
|
||||
if (legend.padding.show)
|
||||
{
|
||||
legend.context.width += legend.padding.left + legend.padding.right;
|
||||
legend.context.height += legend.padding.top + legend.padding.bottom;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsBeyondWidth(Legend legend, float maxWidth)
|
||||
{
|
||||
var totalWidth = 0f;
|
||||
foreach (var kv in legend.context.buttonList)
|
||||
{
|
||||
var item = kv.Value;
|
||||
totalWidth += item.width + legend.itemGap;
|
||||
if (totalWidth > maxWidth) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool CheckDataShow(Serie serie, string legendName, bool show)
|
||||
{
|
||||
bool needShow = false;
|
||||
if (legendName.Equals(serie.serieName))
|
||||
{
|
||||
serie.show = show;
|
||||
serie.highlight = false;
|
||||
if (serie.show) needShow = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var data in serie.data)
|
||||
{
|
||||
if (legendName.Equals(data.name))
|
||||
{
|
||||
data.show = show;
|
||||
data.context.highlight = false;
|
||||
if (data.show) needShow = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return needShow;
|
||||
}
|
||||
|
||||
public static int CheckDataHighlighted(Serie serie, string legendName, bool heighlight)
|
||||
{
|
||||
var highlightedDataIndex = 0;
|
||||
if (legendName.Equals(serie.serieName))
|
||||
{
|
||||
serie.highlight = heighlight;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var data in serie.data)
|
||||
{
|
||||
if (legendName.Equals(data.name))
|
||||
{
|
||||
data.context.highlight = heighlight;
|
||||
if (data.context.highlight)
|
||||
{
|
||||
highlightedDataIndex = data.index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return highlightedDataIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc1c14527667e4475a275768371b3b9a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user