Skip to content

Commit

Permalink
feat(interaction): 内置封装 brush 交互 (#2719)
Browse files Browse the repository at this point in the history
* feat(interaction): add brush features and add to scatter

* feat: add brush to column and bar plot, add docs and demos

* docs: 修改 brush demo 截图

* feat(brush): 新增 brush-x, brush-y 的刷选高亮交互 & 增加 demo

* test(brush): 添加column, bar, scatter 等 brush 单测

* feat(brush): 添加 brush filter 的事件监听文档 & demo

* docs(brush): 增加 brush demo

* feat(brush): 添加 brush 交互事件文档和 demo

* docs(brush): 补充 brush 刷选交互的文档

* docs(brush): 优化 brush 文档

* feat(brush-type): 支持更多 brush 类型,如 circle, path

* docs(brush): 刷选demo优化

* test: 修改 brush 单测

* feat(brush): 添加 brush filter 的重置按钮的相关配置
  • Loading branch information
visiky authored Jul 24, 2021
1 parent d0055e1 commit abc4584
Show file tree
Hide file tree
Showing 35 changed files with 1,474 additions and 16 deletions.
58 changes: 58 additions & 0 deletions __tests__/unit/plots/bar/interaction-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Bar } from '../../../../src';
import { salesByArea } from '../../../data/sales';
import { createDiv } from '../../../utils/dom';

describe('bar interaction', () => {
const plot = new Bar(createDiv('x*y'), {
width: 400,
height: 300,
data: salesByArea,
yField: 'area',
xField: 'sales',
});

plot.render();

it('brush', () => {
plot.update({
brush: {
enabled: true,
},
});
expect(plot.chart.interactions['brush']).toBeDefined();

plot.update({ brush: { type: 'circle' } });
expect(plot.chart.interactions['brush']).toBeDefined();

plot.update({ brush: { type: 'x-rect' } });
// 不同 brush 是互斥的
expect(plot.chart.interactions['brush']).not.toBeDefined();
expect(plot.chart.interactions['brush-x']).toBeDefined();

plot.update({ brush: { type: 'path' } });
expect(plot.chart.interactions['brush-x']).not.toBeDefined();
expect(plot.chart.interactions['brush']).toBeDefined();

plot.update({ brush: { type: 'y-rect' } });
expect(plot.chart.interactions['brush-x']).not.toBeDefined();
expect(plot.chart.interactions['brush-y']).toBeDefined();

plot.update({ brush: { type: 'y-rect', action: 'highlight' } });
expect(plot.chart.interactions['brush-y']).not.toBeDefined();
expect(plot.chart.interactions['brush-y-highlight']).toBeDefined();

plot.update({ brush: { type: 'x-rect', action: 'highlight' } });
expect(plot.chart.interactions['brush-x']).not.toBeDefined();
expect(plot.chart.interactions['brush-y-highlight']).not.toBeDefined();
expect(plot.chart.interactions['brush-x-highlight']).toBeDefined();

plot.update({ brush: { type: 'rect', action: 'highlight' } });
expect(plot.chart.interactions['brush-x']).not.toBeDefined();
expect(plot.chart.interactions['brush']).not.toBeDefined();
expect(plot.chart.interactions['brush-highlight']).toBeDefined();
});

afterAll(() => {
plot.destroy();
});
});
58 changes: 58 additions & 0 deletions __tests__/unit/plots/column/interaction-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Column } from '../../../../src';
import { salesByArea } from '../../../data/sales';
import { createDiv } from '../../../utils/dom';

