본문 바로가기
프론트엔드

두 라인 사이에 색 채우기 Chart.js

by 느바 2025. 4. 13.
반응형

두 라인 사이에 색 채우기 Chart.js

 

Chart.js로 두 라인 사이에 색을 채우되, 두 라인 중 더 높은 라인의 색으로 라인 사이를 채우는 차트를 만들어보았다.

차트 내용은 다음과 같다.

  • 서로 다르게 움직이는 In temp와 Out temp가 있다.
  • In temp가 Out temp보다 높을 때는 In temp 라인의 아래에 In Temp 라인 색이 채워짐.
  • Out temp가 더 높아지면 반대로 설정.

구현의 핵심은 fill 속성이다.

fill 속성으로 Chart.js에서 라인 차트 아래 영역을 채우는 방식을 제어한다.

fill 속성 구조

fill은 라인 차트에서 선 아래를 채울지, 그리고 어떻게 채울지를 정하는 설정이다.
각 데이터셋 안에 개별적으로 지정할 수 있다.

fill: {
    target: 1, // 또는 0
    above: 'rgba(...)',
    below: 'transparent'
}

각 속성 설명

1. target

  • 어떤 기준선(혹은 다른 데이터셋)을 기준으로 채울 영역을 정할지를 설정함.

예시:

target: 1

 

  • 이 뜻은: 1번 인덱스 데이터셋 (즉, 두 번째 선) 을 기준으로 이 선과 그 선 사이를 채워줘.
  • 데이터셋 0 (In temp) → 데이터셋 1 (Out temp) 사이를 채우는 효과.
target: 0
  • 이건 반대로, 데이터셋 1 → 데이터셋 0 사이를 채운다는 의미야.

target은 아래처럼 다양하게 쓸 수 있다:

  • true: x축 기준 아래를 전부 채움
  • false: 채우지 않음
  • 'origin': y=0 기준으로 위/아래 채움
  • 숫자: 다른 데이터셋과 비교해서 채움 (지금 이 케이스처럼)

2. above

기준선보다 위쪽에 있는 영역의 색.

 above: 'rgba(108, 185, 193, 0.1)'
  • 기준선보다 위쪽만 밝은 블루 계열로 채워짐.

3. below

  • 기준선보다 아래쪽 영역의 색.
  • transparent이면 아래는 비워두겠다는 뜻이다.

요약

속성 역할
target 어느 선 또는 기준을 기준으로 채울지 정함
above 기준선보다 위에 있는 영역의 색상
below 기준선보다 아래에 있는 영역의 색상

전체 코드

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .chart_wrap {
            width: 400px;
            height: 200px;
        }
    </style>
</head>

