运行时数据注入(UIToolKit)
本章介绍:在 UI Toolkit 工作流下,如何在运行时给 ChartElement 注入数据。
对应脚本:EasyChartDataSource
1. 这套方案适合什么场景?
- 你的图表是 UI Toolkit 体系(
UIDocument+ UXML +ChartElement) - 你希望提供一套“业务侧更容易调用”的注入 API(labels / values / x-y / pie / ring)
- 或者你希望直接拿一段 JSON 注入(
ChartFeed)
2. 快速上手(最推荐的流程)
- 在场景里准备
UIDocument,并确保 UXML 里有ChartElement。 - 在挂着
UIDocument的 GameObject 上添加组件:EasyChartDataSource。 - 在 Inspector 里填写:
uiDocumentchartElementName(默认main-chart,对应 UXML 中ChartElement的name)profile(可选,但强烈建议填:让样式/Series 类型来自你在编辑器配置好的ChartProfile)
- 在运行时用代码调用:
SetCategoryLabels(...)SetSeriesValues(...)/SetSeriesXY(...)- 或
ApplyJson(...)
组件内部会:
- 从
UIDocument.rootVisualElement里找到目标ChartElement - 必要时用
profile初始化图表 Data - 修改
ChartElement.Data并调用RefreshData()
3. Inspector 字段说明
EasyChartDataSource 的核心配置字段:
-
uiDocument- 指向当前 UI 的
UIDocument。 - 如果不填,脚本会尝试
GetComponent<UIDocument>()。
- 指向当前 UI 的
-
chartElementName- 目标
ChartElement的name(UXML/USS 的那个 name)。默认值为main-chart。 - 如果你希望用 JSON 中的
chartId/chartName自动定位,也可以让ChartElement的name与之保持一致(见第 5 节)。
- 目标
-
profile- 可选。
- 如果赋值,组件会将
ChartElement.Profile = profile,用于初始化/保持样式、Series 结构等。
-
playAnimationOnRefresh- 每次注入后调用
RefreshData(..., playAnimation: playAnimationOnRefresh)。
- 每次注入后调用
-
allowCreateSeriesFromFeed- 当你用 JSON(
ApplyJson)注入时,如果 feed 中的 series 无法匹配到现有 Serie:false(默认):不创建新 Serie,只更新匹配到的部分。true:允许根据 feed 创建新的 Serie(可能触发重建 renderers)。
- 当你用 JSON(
4. 常用注入 API(不写 JSON)
4.1 设置类目轴标签
SetCategoryLabels(labels, axisId = AxisId.XBottom)
- 会把该轴设为 Category,并覆盖
labels。
4.2 单序列 y 值(自动 x=0..n-1)
SetSeriesValues("Sales", values)
- 默认会找到/创建一条 Serie(默认类型为 Line,不强制改类型)。
- 写入
SeriesData.value,并把SeriesData.x设为索引。
4.3 XY 点
SetSeriesXY("Scatter", x, y)
- 把
x[]写入SeriesData.x,把y[]写入SeriesData.value。
4.4 Pie / Ring 注入
-
SetPie(serieName, names, values)- 强制该 Serie 为
Pie类型。 - 使用
SeriesData.name作为切片名,SeriesData.value为数值。
- 强制该 Serie 为
-
SetRing(serieName, names, percents)- 强制该 Serie 为
RingChart类型。 - 使用
SeriesData.name作为环名,SeriesData.value为进度值。
- 强制该 Serie 为
5. JSON 注入(ChartFeed)
你可以用:ApplyJson(json)
该方法会把 JSON 解析为 ChartFeed 并应用到 ChartElement.Data。
5.1 ChartFeed 结构
{
"chartId": "optional",
"chartName": "optional",
"axes": [
{
"axisId": "XBottom",
"labels": ["Mon", "Tue", "Wed"]
}
],
"series": [
{
"serieId": "optional",
"name": "optional",
"type": "Line",
"datas": [
{ "x": 0, "value": 12 },
{ "x": 1, "value": 18 }
]
}
]
}
对应字段见运行时代码 Scripts/Runtime/Feed/ChartFeed.cs。
5.2 ChartElement 的定位规则(chartId / chartName)
ApplyJson 内部会尝试:
- 如果 feed 提供了
chartId:优先rootVisualElement.Q<ChartElement>(chartId) - 其次如果提供了
chartName:尝试Q<ChartElement>(chartName) - 都找不到才退回到
chartElementName(默认main-chart)
因此:
- 如果你只有一个图表,保持默认值也没问题。
- 如果你一个 UI 里有多个
ChartElement,建议让每个图表的name与 feed 的chartId或chartName对齐。
5.3 series 匹配与类型覆盖
ApplyJson 会先检查 JSON 内是否出现过 "type":,若出现则认为你希望允许类型覆盖(allowTypeOverride=true)。
Serie 匹配规则:
- 如果
serieId非空:按Serie.id匹配 - 否则如果
name非空:按Serie.name匹配 - 否则(索引模式):按 feed 的序号匹配(第 i 条对第 i 条)
当无法匹配到 Serie 时:
allowCreateSeriesFromFeed=false(默认):该条 feed 会被跳过(不创建)。allowCreateSeriesFromFeed=true:会创建新的 Serie,并使用 feed 的type/name/serieId。
对已匹配到的 Serie:
- 仅当
allowTypeOverride=true且不是索引模式时,才会允许覆盖id/name/type。
6. 常见问题与排错
-
不显示 / TryGetChart 失败
- 确认
uiDocument赋值正确 - 确认 UXML 中
ChartElement的name与chartElementName一致
- 确认
-
JSON 解析失败
EasyChartDataSource解析 JSON 时:- 会优先尝试 Newtonsoft(若项目里存在
Newtonsoft.Json) - 否则使用 Unity
JsonUtility,并把type/axisId的字符串写法转换为枚举整数再解析
- 会优先尝试 Newtonsoft(若项目里存在
- 建议先用一份已知能解析的 JSON(例如从编辑器 JSON 面板生成)再改。
-
注入后 Series 对不上 / 更新错了线
- 优先使用
serieId做稳定匹配。 - 如果只用
name,且同名 Serie 存在多个,脚本会使用第一个并给 warning。
- 优先使用
-
JSON 想新增 Serie 但没新增
- 把
allowCreateSeriesFromFeed打开。
- 把