Responsive legend font size in react-chartjs 2 - chart.js

I have tried to make a pie chart using react-chartjs 2, It is working fine in desktop view but in mobile view the legend is not responsive it is taking much space and due to this the size of pie chart become very small.
my code:
function Chart(props: any) {
const option = {
tooltips: {enter image description here
callbacks: {
label: function (tooltipItem: any, data: any) {
var dataset = data.datasets[tooltipItem.datasetIndex];
var meta = dataset._meta[Object.keys(dataset._meta)[0]];
var total = meta.total;
var currentValue = dataset.data[tooltipItem.index];
var percentage = parseFloat(
((currentValue / total) * 100).toFixed(1)
);
return currentValue + " (" + percentage + "%)";
},
title: function (tooltipItem: any, data: any) {
return data.labels[tooltipItem[0].index];
},
},
},
legend: {
display: true,
labels: {
fontSize: 12,
},
position: "right",
},
};
return (
<div className="chart">
<Pie data={props.ChartData} options={option} />
</div>
);

You can set your fontSize object as a ternery operator that checks the widts (or something else) to see if you are on a mobile device and give back the right fontSize according to it
If you want to update it real time because screen sizes change you can do that by mutating the chart options itself in a resizeEvent listner
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
legend: {
labels: {
fontSize: window.innerWidth > 350 ? 20 : 10
}
},
scales: {
yAxes: [{
ticks: {
reverse: false
}
}]
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
const chart = new Chart(ctx, options);
window.addEventListener('resize', () => {
if (window.innerWidth < 350) {
chart.options.legend.labels.fontSize = 10;
} else {
chart.options.legend.labels.fontSize = 20
}
});
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js" integrity="sha512-hZf9Qhp3rlDJBvAKvmiG+goaaKRZA6LKUO35oK6EsM0/kjPK32Yw7URqrq3Q+Nvbbt8Usss+IekL7CRn83dYmw==" crossorigin="anonymous"></script>
</body>

Here is the way to have a responsive legend font size (also explained here)
options: {
plugins: {
legend: {
labels: {
// This more specific font property overrides the global property
font: {
size: 14
}
}
}
}
}

Related

Add line from point to x-axis and bold label of him

I have a chart.js in my website
When hovering over a point in the graph, I need to draw a line that goes down to the x-axis and bold his label
like this:
[chart][1]
Can someone help me?
You will need a custom plugin for this, see live example:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'red',
backgroundColor: 'red'
}]
},
options: {
plugins: {
selector: {
color: 'blue',
width: 2,
// If canvas has a different backgroundColor set this to match
boxColor: 'white'
}
}
},
plugins: [{
id: 'selector',
beforeDatasetsDraw: (chart, args, opts) => {
// Return if no hover
if (chart._active.length === 0) {
return;
}
// Set all variables needed
const activeEl = chart._active[0].element;
const labelItem = chart.scales.x._labelItems[chart._active[0].index];
const {
ctx,
scales: {
y
}
} = chart;
const metrics = ctx.measureText(labelItem.label);
const labelWidth = metrics.width;
const labelHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
// Draw white box over old label
ctx.save();
ctx.fillStyle = opts.boxColor || '#FFFFFF';
ctx.fillRect((labelItem.translation[0] - labelWidth / 2), labelItem.translation[1], labelWidth, labelHeight);
ctx.restore();
// Draw new text on canvas
ctx.save();
ctx.font = Chart.helpers.toFontString(Object.assign(labelItem.font, {
style: 'bold'
}));
ctx.fillText(labelItem.label, (labelItem.translation[0] - labelWidth / 2), labelItem.translation[1] + labelItem.textOffset)
ctx.restore();
// Draw vertical line down from point
ctx.save();
ctx.lineWidth = opts.width || 1;
ctx.strokeStyle = opts.color || 'black';
ctx.beginPath();
ctx.moveTo(activeEl.x, activeEl.y);
ctx.lineTo(activeEl.x, y.getPixelForValue(y.min));
ctx.stroke();
ctx.restore();
}
}]
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.0/chart.js"></script>
</body>

