in src/Wbar/index.tsx [142:579]
init(chart: Chart, config: WbarConfig, data: any) {
// 设置数据度量
const defs: Record<string, Types.ScaleOption> = {
x: propertyAssign(
propertyMap.axis,
{
// type: 'cat',
mask: 'auto',
tickCount: null
},
config.xAxis,
),
y: propertyAssign(
propertyMap.axis,
{
nice: true,
type: 'linear',
tickCount: 5,
sync: 'y'
},
config.yAxis,
),
type: {
type: 'cat',
sync: true,
},
facet: {
sync: true,
},
sum: {
nice: true,
sync: 'y'
},
percent: propertyAssign(
propertyMap.axis,
{
nice: true,
type: 'linear',
tickCount: 5,
},
config.yAxis,
),
};
if (Array.isArray(config.yAxis)) {
config.yAxis.forEach((axis, yIndex) => {
defs[`y${yIndex}`] = propertyAssign(
propertyMap.axis,
{
nice: true,
type: 'linear',
tickCount: 5,
},
axis,
);
});
} else {
defs.y = propertyAssign(
propertyMap.axis,
{
nice: true,
type: 'linear',
tickCount: 5,
},
config.yAxis,
);
}
autoTimeScale(defs, this.rawData, this.language || this.context.language);
chart.scale(defs);
const dataView = computerData(config, data);
this.barDataView = dataView;
if (config.percentage) {
chart.data(dataView.rows);
} else {
if (config.showStackSum) {
data.map((el: any) => {
const filterData = dataView.rows.filter((row: any) => el.x === row.x && el.type === row.type);
if (filterData.length > 0) {
el.sum = filterData[0].sum;
}
});
}
// 排行图
if (typeof config?.column === 'object' && (config?.column?.top || config?.column?.showRanking)) {
data?.sort((a: any, b: any) => {
if (a.sum !== undefined && b.sum !== undefined) {
return config?.column?.rankConfig?.type === 'asc' ? (b?.sum ?? 0) - (a?.sum ?? 0) : (a?.sum ?? 0) - (b?.sum ?? 0);
}
});
const sortList = data?.filter((el: any) => el.sum).slice(-config?.column?.top);
const xList = sortList.map((el: any) => el.x);
data = data?.map(((el: any) => {
return xList.includes(el.x) ? el : false;
}))
}
chart.data(data);
}
chart.axis('sum', false);
if (Array.isArray(config.yAxis)) {
config.yAxis.forEach((axis, yIndex) => {
const yAxisConfig: Types.AxisCfg = {
line: {
style: {
stroke: themes['widgets-axis-line'],
},
},
};
if (yIndex !== 0) {
yAxisConfig.grid = null;
}
if (!config.facet || !config?.percentage) {
console.warn('分面facet或百分比堆叠模式下,暂不支持多轴');
rectYAxis(this, chart, { ...config, yAxis: axis }, `y${yIndex}`, yAxisConfig);
} else {
rectYAxis(this, chart, config);
}
});
} else {
// 设置单个Y轴
if (!config.facet) {
if (config.percentage) {
rectYAxis(this, chart, config, 'percent');
} else {
rectYAxis(this, chart, config);
}
}
}
// 如果是横向柱图,且没有配置省略的话,关闭自动省略
if(config?.column === false && !config?.xAxis?.hasOwnProperty('autoEllipsis') && config.xAxis ) {
config.xAxis.autoEllipsis = false;
}
// 设置X轴
rectXAxis(this, chart, config);
// 需要保证原始数据传入的时候按分组顺序传入
// 这个是分组的顺序
let dodgeGroups: string[] = [];
// 如果开启图例分组,先判定数据中有分组信息
let newItems: G2Dependents.ListItem[] = undefined;
// 如果开启图例折叠,列表型则分组图例不适配
if (config?.legend?.dodge && !config?.legend?.foldable && !config?.legend?.table) {
// 处理默认数据,按照分组顺序排列
newItems = [];
this.rawData?.forEach((subData: ChartData) => {
if (
(subData?.dodge || subData?.facet) &&
newItems?.filter((el) => (el.dodge || el.facet) === (subData?.dodge || subData?.facet))
?.length == 0
) {
dodgeGroups.push(subData?.dodge || subData?.facet);
}
});
this.rawData
?.sort(
(a: any, b: any) =>
dodgeGroups.indexOf(a?.dodge || a?.facet) - dodgeGroups.indexOf(b?.dodge || b?.facet),
)
.forEach((subData: ChartData, index: number) => {
// 当Items里没有分组名称的时候,添加一个name为分组名称的item
if (
(subData?.dodge || subData?.facet) &&
newItems?.filter((el) => (el.dodge || el.facet) === (subData?.dodge || subData?.facet))
?.length == 0
) {
newItems.push({
id: subData?.dodge || subData?.facet,
name: `${subData?.dodge || subData?.facet}: `,
dodge: subData?.dodge || subData?.facet,
value: subData?.dodge || subData?.facet,
marker: {
spacing: index !== 0 ? 24 : 0,
style: {
r: 0,
},
},
});
}
let rawColor;
// 函数暂时不做处理,和默认数组处理方式保持一致
if (typeof config?.colors === 'string') {
rawColor = config?.colors;
} else if (typeof config?.colors === 'object') {
rawColor = config?.colors?.[index];
} else if (typeof config?.colors === 'function') {
rawColor = themes.category_12[index];
}
newItems.push({
id: subData?.name,
name: subData?.name,
value: subData?.name,
marker: {
symbol: 'square',
spacing: 4,
style: {
r: 3,
fill: rawColor,
lineAppendWidth: 0,
fillOpacity: 1,
},
},
unchecked: false,
});
});
} else if (config?.legend?.items) {
// 自定义优先级高于内置配置
newItems = config.legend.items;
}
// 设置图例
rectLegend(
this,
chart,
config,
{
items: newItems,
},
'multiple',
'type',
);
legendFilter(this, chart);
// tooltip
rectTooltip(this, chart, config, {}, null, {
showCrosshairs: false,
showMarkers: false,
});
// 设置坐标系:极坐标/直角坐标
const chartCoord = config.polar
? chart.coordinate('polar', {
innerRadius: config.innerRadius || 0,
})
: chart.coordinate();
// 横向柱状图
if (!config.column || typeof config.column === 'object') {
const columnConfig = typeof config.column === 'object' ? config.column : {};
chartCoord.transpose();
// 横向镜像
if (columnConfig.reflect) {
chartCoord.reflect('x');
}
}
// // 玉玦图,需要手动添加 数据标记
// if (config.polar && !config.column && config.dataType !== 'g2') {
// this.rawData[0].data.forEach((d: any, i: number) => {
// let x = d.x;
// if (Array.isArray(d)) {
// x = d[0];
// } else if (
// config.xAxis &&
// config.xAxis.categories &&
// config.xAxis.categories[i]
// ) {
// x = config.xAxis.categories[i];
// // const y = isNaN(d) ? d[0] : d;
// }
//
// chart.annotation().text({
// position: [x, 0],
// // content: `${x}`,
// style: {
// fill: themes['widgets-axis-label'],
// textAlign: 'start',
// },
// });
// });
// }
if (config.facet) {
const facetConfig = typeof config.facet === 'object' ? config.facet : {};
const facetTitleConfig = merge(
{
offsetX: pxToNumber(themes['widgets-font-size-1']),
// 底层使用 view.annotation().text 绘制,可以使用 rotate 进行翻转
rotate: config.column ? Math.PI / 2 : undefined,
style: {
fontSize: pxToNumber(themes['widgets-font-size-1']),
textAlign: 'center',
fill: themes['widgets-axis-label'],
},
},
facetConfig.title || {},
);
const self = this;
chart.facet(facetConfig.type || 'mirror', {
fields: ['facet'],
transpose: facetConfig.transpose || !config.column,
padding: facetConfig.padding,
spacing: facetConfig.spacing || (config.column ? [0, 18] : [32, 0]),
showTitle: typeof facetConfig.showTitle === 'boolean' ? facetConfig.showTitle : true,
title: facetTitleConfig,
eachView: function (view: any, facet: any) {
let yAxisCustomConfig: Types.AxisCfg = null;
// 为 labelFormatter 的第二个参数添加分面信息
if (config.yAxis && config.yAxis.visible !== false) {
const { labelFormatter } = config.yAxis || {};
if (labelFormatter) {
yAxisCustomConfig = {
label: {
formatter: (text, item, index) => {
return labelFormatter(
text,
{
facet: facet.colValue || facet.rowValue,
...item,
},
index,
);
},
},
};
}
}
rectYAxis(self, view, config, 'y', yAxisCustomConfig);
// 绘制辅助线,辅助背景区域
guide(view, config);
// Tooltip 背景区域
activeRegionWithTheme(view);
drawBar(view, config, config.colors, facet);
},
});
} else {
// 绘制辅助线,辅助背景区域
guide(chart, config);
if (!config.polar) {
// Tooltip 背景区域
activeRegionWithTheme(chart);
}
if (Array.isArray(config.yAxis)) {
config.yAxis.forEach((axis, yIndex) => {
drawBar(chart, config, config.colors, config.facet, `y${yIndex}`);
});
} else {
drawBar(chart, config, config.colors);
}
}
rectZoom(
chart,
config,
getText('reset', this.language || this.context.language, this.context.locale),
);
// 缩略轴
rectSlider(chart, config);
// 滚动条
rectScrollbar(chart, config);
// 判断是否要加padding
// 当开启label、label在柱子上方、legend不在上方,且存在某根柱子数值与y轴最大值接近时需要加padding
// 极坐标柱状图不考虑,分面自己加padding,此处不处理
chart.on('beforepaint', () => {
// y轴刻度最大值
const axisMax = chart?.geometries?.[0]?.scales?.y?.max;
// y轴高度
const height = chart?.coordinateBBox?.height;
// 是否显示label,且label在top
const showLabel =
config?.label === true ||
(typeof config?.label === 'object' &&
config?.label?.visible !== false &&
(config?.label?.position === undefined || config?.label?.position === 'top'));
// 是否隐藏legend,或legend不在top
const hideLegend =
config?.legend === false ||
(typeof config?.legend === 'object' &&
(config?.legend?.visible === false ||
(config?.legend?.position && config?.legend?.position !== 'top')));
if (!config?.appendPadding && showLabel && hideLegend && !config?.polar && !config?.facet) {
let addPadding = false;
// 横向柱图默认加padding
if (config?.column === false || typeof config?.column === 'object') {
addPadding = true;
} else if ((config?.dodgeStack || config?.stack) && config?.percentage) {
// 百分比堆叠默认加padding
addPadding = true;
} else {
const valueMap: Record<string, number> = {};
(data || []).forEach((d: any) => {
const xValue = `${d.x}-${config?.stack ? '' : d.dodge || d.type}`;
if (!(xValue in valueMap)) {
valueMap[xValue] = 0;
}
// 区间柱状图
if (Array.isArray(d.y)) {
valueMap[xValue] += d.y?.[1] || 0;
} else {
// 堆叠、分组堆叠、普通柱图
valueMap[xValue] += d.y;
}
});
const maxY = Math.max(...Object.values(valueMap));
// 判断最高的柱子距离顶部的间距是否过小
const dis = (1 - maxY / axisMax) * height;
if (dis < 20) {
addPadding = true;
}
}
if (addPadding) {
chart.appendPadding = [20, 0, 0, 0];
} else {
chart.appendPadding = undefined;
}
}
});
}