山海鲸可视化

数据读取和处理

二开中对数据的处理主要分为三个部分,分别是数据的读取,数据变化的监听,数据联动的触发和撤回。

0.测试数据准备

首先我们先准备一个测试数据表 Excel 如下:

ID 地区 销售员 产品类型 产品 销量
1 华北 张伟 饮料 咖啡 329
2 华北 李娜 饮料 橙汁 725
3 华北 王成 饮料 酸梅汁 363
4 华南 张荣 坚果 开心果 619
5 华南 韩文文 坚果 碧根果 243

将数据导入山海鲸:
image.png

1.数据的读取

在二开中读取数据目前有两种方式,一种是直接由二开中定义的属性项来读取,一种是直接读取现有组件其他的数据设置项。我们更推荐第一种形式。

1.1 二开数据属性

1.1.1 单个属性的读取

前面的自定义属性面板中已经提到,我们可以通过在二开中直接定义一个数据字段来读取,目前提供了两种函数,分别是 readData 和 readDataAsync,详情可以参考 API 文档:Extension 自定义属性 - 开发教程 - 山海鲸可视化
特别注意:我们推荐采用 readData 方法来读取,因为 readData 将在第一次读取时和数据发生变化时都会触发回调,因此可以将数据处理的代码统一写在回调函数之中,而不需要分别处理首次读取和数据变化两种情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ButtonSample {
setting = Field.default({
maxFields: 3, //最多能放几个字段
});
init() {
this.setting.readDataAsync(
(data) => {
//每次数据内容变化或者数据设置项修改都会触发这个回调
console.log("data", data);
},
{
//要开启变化时回调
callbackOnDataChanged: true,
}
);
}
}
export default ButtonSample;

载入后我们在数据的 tab 下能看到一个新的数据项
image.pngimage.png
将导入的数据拖入字段中,我们拖入两个字段:
image.png
设置完之后,我们点击按钮查看打印信息的内容:
image.png
可以看到,数据以数组的形式返回,如果希望以其他形式获取数据,也可以传入相应的类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ButtonSample {
setting = Field.default({
maxFields: 3, //最多能放几个字段
});
init() {
this.setting.readData(
(data) => {
//每次数据内容变化或者数据设置项修改都会触发这个回调
console.log("data", data);
},
{
dataFormat: "object",
callbackOnDataChanged: true,
}
);
}
}
export default ButtonSample;

我们目前提供了三种类型的数据读取方式分别是 object,row 和 column,具体读取到的结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 异步读取该字段中设置的数据
* @since 4.2.0
* @param options
* * dataFormat 可选值有"row", "column", "object"。默认值为"row"
* 对于以下示例表格数据:
* | A | B | C |
* | a1 | b1 | c1 |
* | a2 | b2 | c2 |
* | a3 | b3 | c3 |
* 返回结果如下
* "object" : [{A:"a1", B:"b1", C:"c1"}, {A:"a2", B:"b2", C:"c2"}, {A:"a3", B:"b3", C:"c3"}]
* "row" : [[a1, b1, c1], [a2, b2, c2], [a3, b3, c3]]
* "column" : [[a1, a2, a3], [b1, b2, b3], [c1, c2, c3]]
* @returns resolve数据读取结果的Promise
*/
async readDataAsync(options?: ReadDataAsyncOptions): Promise<any[]>;

重新加载代码后看到打印的结果如下:
image.png

1.1.2 多个属性的合并读取

有的时候,我们会需要多个数据属性,而多个属性同时又归属同一个属性,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class ButtonSample {
latitude = Field.default({
maxFields: 1, //最多能放几个字段
});
longitude = Field.default({
maxFields: 1, //最多能放几个字段
});
init() {
Field.readData(
[this.latitude, this.longitude],
(data) => {
//每次数据内容变化或者数据设置项修改都会触发这个回调
console.log("data", data);
},
{
dataFormat: "object",
callbackOnDataChanged: true,
}
);
}
}
export default ButtonSample;

虽然经度和纬度分为了两个字段,读取的时候,可以将两个字段合并起来一起读取,因此不需要在读取后对数据做合并操作。

1.2 读取组件已有数据项

