创建可视化插件
前言
Superset 中的可视化是用 JavaScript 或 TypeScript 实现的。Superset 预装了几种可视化类型(以下简称 “viz 插件”),可在 superset-frontend/plugins
目录下找到。可视化插件在 superset-frontend/src/visualizations/presets/MainPreset.js
中添加到应用程序中。
注意:在开始下面的步骤前应确保你使用的是普通用户,使用root用户执行到yo @superset-ui/superset
命令时会报错,目前还没有很好的解决办法。下面创建可视化插件的步骤可以跳过,直接下载可视化插件模板
创建一个简单的可视化插件
要开始使用,您需要 Superset Yeoman 生成器。建议使用您正在使用的 Superset 版本所附带的模板版本。安装方法如下:
npm i -g yo
cd superset-frontend/packages/generator-superset
npm i
npm link
之后,您就可以继续创建 viz 插件了。为您的 viz 插件创建一个新目录,前缀为 superset-plugin-chart
,然后运行 Yeoman 生成器
mkdir /tmp/superset-plugin-chart-hello-world
cd /tmp/superset-plugin-chart-hello-world
初始化可视化插件:
yo @superset-ui/superset
之后,生成器会问几个问题(默认值应该没问题):
$ yo @superset-ui/superset
_-----_ ╭──────────────────────────╮
| | │ Welcome to the │
|--(o)--| │ generator-superset │
`---------´ │ generator! │
( _´U`_ ) ╰──────────────────────────╯
/___A___\ /
| ~ |
__'.___.'__
´ ` |° ´ Y `
? Package name: superset-plugin-chart-hello-world
? Description: Hello World
? What type of chart would you like? Time-series chart
create package.json
create .gitignore
create babel.config.js
create jest.config.js
create README.md
create tsconfig.json
create src/index.ts
create src/plugin/buildQuery.ts
create src/plugin/controlPanel.ts
create src/plugin/index.ts
create src/plugin/transformProps.ts
create src/types.ts
create src/SupersetPluginChartHelloWorld.tsx
create test/index.test.ts
create test/__mocks__/mockExportString.js
create test/plugin/buildQuery.test.ts
create test/plugin/transformProps.test.ts
create types/external.d.ts
create src/images/thumbnail.png
要构建可视化插件,请运行以下命令:
npm i --force
npm run build
或者,要在开发模式下运行可视化插件(每当进行更改时重建),请使用以下命令启动开发服务器:
npm run dev
要将软件包添加到 Superset,请进入 Superset 源文件夹中的 superset-frontend 子目录,运行以下命令:
npm i -S /tmp/superset-plugin-chart-hello-world
如果您将包发布到 npm,您自然也可以直接从那里安装。之后编辑 superset-frontend/src/visualizations/presets/MainPreset.js
并进行以下更改:
import { SupersetPluginChartHelloWorld } from 'superset-plugin-chart-hello-world';
导入 viz 插件,然后将以下内容添加到传递给 plugins 属性的数组中:
new SupersetPluginChartHelloWorld().configure({ key: 'ext-hello-world' }),
之后,在运行 Superset(例如开发服务器)时,就会显示 viz 插件:
npm run dev-server
可视化插件源码讲解
上面的内容来自官方文档翻译,经过上面的步骤我们完成了可视化插件的创建以及如何添加到superset中,接下来将详细讲解可视化插件文件夹下包含哪些内容,逐步揭开superset的面纱,如何开发自己的可视化插件。
以echart pie 饼图为例,进入到可视化插件目录superset-frontend/plugins/plugin-chart-echarts/src/Pie,我们可以看到这样的目录结构:
.
├── buildQuery.ts
├── controlPanel.tsx
├── EchartsPie.tsx
├── images
│ ├── Pie1.jpg
│ ├── Pie2.jpg
│ ├── Pie3.jpg
│ ├── Pie4.jpg
│ └── thumbnail.png
├── index.ts
├── transformProps.ts
└── types.ts
EchartsPie.tsx
这是一个react 方法组件,接收一个由transformProps.ts
返回的props
,包含了图表组件所需的数据以及配置。图表组件的展示内容由你制定。
controlPanel.tsx
该文件主要包括一个对象,用于定义superset创建图表时左侧的控制面板,,其中包含可视化插件中使用的每个设置的数组。它将设置传递给主组件,由主组件创建数据可视化查询。
控制面板分为两个选项卡: “查询 “和 ”图表选项"。定义图表数据请求输入(如列和度量)的控件通常位于 “查询 ”部分, 而影响图表视觉外观或功能的控件则位于 “图表选项 ”部分。
控件的类型
这里有两种控件: 预定义控件和自定义控件
下面有几种预定义控件可以使用:
groupby
: 按列分组(转换为 GROUP BY 语句)series
: 与 groupby 相同,但只有一个选择。metrics
: 多个度量(转换为聚合表达式:Sum、Avg、Max、Min等)metric
: 与 metrics 相同,但只有一个选择。adhoc_filters
:过滤器(根据过滤器类型转换为 WHERE 或 HAVING)row_limit
: 最大记录数(转换为 LIMIT 语句)
如果控制面板上同时有series
和groupby
控件,而用户选择col1
作为series
控件的值,并且col2
和 col3
作为groupby
控件的值。 结果查询将包含三个groupby
列。 这是因为我们认为 series
控件是一个 groupby
查询字段,其值将在生成查询时自动追加到 groupby
字段。
所有现有 预定义的控件列表可在以下文件中找到:superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx
可以看到有这些控件:
export default {
metrics: dndAdhocMetricsControl,
metric: dndAdhocMetricControl,
datasource: datasourceControl,
viz_type,
color_picker,
metric_2: dndAdhocMetricControl2,
linear_color_scheme,
secondary_metric: dndSecondaryMetricControl,
groupby: dndGroupByControl,
columns: dndColumnsControl,
granularity,
granularity_sqla: dndGranularitySqlaControl,
time_grain_sqla,
time_range,
row_limit,
limit,
timeseries_limit_metric: dndSortByControl,
orderby: dndSortByControl,
order_desc,
series: dndSeriesControl,
entity: dndEntityControl,
x: dndXControl,
y: dndYControl,
size: dndSizeControl,
y_axis_format,
x_axis_time_format,
adhoc_filters: dndAdhocFilterControl,
color_scheme,
time_shift_color,
series_columns: dndColumnsControl,
series_limit,
series_limit_metric: dndSortByControl,
legacy_order_by: dndSortByControl,
truncate_metric,
x_axis: dndXAxisControl,
show_empty_columns,
temporal_columns_lookup,
currency_format,
sort_by_metric,
};
自定义控件
可以通过导入必要的依赖关系和覆盖默认参数来定义自定义控件,然后将其放置在 “查询 ”部分的controlSetRows
部分,而不是预定义控件中。
重写预定义控件:
const config: ControlPanelConfig = {
controlPanelSections: [
{
label: t('Query'),
expanded: true,
controlSetRows: [
['groupby'],
['metric'],
['adhoc_filters'],
['row_limit'],
[
{
name: 'sort_by_metric',
config: {
...sharedControls.sort_by_metric,
default: true,
},
},
],
],
},
]
}
上面代码中导入了一个sort_by_metric
组件,并且重写了default
属性为true。
除了基本的下拉控件外,还有几种预定义的控件类型(可通过 type
属性设置)可以使用。一些常用的示例如下:
- SelectControl: 用于选择单个或多个值的下拉菜单,通常为列
- MetricsControl: 下拉选择度量标准,触发模态 来定义指标详情
- AdhocFilterControl: 控制选择过滤器
- CheckboxControl: 用于选择真/假值的复选框
- SliderControl: 带有最小/最大值的滑块
- TextControl: 文本输入控件
要了解更多控制输入类型,请查看以下文件: superset-frontend/src/explore/components/controls/index.js
自定义控件:
{
name: 'show_labels_threshold',
config: {
type: 'TextControl',
label: t('Percentage threshold'),
renderTrigger: true, // 如果值改变,会触发图表的渲染
isFloat: true,
default: 5,
description: t(
'Minimum threshold in percentage points for showing labels.',
),
},
}
show_labels_threshold
是你的字段名称,输入的值会保存在你定义的这个字段中。 有关config的更多配置参数,建议查看superset中的现有控件,并比较相关控制面板的编辑方式。
为确保正确填写所有控件,提供了以下验证器,来自 @superset-ui/core/lib/validator
:
validateNonEmpty
: 必须且至少有一个值validateInteger
: 必须是整数值validateNumber
: 必须是整数或小数值
有关控制输入类型,请参阅: superset-frontend/src/explore/components/controls/index.js
我们可从官方源码中看到控件是如何定义的,例如行限制控件:
const row_limit: SharedControlConfig<'SelectControl'> = {
type: 'SelectControl',
freeForm: true,
label: t('Row limit'),
clearable: false,
mapStateToProps: state => ({ maxValue: state?.common?.conf?.SQL_MAX_ROW }),
validators: [
legacyValidateInteger,
(v, state) => validateMaxValue(v, state?.maxValue || DEFAULT_MAX_ROW),
],
default: 10000,
choices: formatSelectOptions(ROW_LIMIT_OPTIONS),
description: t(
'Limits the number of the rows that are computed in the query that is the source of the data used for this chart.',
),
};
所以,只需使用共享控件中的预设选项,你就能建立自己的控制面板。选择你需要的控件名称,然后像这样设置即可:
const config: ControlPanelConfig = {
controlPanelSections: [
{
label: t('Query'),
expanded: true,
controlSetRows: [
['entity'],
['adhoc_filters'],
['row_limit'],
//...
//其他的控件
//...
],
},
...
]
}
- 这些值Superset会为你保存到一个formData的对象中,其中key是你定义的控件名称,value是用户在界面输入数据,这个formData会在你保存图表时存储在图表的元数据中。
- superset会将formData传递给transformProps.ts文件中定义的
transformProps
的props
,你能够通过props.formData
解包出你想要的控件值。
buildQuery.ts
定义查询数据的方式。每次打开图表时,图表会向服务器发起请求http://example.com/api/v1/chart/data
请求图表的数据,可以看到请求负载为:
buildQuery
函数用于创建一个 QueryContext 实例,并将其发送到图表数据端点. 除了包含要使用的数据源信息外,它还指定了返回的类型(如完整有效载荷:full
、样本:samples
、查询:query
)和格式(如 CSV 或 JSON), 以及是否从数据源强制刷新数据,而不是使用缓存的数据副本。想要知道更多返回类型,请查看:superset/common/query_actions.py:193
你也可以看到你定义的控件的值存放在form_data
中,当你保存图表时,这些值最终会为你存放在服务器中,你下次去请求 获取图表时返回这些数据。
更重要的是,QueryContext 包含一个属性 queries
,它是一个数组,其中包含QueryObjects 的数组。
一个 QueryObject 可以指定列、度量和过滤器等。通常只需在 baseQueryObject 的基础上指定一个查询即可,
但对于一些更高级的用例,可以在 QueryObject 中定义后处理操作,或者在 viz 需要多个不同结果集时定义多个查询。
transformProps.ts
从图表数据端点收到成功响应后调用此函数,用于在将传入数据发送到可视化之前对其进行转换。
transformProps 函数向数据可视化组件返回额外的或修改的Props时非常有用。你也可以从 EchartsPie.tsx 文件访问直接formData,但在这里提供自定义props通常便于集成依赖特定props的第三方库。
对 chartProps
中属性的描述:
height
,width
: 图表所在 DOM 元素的高度/宽度formData
: 发送到后端的图表数据请求有效载荷。queriesData
: 接收到的图表数据响应的有效载荷 从后端获取。queriesData` 的一些重要属性:data
: 是一个包含数据的数组,每一行都包含一个将列/别名映射到其值的对象。
例如:[{ col1: 'abc', metric1: 10 }, { col1: 'xyz', metric1: 20 }]
rowcount
:data
中的行数query
: 发出的查询。
请注意:应用程序加载时会缓存 transformProps 函数。在开发过程中通过热加载对 transformProps
函数进行更改时,只有重新启动开发服器才能看到更改。
index.ts
定义图表插件,配置插件的元数据。
这些元数据我们能够在superset新建图表中看到:
images
这个目录用于存放图表的缩略图。
总结
相信从上面阅读下来对可视化插件的整个架构有了大致的了解,有了这部分基础,在接下来的章节中,会使用3个小练习来带大家熟悉如何二次开发可视化插件。在实际情况中,superset已经提供了大部分常用的图表类型,这些图表类型也能够满足我们的开发需求,有些图表可能在某些功能上不满足我们的需求,我们可以在原有图表的基础上进行二次开发、改造来达到我们的需求,而完全自定义自己的图表组件的情况还是比较少的。所以了解如何在原有的图表插件上扩展就够了。(个人的体会)