반응형
두 라인 사이에 색 채우기 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>
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 |