@antv/g2plot
Version:
An interactive and responsive charting library
249 lines (218 loc) • 6.04 kB
text/typescript
import { Geometry } from '@antv/g2';
import { get } from '@antv/util';
import { Datum } from '../../types';
import { Params } from '../../core/adaptor';
import { interaction, animation, theme, state, scale, annotation } from '../../adaptor/common';
import { interval } from '../../adaptor/geometries';
import { getLocale } from '../../core/locale';
import { findGeometry, flow, transformLabel, deepAssign } from '../../utils';
import { Y_FIELD, ABSOLUTE_FIELD, DIFF_FIELD, IS_TOTAL } from './constant';
import { WaterfallOptions } from './types';
import { transformData } from './utils';
import './shape';
/**
* 处理默认配置项
* @param params
* @returns
*/
function defaultOptions(params: Params<WaterfallOptions>): Params<WaterfallOptions> {
const { locale, total } = params.options;
const localeTotalLabel = getLocale(locale).get(['waterfall', 'total']);
if (total && typeof total.label !== 'string' && localeTotalLabel) {
// @ts-ignore
params.options.total.label = localeTotalLabel;
}
return params;
}
/**
* 字段
* @param params
*/
function geometry(params: Params<WaterfallOptions>): Params<WaterfallOptions> {
const { chart, options } = params;
const { data, xField, yField, total, leaderLine, columnWidthRatio, waterfallStyle, risingFill, fallingFill, color } =
options;
// 数据处理
chart.data(transformData(data, xField, yField, total));
// 瀑布图自带的 colorMapping
const colorMapping =
color ||
function (datum: Datum) {
if (get(datum, [IS_TOTAL])) {
return get(total, ['style', 'fill'], '');
}
return get(datum, [Y_FIELD, 1]) - get(datum, [Y_FIELD, 0]) > 0 ? risingFill : fallingFill;
};
const p = deepAssign({}, params, {
options: {
xField: xField,
yField: Y_FIELD,
seriesField: xField,
rawFields: [yField, DIFF_FIELD, IS_TOTAL, Y_FIELD],
widthRatio: columnWidthRatio,
interval: {
style: waterfallStyle,
shape: 'waterfall',
color: colorMapping,
},
},
});
const { ext } = interval(p);
const geometry = ext.geometry as Geometry;
// 将 waterfall leaderLineCfg 传入到自定义 shape 中
geometry.customInfo({ leaderLine });
return params;
}
/**
* meta 配置
* @param params
*/
function meta(params: Params<WaterfallOptions>): Params<WaterfallOptions> {
const { options } = params;
const { xAxis, yAxis, xField, yField, meta } = options;
const Y_FIELD_META = deepAssign({}, { alias: yField }, get(meta, yField));
return flow(
scale(
{
[xField]: xAxis,
[yField]: yAxis,
[Y_FIELD]: yAxis,
},
deepAssign({}, meta, { [Y_FIELD]: Y_FIELD_META, [DIFF_FIELD]: Y_FIELD_META, [ABSOLUTE_FIELD]: Y_FIELD_META })
)
)(params);
}
/**
* axis 配置
* @param params
*/
function axis(params: Params<WaterfallOptions>): Params<WaterfallOptions> {
const { chart, options } = params;
const { xAxis, yAxis, xField, yField } = options;
// 为 false 则是不显示轴
if (xAxis === false) {
chart.axis(xField, false);
} else {
chart.axis(xField, xAxis);
}
if (yAxis === false) {
chart.axis(yField, false);
chart.axis(Y_FIELD, false);
} else {
chart.axis(yField, yAxis);
chart.axis(Y_FIELD, yAxis);
}
return params;
}
/**
* legend 配置 todo 添加 hover 交互
* @param params
*/
function legend(params: Params<WaterfallOptions>): Params<WaterfallOptions> {
const { chart, options } = params;
const { legend, total, risingFill, fallingFill, locale } = options;
const i18n = getLocale(locale);
if (legend === false) {
chart.legend(false);
} else {
const items = [
{
name: i18n.get(['general', 'increase']),
value: 'increase',
marker: { symbol: 'square', style: { r: 5, fill: risingFill } },
},
{
name: i18n.get(['general', 'decrease']),
value: 'decrease',
marker: { symbol: 'square', style: { r: 5, fill: fallingFill } },
},
];
if (total) {
items.push({
name: total.label || '',
value: 'total',
marker: {
symbol: 'square',
style: deepAssign({}, { r: 5 }, get(total, 'style')),
},
});
}
chart.legend(
deepAssign(
{},
{
custom: true,
position: 'top',
items,
},
legend
)
);
chart.removeInteraction('legend-filter');
}
return params;
}
/**
* 数据标签
* @param params
*/
function label(params: Params<WaterfallOptions>): Params<WaterfallOptions> {
const { chart, options } = params;
const { label, labelMode, xField } = options;
const geometry = findGeometry(chart, 'interval');
if (!label) {
geometry.label(false);
} else {
const { callback, ...cfg } = label;
geometry.label({
fields: labelMode === 'absolute' ? [ABSOLUTE_FIELD, xField] : [DIFF_FIELD, xField],
callback,
cfg: transformLabel(cfg),
});
}
return params;
}
/**
* tooltip 配置
* @param params
*/
export function tooltip(params: Params<WaterfallOptions>): Params<WaterfallOptions> {
const { chart, options } = params;
const { tooltip, xField, yField } = options;
if (tooltip !== false) {
chart.tooltip({
showCrosshairs: false,
showMarkers: false,
shared: true,
// tooltip 默认展示 y 字段值
fields: [yField],
...tooltip,
});
// 瀑布图默认以 yField 作为 tooltip 内容
const geometry = chart.geometries[0];
tooltip?.formatter ? geometry.tooltip(`${xField}*${yField}`, tooltip.formatter) : geometry.tooltip(yField);
} else {
chart.tooltip(false);
}
return params;
}
/**
* 瀑布图适配器
* @param params
*/
export function adaptor(params: Params<WaterfallOptions>) {
return flow(
defaultOptions,
theme,
geometry,
meta,
axis,
legend,
tooltip,
label,
state,
interaction,
animation,
annotation()
)(params);
}