💡 원인
→ ApexCharts는 차트라이브러리이다.
→ 원하는 디자인대로 커스텀하기 생각보다 어렵다.
🗡 해결
→ 하지만 못할 것은 없다, 나에겐 무적 CSS가 있다.
→ 원하는 위치, 원하는 내용을 넣엔 CSS position: relative; position: absolute;가 있다.
→ 차트의 기본 기능만 사용하고 나머지는 CSS를 이용해서 열심히 커스텀해보자!
ApexCharts 공식 홈페이지
ApexCharts.js - Open Source JavaScript Charts for your website
bar차트에 대한 기본 옵션 공식 문서
수많은 codepen 예제 모음
목표는 디자이너님에게 최대한 맞드는 것이다.
하지만 일반 기능으로는 원하는 디자인으로 만들기 불가능한것 같다.
이것이 디자이너 님께서 만들어준 Top 10 차트이다.
1차로 기본으로 만들 수 있는건 여기까지였다.
커스텀에 커스텀을 해보자.
사이즈 변경에 답이 없다.
계속 hight가 동적으로 늘어나고 줄어드는 문제가 있었다.
ApexCharts가 각 Bar에 대해서 %로만 나오기 때문에 높이가 변하면 각 바의 간격이 계속 변경된다.
→ 세로 높이를 고정할수 밖에 없었다.
글도 왼쪽에 나오는게 아니라 내부에 넣고싶다…
내부에 넣을 수 있는 기본 옵션같은건 없다.
→ position: relative; position: absolute;를 이용해서 표와 글자가 따로 가는 방법밖에 생각할 수 없었다.
완성… 이정도면…성공적이지 않을까…?
조금 더 만져봐야하지만…얼추 비슷하다.
전체코드
import styled from "styled-components";
import ApexCharts from "react-apexcharts";
import { useState, useEffect } from "react";
import axios from "axios";
import BestGoodIcon from "../../../assets/images/main_bset_bl_24.svg";
function setChartOption(threeData) {
const ChartOptions = {
options: {
chart: {
type: "bar",
stacked: true, //여러개의 값 한줄로 보여줌
toolbar: {
show: false, //상단 툴바 조정(필수)
},
},
plotOptions: {
bar: {
horizontal: true,
startingShape: "rounded",
endingShape: "rounded",
barHeight: "20", //바 하나의 너비(필수)
colors: {
backgroundBarColors: ["#E6F0FF"],
backgroundBarOpacity: 1,
backgroundBarRadius: 9,
},
},
},
title: {
text: "ㅤ",
offsetY: 10,
offsetX: 10,
style: {
fontFamily: "GangwonEduPower",
fontSize: "18px",
fontWeight: "400",
lineHeight: "26px",
color: "#222222",
},
},
//하단 삼대력 수치 표
xaxis: {
categories: threeData.map((item, rank) => ""), //세로축에 영향줌 필수
labels: {
formatter: function (val) {
return val + "KG";
},
style: {
fontFamily: "Pretendard",
fontStyle: "normal",
fontWeight: "400",
fontSize: "12px",
lineHeight: "20px",
textAlign: "right",
color: "#888888",
},
},
},
//왼쪽 y축
yaxis: {
title: {
text: undefined,
},
},
fill: {
opacity: 1,
colors: ["#0066FF", "#7AFFBF", "#00D1FF"],
},
legend: {
//상단 점수 색상별 종류 나열
position: "top",
offsetX: -80,
offsetY: 10,
fontFamily: "Pretendard",
fontStyle: "normal",
fontWeight: "400",
fontSize: "12px",
lineHeight: "20px",
markers: {
width: 20,
height: 10,
fillColors: ["#0066FF", "#7AFFBF", "#00D1FF"],
},
},
dataLabels: {
enabled: false, //바 내부에 값 숫자 표기
},
grid: {
yaxis: {
lines: {
show: false, //각 차트의 구분을 짖는 세로 실선
},
},
xaxis: {
lines: {
show: true, //각 차트의 구분을 짖는 가로 실선
},
},
},
},
};
return ChartOptions.options;
}
export default function HomeChart() {
const [threeData, setThreeData] = useState([]);
useEffect(() => {
axios.get(`/api`).then(({ data }) => {
setThreeData(data.data.users);
});
}, []);
if (!threeData) {
return <></>;
}
return (
<HomeChartBox>
<ApexCharts
options={setChartOption(threeData)}
series={[
{
name: "데드리프트",
data: threeData.map((item) => item.bigThreePower.dead),
},
{
name: "벤치프레스",
data: threeData.map((item) => item.bigThreePower.bench),
},
{
name: "스쿼트",
data: threeData.map((item) => item.bigThreePower.squat),
},
]}
width="100%"
height="100%"
type="bar"
/>
<TopTitleGroup>
<img src={BestGoodIcon} alt="3대력 측정 Top 10"></img>
<TopTitleText>3대력 top 10</TopTitleText>
</TopTitleGroup>
<InnerInfo>
{threeData.map((item, rank) => (
<InfoGroup key={rank}>
<TopRankLabel>{rank + 1}</TopRankLabel>
<TopNickLabel>
{item.userNickName.includes("_")
? item.userNickName.split("_")[1]
: item.userNickName}
</TopNickLabel>
<TopPowerLabel>{`${item.bigThreePower.dead} / ${item.bigThreePower.bench} / ${item.bigThreePower.squat}`}</TopPowerLabel>
</InfoGroup>
))}
</InnerInfo>
</HomeChartBox>
);
}
const HomeChartBox = styled.div`
position: relative;
width: 100%;
min-width: 350px;
height: 900px;
margin: 20px auto;
font-size: ${(props) => props.theme.fontSizeH1};
box-shadow: 1px 2px 16px rgba(0, 0, 0, 0.16);
border-radius: 8px;
@media screen and (max-width: 1440px) {
width: 900px;
}
@media screen and (max-width: 1024px) {
width: 556px;
}
@media screen and (max-width: 600px) {
width: 400px;
}
`;
const InnerInfo = styled.div`
position: absolute;
width: 250px;
top: 47px; //숫자가 클수록 바에 붙음, 라벨 위치 조정(차트 높이 변경시 마진으로 텍스트 info 위치 조정)
left: 37px;
display: flex;
flex-direction: column;
`;
const InfoGroup = styled.div`
display: flex;
align-items: center;
margin: 26.5px 0; //라벨 위치 조정(차트 높이 변경시 마진으로 텍스트 info 위치 조정)
`;
const TopRankLabel = styled.span`
font-size: 18px;
line-height: 26px;
text-align: center;
color: ${(props) => props.theme.reverseFontColor};
margin-right: 8px;
`;
const TopNickLabel = styled.span`
font-size: 16px;
line-height: 24px;
color: ${(props) => props.theme.reverseFontColor};
margin-right: 8px;
`;
const TopPowerLabel = styled.span`
font-size: 14px;
line-height: 22px;
color: #ff7a00;
margin-right: 8px;
`;
const TopTitleGroup = styled.span`
position: absolute;
left: 28px;
top: -4px;
`;
const TopTitleText = styled.span`
font-family: "GangwonEduPower";
font-style: normal;
font-weight: 400;
font-size: 18px;
line-height: 26px;
margin-left: 8px;
color: ${(props) => props.theme.reverseFontColor};
`;
'웹 개발 > React 프로젝트' 카테고리의 다른 글
[React] ApexCharts 커스텀(Donut, 도넛 그래프) (0) | 2022.09.10 |
---|---|
[React] useCallback을 사용해서 한번만 api 요청하게 하자 (1) | 2022.09.10 |
[React] 로그인, 로그아웃 에러핸들링 고민 (0) | 2022.09.10 |
[React] 비동기 데이터 axios Post 전송(Query String, Request body) (1) | 2022.09.10 |
[React] Warning Received true for non-boolean attribute 오류 해결 (0) | 2022.07.25 |