antvis/G2
The issue has been closed
Add Rect #4176
pearmini posted onGitHub
新增 Rect Mark
主要用于绘制直方图、聚合热力图和矩阵树图。
// 绘制一个直方图
G2.render({
type: 'rect',
transform: [{ type: 'binX', y: 'count' }],
encode: { x: 'Volume' },
});
设计思考
在 4.0 里面的直方图是用 Interval 绘制的,存在的问题有至少有两点:
- 理解成本:Interval 的 x 理论上应该是离散的,但是直方图的 x 是连续的。用一个 Mark 绘制这个地方是有点混淆的。
- 坐标轴 tick 的生成:正是上面离散和连续的区别,导致了绘制出来的坐标轴应该是不一样的。离散的应该是每一段一个 tick,连续的应该是每一段的两端都有 tick。
绘制直方图的图的另一个思路是用 Polygon Mark,但是这样就需要提供 4 个 x 和 4 个 y 用来生成控制点。这样最大的问题就是不能直接使用 StackY 等 transform,因为它们都是只处理两个 y 通道。
所以这里独立一个 Mark 出来:Rect,它的 x 和 y 通道都是离散的,并且只有 2 个 x 通道和 2 个 y 通道。
实现细节
- shape 直接复用 interval 下面的 rect 和 hollow。
- 给 rect 和 hollow 增加笛卡尔坐标系下的 inset 配置。
- props 如下:
Rect.props = {
defaultShape: 'rect',
defaultLabelShape: 'label',
channels: [
...baseGeometryChannels(),
{ name: 'x', required: true },
{ name: 'y', required: true },
],
preInference: [...basePreInference(), { type: 'maybeZeroY1' },],
postInference: [
...basePostInference(),
{ type: 'maybeTitleX' },
{ type: 'maybeTooltipY' },
],
shapes: ['rect', 'hollow'],
};
案例验证
目前还没有添加 binX 和 binY transform,所以暂时用矩阵树图验证就好。替换这里的案例如下:
(() => {
const width = 640;
const height = 480;
const padding = 3;
const layout = (data) => {
const root = d3.hierarchy(data);
root.count();
d3.treemap().size([width, height]).padding(padding)(root);
return root
.descendants()
.map((d) =>
Object.assign(d, {
x: [d.x0, d.x1],
y: [d.y0, d.y0],
}),
)
.filter((d) => d.height === 0);
};
const name = (d) => {
const { name } = d.data;
return name.length > 5 ? name.slice(0, 4) + '...' : name;
};
const chart = new G2.Chart({
width,
height,
paddingLeft: padding,
paddingBottom: padding,
paddingRight: padding,
});
chart.data({
type: 'fetch',
value: 'https://gw.alipayobjects.com/os/bmw-prod/5155ef81-db23-49f3-b72b-d436a219d289.json',
transform: [{ type: 'custom', callback: layout }],
});
chart
.rect()
.encode('x', 'x')
.encode('y', 'y')
.encode('size', 'r')
.encode('color', (d) => d.parent.data.name)
.encode('tooltip', (d) => d.parent.data.name)
.encode('title', '')
.scale('x', { domain: [0, width], guide: null })
.scale('y', { domain: [0, height], guide: null, range: [0, 1] })
.scale('color', {
field: '学派',
guide: { size: 72, autoWrap: true, maxRows: 3, cols: 6 },
})
.scale('size', { type: 'identity' })
.scale('tooltip', { field: '流派' });
chart
.text()
.data({
transform: [
{ type: 'filterBy', fields: ['height'], callback: (d) => d === 0 },
],
})
.encode('x', (d) => d.x[0])
.encode('y', (d) => d.y[0])
.encode('text', name)
.style('dy', '15px')
.style('dx', '5px')
.style('fill', 'black')
.style('fontSize', 12)
.style('textAnchor', 'start');
return chart.render().node();
})();
待办
下面两件事情分成两个 PR:
- 更名 - Rect -> Square:API、Spec、Mark、测试以及案例,分面
- 新增 - Rect