Skip to content

Commit

Permalink
treemap 允许设置纵横比 & 滚动时阻止默认事件 (#2360)
Browse files Browse the repository at this point in the history
* fix: treemap, 增加 view-zoom 时, 阻止默认滚动事件

* feat: 允许配置纵横比

* fix: 恢复 ratio 逻辑

* feat: 更新文档

* fix: 更新文档&测试用例

* feat: 新增测试用例

* feat: 更新测试用例

Co-authored-by: aiyin.lzy <nadia.lzy@antfin.com>
  • Loading branch information
liuzhenying and aiyin.lzy authored Mar 1, 2021
1 parent 6cb7eb1 commit c849383
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 26 deletions.
36 changes: 36 additions & 0 deletions __tests__/unit/plots/treemap/interactions/view-zoom-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Treemap } from '../../../../../src';
import { createDiv } from '../../../../utils/dom';
import { TREEMAP } from '../../../../data/treemap';

describe('treemap view zoom interaction', () => {
it('basic treemap', async () => {
const treemapPlot = new Treemap(createDiv(), {
data: TREEMAP,
colorField: 'name',
});

treemapPlot.render();

// 默认不开启
expect(treemapPlot.chart.getCanvas().getEvents().mousewheel).toBeUndefined();

// 开启
treemapPlot.update({
interactions: [{ type: 'view-zoom' }, { type: 'drag-move' }],
});

const mousewheelEvent = treemapPlot.chart.getCanvas().getEvents().mousewheel;

expect(Array.isArray(mousewheelEvent)).toBeTruthy();
expect(mousewheelEvent.length).toBe(1);

// 关闭
treemapPlot.update({
interactions: [{ type: 'view-zoom', enable: false }],
});

expect(treemapPlot.chart.getCanvas().getEvents().mousewheel).toBeUndefined();

treemapPlot.destroy();
});
});
3 changes: 3 additions & 0 deletions __tests__/unit/plots/treemap/utils-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ describe('treemap transformData', () => {
data: data1,
colorField: 'name',
openDrillDown: false,
hierarchyConfig: {},
});

const areaArr = data.map((dt) => {
Expand Down Expand Up @@ -181,6 +182,7 @@ describe('treemap transformData', () => {
data: data3,
colorField: 'category',
openDrillDown: false,
hierarchyConfig: {},
});
data.forEach((d) => {
expect(d.category).toEqual(d.expectCategory);
Expand Down Expand Up @@ -212,6 +214,7 @@ describe('treemap transformData', () => {
data: data3,
colorField: 'category',
openDrillDown: true,
hierarchyConfig: {},
});
expect(data.length).toEqual(2);
});
Expand Down
51 changes: 34 additions & 17 deletions __tests__/unit/utils/hierarchy/treemap-spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { treemap } from '../../../../src/utils/hierarchy/treemap';
import * as d3Hierarchy from 'd3-hierarchy';
import { treemap, getTileMethod } from '../../../../src/utils/hierarchy/treemap';

const data = {
children: [
Expand Down Expand Up @@ -32,26 +33,42 @@ describe('hierarchy/treemap', () => {
});
}).toThrow(`Invalid as: it must be an array with 2 strings (e.g. [ "x", "y" ])!`);
});
});

