Job/React
[React] 도넛 프로그레스 animation 적용 (style-component, transition)
웃던날
2023. 6. 23. 17:10
1. 구현목적
구현을 하게된 계기는 도넛 progress를 만들어야하는데, 라이브러리는 사용하고싶지 않았고, 내가 직접 한번 만들어보고 싶었다. 그것도 컴포넌트로 말이다!
사용한 라이브러리는 style-component밖에 없다.
혹시나 스타일 컴포넌트에서 props를 사용못하는 사람들은 document 한번 읽고오길 권장한다...
2. 구현 코드
import { styled } from "styled-components";
import { CustomFlex } from "../theme/style";
interface DonutBackType {
width : number,
height : number,
frontColor : string,
backColor : string,
donutper : number,
}
interface DonutFrontType {
width : number,
height : number,
}
//도넛 뒷배경
export const DonutBack = styled.div<DonutBackType>`
display:'flex';
justify-content:'center';
align-items:'center';
width: ${({width}) => width+'rem'};
height: ${({height}) => height+'rem'};
margin: 0 auto;
border-radius: 50%;
position: relative;
text-align: center;
@property --tranDonutPer{
syntax: '<percentage>'; /* its type */
inherits: false;
initial-value: ${({donutper}) => `${donutper}%`}; /* the initial value */
}
transition:--tranDonutPer 0.5s;
background : ${({frontColor,backColor,donutper}) => `conic-gradient(${frontColor} 0% var(--tranDonutPer), ${backColor} var(--tranDonutPer) 100%)`};
`
//도넛 앞배경 (텍스트 들어가면서, 도넛모양을 잡아줌)
export const DonutFront = styled(CustomFlex)<DonutFrontType>`
display:'flex';
justify-content:'center';
align-items:'center';
position:absolute;
width:${({width}) => width+'rem'};
height:${({height}) => height+'rem'};
border-radius: 50%;
top:50%;
left:50%;
transform: translate(-50%,-50%);
background-color:white;
`
도넛이 채워지는 색상은 frontColor, 채워지지 않은 색상은 backColor로 설정해주었다.
배경은 따로 라이브러리를 사용하지않고, conic-gradient를 사용해주었다. 도넛 프로그레스에는 최적의 스타일이라고 생각했다.
자세하게 봐야할 내용은 DonutBack 컴포넌트인데, 여기서 transition을 @property 변수로 적용했다.
conic-gradient는 transition에 변화가 감지가 되지 않는다는 얘기를 들었고, 역시 했을때 제대로 감지되지 않았다.
그런데 @property 변수는 transition으로 감지가 가능하다고 한다.
여기서 @property에 들어가는 속성들은 다음과 같다.
- syntax : 변수의 유형을 정의한다. 여기서는 percentage를 선언하였으며, 퍼센트 단위를 사용한다고 선언한것이다.
- inherits : css Custom Property가 상속되는지 여부를 나타낸다. 해당 코드에서는 false로 설정되어있으므로, tranDonutPer은 상속되지 않는다.
- initial-value : css customProperty의 초기값을 나타낸다. 해당코드에서는 props로 가져온 percent값을 기본값으로 설정하였다.
자 그러면 컴포넌트에서는 어떻게 사용하는지 살펴보자.
import React from 'react';
import { DonutBack, DonutFront } from './ComponentStyle';
import { CustomSpanText } from '../theme/style';
export const DonutGraph = () => {
const [donutPer , setDonutPer] = React.useState(0);
return(
<>
<DonutBack
width={9}
height={9}
frontColor={'#FFC888'}
backColor={'#DBDFE8'}
donutper={donutPer}
>
<DonutFront
width={7}
height={7}
>
<CustomSpanText>{donutPer}%</CustomSpanText>
</DonutFront>
</DonutBack>
<button onClick={()=>{
if(donutPer < 100){
setDonutPer(donutPer+10);
}
}}>
<p>올리기</p>
</button>
</>
)
}
출력 코드는 별로 어려울게 없다.
그냥 컴포넌트만 불러와서 색상 및 donutPer값만 넣어주면된다.