<body>
    <div class="chart_wrap">
        <canvas id="temperature_chart"></canvas>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script>
        let item_content = {
            title: 'Temp',
            min: 0,
            max: 100,
            series_names: ['In temp', 'Out temp']
        }
        makeChartTemperature(item_content);
        function makeChartTemperature(chart_info) {
            let ctx = document.getElementById(`temperature_chart`).getContext('2d');
            let chart_minY = chart_info.min;
            let chart_maxY = chart_info.max;

            // y축의 min max 및 간격
            let split_number = 3;
            let y_range = chart_maxY - chart_minY;
            let y_step = (y_range / (split_number - 1)); // 간격 계산
            let y_min = (chart_minY / y_step) * y_step; // 최솟값 정렬
            let y_max = y_min + y_step * (split_number - 1);   // 최댓값 계산	
            // y_max가 chart_maxY보다 작다면 y_step을 추가하여 보정
            if (y_max < chart_maxY) {
                y_max += y_step;
            }

            // 초기 데이터 설정
            const maxDataPoints = 30;
            let inTempData = Array(maxDataPoints).fill(0);
            let outTempData = Array(maxDataPoints).fill(0);
            let labels = Array(maxDataPoints).fill('').map(() => {
                const now = new Date();
                const startTime = new Date().getTime();
                if (now.getTime() - startTime < 30000) { // 30초 동안
                    return '';  // 빈 문자열 반환
                }

                return now.toLocaleTimeString('en-US', {
                    hour: '2-digit',
                    minute: '2-digit',
                    hour12: true
                });
            });
            let data = {
                labels: labels,
                datasets: [
                    {
                        label: chart_info.series_names[0],
                        data: inTempData,
                        borderColor: 'rgba(108, 185, 193, 1)',
                        borderWidth: 1,
                        backgroundColor: 'rgba(108, 185, 193, 0.1)',
                        fill: {
                            target: 1,
                            above: 'rgba(108, 185, 193, 0.1)',
                            below: 'transparent'
                        },
                        tension: 0.4,
                        pointStyle: 'circle',
                        pointRadius: 5,
                        pointHoverRadius: 5,
                        pointBorderColor: 'rgba(255,255,255,0)',
                        pointBackgroundColor: 'rgba(108, 185, 193, 0)',
                        pointBorderWidth: 2,
                        pointHoverBorderColor: 'rgba(255,255,255,1)',
                        pointHoverBackgroundColor: 'rgba(108, 185, 193, 1)',
                        pointHoverBorderWidth: 2,
                    },
                    {
                        label: chart_info.series_names[1],
                        data: outTempData,
                        borderColor: 'rgba(154, 76, 241, 1)',
                        borderWidth: 1,
                        backgroundColor: 'rgba(154, 76, 241, 0.1)',
                        fill: {
                            target: 0,
                            above: 'rgba(154, 76, 241, 0.1)',
                            below: 'transparent'
                        },
                        tension: 0.4,
                        pointStyle: 'circle',
                        pointRadius: 5,
                        pointHoverRadius: 5,
                        pointBorderColor: 'rgba(255,255,255,0)',
                        pointBackgroundColor: 'rgba(154, 76, 241, 0)',
                        pointBorderWidth: 2,
                        pointHoverBorderColor: 'rgba(255,255,255,1)',
                        pointHoverBackgroundColor: 'rgba(154, 76, 241, 1)',
                        pointHoverBorderWidth: 2,
                    }
                ]
            };

            let options = {
                responsive: true,
                plugins: {
                    title: {
                        display: false,
                    },
                },
                scales: {
                    x: {
                        display: false,
                        title: {
                            display: false
                        },
                        grid: {
                            drawBorder: false,
                            display: false
                        },
                    },
                    y: {
                        min: y_min,
                        max: y_max,
                        display: true,
                        title: {
                            display: false
                        },
                        ticks: {
                            display: false,
                            stepSize: y_step,
                        },
                        grid: {
                            display: true,
                            color: 'rgba(255,255,255,0.05)',
                            drawTicks: false,
                        },
                        border: {
                            display: false
                        },
                        beginAtZero: false,
                    }
                }
            };

            let myChart = new Chart(ctx, {
                type: 'line',
                data: data,
                options: options,

            });

            // 새로운 데이터 생성 함수
            function generateNewData() {
                return Math.floor(Math.random() * (chart_maxY - chart_minY)) + chart_minY; // chart_minY에서 chart_maxY 사이의 값
            }

            // 차트 업데이트 함수
            function updateChart() {
                // 데이터 이동
                inTempData.shift();
                outTempData.shift();
                myChart.data.labels.shift();

                // 현재 시간 가져오기
                const now = new Date();
                const currentTime = now.toLocaleTimeString('en-US', {
                    hour: '2-digit',
                    minute: '2-digit',
                    hour12: true
                });

                // 새로운 데이터 추가
                inTempData.push(generateNewData());
                outTempData.push(generateNewData());
                myChart.data.labels.push(currentTime);

                // 차트 데이터 업데이트
                /* myChart.data.datasets[0].data = inTempData;
                myChart.data.datasets[1].data = outTempData; */

                // 차트 다시 그리기
                myChart.update('none'); // 애니메이션 없이 업데이트			
            }

            // 1초마다 차트 업데이트
            setInterval(updateChart, 3000);	// 화면이 전환되면 interval 중단되도록 해야 한다!!!!!!    
        }
    </script>
</body>

</html>

 

 

https://www.chartjs.org/

 

Chart.js

Simple yet flexible JavaScript charting library for the modern web

www.chartjs.org

 

'프론트엔드' 카테고리의 다른 글

Pretendard 폰트  (0) 2025.04.13
Lottie 애니메이션  (0) 2025.04.12
Vite 기본 폴더 구조  (1) 2025.03.29
Vite vs 프레임워크  (0) 2025.03.29
DispatcherServlet web.xml  (1) 2025.01.26