对于已有组件的数据项,如表格数据中的数据字段,二开也提供了读取的方式,具体如下:
首先我们添加一个表格组件,并绑定数据:
image.png
由于这个数据项是组件自己生成的,我们二开代码中并没有这个属性的直接引用,因此需要调用 Element 类上的方法进行读取,详细参考以下 API 文档:Element 类 - 开发教程 - 山海鲸可视化
首先我们要获取到我们需要读取的数据字段的 Path,我们鼠标移动到数据字段上,在三个点上点击后,选择调用代码示例:
image.png
打开窗口中复制 getOption 里的参数值,即为该属性的 path:
image.png
同样的,我们在点击事件中获取表格的数据内容:
特别注意:我们推荐采用 readData 方法来读取,因为 readData 将在第一次读取时和数据发生变化时都会触发回调,因此可以将数据处理的代码统一写在回调函数之中,而不需要分别处理首次读取和数据变化两种情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class TableSample {
init() {
this.element.readData(
["axis-fields"],
(data) => {
//每次数据内容变化或者数据设置项修改都会触发这个回调
console.log("data", data);
},
{
dataFormat: "object",
callbackOnDataChanged: true,
}
);
}
}
export default TableSample;

点击表格后可以查看打印结果:
image.png

2.数据变化的监听

注意,实际上我们使用 readData 方法时就可以自动监听了数据的变化,并且在变化时会自动触发回调。但依然有的时候我们需要单独监听数据的变化,下面就这些情况下如何监听进行说明。
数据的变化实际上分为两种情况,一种是数据项设置的变化,一种是数据内容发生了变化:

2.1 监听数据字段的设置变化

对于数据字段设置的变化也分为两种,也就是前面提到的,由二开代码生成的数据字段或者组件中自带的数据字段设置的变化。下面分别就这两种情况进行介绍:

2.1.1 监听二开代码生成的数据字段的变化

可以参考前面关于二开属性变化的监听方法:onPropertyChanged。具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
class ButtonSample {
setting = Field.default({
maxFields: 1, //最多能放几个字段
});
async onPropertyChanged(property) {
if (property == "setting") {
//注意 这里就不能用readData,因为readData会自动监听数据变化
const data = await this.setting.readDataAsync();
console.log(data);
}
}
}
export default ButtonSample;

我们将销售员的数据字段拖入到二开代码生成的数据字段中:
image.png
松开鼠标后可以看到调试窗中就已经打印出了数据结果:
image.png

2.1.2 监听组件自带的数据字段的变化

和二开中监听方式不一样,对于组件自带数据字段的监听,我们采用监听 Element 类上的 option-changed 事件的方式,具体可以参考 API 文档:Element 类 - 开发教程 - 山海鲸可视化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class TableSample {
init() {
//出于性能优化考量,必须先读取一次该属性,才能监听到这个属性的变化事件
const fields = this.element.getOption(["axis-fields"]);

this.element.addEventListener("option-changed", async (ev) => {
const paths = ev.paths;
//如果有多个属性被监听,则需要判断一下paths是否为目标值
if (Paths.equals(paths, ["axis-fields"])) {
const data = await this.element.readDataAsync(["axis-fields"], {
dataFormat: "object",
});
console.log(data);
}
});
}
}
export default TableSample;

2.2 监听数据内容的变化

数据内容的变化,只需要监听 data-changed 的事件即可实现,代码如下:

1
2
3
4
5
6
7
8
9
10
11
class TableSample {
init() {
this.element.addEventListener("data-changed", async (ev) => {
const data = await this.element.readDataAsync(["axis-fields"], {
dataFormat: "object",
});
console.log(data);
});
}
}
export default TableSample;

3.数据联动

有的时候,我们需要在二开代码中直接触发或者取消数据联动,这里我们实现一个点击按钮实现筛选表格数据,再点击一次取消筛选联动的功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class ButtonSample {
setting = Field.default({
maxFields: 3, //最多能放几个字段
});
#linkageApplied = false;
init() {
this.element.addEventListener("click", () => {
if (!this.#linkageApplied) {
//点一次触发数据筛选联动
//name填入字段的名称
//value填入筛选的目标值
this.element.applyLinkage({
name: "地区",
value: "华北",
});
} else {
//再点一次取消数据筛选联动
this.element.withdrawLinkage();
}
this.#linkageApplied = !this.#linkageApplied;
});
}
}
export default ButtonSample;

将这个代码挂载到按钮上,同时不要忘记打开按钮的数据联动功能和表格的被联动开关image.pngimage.png
设置好之后,点击按钮即可看到表格的数据被筛选成了华北的数据,再次点击则取消筛选:
image.png
我们也可以同时约束多个数据条件,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class ButtonSample {
setting = Field.default({
maxFields: 3, //最多能放几个字段
});
#linkageApplied = false;
init() {
this.element.addEventListener("click", () => {
if (!this.#linkageApplied) {
//name填入字段的名称
//value填入筛选的目标值
this.element.applyLinkage([
{
name: "地区",
value: "华北",
},
{
name: "销售员",
value: "张伟",
},
]);
} else {
this.element.withdrawLinkage();
}
this.#linkageApplied = !this.#linkageApplied;
});
}
}
export default ButtonSample;