Grouped bar chart having each group with different data using chart.js

I am looking to build the same as shown in the image, I checked chart.js documentation(https://www.chartjs.org/docs/3.0.2/) but didn't find anything like this. Is it possible to create a chart like this using chart.js?
Yes you can use the datalabels plugin to achieve what you want:
Example:
Chart.register(ChartDataLabels);
var options = {
type: 'bar',
data: {
labels: ["Category 1", "Category 2", "Category 3"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3],
animals: ['cat', 'dog', 'bear'],
borderWidth: 1,
backgroundColor: ['orange', 'blue', 'gray']
},
{
label: '# of Points',
data: [7, 11, 5],
animals: ['monkey', 'bird', 'fish'],
borderWidth: 1,
backgroundColor: ['yellow', 'cyan', 'purple']
}
]
},
options: {
plugins: {
title: {
display: true,
text: 'title'
},
datalabels: {
anchor: 'end', // remove this line to get label in middle of the bar
align: 'end',
formatter: (val, x) => (x.dataset.animals[x.dataIndex]),
labels: {
value: {
color: 'purple'
}
}
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.3.2/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#2.0.0-rc"></script>
</body>
you can use Plotly.js for grouped chart please check below code
Reference URL : https://plotly.com/javascript/bar-charts/
var trace1 = {
x: ['giraffes', 'orangutans', 'monkeys'],
y: [20, 14, 23],
name: 'SF Zoo',
type: 'bar'
};
var trace2 = {
x: ['giraffes', 'orangutans', 'monkeys'],
y: [12, 18, 29],
name: 'LA Zoo',
type: 'bar'
};
var data = [trace1, trace2];
var layout = {barmode: 'group'};
Plotly.newPlot('myDiv', data, layout);
<head>
<!-- Load plotly.js into the DOM -->
<script src='https://cdn.plot.ly/plotly-1.58.4.min.js'></script>
</head>
<body>
<div id='myDiv'><!-- Plotly chart will be drawn inside this DIV --></div>
</body>

Chart.js Tooltip over the line not only over points

I have a line chart in chart.js. Now I would like to have a tooltip, when I hover over the line not just when i hover over a point.
The tooltip should then be displayed at the position of the mouse.
Is this somehow possible?
I have tried all interaction.mode options, but non of them have this behavior.
Thank You
You can use the croshair plugin for this if you are still using v2 of the lib: https://chartjs-plugin-crosshair.netlify.app/
Live example:
var ctx = document.getElementById("myChart");
function generateDataset(shift, label, color) {
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
let data = [];
let index = 0;
while (index < 5) {
data.push({
x: index,
y: getRandomInt(10, 40)
});
index++;
}
var dataset = {
backgroundColor: color,
borderColor: color,
showLine: true,
fill: false,
pointRadius: 2,
label: label,
data: data,
lineTension: 0,
interpolate: true,
xAxisID: 'x-axis-0'
};
return dataset;
}
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['A', 'B', 'C', 'D', 'E'],
datasets: [
generateDataset(0, "A", "red"),
generateDataset(1, "B", "green")
]
},
options: {
scales: {
xAxes: [{
display: true,
type: 'linear',
position: 'bottom',
id: 'x-axis-0',
ticks: {
source: 'labels'
}
}]
},
tooltips: {
mode: "interpolate",
intersect: false,
callbacks: {
title: function(a, d) {
// return a[0].xLabel.toFixed(2);
return a[0].xLabel;
},
label: function(i, d) {
return (
d.datasets[i.datasetIndex].label + ": " + i.yLabel.toFixed(2)
);
}
}
},
plugins: {
crosshair: {
line: {
// Add alpha chanel so line becomes transparant so you dont see it
color: '#ffffff00',
},
sync: {
enabled: false
}
}
}
}
});
.myChartDiv {
max-width: 600px;
max-height: 400px;
}
<html>
<body>
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400"></canvas>
</div>
<script src="https://npmcdn.com/chart.js#2.9.4/dist/Chart.bundle.min.js"></script>
<script src="https://unpkg.com/chartjs-plugin-crosshair#1.1.6/dist/chartjs-plugin-crosshair.js"></script>
</body>
</html>
If you are using V3 of the lib you will need to use a custom own plugin
Example:
// Options for the indicators
const indicatorOptions = {
radius: 4, borderWidth: 1, borderColor: 'red', backgroundColor: 'transparent'
};
// Override getLabelAndValue to return the interpolated value
const getLabelAndValue = Chart.controllers.line.prototype.getLabelAndValue;
Chart.controllers.line.prototype.getLabelAndValue = function(index) {
if (index === -1) {
const meta = this.getMeta();
const pt = meta._pt;
const vScale = meta.vScale;
return {
label: 'interpolated',
value: vScale.getValueForPixel(pt.y)
};
}
return getLabelAndValue.call(this, index);
}
// The interaction mode
Chart.Interaction.modes.interpolate = function (chart, e, option) {
const x = e.x;
const items = [];
const metas = chart.getSortedVisibleDatasetMetas();
for (let i = 0; i < metas.length; i++) {
const meta = metas[i];
const pt = meta.dataset.interpolate({ x }, "x");
if (pt) {
const element = new Chart.elements.PointElement({...pt, options: {...indicatorOptions}});
meta._pt = element;
items.push({element, index: -1, datasetIndex: meta.index });
} else {
meta._pt = null;
}
}
return items;
};
// Plugin to draw the indicators
Chart.register({
id: 'indicators',
afterDraw(chart) {
const metas = chart.getSortedVisibleDatasetMetas();
for (let i = 0; i < metas.length; i++) {
const meta = metas[i];
if (meta._pt) {
meta._pt.draw(chart.ctx);
}
}
},
afterEvent(chart, args) {
if (args.event.type === 'mouseout') {
const metas = chart.getSortedVisibleDatasetMetas();
for (let i = 0; i < metas.length; i++) {
metas[i]._pt = null;
}
args.changed = true;
}
}
})
var ctx = document.getElementById("myChart").getContext("2d");
var chart = new Chart(ctx, {
type: "line",
data: {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [
{
fill: true,
label: "My First dataset",
backgroundColor: "rgba(132, 0, 0, 1)",
borderColor: "rgb(255, 99, 132)",
data: [0, 10, 5, 2, 20, 30, 45]
},
{
data: [30, 40, 50],
label: 'My Second Dataset',
fill: true,
backgroundColor: "lightgreen",
borderColor: "green"
}
]
},
options: {
interaction: {
mode: "interpolate",
intersect: false,
axis: "x"
},
plugins: {
tooltip: {
position: 'nearest',
displayColors: false,
}
}
},
});
.myChartDiv {
max-width: 600px;
max-height: 400px;
}
<h1>Interpolating line values</h1>
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.3.2/chart.js"></script>
</div>

