I'm trying to find the way how to show tooltip when user hovers the legend in Chart.js library. I have found several issues but none of them was solved.
https://github.com/chartjs/Chart.js/issues/4023
Chart.js - show tooltip when hovering on legend
Does anybody have any idea how to manage that? Thank you
This is quite straightforward using the onHover callback.
Below is a snippet with a crude implementation but it is illustrative of the technique required.
let hovering = false,
tooltip = document.getElementById("tooltip"),
tooltips = ["such tooltip", "blah blah"],
mychart = new Chart(document.getElementById("chart"), {
type: "bar",
data: {
labels: ['a', 'b', 'c'],
datasets: [{
label: "series 1",
data: [1, 2, 3]
}, {
label: "series 2",
data: [1, 2, 3]
}]
},
options: {
legend: {
onHover: function(event, legendItem) {
if (hovering) {
return;
}
hovering = true;
tooltip.innerHTML = tooltips[legendItem.datasetIndex];
tooltip.style.left = event.x + "px";
tooltip.style.top = event.y + "px";
},
onLeave: function() {
hovering = false;
tooltip.innerHTML = "";
}
}
}
});
#tooltip {
background-color: #000;
color: #fff;
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<canvas id="chart"></canvas>
<div id="tooltip"></div>
Related
I need the value of chart show after name of data for example ([colour of data] Car 50, [colour of data] Motorcycle 200). I've tried change the value of legend title but it doesn't work at all
Here is it my code:
var ctx = document.getElementById('top-five').getContext('2d');
var myChartpie = new Chart(ctx, {
type: 'pie',
data: {
labels: {!! $top->pluck('name') !!},
datasets: [{
label: 'Statistics',
data: {!! $top->pluck('m_count') !!},
backgroundColor: {!! $top->pluck('colour') !!},
borderColor: {!! $top->pluck('colour') !!},
}]
},
options: {
plugins: {
legend: {
display: true,
title: {
text: function(context) {//I've tried to override this but doesn't work
var value = context.dataset.data[context.dataIndex];
var label = context.label[context.dataIndex];
return label + ' ' + value;
},
}
},
},
responsive: true,
}
});
You can use a custom generateLabels function for this:
var options = {
type: 'doughnut',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
}]
},
options: {
plugins: {
legend: {
labels: {
generateLabels: (chart) => {
const datasets = chart.data.datasets;
return datasets[0].data.map((data, i) => ({
text: `${chart.data.labels[i]} ${data}`,
fillStyle: datasets[0].backgroundColor[i],
index: i
}))
}
}
}
}
}
}
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.5.1/chart.js"></script>
</body>
The below is a direct over ride of the default label generation found in the controller here. I have made one change on the text property within the generateLabels function in order to append the data value. It preserves the data toggling and strikethrough styling when a label is toggled.
plugins: {
legend: {
labels: {
generateLabels(chart) {
const data = chart.data;
if (data.labels.length && data.datasets.length) {
const {labels: {pointStyle}} = chart.legend.options;
return data.labels.map((label, i) => {
const meta = chart.getDatasetMeta(0);
const style = meta.controller.getStyle(i);
return {
text: `${label}: ${data['datasets'][0].data[i]}`,
fillStyle: style.backgroundColor,
strokeStyle: style.borderColor,
lineWidth: style.borderWidth,
pointStyle: pointStyle,
hidden: !chart.getDataVisibility(i),
// Extra data used for toggling the correct item
index: i
};
});
}
return [];
}
},
onClick(e, legendItem, legend) {
legend.chart.toggleDataVisibility(legendItem.index);
legend.chart.update();
}
}
//...
}
[1]: https://github.com/chartjs/Chart.js/blob/master/docs/samples/legend/html.md
You can also use the base implementation to reduce the amount of copied code. Note that some chart types (like donut) already overrides the default label generation.
plugins: {
legend: {
labels: {
generateLabels: function (chart) {
return Chart.defaults.plugins.legend.labels.generateLabels(chart).map(function (label) {
var dataset = chart.data.datasets[label.datasetIndex];
var total = 0;
for (var j = 0; j < dataset.data.length; j++)
total += dataset.data[j].y;
label.text = dataset.label + ': ' + total;
return label;
});
}
}
}
}
I have a bar chart that always shows 4 bars. The bars are coloured dynamically. It looks like the coloured box takes its colour from the first data. I would like to use the colour from the 4th (last) data value. Maybe the options:plugins:legend:label:sort function helps but I don't understand what it does.
options
const options = {
scales: {
x: {
grid: {
display: false,
color: 'rgba(0,0,0)'
}
},
y: {
display: false,
min: 0,
max: 4
},
},
plugins: {
legend: {
position: 'bottom'
}
}
}
So I don't know if I can change the data that the box color comes from, or if there is a config option somewhere where I can change it manually.
You can use the generateLabels function as described here.
Please take a look at below runnable sample code and see how it works.
new Chart('myChart', {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow'],
datasets: [{
label: 'My Dataset',
data: [300, 50, 100],
backgroundColor: ['#FF6384', '#36A2EB', '#FFCE56']
}]
},
options: {
responsive: false,
plugins: {
legend: {
labels: {
generateLabels: chart => {
let ds = chart.data.datasets[0];
let color = ds.backgroundColor[ds.backgroundColor.length - 1];
return [{
datasetIndex: 0,
text: ds.label,
fillStyle: color,
strokeStyle: color
}];
}
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<canvas id="myChart" height="180"></canvas>
Following up with #uminder's answer, if you want to keep the hide/show chart and the line-through style after clicking on the legend, you can add the following line:
options: {
responsive: false,
plugins: {
legend: {
labels: {
generateLabels: chart => {
let ds = chart.data.datasets[0];
let color = ds.backgroundColor[ds.backgroundColor.length - 1];
return [{
datasetIndex: 0,
text: ds.label,
fillStyle: color,
strokeStyle: color,
+ hidden: !chart.isDatasetVisible(0)
}];
}
}
}
}
}
I'm using chartjs to generate a bar chart, and one of the requirements is to have the x-axis labels appear at the top of the chart rather than the bottom. (Even though I disagree with this, apparently there is no leeway from the client) and I'm having trouble following the documentation and any examples I find are for older versions.
The relative packages I'm using are:
"chart.js": "^3.7.1",
"react-chartjs-2": "^4.0.0",
Secondly they want the labels to wrap rather being a single line based on bar width, since it's responsive. I was experimenting with using arrays to break up the words as an example, but wondering if this can be done within chartjs. Here is the code I have setup so far (I had to use some lorem ipsum cause of sensitive data):
import * as React from 'react';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
ChartOptions
} from 'chart.js';
import { Bar } from 'react-chartjs-2';
import { Chart } from 'react-chartjs-2';
ChartJS.register(
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend
);
// added as an example. if there is a negative value, the bar color changes.
const generateBgColors = (data : number[]) => {
const bgColors = [];
for(let i = 0; i < data.length; i++) {
const value = data[i];
if(value > 0) {
bgColors.push('rgba(53, 162, 235, 0.5)');
} else {
bgColors.push('rgba(255, 99, 132, 0.5)');
}
}
return bgColors;
}
const options = {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
display: false
}
},
scales: {
}
}
var data = [2.0, -2.0, 0.5, 1.5];
const labels = [
['Lorem ipsum dolor sit amet,', ' consectetur adipiscing elit.', ' Integer eget auctor felis.'],
['label2'],
['label3'],
['label4'],
];
const chartData = {
labels: labels,
datasets: [
{
data: [2.0, -2.0, 0.5, 1.5],
backgroundColor: generateBgColors(data)
}
]
}
const BeliefsChart : React.FunctionComponent = (props) => {
const chartRef = React.useRef<ChartJS>(null);
return (
<React.Fragment>
<Chart type="bar" ref={chartRef} options={options} data={chartData} height={50} />
</React.Fragment>
);
}
To make the labels appear on top in V3 of chart.js you need to specify the position to top in options.scales.x like so:
options: {
scales: {
x: {
position: 'top'
}
}
}
To achieve multi line labels you will need to define your labels array as arrays for the the labels that have to be multi lined. Each entry in the nested arrray will be a new line
labels = ['singel line', ['line 1', 'line 2'], ['line 1', 'line 2', 'line3']]
Live Example:
const options = {
type: 'bar',
data: {
labels: ['singel line', ['line 1', 'line 2'], ['line 1', 'line 2', 'line3']],
datasets: [{
label: '# of Votes',
data: [12, 19, 3],
backgroundColor: 'orange'
},
{
label: '# of Points',
data: [7, 11, 5],
backgroundColor: 'pink'
}
]
},
options: {
scales: {
x: {
position: 'top'
}
}
}
}
const 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.7.1/chart.js"></script>
</body>
Apologies in advance since I'm not familiar with Typescript, but hopefully the following answers will be of help to you regardless.
To position the x-axis labels, try adding the following scales details to your options:
const options = {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
display: false
}
},
scales: {
xAxes: [{
position: "top"
}]
}
}
I don't know if it's possible to make the labels wrap, but an alternative responsive solution might be to use a variable for the fontSize of the ticks (labels) and vary the fontSize value based on the size of the screen using a media query. For example:
import { useMediaQuery } from "react-responsive";
const isMobile = useMediaQuery({ query: '(max-width: 480px)' });
const responsiveFontSize = isMobile ? 12 : 16;
const options = {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
display: false
}
},
scales: {
xAxes: [{
position: "top"
}]
ticks: {
fontSize: responsiveFontSize,
}
}
}
I am trying to add percentage to pie chart in ChartJS 3.2.1
All the answers and code I have found from extensive searching reference ChartJS version 1 or 2.
Including This question and This question and this question which all fail or do not actually change any tooltip display.
There is numerous reference to https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#0.7.0 but this doesn't work on ChartJS v3; I have installed the ChartJS Datalabels for Version 3 from here:
https://github.com/chartjs/chartjs-plugin-datalabels/releases/tag/v2.0.0
but using This answer still does not work.
I can not see on the ChartJS Datalabels Plugin documentation how to implement what I'm looking for.
I am looking for the percentage for each piece of the pie to be shown on the tooltip hover OR on the pie piece itself, but not on the label/legend.
I can't see anything on the ChartJS Tooltip documentation about how to actually edit the textual content of the tooltip.
So, my code:
JS:
var dnct1 = document.getElementById('DoeNut1');
var myChart1 = new Chart(dnct1, {
type: 'doughnut',
data: {
labels: ["Scotland and Northern Ireland","North East England","North West","Midlands","East Anglia","South England"],
datasets: [{
label: ["Scotland and Northern Ireland","North East England","North West","Midlands","East Anglia","South England"],
data: ["510","887","720","837","993","774","977"],
borderWidth: 0,
hoverOffset: 5,
backgroundColor: ['#F3AC16','#9F9F9F','#FF3355', '#55EE22','#354D73','#553FCF'],
cutout: 0
}]
},
options: {
tooltips: {
enabled: true,
},
layout: {
padding: {
bottom: 25
}
},
plugins: {
/** Imported from a question linked above.
Apparently Works for ChartJS V2 **/
datalabels: {
formatter: (value, dnct1) => {
let sum = 0;
let dataArr = dnct1.chart.data.datasets[0].data;
dataArr.map(data => {
sum += data;
});
let percentage = (value*100 / sum).toFixed(2)+'%';
return percentage;
},
color: '#ff3'
}
}
}
});
HTML:
<div class='chartBox'>
<h2>Title</h2>
<canvas id='DoeNut1'></canvas>
</div>
The above no browser console errors are returned and all charts display correctly but the tooltips don't show any percentages. I can't see what's wrong.
If you are using ChartJS v3 then I got it to work without any additional plugins. I overrode the tooltip at the dataset level.
datasets: [{
label: 'Industries',
data: [1, 5, 10, 14, 15],
tooltip: {
callbacks: {
label: function(context) {
let label = context.label;
let value = context.formattedValue;
if (!label)
label = 'Unknown'
let sum = 0;
let dataArr = context.chart.data.datasets[0].data;
dataArr.map(data => {
sum += Number(data);
});
let percentage = (value * 100 / sum).toFixed(2) + '%';
return label + ": " + percentage;
}
}
}
}]
To use the datalabels plugin you will need to register it also please read the migration guide (https://www.chartjs.org/docs/master/getting-started/v3-migration.html) first because you are using v2 syntax for your tooltip for example which wont work.
To get the percentage in the tooltip you can use any of the callbacks (https://www.chartjs.org/docs/master/configuration/tooltip.html#tooltip-callbacks) see example below for datalabels and the footer callback to display the percentages:
var dnct1 = document.getElementById('DoeNut1');
var myChart1 = new Chart(dnct1, {
type: 'doughnut',
data: {
labels: ["Scotland and Northern Ireland", "North East England", "North West England", "North Wales and West Midlands", "East Midlands and East Anglia", "South Wales and South West England", "South East England"],
datasets: [{
label: ["Scotland and Northern Ireland", "North East England", "North West England", "North Wales and West Midlands", "East Midlands and East Anglia", "South Wales and South West England", "South East England"],
data: ["510", "887", "720", "837", "993", "774", "977"],
borderWidth: 0,
hoverOffset: 5,
backgroundColor: ['#F3AC16', '#9F9F9F', '#FF3355', '#55EE22', '#354D73', '#666633', '#553FCF'],
cutout: 0
}]
},
options: {
layout: {
padding: {
bottom: 25
}
},
plugins: {
tooltip: {
enabled: true,
callbacks: {
footer: (ttItem) => {
let sum = 0;
let dataArr = ttItem[0].dataset.data;
dataArr.map(data => {
sum += Number(data);
});
let percentage = (ttItem[0].parsed * 100 / sum).toFixed(2) + '%';
return `Percentage of data: ${percentage}`;
}
}
},
/** Imported from a question linked above.
Apparently Works for ChartJS V2 **/
datalabels: {
formatter: (value, dnct1) => {
let sum = 0;
let dataArr = dnct1.chart.data.datasets[0].data;
dataArr.map(data => {
sum += Number(data);
});
let percentage = (value * 100 / sum).toFixed(2) + '%';
return percentage;
},
color: '#ff3',
}
}
},
plugins: [ChartDataLabels]
});
<body>
<canvas id="DoeNut1" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.0/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0-rc.1/chartjs-plugin-datalabels.js" ></script>
</body>
Is there any way to generate bar colours dynamically in ZingChart?
in screen-shot there is two colours generated in bar chart, i want to get list of colors used in bar chart.
html file
<zingchart id="timesheet-bar-chart" zc-values="barValues" zc- json="myObj"></zingchart>
controller
$scope.myObj = {
"type": "bar",
"plot":{
"stacked":true,
"stack-type":"normal" /* Optional specification */
},
"scale-x":{
"transform":{
"type":"date",
"all":"%d %M",
"item": {
"visible":false
}
},
"values":$scope.bar_x_axis,
},
};
and barValues is a list of integer values.
Since your question is asking how to get the bar colors, not set the bar colors. I thought my answer would be appropriate as well.
You can use the API to getobjectinfo from the chart.
demo here
$scope.myRender = {
events : {
complete : function(p) {
var info1 = zingchart.exec(p.id, 'getobjectinfo', {
object : 'plot',
plotindex: 0
});
var info2 = zingchart.exec(p.id, 'getobjectinfo', {
object : 'plot',
plotindex: 1
});
console.log(info1, info2);
}
}
}
If youre confused on the $scope.myRender variable you can read up more on the angular directive here.
You can set the colors like this,
$scope.myJson = {
'plot': {
'styles': ['#yellow', 'red', 'blue']
},
'scale-x': {
'values': ['white', 'red', 'pink']
},
'type': 'bar',
'series': [{
'text': 'Product History Color',
'values': [2, 6, 8]
}]
}
DEMO
You can specify the colors, fonts etc by yourself.
e.g.
scaleX: {
labels: ['Facebook','Apple', 'Microsoft', 'Intel','Google', 'Amazon'],
item: {
fontFamily: "Roboto",
fontSize: 14
},
lineColor: "#DDD",
tick:{
visible: false
}
},