一、所謂前言
公司某個項目後期優化,分組區間柱狀圖改成分組箱形圖,因爲這兩天剛好用到箱形圖,就想着分組箱形圖與箱型圖之間應該和柱狀圖與分組柱狀圖一樣,想着,就去查找官網,結果,就4個橫座標、3個圖例,源數據居然有150條,3(圖例)、4(橫座標)、5(單個箱形圖數據)怎麼也湊不到150,好吧,瞬間放棄了,換個思路。
輸出了官網轉換後的數據,12個,這才符合我的認知嘛。可是每個卻又有4個字段,其中“value是什麼意思?不得而知了。琢磨半天,也沒想明白,於是在羣裏問,邊問邊自己不斷研究,試着自己將value字段去掉,發現並沒有什麼影響,好吧……是我想多了,正常思路就行,誰讓我一開始就慫了。
二、代碼
import React from 'react';
import { Chart, Geom, Axis, Tooltip, Legend, G2 } from 'bizcharts';
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[];
}
/**
* 分組箱形圖
* @param props
* @constructor
*/
const GropuedBoxChart: React.FC<IGropuedBoxChartProps> = props => {
const {
height = 400,
data = [],
xAxis,
xNickName,
yNickName,
legendName = [],
boxValue = '',
colors,
} = props;
const cols: {
[key: string]: { [key: string]: string | number | string[] | number[] | any };
} = {};
cols[xAxis] = {
alias: xNickName || '',
};
cols[boxValue] = {
alias: yNickName || '',
};
const toolTipItemTpl =
'<li data-index={index} style="margin-bottom:4px;">' +
'<span style="color:#242424;font-size:13px;">{name}</span><br />' +
'<span style="color:##999999;font-size:12px;">最高分:{high}分</span>, ' +
'<span>上四分位分:{q3}分</span>, ' +
'<span>平均分:{median}分</span>, ' +
'<span>下四分位分:{q1}分</span>, ' +
'<span>最低分:{low}分</span>' +
'</li>';
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];
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;
}
return (
<Chart height={height} data={data} padding="auto" forceFit scale={cols}>
<Axis
/>
<Tooltip
showTitle={false}
crosshairs={{
type: 'rect',
style: {
fill: '#E4E8F1',
fillOpacity: 0.43,
},
}}
itemTpl={toolTipItemTpl}
/>
<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)]}
style={[
`${legendName}`,
{
stroke: 'rgba(0, 0, 0, 0.45)',
fill: (val: any) => getCurrentColor(val),
fillOpacity: 0.3,
},
]}
adjust="dodge"
tooltip={
[
`${xAxis}*${legendName}*${boxValue}`,
(x: string, legend: string, values: string[]) => ({
name: `${legend}-${x}`,
low: values[0],
q1: values[1],
median: values[2],
q3: values[3],
high: values[4],
}),
] as any
}
/>
</Chart>
);
};
export default GropuedBoxChart;
三、小結
分組箱形圖的難點在於數據結構,於我而言,主要是被官網的源數據嚇到了,還有就是單個箱型圖掌握的不好。
箱型圖與其他圖標我覺得最大的不同在於color需要明確的設置出來,單個箱形圖好辦,寫死就行,而多個就比較麻煩了,需要根據數據自己處理下,而這裏又涉及到顏色使用自帶顏色還是自定義顏色的問題,代碼中均有考慮到。
箱型圖的tooltip也需要自定義,同樣的,單個的好處理,官網demo有,而多個的情況下,官網demo的tooltip給人的感覺就有些敷衍了。按照單個的思路,寫出了多個分組箱形圖的tooltip,發現如果超過三四個,就會太長,最終索性,一個箱型圖佔一行,勉強能看得過去了。
很多事情在自己認輸的那一刻就徹底輸了,後面再怎麼讓努力都是垂死掙扎了。消極的心理暗示真的是害死人。做人也是,敲代碼更是如此。