山海鲸可视化

数据读取和处理

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

0.测试数据准备

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

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

将数据导入山海鲸:

1.数据的读取

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

1.1 二开数据属性

1.1.1 单个属性的读取

前面的自定义属性面板中已经提到,我们可以通过在二开中直接定义一个数据字段来读取,目前提供了两种函数,分别是 readData 和 readDataAsync,详情可以参考 API 文档:Extension 自定义属性 - 开发教程 - 山海鲸可视化

特别注意:我们推荐采用 readData 方法来读取,因为 readData 将在第一次读取时和数据内容发生变化时都会触发回调,因此可以将数据处理的代码统一写在回调函数之中,而不需要分别处理首次读取和数据变化两种情况:

class ButtonSample {
  setting = Field.default({
    maxFields: 3, //最多能放几个字段
  });
  init() {
    this.setting.readData(
      (data) => {
        //每次数据内容变化或者数据设置项修改都会触发这个回调
        console.log("data", data);
      },
      {
        //要开启变化时回调
        callbackOnDataChanged: true,
      }
    );
  }
}
export default ButtonSample;

载入后我们在数据的 tab 下能看到一个新的数据项

将导入的数据拖入字段中,我们拖入两个字段:

设置完之后,我们点击按钮查看打印信息的内容:

可以看到,数据以数组的形式返回,如果希望以其他形式获取数据,也可以传入相应的类型:

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,具体读取到的结果可以参考代码注释中的例子:

/**
 * 读取该字段中设置的数据
 * @since 4.2.0
 * @param callback 数据读取完时回调
 * @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]]
 * * callbackOnDataChanged 为true时,监听数据变化,每次数据变化时都会回调callback
 */
readData(callback: ReadDataCallback, options?: ReadDataOptions): void;
/**
 * 异步读取该字段中设置的数据
 * @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[]>;

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

1.1.2 多个属性的合并读取

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

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 读取组件已有数据项

对于已有组件的数据项,如表格数据中的数据字段,二开也提供了读取的方式,具体如下:

首先我们添加一个表格组件,并绑定数据:

由于这个数据项是组件自己生成的,我们二开代码中并没有这个属性的直接引用,因此需要调用 Element 类上的方法进行读取,详细参考以下 API 文档:Element 类 - 开发教程 - 山海鲸可视化

首先我们要获取到我们需要读取的数据字段的 Path,我们鼠标移动到数据字段上,在三个点上点击后,选择调用代码示例:

打开窗口中复制 getOption 里的参数值,即为该属性的 path:

同样的,我们在点击事件中获取表格的数据内容:

特别注意:我们推荐采用 readData 方法来读取,因为 readData 将在第一次读取时和数据发生变化时都会触发回调,因此可以将数据处理的代码统一写在回调函数之中,而不需要分别处理首次读取和数据变化两种情况:

class TableSample {
  init() {
    this.element.readData(
      ["axis-fields"],
      (data) => {
        //每次数据内容变化或者数据设置项修改都会触发这个回调
        console.log("data", data);
      },
      {
        dataFormat: "object",
        callbackOnDataChanged: true,
      }
    );
  }
}
export default TableSample;

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

2.数据变化的监听

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

数据的变化实际上分为两种情况,一种是数据项设置的变化,一种是数据内容发生了变化:

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

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

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

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

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;

我们将销售员的数据字段拖入到二开代码生成的数据字段中:

松开鼠标后可以看到调试窗中就已经打印出了数据结果:

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

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

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 的事件即可实现,代码如下:

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.数据联动

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

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;

将这个代码挂载到按钮上,同时不要忘记打开按钮的数据联动功能和表格的被联动开关

设置好之后,点击按钮即可看到表格的数据被筛选成了华北的数据,再次点击则取消筛选:

我们也可以同时约束多个数据条件,代码如下:

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;