ChartJS with ChartJS DataLabels: Change Color per Dataset for Value Labels

I'm using ChartJS with the plug-in ChartJS DataLabels to show text values right next to the points (who would have thought that a plugin is necessary for this basic task, but I digress).
My issue I need to vary the color of my text labels along with the individual dataset. But so far I haven't found a solution. I'm adding new datasets dynamically, they're not statically pre-loaded. The color should match the color of the dataset.
Suppose I have
var colorpalette = ["red", "blue", "green", "magenta", "yellow", "brown", "purple", "orange", "black", "gray"];
var currseriesnum = 0;
var chart = null;
function setUpChart() {
var ctx = document.getElementById('chartArea').getContext('2d');
chart = new Chart(ctx, {
type: 'line',
data: {
labels: monthnames,
datasets: [] // Initially blank - series added dynamically with chart.update()
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
plugins: { // ChartsJS DataLabels initialized here
datalabels: {
anchor: 'end',
align: 'bottom',
formatter: Math.round,
font: {
weight: 'bold',
size: 16
},
color: colorpalette[currseriesnum] // Pick color dynamically
}
}
}
});
}
Doesn't work. Also tried a function, color: function(context), but unsure how to retrieve the current index of the dataset I'm getting here.
I'm adding series to the chart dynamically (initially empty) as below, and incrementing the global var currseriesnum.
chart.data.datasets.push({
label: keyValueSelection.label,
fill: false,
data: keyValueSelection.value,
borderColor: colorpalette[currseriesnum],
borderWidth: 2
});
chart.update();
currseriesnum++;
They gave me the answer on the ChartJS DataLabels forum:
plugins: {
datalabels: {
color: function(ctx) {
// use the same color as the border
return ctx.dataset.borderColor
}
}
}

