STUDY/javascript

css, javascript 다중 도넛 그래프

수밤바 2023. 3. 9. 12:01
728x90

css conic-gradient를 이용한 도넛그래프

 

아래 블로그를 참고했으며 data추가하여 유동적으로 사용할수 있도록 수정했다

 

https://guiyomi.tistory.com/66

 

CSS로 직접 그래프 만들기(bar, donut 그래프) + 애니메이션 효과 추가

보통 웹 개발을 할 때 그래프를 다룰 일이 생기면 라이브러리를 찾아서 사용하곤 했다. 이번에도 라이브러리를 이용하여 도넛 그래프 8개를 2행 4열로 배치하는 화면을 만드는 작업을 하게 됐는

guiyomi.tistory.com

 

 

 

 

 

<div class="donut"><span class="donut-desc"></span></div>

 

    .donut {
        position: relative;
        width: 300px;
        height: 300px;
        border-radius: 50%;
    }
    .donut:after {
    	content:'';
        position: absolute;
        top:7%;
        left:7%;
        z-index: 1;
        width: calc(100% - 14%);
        height: calc(100% - 14%);
        border-radius: 50%;
        background: #fff;
    }
    .donut-desc {
        display: flex;
        justify-content: center;
        flex-direction: column;
        position: absolute;
        top:0;
        left:0;
        width: 100%;
        height: 100%;
        padding: 20%;
        box-sizing: border-box;
        z-index: 2;
        color: #000;
        font-size: 20px;
    }
    .donut-desc span {
        display: flex;
        align-items: center;
        gap: 10px;
    }
    .donut-desc span i {
        display: inline-block;
        width: 10px;
        height: 10px;
        background-color: attr(data-color);
    }

 

<script>
    const donutEl = document.querySelector('.donut')
    let total = 0
    let count = 0
    let dCount=0;
    const data = [
        {title : '지하철', percent : 5},
        {title : '버스', percent : 10},
        {title : '자가용', percent : 15},
        {title : '자전거', percent : 20},
        {title : '도보', percent : 25},
    ]
  
    const colorArr = ['skyblue', 'blue', 'pink','deeppink', 'greenyellow', 'green', 'mediumpurple', 'purple', 'violet', 'blueviolet']
    const dataSection = [data[0].percent]
    let descText = ''
    data.forEach((item, index)=>{
        total += item.percent
        if (index !== 0) dataSection.push(item.percent + dataSection[dataSection.length-1]) // 순차적으로 더하기
        descText += `<span><i style="background-color:${colorArr[index*2+1]}"></i>${item.title} : ${item.percent} </span>`
    })

    const donutGradient = (section, idx)=> {
        const donutAnimation = setInterval(() => {
            let bg = ''
            let bgCode = [`${colorArr[0]} 0`];
            for (let k = 0; k < idx; k++) {
                bgCode.push(`${colorArr[k+k+1]} ${dataSection[k]}%`);
                bgCode.push(`${colorArr[k+k+2]} ${dataSection[k]}%`);
            }
            bg = `conic-gradient(${bgCode.join(', ')}, ${colorArr[idx*2+1]} ${count}%, #dedede ${count}% ${section}%)`;
            donutEl.style.background = bg
            console.log(bg)
            count++
            if(count >= dataSection[dCount]) {
                // console.log('clear')
                clearInterval(donutAnimation)
                if (dCount<dataSection.length-1) {
                    dCount++
                    donutGradient(dataSection[dCount], dCount)
                }
            }
        },30)
    }

    donutGradient(dataSection[dCount], dCount)
    donutEl.querySelector('.donut-desc').innerHTML = descText
            

</script>

const data = [ {title:'타이틀', percent:'00%'}, {}, ... ]

colorArr에 각 항목에 들어갈 색상 2가지를 쌍으로 넣어줘야 한다

dataSection은 각 percent를 순차적으로 합한 값인데

colorArr과 매칭하는 부분이 복잡하다

conic-gradient(
                 colorArr[0] 0,
                colorArr[1] dataSection[0]%, colorArr[2] dataSection[0]%,
                colorArr[3] dataSection[1]%, colorArr[4] dataSection[1]%,
                colorArr[5] dataSection[2]%, colorArr[5] dataSection[2]%,
                 100%
)
 

조금 이상하게 짰지만

일단 되니까..

 

이상한부분 

더보기
bgCode.push(`${colorArr[k+k+1]} ${dataSection[k]}%`);
bgCode.push(`${colorArr[k+k+2]} ${dataSection[k]}%`);
 
bg = `conic-gradient(${bgCode.join(', ')}, ${colorArr[idx*2+1]} ${count}%, #dedede ${count}% ${section}%)`;