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;
});
}
}
}
}
Related
I've got a line chart that has a tooltip on each data point. The data are prices so I want to add a euro sign before them but this seems harder than it sounds.
My code:
const labelsjaar = [
'jan',
'feb',
'mrt',
'apr',
'mei',
'jun',
'jul',
'aug',
'sept',
'okt',
'nov',
'dec',
];
const datajaar = {
labels: labelsjaar,
datasets: [{
label: 'Omzet',
backgroundColor: 'rgb(230 0 126)',
borderColor: 'rgb(230 0 126)',
data: [0,0,0,0,0,0,0,24,177,590.44,801.38,98.62],
}]
};
Chart.defaults.font.family = 'Panton';
Chart.defaults.font.size = 16;
const configjaar = {
type: 'line',
data: datajaar,
options: {
maintainAspectRatio: false,
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
label: function (tooltipItems, data) {
var i = tooltipItems.index;
return data.labels[i] + ': ' + data.datasets[0].data[i] + ' €';
}
}
}
}
};
const myChartjaar = new Chart(
document.getElementById('myChartjaar'),
configjaar
);
I found this solution online:
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
label: function (tooltipItems, data) {
var i = tooltipItems.index;
return data.labels[i] + ': ' + data.datasets[0].data[i] + ' €';
}
}
}
But my tooltips remain unchanged, there is no euro sign to be seen.
What am I doing wrong?
A jsfiddle of my chart can be seen here: https://jsfiddle.net/r4nw91bo/
After the comment below that I was looking at the wrong documentation I tried the following:
const labeltext = (tooltipItems) => {
tooltipItems.forEach(function(tooltipItem) {
tooltiplabel = '€' + tooltipItem.parsed.y.toLocaleString();
});
return tooltiplabel;
};
const configjaar = {
type: 'line',
data: datajaar,
options: {
plugins:{
tooltip:{
callbacks: {
label: labeltext,
}
}
},
maintainAspectRatio: false,
}
};
But this gives me the error: tooltipItems.forEach is not a function. If instead of label I use footer or title it works perfectly, but I don't want to add a title or a footer to my tooltip, I want to replace the existing content with my added € sign.
I also tried using their example for adding a dollar sign like this:
const configjaar = {
type: 'line',
data: datajaar,
options: {
plugins:{
tooltip:{
callbacks: {
label: function(context) {
const label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
label += new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(context.parsed.y);
}
return label;
}
}
}
},
maintainAspectRatio: false,
}
};
But on hover of a data point this gives an error: Assignment to constant variable.
This is because you are using V2 syntax in V3, V3 has some major breaking changes over V2. Please read the migration guide for all of them.
For your callback to work you need to define it in options.plugins.tooltip.callbacks.label
EDIT:
Like the error says you are getting you can't reassign a constant variable since its a constant. If you change it to a let it works fine:
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink'
}]
},
options: {
plugins: {
tooltip: {
callbacks: {
label: function(context) {
let label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
label += new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(context.parsed.y);
}
return label;
}
}
}
},
}
}
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.6.0/chart.js"></script>
</body>
I'm using Chart JS version 3.5.1, and I can't get the onHover function to work. My goal is to have the user hover or a data point, and then have the dataset values available to me inside the onHover.
Here's my setup:
var context = document.getElementById('canvas').getContext('2d')
var options = {
onHover: function(evt) {
console.log(evt)
var item = myChart.getElementAtEvent(evt)
console.log(item)
},
interaction: {
mode: 'index',
intersect: false,
},
plugins: {
legend: {
display: false,
}
},
responsive: true,
maintainAspectRatio: false
}
var myChart = new Chart(context, {
type: 'line',
data: {
labels: obj.labels,
datasets: [...]
},
options: options
})
I'm getting and error on this line:
var item = myChart.getElementAtEvent(evt)
The error says:
myChart.getElementAtEvent is not a function
I have confirmed that myChart is an object, but there doesn't appear to be a getElementAtEvent function.
I also tried the example in the docs here:
const canvasPosition = Chart.helpers.getRelativePosition(e, chart);
// Substitute the appropriate scale IDs
const dataX = chart.scales.x.getValueForPixel(canvasPosition.x);
const dataY = chart.scales.y.getValueForPixel(canvasPosition.y);
But it says:
Cannot read property 'getValueForPixel' of undefined
Does anyone know how I can successfully use onHover with version 3.5.1 of Chart JS?
You are using chart.js v3, in v3 there is no getElementAtEvent, it has been replaced with getElementsAtEventForMode. You can use this to get the active elements but you can also use the second argument the onHover function recieves which is an array with all the active elements:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderColor: 'orange'
}
]
},
options: {
onHover: (evt, activeEls, chart) => {
if (activeEls.length === 0 || chart.getElementsAtEventForMode(evt, 'nearest', {
intersect: true
}, true).length === 0) {
return;
}
console.log('Function param: ', activeEls[0].index);
console.log('lookup with the event: ', chart.getElementsAtEventForMode(evt, 'nearest', {
intersect: true
}, true)[0].index);
activeEls.forEach(point => {
console.log('val: ', chart.data.datasets[point.datasetIndex].data[point.index])
})
}
}
}
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>
I have a flask app that utilizes chart.js,
live app can viewed here: https://flaskapp.gullp.repl.co/
I'm trying to pull the clicked value from the chart and put it into a variable that resides outside of the chart function.
Here is my chart logic:
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: /* {{ labels }}*/ ['Big Home', 'Medium Home', 'Small Home'] ,
datasets: [{
label: 'count per label',
data: /*{{ values }} */ [3,2,1]
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
//below allows you to click the chart and get the respective value. you will pass this value to python
,onClick: function(c,i) {
e = i[0];
//console.log(e._index)
var x_value = this.data.labels[e._index];
var y_value = this.data.datasets[0].data[e._index];
// console.log(x_value);
//console.log(y_value);
console.log('you clicked the graph, now the x value is = ' + x_value)
console.log('since you clicked, this is the chart clicked data = ' + JSON.stringify(chart_clicked_data) )
document.querySelectorAll("tr").forEach((tr, i) => {
if(i === 0){
// skip column names
return
}
if(tr.children[0].innerText != x_value){
tr.style.display = 'none';
}else {
tr.style.display = 'table-row';
}
})
}
}
});
Here is my code trying to extract the x-value:
var chart_clicked_data = { 'score' : myChart.options.x_value}
console.log('this is the json chart clicked data that we want to pass back to flask = ' + JSON.stringify(chart_clicked_data) )
seems like this is not doing the trick:
myChart.config.options.x_value
when i check the console after i click the value, its not showing to be picking up.
entire live code here:
https://repl.it/join/rbkobiqi-gullp
Add an variable outside of your chartFunctions, set that variable in the click handler and then use it
let xVal = ''
var options = {
type: 'bar',
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: {
onClick: function(c, i) {
e = i[0];
//console.log(e._index)
var x_value = this.data.labels[e._index];
var y_value = this.data.datasets[0].data[e._index];
// console.log(x_value);
//console.log(y_value);
console.log('you clicked the graph, now the x value is = ' + x_value)
xVal = x_value
},
scales: {
yAxes: [{
ticks: {
reverse: false
}
}]
}
}
}
document.getElementById('temp').addEventListener('click', () => {
console.log('X val: ', xVal);
alert('X val: ' + xVal)
})
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
canvas {
background-color: #eee;
}
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<button id="temp">
show pressed X value
</button>
<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>
I have successfully displayed the value, but why is only one value displayed? I want the value in sequence
This my code
/*my datasets code*/
datasets: [{
label: 'Daily Data',
data: [730000, 1012000, 1220000, 1831000, 560000, 2012000, 890000],
borderColor: '#3f89fb',
borderWidth: 3,
fill: false
}]
/*my tooltips code*/
tooltips: {
callbacks: {
label: function(tooltipItem, chart) {
for (var i = 0; i < chart.datasets[0].data.length; i++) {
return chart.datasets[0].data[i] / 1e6 + 'M';
}
}
}
}
and this my result, all day value is 0.73M
Look in the Tooltip Item Documentation.
In your case tooltipItem.index contains the index of this data item in the dataset. So you can return the value doing so:
function(tooltipItem, chart) {
return chart.datasets[0].data[tooltipItem.index] / 1e6 + 'M';
}
And here is the demo:
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: 'Daily Data',
data: [730000, 1012000, 1220000, 1831000, 560000, 2012000, 890000],
borderColor: '#3f89fb',
borderWidth: 3,
fill: false
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
},
tooltips: {
callbacks: {
label: function(tooltipItem, chart) {
return chart.datasets[0].data[tooltipItem.index] / 1e6 + 'M';
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="myChart" width="400" height="400"></canvas>
Instead of return inside for loop which will exit the loop, you can save your results somewhere like below
var result = []
for (var i = 0; i < chart.datasets[0].data.length; i++) {
result.push(chart.datasets[0].data[i] / 1e6 + 'M');
}
This is because return stops execution and exits the function. return always exits its function immediately, with no further execution if it's inside a loop.
See this answer:
Does return stop a loop?
How do I modify an existing legend in Chart.js?
I've seen complex methods of creating a custom HTML legend (using generateLegend or legendCallback), and a simple method of options.legend.legendText which should accept an array, but saw no change so assumed that was for version 1.
I'm looking to add text to the default legend:
type: 'doughnut',
data: {
datasets: [{
data: series,
}],
labels: labels,
},
options: {
legend: {
legendText = labels.map((label, index) => `${label} - ${series[index]}%`);
}
}
Edit:
I noticed that if the chart was redrawn (e.g. if the browser window is resized) the legend would lose the extra text.
I've modified the approach to work as an inline plugin so that the label object is modified before the legend is drawn.
let labels = ['a', 'b', 'c', 'd'],
series = [4, 2, 1, 3],
myChart = new Chart(document.getElementById('chart'), {
type: 'doughnut',
data: {
labels: labels,
datasets: [{
data: series,
backgroundColor: ['red', 'blue', 'green', 'orange']
}]
},
options: {
maintainAspectRatio: false
},
plugins: [{
afterLayout: function(chart) {
let total = chart.data.datasets[0].data.reduce((a, b) => {
return a + b;
});
chart.legend.legendItems.forEach(
(label) => {
let value = chart.data.datasets[0].data[label.index];
label.text += ' - ' + (value / total * 100).toFixed(0) + '%'
return label;
}
)
}
}]
});
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="chart"></canvas>
Chart.js 3.xx
I've included a sample for version 3.5 too.
You can alter the legend text by overriding the generateLabels method.
let labels = ['a', 'b', 'c', 'd'],
series = [4, 2, 1, 3],
myChart = new Chart(document.getElementById('chart'), {
type: 'doughnut',
data: {
labels: labels,
datasets: [{
data: series,
backgroundColor: ['red', 'blue', 'green', 'orange']
}]
},
options: {
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: "bottom",
align: "center",
fontFamily: "Arial",
labels: {
usePointStyle: true,
fontColor: "red",
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: 'This is ' + label + ' - ' + chart.data.datasets[0].data[i],
fillStyle: style.backgroundColor,
strokeStyle: style.borderColor,
lineWidth: style.borderWidth,
pointStyle: pointStyle,
hidden: !chart.getDataVisibility(i),
index: i
};
});
}
return [];
}
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<canvas id="chart"></canvas>