图表数据结构和插件属性配置是实现自定义可视化的核心环节之一,本文旨在为您介绍关于图表插件开发中的数据结构设计和属性配置的相信内容。您可以通过本文深入了解到插件开发中关键字段的详细说明,以及如何为您的图表插件设定属性,从而确保您的自定义可视化插件不仅功能完备,而且能够满足特定的业务需求和用户偏好。(目前,自定义可视化功能还在内测阶段,若您对该功能有具体需求,欢迎联系火山引擎商务团队,以获取更多购买和合作的详细信息)。
注意:在您阅读并完成本文的配置项前,需要先依次完成《自定义可视化概述》与《自定义图表插件结构与开发》中的相关配置。
本产品内置图表和自定义图表遵循通用的图表数据结构 VizData
进行渲染。
在开发自定义图表时,您需要关注 VizData
中的相关字段。
type FieldId = string
interface VizData {
// 字段位置信息
locationMap: Record<string, FieldId[]>;
// 字段信息
fieldMap: Record<FieldId, FieldInfo>;
// 图表数据
datasets: Record<FieldId, string>[];
}
(1)locationMap
字段位置信息,记录每一个自定义字段的 FieldId
数组
(2)fieldMap
描述 FieldId
对应的完整字段信息,FieldInfo
类型如下:
interface FieldInfo {
// 字段别名(名称)
alias: string;
// 字段类型
type: string;
// 字段值域
domain: string[];
}
注意:排序功能后,fieldInfo
中的 domain
字段将同时包含字段的值域和排序结果。需要参考 domain
字段的值顺序实现图表排序。
(3)datasets
图表查询结果数组。数组中的单个对象表示查询结果中的一行,对象的 key
为字段id,对象的 value
为字段值。
以示例插件包为例:Pie Chart
图表是一个基于echarts
绘制的饼图,有1个维度字段,1个指标字段。
以下为示例插件包注册自定义字段的相关代码:
export const activate = (context) => {
context.vizQueryChartRenderer.register({
fields: [
{
label: '维度',
location: 'dimensions',
fieldType: 0,
},
{
label: '指标',
location: 'measures',
fieldType: 1,
}
],
})
}
您可以基于 VizData
的 locationMap
获取 FieldId
。
首先通过 locationMap[location]
获取 location
上的 FieldId
数组,然后使用对应的索引获取字段的 FieldId
。Pie Chart
图表有 'dimensions'
, 'measures'
2个 location
,每个 location
有且只有1个字段。
如下示例获取Pie Chart
图表所有自定义字段的 FieldId
:
const { locationMap } = vizData
const xId = locationMap['dimensions'][0]
const yId = locationMap['measures'][0]
您可以基于 VizData
的 fieldMap
获取 FieldInfo
,即字段详细信息。
如下示例获取了Pie Chart
图表['dimensions'][0]
对应字段的详细信息:
const { locationMap, fieldMap } = vizData
const xId = locationMap['dimensions'][0]
const xFieldInfo = fieldMap[xId]
const { alias, type, domain } = xFieldInfo
VizData
的 datasets
表示单次查询的查询结果,类型为 Record<FieldId, string>[]
。如果您希望将Pie Chart
图表的 datasets
转化为 { x: string, y: string }[]
的格式,可以参考以下代码:
const { locationMap, datasets } = vizData
const xId = locationMap['dimensions'][0]
const yId = locationMap['measures'][0]
const data: { x: string, y: string, z: string }[] = datasets.map(item => ({
x: item[xId],
y: item[yId],
}))
本产品的可视化查询模块为了保留精度将所有 datasets
数据返回为 string
格式。
如果需要聚合过后的数值字段,您可以直接将其转化为 number
类型:
const data: { x: string, y: string, z: number }[] = datasets.map(item => ({
x: item[xId],
y: +item[yId],
}))
自定义图表默认无图表属性配置。在注册自定义图表时,您可以通过 settings
字段定义属性配置表单。
如下的 register
方法为自定义图表注册了两个 SettingGroup
,第一个包括一个 Input
组件和一个 Select
组件,第二个包括一个 CheckboxGroup
组件。
import { ContributeContext } from '@aeolus/extension-context'
import Localize, {
localize
} from '@aeolus-developers/localize'
export enum FieldMap {
Dimension = 'dimensions',
Measure = 'measures',
}
export const activate = (context: ContributeContext) => {
Localize.init(context.language)
context.vizQueryChartRenderer.register({
id: '@aeolus-developers/chartjs-line',
fields: [
{
label: localize("settings.info.dimension"),
location: FieldMap.Dimension,
fieldType: 0,
},
{
label: localize("settings.info.measure"),
location: FieldMap.Measure,
fieldType: 1,
}
],
constraints: [
{
[FieldMap.Dimension]: [1, 1],
[FieldMap.Measure]: [1, 1],
}
]
})
}
一个图表的配置包含多个 SettingGroup
,一个 SettingGroup
包含多个 SettingItem
。
SettingGroup
在 UI 上包括它的 label
与 switch
, 其中 switch
用于控制整个 SettingGroup
是否生效。SettingItem
在 UI 上包括它的 label
与 component
,其中 component
用于描述需要使用的自定义图表配置组件。接下来描述 context.vizQueryChartRenderer.register
中 settings
的类型参数。
interface VizQueryChartRendererRegisterParameters {
/**
* ensure it is unique for all chart renderers,
* `extension-package-name:chart-name` is recommended
* for example `@aeolus-developers/extension-3d-bar-chart`
* */
id: string;
/**
* custom fields
* */
fields: FieldGroup[];
/**
* fields constraints
* */
constraints?: Constraint[];
/**
* custom chart settings
*/
settings?: SettingGroup[];
}
(1)SettingGroup
自定义图表配置的配置组
Property | Type | Description |
---|---|---|
key | string | 在图表插件中通过[SettingGroup.key].[SettingItem.key]访问自定义配置值 |
label | string | 配置组名称 |
switch | boolean | 是否显示配置组开关,默认不显示 |
items | SettingItem[] | 配置组包含的自定义配置项 |
(2)SettingItem
自定义配置项
Property | Type | Description |
---|---|---|
key | string | 在图表插件中通过[SettingGroup.key][SettingItem.key]访问自定义配置值 |
label | string | 配置项名称 |
component | SettingComponentType | 配置项组件 |
(3)SettingComponentType
配置项组件,当前datawind
提供的组件类别如以下所示:
type SettingComponentType =
| CheckboxGroupType
| InputType
| InputNumberType
| SelectType
| SwitchType
| RadioGroupType
| ColorPickerType;
每一个 SettingItem
均需要描述 component
属性,对应的类型可以为以下组件类型的其中之一。
(4)CheckboxGroupType
interface CheckboxGroupType {
type: "CheckboxGroup";
props: Partial<{
defaultValue: string[] | number[];
options: {
label: string;
value: string | number;
}[];
direction: "vertical" | "horizontal";
}>;
}
(5)InputType
interface InputType {
type: "Input";
props: Partial<{
defaultValue: string;
}>;
}
(6)InputNumberType
interface InputNumberType {
type: "InputNumber";
props: Partial<{
defaultValue: number;
min: number;
max: number;
step: number;
}>;
}
(7)SelectType
interface SelectType {
type: "Select";
props: Partial<{
mode: "default" | "multiple";
defaultValue: string | string[] | number | number[];
options: {
label: string;
value: string;
}[];
}>;
}
(8)SwitchType
interface SwitchType {
type: "Switch";
props: Partial<{
defaultValue: boolean;
checkedText: string;
uncheckedText: string;
}>;
}
(9)RadioGroupType
interface RadioGroupType {
type: "RadioGroup";
props: Partial<{
type: "radio" | "button";
defaultValue: string | number;
options: {
label: string;
value: string | number;
}[];
direction: "vertical" | "horizontal";
}>;
}
(10)ColorPickerType
interface ColorPickerType {
type: "ColorPicker";
props: Partial<{
type: "default" | "linear" | "theme";
defaultValue: string[];
}>;
}
import { ContributeContext } from "@aeolus/extension-context";
export const activate = (context: ContributeContext) => {
context.vizQueryChartRenderer.register({
id: "@aeolus-developers/visual-data-explorer",
extend: "table",
settings: [
{
key: "checkboxGroup",
label: "CheckboxGroup",
switch: true,
items: [
{
key: "base",
label: "Base Component",
component: {
type: "CheckboxGroup",
props: {
options: [
{ label: "A", value: "a" },
{ label: "B", value: "b" },
{ label: "C", value: "c" },
],
},
},
},
{
key: "vertical",
label: "Vertical Layout",
component: {
type: "CheckboxGroup",
props: {
direction: "vertical",
options: [
{ label: "A", value: "a" },
{ label: "B", value: "b" },
{ label: "C", value: "c" },
],
},
},
},
{
key: "default",
label: "Default Value",
component: {
type: "CheckboxGroup",
props: {
defaultValue: ["a", "b"],
options: [
{ label: "A", value: "a" },
{ label: "B", value: "b" },
{ label: "C", value: "c" },
],
},
},
},
],
},
{
key: "input",
label: "Input",
switch: true,
items: [
{
key: "base",
label: "Base Component",
component: {
type: "Input",
props: {},
},
},
],
},
{
key: "inputNumber",
label: "InputNumber",
switch: true,
items: [
{
key: "base",
label: "Base Component",
component: {
type: "InputNumber",
props: {},
},
},
{
key: "decimal",
label: "Using min, max and step",
component: {
type: "InputNumber",
props: {
min: 0,
max: 10,
step: 0.5,
},
},
},
],
},
{
key: "select",
label: "Select",
switch: true,
items: [
{
key: "base",
label: "Base Component",
component: {
type: "Select",
props: {
options: [
{ label: "A", value: "a" },
{ label: "B", value: "b" },
{ label: "C", value: "c" },
{ label: "D", value: "d" },
],
},
},
},
{
key: "multiple",
label: "Multiple",
component: {
type: "Select",
props: {
mode: "multiple",
options: [
{ label: "A", value: "a" },
{ label: "B", value: "b" },
{ label: "C", value: "c" },
{ label: "D", value: "d" },
],
},
},
},
],
},
{
key: "switch",
label: "Switch",
switch: true,
items: [
{
key: "base",
label: "Base Component",
component: {
type: "Switch",
props: {},
},
},
],
},
{
key: "radioGroup",
label: "RadioGroup",
switch: true,
items: [
{
key: "base",
label: "Base Component",
component: {
type: "RadioGroup",
props: {
options: [
{ label: "A", value: "a" },
{ label: "B", value: "b" },
{ label: "C", value: "c" },
{ label: "D", value: "d" },
],
},
},
},
{
key: "button",
label: "Button Mode",
component: {
type: "RadioGroup",
props: {
type: "button",
options: [
{ label: "A", value: "a" },
{ label: "B", value: "b" },
{ label: "C", value: "c" },
{ label: "D", value: "d" },
],
},
},
},
{
key: "vertical",
label: "Vertical Layout",
component: {
type: "RadioGroup",
props: {
direction: "vertical",
options: [
{ label: "A", value: "a" },
{ label: "B", value: "b" },
{ label: "C", value: "c" },
{ label: "D", value: "d" },
],
},
},
},
],
},
],
});
};
在插件中,您可以通过 window.onmessage
监听插件图表 propertiesChange
事件,通过 e.data.data.settings
获取自定义配置值。
window.onmessage = (
e: MessageEvent<{
type: string;
data: any;
}>
) => {
const { type, data } = e.data;
if (type === "propertiesChange") {
// outputs { vizData, settings }
// using settings[settingGroup.key]?.[settingItem.key] to visit a value
console.log(data);
}
};