원래 chart.js 에서 함수를 직접 작성해가면서 기능을 추가했는데
기존 네 영역에도 색을 주고
호버하면 색을 또 주고
클릭하면 또 주고..
코드가 길어질 것 같아서 html 객체를 생성했다.
<div class="wrap">
<div class="chart">
<ul class="background">
<li class="group group1"></li>
<li class="group group2"></li>
<li class="group group3"></li>
<li class="group group4"></li>
</ul>
<canvas id="myChart"></canvas>
</div>
<div class="tab_wrap">
<div class="tab tab1 active">11번 탭탭탭</div>
<div class="tab tab2">22번 탭탭탭</div>
<div class="tab tab3">3번 탭탭탭</div>
<div class="tab tab4">4번 탭탭탭</div>
</div>
</div>
.background도 영역 나누기
.chart {
position: relative;
width: 700px;
}
.background {
width: calc(100% - 47px);
height: calc(100% - 61px);
left: 27px;
top: 32px;
position: absolute;
}
.background > li {
width: 50%;
height: 50%;
position: absolute;
}
.group2 {
top: 0;
right: 0;
}
.group3 {
bottom: 0;
left: 0;
}
.group4 {
bottom: 0;
right: 0;
}
.group.clicked {
border: 1px solid red;
box-sizing: border-box;
}
.group1 {background: rgba(0, 0, 0, 0.1);}
.group2 {background: rgba(0, 0, 0, 0.3)}
.group3 {background: rgba(0, 0, 0, 0.4)}
.group4 {background: rgba(0, 0, 0, 0.5)}
.group1.active {background: rgb(250, 128, 114, 0.5);}
.group2.active {background: rgb(250, 128, 114, 0.5)}
.group3.active {background: rgb(250, 128, 114, 0.5)}
.group4.active {background: rgb(250, 128, 114, 0.5)}
#myChart {position: relative; z-index:10; cursor:pointer;}
.tab {display: none; font-size: 40px;}
.tab.active {display: block;}
.tab1 {background: yellow;}
.tab2 {background: blue;}
.tab3 {background: green;}
.tab4 {background: orange;}
. 위치 잘 조정하고 색깔도 주고 잘 슥삭슥삭
function getCurrentZone(chart, x, y) {
const { left, top, right, bottom, width, height } = chart.chartArea;
if (x < left || x > right || y < top || y > bottom) {
return null;
} else if (x < left + width / 2 && y < top + height / 2) {
return 1;
} else if (x > left + width / 2 && y < top + height / 2) {
return 2;
} else if (x < left + width / 2 && y > top + height / 2) {
return 3;
} else {
return 4;
}
}
function onClickTab(chart, event) {
let clickedZone = getCurrentZone(chart, event.x, event.y);
const tabs = document.querySelectorAll('.tab_wrap .tab');
tabs.forEach(tab => {
if(tab.classList.contains(`tab${clickedZone}`)) {
tab.classList.add('active')
} else {
tab.classList.remove('active')
}
})
const tabWrap = document.querySelectorAll('.wrap .background li');
tabWrap.forEach(tab => tab.classList.remove('clicked'));
const clickTab = document.querySelector(`.background li:nth-child(${clickedZone})`);
clickTab.classList.add('clicked')
chart.update('none');
}
function onHoverActive(chart, event) {
let number = getCurrentZone(chart, event.x, event.y);
const tabBackground = document.querySelectorAll('.background li');
const correctZone = event.x >= chart.chartArea.left &&
event.x <= chart.chartArea.right &&
event.y >= chart.chartArea.top &&
event.y <= chart.chartArea.bottom;
tabBackground.forEach(tab => tab.classList.remove('active'));
if (number !== null) {
const background = document.querySelector(`.background li:nth-child(${number})`);
if (background) {
background.classList.add('active');
}
}
if (!correctZone) {
tabBackground.forEach(tab => tab.classList.remove('active'));
}
}
const data = {
datasets:[{
data: [{
x: -10,
y: 0
}, {
x: 0,
y: 10
}, {
x: 10,
y: 5
}, {
x: 0.5,
y: 5.5
}],
backgroundColor: [
'red',
'salmon',
'orange',
'green'
],
borderColor: [
'red',
'salmon',
'orange',
'green'
],
borderWidth: 3,
usePointStyle: true,
pointStyle: 'circle',
clip: false,
hoverBackgroundColor: ['blue', 'blue', 'blue', 'blue']
}]
};
const config = {
type: 'scatter',
data,
options: {
responsive: true,
interaction: {
intersect: false,
mode: 'nearest',
},
onClick: function(e) {
onClickTab(myChart, e);
},
layout: {
padding: {
right: 20
}
},
scales: {
y: {
beginAtZero: true
},
x: {
type: 'linear',
position: 'bottom',
}
}
},
plugins: [onClickTab]
}
const ctx = document.getElementById('myChart');
const myChart = new Chart(
ctx,
config
);
ctx.addEventListener('mousemove',(e) => {
e.preventDefault();
onHoverActive(myChart, e);
});
. 원래 차트 옵션 onHover로 이벤트를 줬었는데 마우스가 차트 영역을 떠나도 클래스 active가 사라지지 않는 현상이 있었다.
확인해보니 마우스이벤트 좌표를 잘 잡지 못해서 일어난 현상이어서 onHover말고 이벤트리스너를 이용해서 줬다.
아래는 chart.js를 이용한 방법
코드를 다시보니 줄일 수 있는데 내가 길게 쓴 것 같기도..
공부하자..
더보기
let mouseX = null;
let mouseY = null;
let clickedZone = null;
function getCurrentZone(chart, x, y) {
const { left, top, right, bottom, width, height } = chart.chartArea;
if (x < left || x > right || y < top || y > bottom) {
return null;
} else if (x < left + width / 2 && y < top + height / 2) {
return 1;
} else if (x > left + width / 2 && y < top + height / 2) {
return 2;
} else if (x < left + width / 2 && y > top + height / 2) {
return 3;
} else {
return 4;
}
}
function onClickTab(chart, event) {
clickedZone = getCurrentZone(chart, event.x, event.y);
const tabs = document.querySelectorAll('.tab_wrap .tab');
tabs.forEach(tab => {
if(tab.classList.contains(`tab${clickedZone}`)) {
tab.classList.add('active')
} else {
tab.classList.remove('active')
}
})
chart.update('none');
}
const onHoverBackground = {
id: 'bgColorArea',
beforeDraw(chart, args, options) {
const {
ctx,
chartArea: { left, top, width, height }
} = chart;
ctx.save();
const drawZone = (zone, color) => {
const halfWidth = width / 2;
const halfHeight = height / 2;
ctx.fillStyle = color;
switch (zone) {
case 1:
ctx.fillRect(left, top, halfWidth, halfHeight);
break;
case 2:
ctx.fillRect(left + halfWidth, top, halfWidth, halfHeight);
break;
case 3:
ctx.fillRect(left, top + halfHeight, halfWidth, halfHeight);
break;
case 4:
ctx.fillRect(left + halfWidth, top + halfHeight, halfWidth, halfHeight);
break;
}
}
const currentZone = getCurrentZone(chart, mouseX, mouseY);
if (mouseX <= width && mouseY <= height) {
drawZone(currentZone, 'rgba(0,0,0,0.2)')
}
if (clickedZone !== null) {
drawZone(clickedZone, 'skyblue')
}
ctx.restore();
}
}
const config = {
type: 'scatter',
data: {
datasets: [{
data: [{
x: -10,
y: 0,
}, {
x: 0,
y: 10,
}, {
x: 0,
y: 10,
}, {
x: 10,
y: 5,
}, {
x: 0.5,
y: 5.5,
}],
backgroundColor: [
'red',
'salmon',
'blue',
'orange',
'green'
],
borderColor: [
'red',
'salmon',
'blue',
'orange',
'green'
],
borderWidth: 3,
usePointStyle: true,
pointStyle: 'circle',
hoverPointStyle : image,
clip: false
}]
},
options: {
interaction: {
intersect: false,
mode: 'nearest',
},
onHover: function(event, chartElement) {
const canvasPosition = Chart.helpers.getRelativePosition(event, myChart);
const chartArea = myChart.chartArea;
if (
canvasPosition.x >= chartArea.left &&
canvasPosition.x <= chartArea.right &&
canvasPosition.y >= chartArea.top &&
canvasPosition.y <= chartArea.bottom
) {
event.native.target.style.cursor = 'pointer';
} else {
event.native.target.style.cursor = 'default';
}
mouseX = canvasPosition.x;
mouseY = canvasPosition.y;
myChart.update('none');
},
onClick: function(e) {
onClickTab(myChart, e);
},
layout: {
padding: {
right: 20
}
},
scales: {
y: {
beginAtZero: true
},
x: {
type: 'linear',
position: 'bottom',
}
},
plugins: {
tooltip: {
enabled: false,
events: ['mousemove'],
external: pluginCustomTooltip,
}
}
},
plugins: [onHoverBackground]
};
const ctx = document.getElementById('myChart');
const myChart = new Chart(
ctx,
config
);
'언어 > Chart.js' 카테고리의 다른 글
[Chart.js] 데이터 값마다 포인트 이미지 다르게 주고 싶다. (1) | 2024.06.27 |
---|---|
[chart.js] 분산형 그래프 포인트를 이미지로 (0) | 2024.03.16 |
[chart.js] 라인차트 데이터가 있는 곳만 표시하기 (0) | 2024.03.12 |
[chart.js] 그래프 hover시 마우스 포인터(v.4.2.1) (1) | 2024.03.06 |
[Chart.js] 그래프 클릭하면 모달 창 띄우기(v.4.2.1) (0) | 2024.01.18 |