Skip to content

Commit

Permalink
docs: 增加 get cell data 示例
Browse files Browse the repository at this point in the history
  • Loading branch information
wjgogogo committed Nov 28, 2023
1 parent a688b5e commit 31016ed
Show file tree
Hide file tree
Showing 11 changed files with 334 additions and 157 deletions.
4 changes: 2 additions & 2 deletions packages/s2-core/src/data-set/pivot-data-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,11 +391,11 @@ export class PivotDataSet extends BaseDataSet {
// 判断当前是否为下钻节点
// 需检查 rowNode.id 是否属于下钻根节点(drillDownIdPathMap.keys)的下属节点
const isDrillDown = Array.from(drillDownIdPathMap?.keys() ?? []).some(
(parentPath) => rowNode.id.startsWith(parentPath),
(parentPath) => rowNode?.id.startsWith(parentPath),
);

// 如果是下钻结点,行维度在 originRows 中并不存在
if (!isTotals || isDrillDown) {
if (rowNode && isDrillDown) {
rows = Node.getFieldPath(rowNode, isDrillDown) ?? originRows;
}

Expand Down
1 change: 0 additions & 1 deletion packages/s2-core/src/facet/layout/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ export class Node {
}
return fieldPath.reverse();
}
return [];
}

/**
Expand Down
233 changes: 91 additions & 142 deletions s2-site/docs/manual/advanced/data-process/pivot.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ order: 1

本文会介绍透视表的数据流处理过程,让读者更直观的了解 `S2` 内部数据逻辑。

数据处理流程是:`原始数据 -> 生成多维数组 -> 生成层级结构 -> 获取数据` ,接下来我们会逐一讲解,目标是实现下图透视表:
数据处理流程是:`原始数据 -> 生成 indexesData 多维数据 -> 生成层级结构 -> 获取数据` ,接下来我们会逐一讲解,目标是实现下图透视表:

<img src="https://gw.alipayobjects.com/mdn/rms_56cbb2/afts/img/A*J2fuRIJnQdgAAAAAAAAAAAAAARQnAQ" alt="s2-data-process-demo" width="600" />

Expand Down Expand Up @@ -58,196 +58,145 @@ const options = {
/>
```

## 生成多维数组
## 生成 indexesData 多维数据

首先,处理第三条数据,提取当前明细数据在初始配置条件下的行、列维度结果。
首先,处理数据,提取当前明细数据在初始配置条件下的行、列维度结果。

```ts
// 第四条数据
// 以第四条数据为例
// { "price": 4,"province": "浙江省","city": "绍兴市","type": "家具","sub_type": "沙发" }
const rowDimensionValues = transformDimensionsValue(currentData, ['province', 'city']); // 结果是 ['浙江省', '绍兴市']
const colDimensionValues = transformDimensionsValue(currentData, ['type', 'sub_type']); // 结果是 ['家具', '沙发']
const rowDimensionValues = transformDimensionsValues(currentData, ['province', 'city']); // 结果是 ['浙江省', '绍兴市']
const colDimensionValues = transformDimensionsValues(currentData, ['type', 'sub_type']); // 结果是 ['家具', '沙发']
```

然后,根据数据的行列维度结果和初始配置条件,我们可以获取到当前明细数据的路径(即在行树结构和列树结构的坐标索引)

```ts
const rowPath = getPath(rowDimensionValues); // 结果是 [0, 1]; 因为浙江下面有杭州和绍兴,所以绍兴坐标为 1,下同。
const colPath = getPath(colDimensionValues); // 结果是 [0, 1];
const dataPath = rowPath.concat(...colPath); // 结果是 [0, 1, 0, 1];

lodash.set(indexesData, dataPath, currentData); // [0, 1, 0, 1] 是 { "price": 4,"province": "浙江省","city": "绍兴市","type": "家具","sub_type": "沙发" }
// 以第四条数据为例
const prefix = 'province[&]city[&]type[&]sub_type';
// 第 0 位 始终是小计、总计的专属位,明细数据都是从第 1 位开始
const rowPath = getDataPath(rowDimensionValues); // 结果是 [1, 2];
const colPath = getDataPath(colDimensionValues); // 结果是 [1, 2];
const dataPath =[prefix, ...rowPath.concat(...colPath)] ; // 结果是 ['province[&]city[&]type[&]sub_type', 1, 2, 1, 2];
const indexesData={};
lodash.set(indexesData, dataPath, currentData);
```

最后,按照上述流程,遍历所有数据,得到最终的多维数组,结果是:
最后,按照上述流程,遍历所有数据,得到最终的 indexesData,结果是:

```ts
[
[
{
"province[&]city[&]type[&]sub_type": [
null,
[
null,
[
[{
"price": 1,
"province": "浙江省",
"city": "杭州市",
"type": "家具",
"sub_type": "桌子",
"$$extra$$": "price",
"$$value$$": 1
}],
[{
"price": 3,
"province": "浙江省",
"city": "杭州市",
"type": "家具",
"sub_type": "沙发",
"$$extra$$": "price",
"$$value$$": 3
}]
]
],
[
null,
[
null,
[
null,
{
"price": 1,
"province": "浙江省",
"city": "杭州市",
"type": "家具",
"sub_type": "桌子"
}
],
[
null,
{
"price": 3,
"province": "浙江省",
"city": "杭州市",
"type": "家具",
"sub_type": "沙发"
}
]
]
],
[
[{
"price": 2,
"province": "浙江省",
"city": "绍兴市",
"type": "家具",
"sub_type": "桌子",
"$$extra$$": "price",
"$$value$$": 2
}],
[{
"price": 4,
"province": "浙江省",
"city": "绍兴市",
"type": "家具",
"sub_type": "沙发",
"$$extra$$": "price",
"$$value$$": 4
}]
null,
[
null,
[
null,
{
"price": 2,
"province": "浙江省",
"city": "绍兴市",
"type": "家具",
"sub_type": "桌子"
}
],
[
null,
{
"price": 4,
"province": "浙江省",
"city": "绍兴市",
"type": "家具",
"sub_type": "沙发"
}
]
]
]
]
]
]
}
```

## 生成层级结构

接下来是按照数据结构,分别生成行列的树状结构。我们知道,存储明细数据的 Meta 结构一般有三种:扁平数组、图、树,对于表场景查询频率非常高,透视表本身的展现形式也表达了一种树形结构,因此我们选择了构建树形结构来实现 Meta。

下面,我们以行树结构为例,讲解 `S2` 中层级结构的构造过程。
下面,我们以行树结构为例,生成的 Map 结构是:<br/>![rowPivotMeta](https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*BScNTbO2TrIAAAAAAAAAAAAADmJ7AQ/original)

首先,拿到某条数据的行维度枚举值:
## 获取数据

```ts
// 第四条数据
// { "price": 4,"province": "浙江省","city": "绍兴市","type": "家具","sub_type": "沙发" }
const rowDimensionValues = transformDimensionsValue(currentData, ['province', 'city']); // 结果是 ['浙江省', '绍兴市']
```
### 获取单个数据

然后,遍历此条数据的行维度枚举
当渲染透视表数据单元格时,需要获取对应的展示内容(数据)。举个例子,需要右下角单元格数据时,代码如下

```ts
let currentMeta = this.rowPivotMeta; // 存储行树形结构 Map.
for (let i = 0; i < rowDimensionValues.length; i++) { // 遍历 ['浙江省', '绍兴市'];
if (isFirstCreate) {
currentMeta.set(rowDimensionValues[i], { // currentMeta =
level: currentMeta.size,
children: new Map(),
});
}
const meta = this.rowPivotMeta.get(value);
currentMeta = meta?.children;
}
const data = getCellData({
query: { province: '浙江省', city: '绍兴市', type: '家具', sub_type: '沙发', $$extra$$: 'price' }
});
```

第一次循环 `['浙江省', '绍兴市']` 时,`currentMeta` 的结果是
实现过程是,先拿到行、列维度枚举值

```ts
Map(1) {
[[entries]] => [{
'浙江省' => { key: '浙江省', value: { children: Map(0)}})
}]
}
const rowDimensionValues = transformDimensionsValues(query, ['province', 'city']); // ['浙江省', '绍兴市']
const colDimensionValues = transformDimensionsValues(query, ['type', 'sub_type', '$$extra$$']); // ['家具', '沙发', 'price']
```

第二次循环的结果是:

```ts
Map(1) {
[[Entries]] => [{
'浙江省' => { key: '浙江省', value: {
children: Map(1) {
[[Entries]] => [{
'绍兴市' => { key: '绍兴市', value: { children: Map(0)}}
}]
}
}}
}]
}
```

当遍历一条明细数据后,变成 `浙江省 => 绍兴市` 这样层级结构。当遍历完所有明细数据后,最终的行层级结构如下:
然后通过枚举值获取数据查询路径,并从前面生成的多维数组中拿到具体数据。

```ts
Map(1) {
[[Entries]] => [{
'浙江省' => { key: '浙江省', value: {
childField: 'city',
children: Map(2) {
[[Entries]] => [{
'杭州市' => { key: '杭州市', value: { children: Map(0)}}
}, {
'绍兴市' => { key: '绍兴市', value: { children: Map(0)}}
}]
}
}}
}]
}
const path = getDataPath({ rowDimensionValues, colDimensionValues });
const rowData = lodash.get(indexesData, path);
```

列的最终层级结构如下:
在拿到数据后,我们需要为原始数据增加 `$$extra$$` 等信息,用于标识所选择的具体是哪个维度,因此,内部使用了 Proxy 对 rowData 进行包裹,对其行为进行增强。

```ts
Map(1) {
[[Entries]] => [{
'家具' => { key: '家具', value: {
childField: 'sub_type',
children: Map(2) {
[[Entries]] => [{
'桌子' => { key: '桌子', value: { children: Map(0)}}
}, {
'沙发' => { key: '沙发', value: { children: Map(0)}}
}]
}
}}
}]
}
```
const data=new Proxy(rowData,handler);

## 获取数据

当渲染透视表数据单元格时,需要获取对应的展示内容(数据)。举个例子,需要右下角单元格数据时,代码如下:

```ts
const data = getCellData({
query: { province: '浙江省', city: '绍兴市', type: '家具', sub_type: '沙发', $$extra$$: 'price' }
});
console.log({...data}); //{ "price": 4,"province": "浙江省","city": "绍兴市","type": "家具","sub_type": "沙发", "$$extra$$": "price", "$$value$$": 4 }
```

实现过程是,先拿到行、列维度枚举值:
### 获取多个数据

```ts
const rowDimensionValues = getQueryDimValues(['province', 'city'], query); // ['浙江省', '绍兴市']
const colDimensionValues = getQueryDimValues(['type', 'sub_type', '$$extra$$'], query); // ['家具', '沙发', 'price']
```
如果想获取多个单元格数据,其大致流程和获取单个数据一致;获取多个单元格数据允许有维度缺失,会返回多个符合 query 的数据。

然后通过枚举值获取数据查询路径,并从前面生成的多维数组中拿到具体数据。
比如获取*浙江省*下的所有信息示例代码如下:

```ts
const path = getDataPath({ rowDimensionValues, colDimensionValues }); // [0, 1, 0, 1, 0]
const data = lodash.get(indexesData, path);
const dataList = getMultiData({
query: { province: '浙江省', $$extra$$: 'price' }
});
```

总结下,获取数据是通过查询条件,构造当前查询条件对应的数据路径,然后从多维数组中直接拿取。
22 changes: 10 additions & 12 deletions s2-site/docs/manual/advanced/get-cell-data.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,20 +198,18 @@ const rowCellNode = s2.getRowNodes().find((node) => node.id === 'root[&]浙江
// 找到 "办公用品" 下 "纸张" 对应的 "数量"列头单元格节点
const colCellNode = s2.getColumnNodes().find((node) => node.id === 'root[&]办公用品[&]纸张[&]number')

const data = s2.dataSet.getMultiData({...rowCellNode.query, ...colCellNode.query})
const data = s2.dataSet.getCellData({...rowCellNode.query, ...colCellNode.query})

/**
[
{
"number": 1634,
"province": "浙江省",
"city": "舟山市",
"type": "办公用品",
"sub_type": "纸张",
"$$extra$$": "number",
"$$value$$": 1634
}
]
{
"number": 1634,
"province": "浙江省",
"city": "舟山市",
"type": "办公用品",
"sub_type": "纸张",
"$$extra$$": "number",
"$$value$$": 1634
}
*/
```

Expand Down
6 changes: 6 additions & 0 deletions s2-site/examples/analysis/get-data/API.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: API
order: 4
---

<embed src="@/docs/api/basic-class/base-data-set.en.md"></embed>
6 changes: 6 additions & 0 deletions s2-site/examples/analysis/get-data/API.zh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: API
order: 4
---

<embed src="@/docs/api/basic-class/base-data-set.zh.md"></embed>
Loading

0 comments on commit 31016ed

Please sign in to comment.