横坐标固定8个,哪怕数据只有一个,但是鼠标悬浮时,没有数据的横坐标应该也没有tootip
实现思路:
没有数据的横坐标对应的值置为0=====》产品不同意=====》 没有数据的横坐标对应的值置为null====》解决问题
方法:
没有数据的横坐标对应值设置为null
null在自定义tooltip时,模板无法过滤掉null值
实现思路:
能否找带有参数的自定义tooltip模板
方法:官网刚刚出了一个插件bx-tooltip
1、ticks(<Chart scale/>)
scale type的值为linear和cat是不一样的,当值为linear时,横坐标如果设置ticks时,会按照预期展示,但是如果是cat,则ticks最终的值只能是数据里面有的值,且顺序和数据中出现的顺序一致
2、显示横坐标,但是不显示tooltip
在不需要自定义tootip(提供模板)情况下,如果希望横坐标出现,但是在tooltip中不要出现,可将对应的值置为null
3、完全自定义tootip(一个表格,多种不同的tootip)
使用bx-tooltip插件实现完全自定义
ts:代码
import React from 'react';
import { Chart, Geom, Axis, Tooltip, Legend, G2 } from 'bizcharts';
import DataSet from '@antv/data-set';
// @ts-ignore
import useCustTooltip from 'bx-tooltip';
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
import Slider from 'bizcharts-plugin-slider';
import styles from './GroupedBoxChart.less';
interface IGropuedBoxChartProps {
height?: number;
data: any[];
xAxis: string; // x轴坐标
// yAxis: string; // y轴坐标
boxValue: string; // 代表值的字段
xNickName?: string;
yNickName?: string;
xUnitName?: string;
yUnitName?: string;
legendName: string; // 图例名称
xUnitPosition?: string[];
yUnitPosition?: string[];
colors?: string[];
sliderMaxShowNum?: number;
}
/**
* 分组箱形图
* @param props
* @constructor
*/
const GropuedBoxChart: React.FC<IGropuedBoxChartProps> = props => {
const {
height = 400,
data = [],
xAxis,
xNickName,
yNickName,
legendName = [],
boxValue = '',
colors,
sliderMaxShowNum = 8,
} = props;
const xAxisData = [...new Set(data.map((item: any) => item[xAxis]))];
let ds: any;
let dv: any;
if (xAxisData && xAxisData.length > sliderMaxShowNum) {
const startLength = 0;
const endLength = sliderMaxShowNum - 1;
ds = new DataSet({
state: {
start: xAxisData[startLength],
end: xAxisData[endLength],
},
});
dv = ds.createView(`${xAxis}`).source(data);
dv.transform({
type: 'filter',
// eslint-disable-next-line consistent-return
callback: (obj: any): void => filterSilderData(obj, data),
});
} else {
ds = new DataSet({
state: {
start: '',
end: '',
},
});
dv = ds.createView(`${xAxis}`);
dv.source(data);
}
// eslint-disable-next-line consistent-return
function filterSilderData(obj: any, sliderData: any[]) {
if (xAxisData.length > sliderMaxShowNum) {
// 获取开始节点的下标值
const { start } = ds.state;
const startIndex = sliderData.findIndex((value: any) => value[xAxis] === start);
// 获取末尾节点下标值
const { end } = ds.state;
const endIndex = sliderData.findIndex((value: any) => value[xAxis] === end);
if (startIndex > -1 && endIndex > -1) {
const filterData = sliderData.slice(startIndex, endIndex + 1);
const filterIndex = filterData.findIndex((value: any) => value[xAxis] === obj[xAxis]);
if (filterIndex > -1) {
return obj;
}
}
} else {
return obj;
}
}
const cols: {
[key: string]: { [key: string]: string | number | string[] | number[] | any };
} = {};
cols[xAxis] = {
alias: xNickName || '',
};
cols[boxValue] = {
alias: yNickName || '',
max: 5, // GPA最大值为5
// maxLimit: 5,
};
function onSlideChange(obj: { startText: any; endText: any }) {
const { startText, endText } = obj;
ds.setState('start', startText);
ds.setState('end', endText);
}
function getCurrentColor(key: string): string {
// 获取所有的图例信息
const lend: string[] = [];
data.forEach((item: any) => {
lend.push(item[`${legendName}`]);
});
const lendData = [...new Set(lend)];
const resultMap = [];
let result: string = '';
if (colors && colors.length > 0) {
// 传入颜色
for (let i = 0; i < colors.length && i < lendData.length; i += 1) {
const obj: any = {};
obj[`${lendData[i]}`] = colors[i % 8];
resultMap.push(obj);
}
} else {
// 未传入颜色
for (let i = 0; i < lendData.length; i += 1) {
const obj = {};
obj[`${lendData[i]}`] = G2.Global.colors[i];
resultMap.push(obj);
}
}
if (resultMap && resultMap.length > 0) {
const rr = resultMap.filter((item: any) => item[`${key}`]);
if (rr && rr.length > 0) {
result = rr[0][`${key}`];
}
}
return result;
}
const [BxChart, CustTooltip] = useCustTooltip(Chart, Tooltip);
return (
<>
<BxChart
height={height}
data={dv}
padding="auto"
forceFit
scale={cols}
className={styles.groupBoxChart}
>
<Axis
name={xAxis}
label={{
textStyle: {
fill: '#FFFFFF', // 文本的颜色
},
}}
title={{
offset: 20,
textStyle: {
textAlign: 'right',
fill: '#FFF',
},
position: 'end',
}}
/>
<Axis
name={boxValue}
label={{
textStyle: {
fill: '#FFFFFF', // 文本的颜色
},
}}
title={{
offset: 40,
textStyle: {
textAlign: 'right',
fill: '#FFF',
},
position: 'end',
}}
/>
<CustTooltip enterable triggerOn="mousemove">
{(title: string, items: any[]) => {
let isShow = true; // 是否显示tooltip
const realItem = items.filter(item => item.name !== undefined);
if (!(realItem && realItem.length > 0)) {
isShow = false;
}
if (isShow) {
return (
<div className={styles.custTooltip}>
<span className={styles.title}>{title}</span> <br />
<div className={styles.content}>
<div className={styles.itemTitle}>
<div>最高分:</div>
<div>上四位分:</div>
<div>平均分:</div>
<div>下四位分:</div>
<div>最低分:</div>
</div>
<div className={styles.items}>
{items.map((it: any) => {
const { name, low, q1, median, q3, high } = it;
if (name) {
return (
<div className={styles.item}>
<span className={styles.name}>{name}</span>
<span>{high}</span>
<span>{q3}</span>
<span>{median}</span>
<span>{q1}</span>
<span>{low}</span>
</div>
);
}
return null;
})}
</div>
</div>
</div>
);
}
return null;
}}
</CustTooltip>
<Legend
position="top-right"
textStyle={{
textAlign: 'start', // 文本对齐方向,可取值为: start middle end
fill: '#FFF', // 文本的颜色
}}
/>
<Geom
type="schema"
position={`${xAxis}*${boxValue}`}
shape="box"
color={[`${legendName}`, val => getCurrentColor(val)]}
size={[...new Set(data.map(item => item[xAxis]))].length < 8 ? 38 : undefined}
style={[
`${legendName}`,
{
stroke: 'rgba(0, 0, 0, 0.45)',
fill: (val: any) => getCurrentColor(val),
fillOpacity: 0.8,
},
]}
adjust="dodge"
tooltip={
[
`${xAxis}*${legendName}*${boxValue}`,
(x: string, legend: string, values: string[]) => {
if (
!(
values[0] === null &&
values[1] === null &&
values[2] === null &&
values[3] === null &&
values[4] === null
)
) {
return {
name: `${legend}`,
low: `${values[0]}分`,
q1: `${values[1]}分`,
median: `${values[2]}分`,
q3: `${values[3]}分`,
high: `${values[4]}分`,
};
}
return null;
},
] as any
}
/>
</BxChart>
{xAxisData.length > sliderMaxShowNum && (
<Slider
height={20}
width="auto"
xAxis={xAxis}
yAxis={boxValue}
data={data}
onChange={onSlideChange}
start={ds.state.start}
end={ds.state.end}
textStyle={{
fontSize: '0',
}}
backgroundChart={{
type: 'heatmap',
}}
/>
)}
</>
);
};
export default GropuedBoxChart;
less文件:
.groupBoxChart {
:global {
.bx-tooltip {
padding: 0;
}
}
.custTooltip {
padding: 10px;
.title {
color: #242424;
font-size: 14px;
}
.content {
display: flex;
flex-direction: row;
}
.itemTitle {
margin-top: 28px;
}
.items {
display: flex;
flex-direction: row;
.item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 8px;
.name {
color: #242424;
font-size: 14px;
}
}
}
}
}
四、资源地址:
1、npm 路径:https://www.npmjs.com/package/bx-tooltip
2、在线demo:https://codesandbox.io/s/stoic-lovelace-hv5z2?file=/src/App.js:488-493