describe('column interaction', () => {
const plot = new Column(createDiv('x*y'), {
width: 400,
height: 300,
data: salesByArea,
xField: 'area',
yField: 'sales',
});

plot.render();

it('brush', () => {
plot.update({
brush: {
enabled: true,
},
});
expect(plot.chart.interactions['brush']).toBeDefined();

plot.update({ brush: { type: 'circle' } });
expect(plot.chart.interactions['brush']).toBeDefined();

plot.update({ brush: { type: 'x-rect' } });
// 不同 brush 是互斥的
expect(plot.chart.interactions['brush']).not.toBeDefined();
expect(plot.chart.interactions['brush-x']).toBeDefined();

plot.update({ brush: { type: 'path' } });
expect(plot.chart.interactions['brush-x']).not.toBeDefined();
expect(plot.chart.interactions['brush']).toBeDefined();

plot.update({ brush: { type: 'y-rect' } });
expect(plot.chart.interactions['brush-x']).not.toBeDefined();
expect(plot.chart.interactions['brush-y']).toBeDefined();

plot.update({ brush: { type: 'y-rect', action: 'highlight' } });
expect(plot.chart.interactions['brush-y']).not.toBeDefined();
expect(plot.chart.interactions['brush-y-highlight']).toBeDefined();

plot.update({ brush: { type: 'x-rect', action: 'highlight' } });
expect(plot.chart.interactions['brush-x']).not.toBeDefined();
expect(plot.chart.interactions['brush-y-highlight']).not.toBeDefined();
expect(plot.chart.interactions['brush-x-highlight']).toBeDefined();

plot.update({ brush: { type: 'rect', action: 'highlight' } });
expect(plot.chart.interactions['brush-x']).not.toBeDefined();
expect(plot.chart.interactions['brush']).not.toBeDefined();
expect(plot.chart.interactions['brush-highlight']).toBeDefined();
});

afterAll(() => {
plot.destroy();
});
});
45 changes: 42 additions & 3 deletions __tests__/unit/plots/scatter/interaction-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { createDiv } from '../../../utils/dom';
import { data } from '../../../data/gender';

