const UsageAndBill = ({ tabButtonKey }) => {
const [usageStatus, setUsageStatus] = useState([]);
useEffect(() => {
axios.get('/data/SmartView/usageAndBill.json')
.then((res) => {
const dataTemp = res.data[tabButtonKey].map((data) => {
return {
xAxis: data.MR_HHMI,
usage: data.F_AP_QT,
usageLast: data.LYEAR_F_AP_QT,
bill: data.KWH_BILL,
};
});
setUsageStatus([{}, ...dataTemp, {}]);
});
}, [tabButtonKey]);
return (
<ResponsiveContainer>
<ComposedChart
width={600}
height={400}
data={usageStatus}
margin={{ top: 40, right: 40, bottom: 30, left: 40 }}
>
<CartesianGrid stroke="#f5f5f5" />
<XAxis dataKey="xAxis" />
<YAxis yAxisId="left" />
<YAxis yAxisId="right" orientation="right" />
<Tooltip />
<Legend />
<Bar yAxisId="left" dataKey="bill" barSize={30} fill="#7ac4c0" />
<Line yAxisId="right" type="monotone" dataKey="usage" stroke="#ff7300" />
<Line yAxisId="right" type="monotone" dataKey="usageLast" stroke="#8884d8" />
</ComposedChart>
</ResponsiveContainer>
);
};
한눈에도 아쉬운 점이 눈에 보인다. 먼저 왼쪽, 오른쪽의 y축 단위가 명시돼 있지 않고, 분류별 x축 단위 또한 제대로 나와 있지 않고 백엔드에서 보내 주는 데이터 형식 그대로 되어 있다. 또 x축 마진을 주는 방법을 제대로 찾아보지 않고, 데이터의 앞뒤에 setUsageStatus([{}, ...dataTemp, {}])
이렇게 빈 객체를 넣어서 야매로 구성했기 때문에, 엄밀히 말해 정확한 차트가 아니었다. 또 가격 천단위 콤마가 없는 것도 신경쓰이고, 범례도 날것 그대로의 키값으로 되어 있다.
이제 이것을 차례로 모두 커스텀해 볼 것이다.
<YAxis
yAxisId="left"
label={{ value: '원', offset: 30, angle: 0, position: 'top' }}
/>
<YAxis
yAxisId="right"
label={{ value: 'kWh', offset: 30, angle: 0, position: 'top' }}
/>
label
속성값으로 객체를 넣어 주면 된다. yAxisId
는 왼쪽, 오른쪽 y축 단위라는 뜻인데 해당하는 축의 value
에 원하는 단위를 넣어주고, 위치와 각도를 조절해준다. 옆으로 누운 형태로 만들고 싶다면 angle
에 -90 또는 90 값을 준다.
const formatXAxis = (tickItem) => {
if (tickItem && tabButtonKey === "hourlyUsage") return `${tickItem.slice(0,2)}시`
else if (tickItem && tabButtonKey === "monthlyUsage") return `${tickItem}월`
else if (tickItem && tabButtonKey === "yearlyUsage") return `${tickItem}년`
else return tickItem
};
const formatYAxis = (tickItem) => tickItem.toLocaleString();
const formatTooltip = (tickItem) => tickItem.toLocaleString();
formatXAxis
, formatXAxis
, formatTooltip
이라는 함수를 만들어준다. tickItem
이라는 인자를 받아, 그 값으로 포맷팅을 한 상태로 리턴하는 함수다. 나는 차트 위에 있는 탭버튼의 값에 따라서 눈금 단위가 달라지기 때문에 if문으로 구분하여 각각 다른 값을 리턴하도록 했다.
<XAxis
dataKey="xAxis"
tickFormatter={formatXAxis}
/>
<Tooltip
formatter={formatTooltip}
labelFormatter={formatXAxis}
/>
XAxis
의 props로 formatXAxis
함수를 넣어주면 포맷팅이 완료된다.
<XAxis
dataKey="xAxis"
padding={tabButtonKey === "yearlyUsage" ? { left: 450, right: 450 } : { left: 40, right: 40 }}
tickFormatter={formatXAxis}
/>
XAxis
컴포넌트에 padding
속성값을 설정한다. 내 경우 년도별 버튼을 눌렀을 때와 아닐 때의 padding
값을 다르게 설정하고 싶었기 때문에 삼항연산자를 사용해서 설정해주었다.
useEffect(() => {
axios.get('/data/SmartView/usageAndBill.json')
.then((res) => {
const dataTemp = res.data[tabButtonKey].map((data) => {
return {
xAxis: data.MR_HHMI,
'사용량(kWh)': data.F_AP_QT,
'전년 사용량(kWh)': data.LYEAR_F_AP_QT,
'요금(원)': data.KWH_BILL,
};
});
setUsageStatus(dataTemp);
});
}, [tabButtonKey]);
useEffect
에서 데이터를 state에 담아 올 때 객체의 key값을 내가 설정하고 싶은 범례 값으로 바꾸었다. 나중에 Bar
, Line
등의 컴포넌트에 dataKey
props를 설정해줄 때 자동으로 적용된다.
그 외 세세한 부분을 추가로 커스텀해서 완성해봤다.
const UsageAndBill = ({ tabButtonKey }) => {
const classes = useStyles();
const [usageStatus, setUsageStatus] = useState([]);
useEffect(() => {
axios.get('/data/SmartView/usageAndBill.json')
.then((res) => {
const dataTemp = res.data[tabButtonKey].map((data) => {
return {
xAxis: data.MR_HHMI,
'사용량(kWh)': data.F_AP_QT,
'전년 사용량(kWh)': data.LYEAR_F_AP_QT,
'요금(원)': data.KWH_BILL,
};
});
setUsageStatus(dataTemp);
});
}, [tabButtonKey]);
const formatXAxis = (tickItem) => {
if (tickItem && tabButtonKey === "hourlyUsage") return `${tickItem.slice(0,2)}시`
else if (tickItem && tabButtonKey === "monthlyUsage") return `${tickItem}월`
else if (tickItem && tabButtonKey === "yearlyUsage") return `${tickItem}년`
else return tickItem
};
const formatYAxis = (tickItem) => tickItem.toLocaleString();
const formatTooltip = (tickItem) => tickItem.toLocaleString();
return (
<ResponsiveContainer className={classes.chartRoot}>
<ComposedChart
data={usageStatus}
margin={{ top: 80, right: 40, bottom: 30, left: 40 }}
>
<CartesianGrid stroke="#f5f5f5" />
<XAxis
dataKey="xAxis"
padding={tabButtonKey === "yearlyUsage" ? { left: 450, right: 450 } : { left: 40, right: 40 }}
tickFormatter={formatXAxis}
/>
<YAxis
type="number"
yAxisId="left"
label={{ value: '원', offset: 30, angle: 0, position: 'top' }}
tickFormatter={formatYAxis}
/>
<YAxis
yAxisId="right"
orientation="right"
label={{ value: 'kWh', offset: 30, angle: 0, position: 'top' }}
tickFormatter={formatYAxis}
/>
<Tooltip
cursor={{ strokeDasharray: '3 3' }}
formatter={formatTooltip}
labelFormatter={formatXAxis}
/>
<Legend />
<Bar
yAxisId="left"
dataKey="요금(원)"
barSize={tabButtonKey === "yearlyUsage" ? 150 : 30}
fill="#7ac4c0"
/>
<Line
yAxisId="right"
type="monotone"
dataKey="사용량(kWh)"
stroke="#fcac8d"
strokeWidth="2"
animationDuration="400"
/>
<Line
yAxisId="right"
type="monotone"
dataKey="전년 사용량(kWh)"
stroke="#8fa3d1"
hide={tabButtonKey === "yearlyUsage" && true}
strokeWidth="2"
animationDuration="500"
/>
</ComposedChart>
</ResponsiveContainer>
);
};
커스텀 설정 설명이 그렇게 친절하지는 않지만 매우 다양하고 섬세한 편이다. 만족!