일을 하던 중에 두 모집군의 비율에 따라 크기가 변하는 외접하는 두 원의 코드를 짜달라는 요청을 받았다.
50:50 일때 0:100 일때처음에는 어려울 줄 알았지만 갑자기 아이디어 하나가 떠올라서 쉽게 구현할 수 있었다.
하나의 큰 원만 회전시키고, 그 내부의 원들은 큰 원의 지름상에 위치하여 서로의 크기만을 변화시키는 것이다.
비율에 따라 container div를 rotate시키면서 내부 원의 지름을 변경하는 방식으로 구현했다.
Circle.tsx
import * as S from "./Circle.style";
import { useEffect, useState } from "react";
import { MAX_DIAMETER } from "./Circle.style";
export default function CircleTemplate() {
const [ratio, setRatio] = useState(50);
const [deg, setDeg] = useState(0);
const [diameter, setDiameter] = useState(MAX_DIAMETER / 2);
useEffect(() => {
setDeg(0.9 * Math.abs(ratio - 50));
}, [ratio]);
const onChangeHandler = (e) => {
const target = e.target.value;
setRatio(target);
setDiameter(2 * target);
};
return (
<S.Container>
<S.RatioInput onChange={onChangeHandler} />
<S.CircleContainer deg={deg}>
<S.InnerCircle width={diameter} height={diameter} isLeft={true} />
<S.InnerCircle
width={MAX_DIAMETER - diameter}
height={MAX_DIAMETER - diameter}
isLeft={false}
/>
</S.CircleContainer>
</S.Container>
);
}
Circle.style.ts
import styled from "styled-components";
export const MAX_DIAMETER = 200;
export const QUARTER = MAX_DIAMETER / 4;
export const Container = styled.div`
padding: 100px 20px;
`;
export const RatioInput = styled.input`
width: 240px;
height: 40px;
margin: 20px 0;
`;
export const CircleContainer = styled.div<{ deg }>`
width: ${MAX_DIAMETER}px;
height: ${MAX_DIAMETER}px;
display: flex;
align-items: center; // 내부 두 원을 외부 원의 지름상에 위치하기 위한 가운데 정렬
transition-duration: 1s;
transition-timing-function: cubic-bezier(0, 0, 0.1, 1);
transform: rotate(${({ deg }) => deg}deg);
`;
export const InnerCircle = styled.div<{ width; height; isLeft }>`
width: ${({ width }) => width}px;
height: ${({ height }) => height}px;
border-radius: 50%;
min-width: ${QUARTER}px;
min-height: ${QUARTER}px;
max-width: ${MAX_DIAMETER - QUARTER}px;
max-height: ${MAX_DIAMETER - QUARTER}px;
background-color: ${({ isLeft }) => (isLeft ? "#dadee0" : "#ea0b25")};
transition-duration: 1s;
transition-timing-function: cubic-bezier(0, 0, 0.1, 1);
`;
input에 입력하는 숫자게 따라 원이 변하게 된다. 0~100을 넘어가는 숫자에 대해 딱히 제한하는 코드는 딱히 작성하지 않았다