지난 후기에 이어서 3번째로 진행한 과제 후기를 작성하도록 하겠다.
가능하다면 4번째도 같이 작성해볼까 한다.
기업에서 제공한 Mock data를 가지고 Bar 차트와 Area 차트가 같이 있는 시계열 차트를 만드는 과제였다.
여태껏 진행한 기업 과제와는 조금 다른 성격의 과제여서 새로웠다.
라이브러리 사용에 제한이 없어서 chart 구현을 위해 chart.js를 사용하였는데 만약 chart 를 그리는 라이브러리 사용에 제한이 있었다면 상당히 많은 시간을 투자해야하는 과제였으리라 생각된다.
chart 라이브러리를 사용해 편하기는 했지만 그래도 라이브러리가 익숙하지 않았고 과제를 이해하는 것에서 시간이 꽤 많이 걸렸던 과제였다.
과제 제출 기한을 좀 길게 주셨는데 그 이유를 진행하며 알았다 ㅠㅠ
차트를 그리기 위해서 당연 라이브러리 선정을 하는 시간을 우선 가졌다.
팀원들과 이야기를 해보니 차트 라이브러리를 사용해본 사람이 많지는 않은 상황이라서 어떤 라이브러리가 좋은지 서치하는 시간이 필요했다.
google 검색를 통해 react와 typescript 를 사용하여 차트를 그리기 좋은 라이브러리를 2개로 추렸다.
하나로 정하고 시작을 하면 나중에 best practice로 통합하는 과정에서 무리가 없겠지만 두 라이브러리 중 하나를 선택하는데 의견이 분분했고 결국 각자 하나를 선택하여 개발 후 비교해 하나를 택하는 쪽으로 진행하게 되었다.
두 차트 라이브러리를 사용하고 난 팀원들의 의견은 다음과 같다.
chart.js | apexchart.js | |
---|---|---|
장점 | 1. 가장 유명한 라이브러리이며 일부 팀원이 사용해봤기 때문에 비교적 익숙했다. 2. 개발자가 직접 유튜브로 여러가지 기능을 알려줘서 이용하기 수월했다. 3. d.ts 파일을 따로 받지 않아도 타입이 설정되어 있어서 좋았다. 4. chart.js-adapter-date-fns등 관련 라이브러리가 많아서 좋았다. 5. 디자인 관련 옵션이 많아서 커스텀마이징하는데 편리했다. 6. Dataset parsing 기능 등 차트데이터를 다루기 용이하다. 7. 오픈소스 라이브러리로 부담없이 사용가능 하다. | 1. import시 chart.js와는 다르게 import ApexChart from 'react-apexcharts’만 불러오면 사용이 가능하다. 2. 툴바의 차트다운로드 기능 등 기본차트 탬플릿 자체에서 편의기능을 제공한다. 3. 툴팁설정시 아이콘이 이쁘다 4. 기본적으로 차트를 구현시 + ,- ,줌? 등 여러기능들이 같이 화면에 제공이 된다. |
단점 | 1. react 사용자를 위해 react-chartjs-2 라는 라이브러리가 있어서 다행이었지만 관련 문서는 좀 부족한 편이다. 2. chartjs-adapter-date-fns 등 관련 라이브러리를 따로 다운받아야해서 번거로웠다. 3. types/chart 라이브러리가 있지만 아직 typescript와의 호환성이 부족했다. 4. 문서 읽기 힘들다 | 1. 공식 문서상 시각적 예시 부족한 편이다. 2. 공식문서 이벤트 부분에 event, chartContext, { seriesIndex, dataPointIndex, config}같은 속성들에 대한 설명이 잘 보이지 않았다. 3. 필요치 않은 기능들이 기본으로 설정되어 있는 경우 개별적으로 속성을 찾아서 수정해줘야하는 경우가 있다. 4. react-apexchart관련 레퍼런스가 다양하지 않다. 5. 속성의 설명이 잘되어있지 않아서 무슨 설정인지 헷갈릴 때가 많다. |
결론!
Apex가 다른 라이브러리에 의존하지않고 디자인적인 요소를 많이 갖추고 있지만,
Chart.js가 러닝 커브가 낮고 커뮤니티가 잘 형성되어 있어서 프로젝트를 진행하면서 만나는 이슈를 더욱 수월하게 해결할 수 있으리라 판단!!
chart.js를 사용하기로 했다.
기업에서 제공한 mock data의 모습은 다음과 같다.
{
"response": {
"2023-02-01 14:32:00": {
"id": "성북구",
"value_area": 46,
"value_bar": 13111
},
"2023-02-01 14:32:05": {
"id": "강남구",
"value_area": 9,
"value_bar": 19143
},
}
}
바로 차트에 사용하면 좋지만 차트에 적용하기 위해서 또 bar와 area를 따로 그리기 위해서는 위 data를 chart에 맞게 처리하는 과정이 필요했다.
가공후 데이터 모습
// bar chart data
{
type: 'bar' as const,
label:'bar',
data: [123, 113, 2345, 555, ...],
fill: false,
yAxisID: 'y',
backgroundColor: new Array(100).fill(COLOR_TEMPLATE.bar.barOriginColor),
borderColor: new Array(100).fill(COLOR_TEMPLATE.bar.barBorderColor),
borderWidth: 0.8,
hoverBackgroundColor: COLOR_TEMPLATE.bar.hoverBarColor,
order: 2,
}
// area chart data
{
type: 'line' as const,
label: 'area',
data: [123, 113, 2345, 555, ...],
fill: true,
yAxisID: 'y2',
backgroundColor: COLOR_TEMPLATE.area.areaBgColor,
pointBackgroundColor: new Array(100).fill(
COLOR_TEMPLATE.area.pointBgColor
),
pointHoverBackgroundColor: COLOR_TEMPLATE.area.pointHoverBgColor,
order: 1,
pointBorderWidth: 0.8,
pointBorderColor: 'black',
pointRadius: 3.5,
}
꼭 위와 같은 모습일 필요는 없지만 bar 와 area 구분을 위해 꼭 필요한 값이 존재한다.
위에 작성한 형태로 만들기 위해서 전처리 util 함수를 따로 구현했다.
const convertRawDataToChartData = (
rawData: ITableList,
type: 'bar' | 'line'
) => {
const convertedData = Object.entries(rawData).reduce((acc, curr) => {
const value = curr[1]
return [...acc, type === 'bar' ? value.value_bar : value.value_area]
}, [] as number[])
return {
type,
label: type === 'bar' ? 'bar' : 'area',
data: convertedData,
fill: type !== 'bar',
yAxisID: type === 'bar' ? 'y' : 'y2',
}
}
그리고 chart의 전반적인 기능을 다루기위해 custom hook으로 만든 useChartData hook에서 chart 컴포넌트로 넘기기 전에 나머지 가공을 했다.
// bar 데이터의 경우 예
const barDataSettingHandler = useCallback((rawData: ITableList) => {
const barSets = convertRawDataToChartData(rawData, 'bar')
const styleWrappedBar: ChartDataset = {
...barSets,
backgroundColor: new Array(100).fill(COLOR_TEMPLATE.bar.barOriginColor),
borderColor: new Array(100).fill(COLOR_TEMPLATE.bar.barBorderColor),
borderWidth: 0.8,
hoverBackgroundColor: COLOR_TEMPLATE.bar.hoverBarColor,
order: 2,
}
setBarDataSet(styleWrappedBar)
}, [])
차트 데이터의 처리 부분을 util과 custom hook으로 빼서 chart view를 담당하는 컴포넌트의 무게를 줄였다.
과제의 요구사항 중 필터링 및 하이라이트 기능 구현이 있었다.
- 특정 데이터를 하이라이트 하는 방식으로 필터링 구현
- 버튼 형태로 ID값(지역이름)으로 필터링
- 동일 ID값을 가지는 데이터만 하이라이트 처리
- 특정 데이터 구역을 클릭 시에도 버튼 클릭처럼 하이라이트 처리
이번 과제에서 제일 고민하고 애를 먹은 부분이다.
과제 이해하는 부분에서 고민이 있었고 팀원들의 의견이 조금씩 달랐다.
하이라이트
bar - 다른 값은 안보이게 vs 다른 값은 어두운 색처리
area - 다른 값은 없이 선택된 값만으로 다시 그리기 vs 선택된 값 포인트만 하이라이트
위 갈등이 생긴 이유 중 하나가 사실 area 차트 때문이다.
Area 차트에서 하이라이트는 차트에 찍힌 점 부분만 가능해서 눈에 잘 보이지 않는다는 것 !!!
bar 차트에 대한 의견은 결국 후자로 선택되었는데
area에서는 의견 조율보다는 실현가능성 때문에 후자를 선택하게 되었다.
개인적으로 전자의 옵션으로 구현을 해보려 했지만 계속 실패하여서 후자로 갈 수 밖에 없었다. ㅠㅠ
여튼 구현은
useChartData hook에서 가공한 data를 보낼때 선택된 data로 다시 셋팅 될 수 있도록 state를 다뤄서 잘 진행할 수 있었다.
라이브러리를 사용하니 구현에 제약이 생기고 정확히 라이브러리를 이해하고 있는 상태가 아니니 여기저기 검색하고 찾아보고 하는데 많은 시간을 할애하게 되었다.
그래도 chart.js 는 어느정도 사용해봐서 다음에 차트를 그려할 일이 생긴다면 chart.js 사용을 먼저 고려해볼 것 같다.
음... 쓰고보니 역시 좀 길이가 긴 것 같아 다음 마지막 후기로 돌아오겠다. 뿅!