Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 49 additions & 12 deletions examples/case/statistical-scenario/demo/conversion-funnel.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Column, G2 } from '@antv/g2plot';
import { Column, G2, addWaterWave } from '@antv/g2plot';

const X_FIELD = 'stage';
const Y_FIELD = 'count';
Expand Down Expand Up @@ -64,28 +64,31 @@ G2.registerShape('interval', 'link-funnel', {
rectPath = this.parsePath(rectPath);

const group = container.addGroup();

// 灰色背景
group.addShape('path', {
capture: false,
attrs: {
...attrs,
fill: '#efefef',
fill: '#fff',
lineWidth: 1,
path: this.parsePath([
['M', points[0].x, points[1].y],
['M', points[0].x, 0],
['L', points[0].x, 1],
['L', points[2].x, 1],
['L', points[2].x, points[1].y],
['L', points[2].x, 0],
]),
},
});
// 实际柱子
group.addShape('path', {
name: 'column',
attrs: {
...attrs,
path: rectPath,
},
});

const boxPath = this.parsePath([
['M', points[0].x, 0],
['L', points[0].x, 1],
['L', points[2].x, 1],
['L', points[2].x, 0],
['L', points[0].x, 0],
]);

// 存在下一节点, 添加连接带
if (nextPoints) {
const linkPath = this.parsePath([
Expand Down Expand Up @@ -118,6 +121,40 @@ G2.registerShape('interval', 'link-funnel', {
},
});
}

/** 水波 ---- */
const centerX = (rectPath[0][1] + rectPath[2][1]) / 2;
const centerY = (boxPath[0][2] + boxPath[1][2]) / 2;
const height = boxPath[0][2] - boxPath[1][2];
const r = 1 - (rectPath[0][2] - rectPath[1][2]) / height;
// 1. 绘制一个波
const waves = group.addGroup({
name: 'waves',
});

const waveLength = 30;
// 3. 波对应的 clip 裁剪形状
const clipPath = waves.setClip({
type: 'path',
attrs: {
path: boxPath,
},
});

// 4. 绘制波形
addWaterWave(
centerX,
centerY,
r,
2,
{ fill: attrs.fill, opacity: 0.8 },
waves,
clipPath,
height,
waveLength,
undefined
);

return group;
},
});
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export { Funnel, FUNNEL_CONVERSATION_FIELD } from './plots/funnel';
export type { FunnelOptions } from './plots/funnel';

// 水波图及类型定义 | author by [CarisL](https://github.com/CarisL), [hustcc](https://github.com/hustcc), [pearmini](https://github.com/pearmini)
export { Liquid } from './plots/liquid';
export { Liquid, addWaterWave } from './plots/liquid';
export type { LiquidOptions } from './plots/liquid';

// 子弹图及类型定义 | author by [arcsin1](https://github.com/arcsin1)
Expand Down
2 changes: 2 additions & 0 deletions src/plots/liquid/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { getLiquidData } from './utils';
// register liquid shape
import './shapes/liquid';

export { addWaterWave } from './shapes/liquid';

export type { LiquidOptions };

/**
Expand Down
24 changes: 16 additions & 8 deletions src/plots/liquid/shapes/liquid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ function getWaterWavePath(
* @param radius 绘制图形的高度
* @param waveLength 波的长度
*/
function addWaterWave(
export function addWaterWave(
x: number,
y: number,
level: number,
Expand All @@ -215,16 +215,21 @@ function addWaterWave(
waveLength: number,
animation: LiquidOptions['animation']
) {
// 盒子属性 颜色 宽高
const { fill, opacity } = waveAttrs;
const bbox = clip.getBBox();
const width = bbox.maxX - bbox.minX;
const height = bbox.maxY - bbox.minY;

// 循环 waveCount 个数
for (let idx = 0; idx < waveCount; idx++) {
const factor = waveCount <= 1 ? 0 : idx / (waveCount - 1);

// 画波
const wave = group.addShape('path', {
name: `waterwave-path`,
attrs: {
// 波形路径配置
path: getWaterWavePath(
radius,
bbox.minY + height * level,
Expand All @@ -240,6 +245,7 @@ function addWaterWave(
});

try {
// 默认 underfind 开启动画
if (animation === false) return;
const matrix = transform([['t', waveLength, 0]]);

Expand Down Expand Up @@ -369,6 +375,14 @@ function rect(x: number, y: number, width: number, height: number) {
`;
}

const builtInShapeByName = {
pin,
circle,
diamond,
triangle,
rect,
};

registerShape('interval', 'liquid-fill-gauge', {
draw(cfg: any, container: IGroup) {
const cx = 0.5;
Expand Down Expand Up @@ -399,13 +413,7 @@ registerShape('interval', 'liquid-fill-gauge', {
const waveAttrs = getFillAttrs(cfg);
const outlineAttrs = getLineAttrs(mix({}, cfg, outline));
const innerRadius = radius - border / 2;
const builtInShapeByName = {
pin,
circle,
diamond,
triangle,
rect,
};

const buildPath = typeof shape === 'function' ? shape : builtInShapeByName[shape] || builtInShapeByName['circle'];
const shapePath = buildPath(center.x, center.y, innerRadius * 2, innerRadius * 2);

Expand Down