it('treemap: ignore parent value', () => {
const res = treemap(data, { as: ['x', 'y'], field: 'value' });
const leaves = res[0].leaves();
leaves.forEach((leaf) => {
const width = Math.abs(leaf.x[1] - leaf.x[0]);
const height = Math.abs(leaf.y[2] - leaf.y[1]);
expect(width * height).toEqual(0.5);
it('treemap: ignore parent value', () => {
const res = treemap(data, { as: ['x', 'y'], field: 'value' });
const leaves = res[0].leaves();
leaves.forEach((leaf) => {
const width = Math.abs(leaf.x[1] - leaf.x[0]);
const height = Math.abs(leaf.y[2] - leaf.y[1]);
expect(width * height).toEqual(0.5);
});
});

it('treemap, dont ignore parent value', () => {
const res = treemap(data, { as: ['x', 'y'], field: 'value', ignoreParentValue: false });

const leaves = res[0].leaves();

leaves.forEach((leaf) => {
const width = Math.abs(leaf.x[1] - leaf.x[0]);
const height = Math.abs(leaf.y[2] - leaf.y[1]);
expect(width * height).toEqual(0.25);
});
});
});

it('treemap, dont ignore parent value', () => {
const res = treemap(data, { as: ['x', 'y'], field: 'value', ignoreParentValue: false });
it('getTileMethod', () => {
// @ts-ignore
const spy = jest.spyOn(d3Hierarchy.treemapSquarify, 'ratio').mockImplementation((ratio) => {
return `treemapSquarify_${ratio}`;
});

const leaves = res[0].leaves();
const diceMethod = getTileMethod('treemapDice', 1);
expect(spy).toHaveBeenCalledTimes(0);
expect(diceMethod.name).toBe('treemapDice');

leaves.forEach((leaf) => {
const width = Math.abs(leaf.x[1] - leaf.x[0]);
const height = Math.abs(leaf.y[2] - leaf.y[1]);
expect(width * height).toEqual(0.25);
const squarifyMethod = getTileMethod('treemapSquarify', 2);
expect(spy).toHaveBeenCalledTimes(1);
expect(squarifyMethod).toBe('treemapSquarify_2');
spy.mockRestore();
});
});
2 changes: 1 addition & 1 deletion docs/api/plots/treemap.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Default configuration:
<description>**optional** _object_</description>

Hierarchical layout configuration, such as' tile ', etc., refer to detailed configuration [d3-hierarchy](https://github.com/d3/d3-hierarchy#treemap)
The default is `{tile: 'treemapResquarify'}`
The default is `{tile: 'treemapSquarify', ratio: 0.5 * (1 + Math.sqrt(5))}` (Golden Section Ratio)

### Plot Components

Expand Down
2 changes: 1 addition & 1 deletion docs/api/plots/treemap.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const data = {
<description>**optional** _object_</description>

层级布局配置,例如 `tile`等,详细配置参考[d3-hierarchy](https://github.com/d3/d3-hierarchy#treemap)
默认为 `{tile: 'treemapResquarify'}`
默认为 `{tile: 'treemapSquarify', ratio: 0.5 * (1 + Math.sqrt(5))}` (黄金分割纵横比)

### 图表组件

Expand Down
9 changes: 9 additions & 0 deletions examples/more-plots/treemap/demo/treemap-nest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/mobile.json')
const treemapPlot = new Treemap('container', {
data,
colorField: 'brand',
// 为矩形树图增加缩放,拖拽交互
interactions: [
{
type: 'view-zoom',
},
{
type: 'drag-move',
},
],
});
treemapPlot.render();
});
22 changes: 18 additions & 4 deletions src/plots/treemap/adaptor.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isArray } from '@antv/util';
import { polygon as basePolygon } from '../../adaptor/geometries/polygon';
import { Params } from '../../core/adaptor';
import { interaction as commonInteraction, animation, theme, legend, annotation, tooltip } from '../../adaptor/common';
Expand All @@ -23,7 +24,7 @@ function defaultOptions(params: Params<TreemapOptions>): Params<TreemapOptions>
stroke: '#fff',
},
hierarchyConfig: {
tile: 'treemapResquarify',
tile: 'treemapSquarify',
},
label: {
fields: ['name'],
Expand All @@ -42,8 +43,6 @@ function defaultOptions(params: Params<TreemapOptions>): Params<TreemapOptions>
};
},
},
interactions: [{ type: 'view-zoom' }, { type: 'treemap-element-zoom' }],
// interactions: [{ type: 'drag-move' }],
},
},
params
Expand All @@ -56,11 +55,12 @@ function defaultOptions(params: Params<TreemapOptions>): Params<TreemapOptions>
*/
function geometry(params: Params<TreemapOptions>): Params<TreemapOptions> {
const { chart, options } = params;
const { color, colorField, rectStyle } = options;
const { color, colorField, rectStyle, hierarchyConfig } = options;
const data = transformData({
data: options.data,
colorField: options.colorField,
openDrillDown: isDrillDown(options.interactions),
hierarchyConfig,
});

chart.data(data);
Expand Down Expand Up @@ -112,6 +112,20 @@ export function interaction(params: Params<TreemapOptions>): Params<TreemapOptio
},
});

const viewZoomInteraction = isArray(interactions) && interactions.find((i) => i.type === 'view-zoom');

if (viewZoomInteraction) {
// 开启缩放 interaction 后,则阻止默认滚动事件,避免整个窗口的滚动
if (viewZoomInteraction.enable !== false) {
chart.getCanvas().on('mousewheel', (ev) => {
ev.preventDefault();
});
} else {
// 手动关闭后,清除
chart.getCanvas().off('mousewheel');
}
}

return params;
}

Expand Down
4 changes: 2 additions & 2 deletions src/plots/treemap/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ interface TransformDataOptions {
data: TreemapOptions['data'];
colorField: TreemapOptions['colorField'];
openDrillDown: boolean;
hierarchyConfig?: TreemapOptions['hierarchyConfig'];
hierarchyConfig: TreemapOptions['hierarchyConfig'];
}

export function transformData(options: TransformDataOptions) {
const { data, colorField, openDrillDown, hierarchyConfig = {} } = options;
const { data, colorField, openDrillDown, hierarchyConfig } = options;

const nodes = treemap(data, {
...hierarchyConfig,
Expand Down
10 changes: 9 additions & 1 deletion src/utils/hierarchy/treemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@ const DEFAULT_OPTIONS: HierarchyOption = {
as: ['x', 'y'],
// 默认降序
sort: (a, b) => b.value - a.value,
// 纵横比, treemapSquarify 布局时可用,默认黄金分割比例
ratio: 0.5 * (1 + Math.sqrt(5)),
};

export function getTileMethod(tile: string, ratio: number) {
return tile === 'treemapSquarify' ? d3Hierarchy[tile].ratio(ratio) : d3Hierarchy[tile];
}

export function treemap(data: any, options: HierarchyOption): any[] {
options = assign({} as HierarchyOption, DEFAULT_OPTIONS, options);
const as = options.as;
Expand All @@ -35,10 +41,12 @@ export function treemap(data: any, options: HierarchyOption): any[] {
console.warn(e);
}

const tileMethod = getTileMethod(options.tile, options.ratio);

const partition = (data) =>
d3Hierarchy
.treemap()
.tile(d3Hierarchy[options.tile])
.tile(tileMethod)
.size(options.size)
.round(options.round)
.padding(options.padding)
Expand Down

0 comments on commit c849383

Please sign in to comment.