Skip to content

Instantly share code, notes, and snippets.

@timelf123
Last active February 25, 2025 17:17
Show Gist options
  • Save timelf123/7170fb518e925f4b17de22e6279194aa to your computer and use it in GitHub Desktop.
Save timelf123/7170fb518e925f4b17de22e6279194aa to your computer and use it in GitHub Desktop.
chart.js vertical multiline centered text labels
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chart.js Vertical Multiline Centered Labels</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.chart-container {
width: 90%;
max-width: 800px;
margin: 0 auto;
height: 450px;
padding-bottom: 150px; /* Extra space for labels */
}
h1 {
text-align: center;
color: #333;
}
</style>
</head>
<body>
<h1>Chart with Vertical Multiline Centered Labels</h1>
<div class="chart-container">
<canvas id="myChart"></canvas>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const ctx = document.getElementById('myChart');
// Sample data with labels
const originalLabels = [
'January Sales Department',
'February Marketing Team',
'March Customer Support',
'April Product Development',
'May Quality Assurance',
'June Human Resources'
];
// Create chart with hidden x-axis labels
const myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: originalLabels,
datasets: [{
label: 'Revenue by Department',
data: [65, 59, 80, 81, 56, 55],
backgroundColor: 'rgba(54, 162, 235, 0.5)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
layout: {
padding: {
bottom: 150 // Add padding at bottom of chart for labels
}
},
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: 'Revenue ($1000s)',
font: {
weight: 'bold'
}
}
},
x: {
ticks: {
display: false // Hide default ticks as we'll draw our own
}
}
},
plugins: {
title: {
display: true,
text: 'Department Performance',
font: {
size: 16,
weight: 'bold'
}
},
legend: {
position: 'top'
},
tooltip: {
callbacks: {
title: function(tooltipItems) {
return originalLabels[tooltipItems[0].dataIndex];
}
}
}
}
},
plugins: [{
id: 'customLabelsPlugin',
afterDraw: function(chart) {
const ctx = chart.ctx;
ctx.save();
// Get dimensions
const meta = chart.getDatasetMeta(0);
const yScale = chart.scales.y;
originalLabels.forEach((label, i) => {
// Get exact center of each bar
const bar = meta.data[i];
const centerX = bar.x;
// Split text into words
const words = label.split(' ');
const lineHeight = 15;
// Calculate total label height
const totalLabelHeight = (words.length - 1) * lineHeight;
// Start position below chart
const startY = yScale.bottom + 30;
// Draw text vertically
ctx.save();
ctx.translate(centerX, startY);
ctx.rotate(-Math.PI / 2); // -90 degrees
// Style settings
ctx.font = '12px Arial';
ctx.fillStyle = '#666';
ctx.textAlign = 'center';
// Draw each word on its own line with vertical centering
for (let wordIndex = 0; wordIndex < words.length; wordIndex++) {
// Calculate vertical position with centering offset
const verticalCenter = totalLabelHeight / 2;
const yPos = wordIndex * lineHeight - verticalCenter;
ctx.fillText(words[wordIndex], 0, yPos);
}
ctx.restore();
});
ctx.restore();
}
}]
});
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment