My Chart.js line graph dashed border grid line vanishes for few few seconds when I hover over graph point data. This also happens when I activate and deactivate datasets using the “This Month” and “Last Month” toggles.
Also, my data line appears to be backwards of those grid lines. The grid lines are supposed to be backward of the data line.
I tried increasing the z index for data lines, but it still shows the data line backward of the grid line.
Also, regarding the grid line disappearing concerns, I tried plain grid lines, which worked, but I wanted to use dashed border grid lines.
I want those grid lines to be backward of the data line, and when I hover over a graph point, it should stay fixed rather than disappear for a few seconds. Also, when I activate and deactivate a data line using the toggle option, the grid line should not vanish at all.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Line graph</title>
<link rel="stylesheet" href="../css/bootstrap.min.css">
<style>
.market-activity-chart-container {
width: 100%;
height: auto;
margin: 0 auto;
}
.market-activity-chart-container canvas {
background: #ffffff;
width: 100%;
max-width: 700px;
height: 100%;
}
.market-this-months,
.market-last-months {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
opacity: 0.5;
transition: opacity 0.3s;
}
.market-this-months.active,
.market-last-months.active {
opacity: 1;
}
.market-months-flex {
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
}
</style>
</head>
<body>
<div class="row justify-content-center">
<div class="col-5">
<div class="dashboard-card">
<div class="market-activity-chart-container">
<canvas id="marketActivityChart"></canvas>
</div>
<div class="market-months-flex">
<div class="market-this-months active" id="toggleThisMonth">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none">
<circle cx="6" cy="6" r="4.5" fill="white" stroke="#5159A7" stroke-width="3"/>
</svg>
<span>This Month</span>
</div>
<div class="market-last-months" id="toggleLastMonth">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none">
<circle cx="6" cy="6" r="4.5" fill="white" stroke="#F8C140" stroke-width="3"/>
</svg>
<span>Last Month</span>
</div>
</div>
</div>
</div>
</div>
<script src="../js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
const ctxMarketActivity = document.getElementById('marketActivityChart').getContext('2d');
const marketActivityData = {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'],
datasets: [
{
label: 'This Month',
data: [5500, 2800, 3800, 3900, 7800, 5800, 7600, 4000],
borderColor: '#4F45B6',
borderWidth: 5,
fill: false,
tension: 0,
pointRadius: 0,
pointHoverRadius: 5,
order: 2,
},
{
label: 'Last Month',
data: [3800, 2700, 2800, 1400, 6000, 5500, 5600, 3800],
borderColor: '#F8C140',
borderWidth: 5,
fill: false,
tension: 0,
pointRadius: 0,
pointHoverRadius: 5,
order: 2,
}
]
};
const marketActivityChart = new Chart(ctxMarketActivity, {
type: 'line',
data: marketActivityData,
options: {
responsive: true,
scales: {
y: {
beginAtZero: false,
min: 1000,
max: 10000,
ticks: {
stepSize: 2000,
callback: function(value) {
return value >= 1000 ? value / 1000 + 'k' : value;
},
font: {
family: 'Gilroy-Medium',
size: 18,
style: 'normal',
weight: '400'
},
color: '#101839',
lineHeight: 34,
textTransform: 'capitalize',
opacity: 0.4,
padding: 16
},
grid: {
display: false
},
border: {
display: false
}
},
x: {
ticks: {
display: false
},
grid: {
display: false
}
}
},
plugins: {
legend: {
display: false
},
tooltip: {
enabled: false,
external: function(context) {
const { chart, tooltip } = context;
const tooltipEl = document.querySelector('.chartjs-tooltip') || document.createElement('div');
if (!document.querySelector('.chartjs-tooltip')) {
tooltipEl.classList.add('chartjs-tooltip');
tooltipEl.style.position = 'absolute';
tooltipEl.style.pointerEvents = 'none';
tooltipEl.style.color = '#fff';
tooltipEl.style.padding = '10px 28px';
tooltipEl.style.borderRadius = '10px';
tooltipEl.style.fontSize = '20px';
tooltipEl.style.fontFamily = 'Arial, sans-serif';
tooltipEl.style.zIndex = 1000;
document.body.appendChild(tooltipEl);
}
if (tooltip.opacity === 0) {
tooltipEl.style.opacity = 0;
return;
}
// Determine tooltip background color based on dataset
const datasetIndex = tooltip.dataPoints[0].datasetIndex;
tooltipEl.style.backgroundColor = datasetIndex === 1 ? '#F8C140' : '#5159A7';
// Tooltip content
const tooltipData = tooltip.dataPoints.map(dp => `<div>${dp.formattedValue}</div>`).join('');
tooltipEl.innerHTML = tooltipData;
// Tooltip position
const position = chart.canvas.getBoundingClientRect();
tooltipEl.style.opacity = 1;
tooltipEl.style.left = `${position.left + window.pageXOffset + tooltip.caretX}px`;
tooltipEl.style.top = `${position.top + window.pageYOffset + tooltip.caretY}px`;
}
}
},
animation: {
onComplete: function() {
const chartArea = marketActivityChart.chartArea;
const yScale = marketActivityChart.scales.y;
const ctx = marketActivityChart.ctx;
const yLabels = yScale.ticks.map(tick => tick.value);
ctx.save();
ctx.strokeStyle = '#A098AE';
ctx.lineWidth = 1;
ctx.setLineDash([6, 6]);
yLabels.forEach(label => {
const yPos = yScale.getPixelForValue(label);
ctx.beginPath();
ctx.moveTo(chartArea.left, yPos);
ctx.lineTo(chartArea.right, yPos);
ctx.stroke();
});
ctx.restore();
}
},
elements: {
point: {
radius: function(context) {
return context.active ? 5 : 0;
}
}
}
}
});
function updateToggleStates() {
const thisMonthButton = document.querySelector('.market-this-months');
const lastMonthButton = document.querySelector('.market-last-months');
// Check dataset visibility and update classes
if (marketActivityChart.getDatasetMeta(0).hidden) {
thisMonthButton.classList.add('inactive');
thisMonthButton.classList.remove('active');
} else {
thisMonthButton.classList.add('active');
thisMonthButton.classList.remove('inactive');
}
if (marketActivityChart.getDatasetMeta(1).hidden) {
lastMonthButton.classList.add('inactive');
lastMonthButton.classList.remove('active');
} else {
lastMonthButton.classList.add('active');
lastMonthButton.classList.remove('inactive');
}
}
updateToggleStates();
// Toggle visibility
document.querySelector('.market-this-months').addEventListener('click', function() {
const dataset = marketActivityChart.getDatasetMeta(0);
dataset.hidden = !dataset.hidden;
marketActivityChart.update();
updateToggleStates();
});
document.querySelector('.market-last-months').addEventListener('click', function() {
const dataset = marketActivityChart.getDatasetMeta(1);
dataset.hidden = !dataset.hidden;
marketActivityChart.update();
updateToggleStates();
});
</script>
</body>
</html>