describe('scatter: register interaction', () => {
const scatter = new Scatter(createDiv(), {
const plot = new Scatter(createDiv(), {
width: 400,
height: 300,
appendPadding: 10,
Expand All @@ -24,14 +24,53 @@ describe('scatter: register interaction', () => {
],
});

scatter.render();
plot.render();

it('define: drag-move', () => {
const statisticInteraction = getInteraction('drag-move');
expect(statisticInteraction).toBeDefined();
});

it('brush', () => {
plot.update({
brush: {
enabled: true,
},
});
expect(plot.chart.interactions['brush']).toBeDefined();

plot.update({ brush: { type: 'circle' } });
expect(plot.chart.interactions['brush']).toBeDefined();

plot.update({ brush: { type: 'x-rect' } });
// 不同 brush 是互斥的
expect(plot.chart.interactions['brush']).not.toBeDefined();
expect(plot.chart.interactions['brush-x']).toBeDefined();

plot.update({ brush: { type: 'path' } });
expect(plot.chart.interactions['brush-x']).not.toBeDefined();
expect(plot.chart.interactions['brush']).toBeDefined();

plot.update({ brush: { type: 'y-rect' } });
expect(plot.chart.interactions['brush-x']).not.toBeDefined();
expect(plot.chart.interactions['brush-y']).toBeDefined();

plot.update({ brush: { type: 'y-rect', action: 'highlight' } });
expect(plot.chart.interactions['brush-y']).not.toBeDefined();
expect(plot.chart.interactions['brush-y-highlight']).toBeDefined();

plot.update({ brush: { type: 'x-rect', action: 'highlight' } });
expect(plot.chart.interactions['brush-x']).not.toBeDefined();
expect(plot.chart.interactions['brush-y-highlight']).not.toBeDefined();
expect(plot.chart.interactions['brush-x-highlight']).toBeDefined();

plot.update({ brush: { type: 'rect', action: 'highlight' } });
expect(plot.chart.interactions['brush-x']).not.toBeDefined();
expect(plot.chart.interactions['brush']).not.toBeDefined();
expect(plot.chart.interactions['brush-highlight']).toBeDefined();
});

afterAll(() => {
scatter.destroy();
plot.destroy();
});
});
8 changes: 8 additions & 0 deletions docs/api/plots/bar.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,12 @@ Applicable to base bar charts and base bar charts, the Conversion Rate component

### Plot Interactions

Built-in interactions of scatter are as follows:

| Interaction | Description | Configuration |
| ----------- | ---------------------------------------- | ------------------------------ |
| brush | 用于刷选交互,配置该交互后,可进行刷选。 | `brush: { enabled: true }` |

`markdown:docs/common/brush.en.md`

`markdown:docs/common/interactions.en.md`
9 changes: 9 additions & 0 deletions docs/api/plots/bar.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,12 @@ order: 3

### 图表交互

条形图内置了一些交互,列表如下:

| 交互 | 描述 | 配置 |
| ----------- | ---------------------------------------- | ------------------------------ |
| brush | 用于刷选交互,配置该交互后,可进行刷选。 | `brush: { enabled: true }` |

`markdown:docs/common/brush.zh.md`

`markdown:docs/common/interactions.zh.md`
8 changes: 8 additions & 0 deletions docs/api/plots/column.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,12 @@ Applicable to base bar charts and base bar charts, the Conversion Rate component

### Plot Interactions

Built-in interactions of scatter are as follows:

| Interaction | Description | Configuration |
| ----------- | ---------------------------------------- | ------------------------------ |
| brush | 用于刷选交互,配置该交互后,可进行刷选。 | `brush: { enabled: true }` |

`markdown:docs/common/brush.en.md`

`markdown:docs/common/interactions.en.md`
8 changes: 8 additions & 0 deletions docs/api/plots/column.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,12 @@ order: 2

### 图表交互

柱状图内置了一些交互,列表如下:

| 交互 | 描述 | 配置 |
| ----------- | ---------------------------------------- | ------------------------------ |
| brush | 用于刷选交互,配置该交互后,可进行刷选。 | `brush: { enabled: true }` |

`markdown:docs/common/brush.zh.md`

`markdown:docs/common/interactions.zh.md`
8 changes: 8 additions & 0 deletions docs/api/plots/scatter.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,4 +300,12 @@ regressionLine: {

### Plot Interactions

Built-in interactions of scatter are as follows:

| Interaction | Description | Configuration |
| ----------- | ---------------------------------------- | ------------------------------ |
| brush | 用于刷选交互,配置该交互后,可进行刷选。 | `brush: { enabled: true }` |

`markdown:docs/common/brush.en.md`

`markdown:docs/common/interactions.en.md`
8 changes: 8 additions & 0 deletions docs/api/plots/scatter.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,4 +300,12 @@ regressionLine: {

### 图表交互

散点图内置了一些交互,列表如下:

| 交互 | 描述 | 配置 |
| ----------- | ---------------------------------------- | ------------------------------ |
| brush | 用于刷选交互,配置该交互后,可进行刷选。 | `brush: { enabled: true }` |

`markdown:docs/common/brush.zh.md`

`markdown:docs/common/interactions.zh.md`
24 changes: 12 additions & 12 deletions docs/api/plots/sunburst.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type Node = { name: string; value?: number; children: Node[]; }
`Sunburst.SUNBURST_ANCESTOR_FIELD`| 当前节点的祖先节点 | _string_ |
`Sunburst.NODE_ANCESTORS_FIELD`| 当前节点的祖先节点列表 |_object[]_ |
`nodeIndex`| 当前节点在同一父节点下的所有节点中的索引顺序 |_number_ |
| `childNodeCount` | 当前节点的儿子节点数 |_number_ |
| `childNodeCount` | 当前节点的儿子节点数 |_number_ |
`depth`| |_number_ |
`height`| | _number_ |

Expand Down Expand Up @@ -86,14 +86,14 @@ meta: {

支持配置属性:

| Properties | Type | Description |
| ---------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| field | _string_ | 数据节点权重映射字段,默认为:`value`. 当你的节点数据格式不是:`{ name: 'xx', value: 'xx' }`, 可以通过该字段来指定,详细见:图表示例 |
| padding | _number\|number[]_ | 默认:`0`。参考:[d3-hierarchy#partition_padding](https://github.com/d3/d3-hierarchy#partition_padding) |
| size | _number[]_ | 默认:`[1, 1]`。参考:[d3-hierarchy#partition_size](https://github.com/d3/d3-hierarchy#partition_size) |
| round | _boolean_ | 默认:`false`。参考:[d3-hierarchy#partition_round](https://github.com/d3/d3-hierarchy#partition_round) |
| sort | _Function_ | 数据节点排序方式,默认:降序。参考: [d3-hierarchy#node_sort](https://github.com/d3/d3-hierarchy#node_sort) |
| ignoreParentValue | _boolean_ | 是否忽略 parentValue, 默认:true。 当设置为 true 时,父节点的权重由子元素决定 |
| Properties | Type | Description |
| ----------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| field | _string_ | 数据节点权重映射字段,默认为:`value`. 当你的节点数据格式不是:`{ name: 'xx', value: 'xx' }`, 可以通过该字段来指定,详细见:图表示例 |
| padding | _number\|number[]_ | 默认:`0`。参考:[d3-hierarchy#partition_padding](https://github.com/d3/d3-hierarchy#partition_padding) |
| size | _number[]_ | 默认:`[1, 1]`。参考:[d3-hierarchy#partition_size](https://github.com/d3/d3-hierarchy#partition_size) |
| round | _boolean_ | 默认:`false`。参考:[d3-hierarchy#partition_round](https://github.com/d3/d3-hierarchy#partition_round) |
| sort | _Function_ | 数据节点排序方式,默认:降序。参考: [d3-hierarchy#node_sort](https://github.com/d3/d3-hierarchy#node_sort) |
| ignoreParentValue | _boolean_ | 是否忽略 parentValue, 默认:true。 当设置为 true 时,父节点的权重由子元素决定 |

#### radius

Expand Down Expand Up @@ -169,9 +169,9 @@ meta: {

旭日图内置了一些交互,列表如下:

| Interaction | Description | Configuration |
| ----------- | ---------------------------------------- | ------------------------------ |
| drill-down | 用于下钻交互,配置该交互后,点击可下钻。 | `drilldown: { enabled: true }` |
| 交互 | 描述 | 配置 |
| ---------- | ---------------------------------------- | ------------------------------ |
| drill-down | 用于下钻交互,配置该交互后,点击可下钻。 | `drilldown: { enabled: true }` |

`markdown:docs/common/drill-down.zh.md`

Expand Down
79 changes: 79 additions & 0 deletions docs/common/brush.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#### brush

<description>**optional** _BrushCfg_</description>

Configuration of brush interaction.

**Properties**

Types of _BrushCfg_ are as follows:

| Properties | Type | Description |
| ---------- | ----------- | ------------------------------------------------------------------------------------------------ |
| enabled | _boolean_ | 是否开启 brush 刷选交互,默认为:'false' |
| type | _string_ | brush 类型,可选项:'rect' \| 'x-rect' \| 'y-rect' \| 'cirlce' \| 'path' (polygon). 默认: 'rect' |
| action | _string_ | brush action, options: 'filter' \| 'highlight'. Default: 'filter' |
| mask | _MaskCfg_ | Configuration of mask. |
| button | _ButtonCfg_ | Configuration of rRset Button,works when action is equal to 'filter' |

Types of _MaskCfg_ are as follows:

| Properties | Type | Description |
| ---------- | ------------ | ----------- |
| style | _ShapeAttrs_ | mask 样式 |

Types of _ButtonCfg_ are as follows:

```ts
export type ButtonCfg = {
/**
* padding of button
*/
padding?: number | number[];
/**
* text of button
*/
text?: string;
/**
* custom style of text
*/
textStyle?: {
default?: ShapeAttrs;
};
/**
* custom style of button
*/
buttonStyle?: {
default?: ShapeAttrs;
active?: ShapeAttrs;
};
};
```

**Events**

1. List of vents of `brush-filter` interaction,

| Event Name | Description |
| -------------------------------------- | -------------------------------------------------------- |
| `G2.BRUSH_FILTER_EVENTS.BEFORE_FILTER` | Hook before brush event to trigger `filter` append |
| `G2.BRUSH_FILTER_EVENTS.AFTER_FILTER` | Hook after brush event to trigger `filter` append |
| `G2.BRUSH_FILTER_EVENTS.BEFORE_RESET` | Hook before brush event to trigger filter `reset` append |
| `G2.BRUSH_FILTER_EVENTS.AFTER_RESET` | Hook after brush event to trigger filter `reset` append |

example:

<playground path="dynamic-plots/brush/demo/advanced-brush1.ts" rid="brush-filter-event"></playground>

2. List of vents of `brush-highlight` interaction,

| Event Name | Description |
| ---------------------------------------------------- | ------------------------------------------------------------------- |
| `G2.ELEMENT_RANGE_HIGHLIGHT_EVENTS.BEFORE_HIGHLIGHT` | Hook before event to trigger element-range `highlight` append |
| `G2.ELEMENT_RANGE_HIGHLIGHT_EVENTS.AFTER_HIGHLIGHT` | Hook after event to trigger element-range `highlight` append |
| `G2.ELEMENT_RANGE_HIGHLIGHT_EVENTS.BEFORE_CLEAR` | Hook before event to trigger element-range-highlight `reset` append |
| `G2.ELEMENT_RANGE_HIGHLIGHT_EVENTS.AFTER_CLEAR` | Hook after event to trigger element-range-highlight `reset` append |

example:

<playground path="dynamic-plots/brush/demo/advanced-brush2.ts" rid="brush-highlight-event"></playground>
Loading

0 comments on commit abc4584

Please sign in to comment.