Chart.js v2 hide dataset labels

I have the following code to create a graph using Chart.js v2.1.3:
var ctx = $('#gold_chart');
var goldChart = new Chart(ctx, {
type: 'line',
data: {
labels: dates,
datasets: [{
label: 'I want to remove this Label',
data: prices,
pointRadius: 0,
borderWidth: 1
}]
}
});
The code looks simple, but I cannot remove the label from the graph. I tried a lot of solutions I found online, but most of them use Chart.js v1.x.
How can I remove the dataset labels?
Just set the label and tooltip options like so
...
options: {
legend: {
display: false
},
tooltips: {
callbacks: {
label: function(tooltipItem) {
return tooltipItem.yLabel;
}
}
}
}
Fiddle - http://jsfiddle.net/g19220r6/
As of 2021, the namespace has changed from options.legend to options.plugins.legend. This simple code worked for me -
options: {
plugins: {
legend: {
display: false
}
}
}
Documentation reference
add:
Chart.defaults.global.legend.display = false;
in the starting of your script code;
New Solution ChartJS v3.1.1
The above solution is correct for previous versions of chart js prior to v3.1 for v3.1.1 use the following
...
options: {
plugins:{
legend: {
display: false
}
}
}
For those who want to remove the actual axis labels and not just the legend in 2021 (Chart.js v.3.5.1). Note: this also removes the axes.
const chartWrap = document.querySelector('.chart-wrap')
const canvas = document.createElement('canvas')
chartWrap.appendChild(canvas)
const ctx = canvas.getContext('2d')
const myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['Your', 'axis', 'labels'],
datasets: [
{
label: 'Your legend label',
data: [1, 3, 2],
backgroundColor: '#54ACEF'
}
]
},
options: {
maintainAspectRatio: false,
plugins: {
legend: false // Hide legend
},
scales: {
y: {
display: false // Hide Y axis labels
},
x: {
display: false // Hide X axis labels
}
}
}
})
<div class="chart-wrap" style="width: 200px; height: 100px;"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js" integrity="sha512-Wt1bJGtlnMtGP0dqNFH1xlkLBNpEodaiQ8ZN5JLA5wpc1sUlk/O5uuOMNgvzddzkpvZ9GLyYNa8w2s7rqiTk5Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
You can also put the tooltip onto one line by removing the "title":
this.chart = new Chart(ctx, {
type: this.props.horizontal ? 'horizontalBar' : 'bar',
options: {
legend: {
display: false,
},
tooltips: {
callbacks: {
label: tooltipItem => `${tooltipItem.yLabel}: ${tooltipItem.xLabel}`,
title: () => null,
}
},
},
});
It's just as simple as adding this:
legend: {
display: false,
}
Or if you want you could use this other option which should also work:
Chart.defaults.global.legend.display = false;``
new Chart('idName', {
type: 'typeChar',
data: data,
options: {
legend: {
display: false
}
}
});
Replace options with this snippet, will fix for Vanilla JavaScript Developers
options: {
title: {
text: 'Hello',
display: true
},
scales: {
xAxes: [{
ticks: {
display: false
}
}]
},
legend: {
display: false
}
}