Is there any way to expand the slice of donut chart onclick event or mouse hover in chartjs ?.
I am using chart.js#2.8.0 version.
I have fixed this issue using the following code:
let segment;
this.chart = new Chart(this.canvas, {
type: this.type,
data: this.data,
options: {
...this.options,
onHover: function (evt, elements) {
if (elements && elements.length) {
segment = elements[0];
this.chart.update();
selectedIndex = segment["_index"];
segment._model.outerRadius += 10;
} else {
if (segment) {
segment._model.outerRadius -= 10;
}
segment = null;
}
},
layout: {
padding: 30
}
}
});
I hope it helps you.
Shift-zooming the currently selected slice is not a feature but it has been discussed several times on various forums and the project's GitHub community:
https://forum.mendixcloud.com/link/questions/85582
https://github.com/chartjs/Chart.js/issues/1451
The Github discussion contains a fiddle someone wrote for a Pie chart with Chart.js 1.0. Here is an updated version for the current Chart.js version that supports Donut charts.
Code:
This part only shows the part that zooms the active element, it is just to give you the idea of how to use the active elements .innerRadius and .outerRadius properties to shift the element. The fiddle contains the complete code that also handles shrinking the previously selected element.
<div style="width:400px;">
<canvas id="myChart" width="200" height="200"></canvas>
</div>
var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
type: 'doughnut',
options: {
layout: {
padding: 30
}
},
data: {
labels: ['Red', 'Blue', 'Yellow'],
datasets: [
{
label: '# of Votes',
data: [4, 5, 3],
backgroundColor: [
'rgba(255, 0, 0, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)'
],
borderWidth: 3
}]
}
});
var addRadiusMargin = 10;
$('#myChart').on('click', function(event) {
var activePoints = myChart.getElementsAtEvent(event);
if (activePoints.length > 0) {
// update the newly selected piece
activePoints[0]['_model'].innerRadius = activePoints[0]['_model'].innerRadius +
addRadiusMargin;
activePoints[0]['_model'].outerRadius = activePoints[0]['_model'].outerRadius +
addRadiusMargin;
}
myChart.render(300, false);
}
Sample image:
Here is a sample of the highlighted slice:
Limitations:
There are two limitations of the sample that I haven't included:
Chart.js does not allow to define a margin between legend and chart content so when you are "zooming"/"moving", the zoomed slice might overlap parts of the legend. You may solve this by extending the legend as shown in Jordan Willis' Codepen which was the result of this SO question.
The selected slice will stay in contact with the remaining slices. If you want it to have a gap, you need to translate x and y of the active slice based on the .startAngle and .endAngleproperties of the active slice.
Another simple trick : hoverBorderWidth
var ctx = document.getElementById("chart").getContext('2d');
var chart = new Chart(ctx, {
type: 'pie',
data: {
labels: ["Microsoft Internet Explorer", "Google Chrome", "Mozilla Firefox", "Opera", "Safari"],
datasets: [{
label: 'Number of votes',
data: [60, 20, 10, 8, 5],
backgroundColor: ['#96ceff', '#424348', '#91ee7c', '#f7a35b', '#8286e9'],
borderColor: '#fff',
borderWidth: 1,
hoverBorderColor: ['#96ceff', '#424348', '#91ee7c', '#f7a35b', '#8286e9'],
hoverBorderWidth: 8
}]
},
options: {
responsive: false,
legend: {
display: false
},
tooltips: {
displayColors: false
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<canvas id="chart" width="350" height="350"></canvas>
Related
I am currently creating a LineChart with ChartJs that represents someone's profits. These can be positive or negative.
I want the lines above zero to be green and the lines below to be red. Also, the background must be red when the values are negative.
I have already seen solutions with previous versions of ChartJS on Stackoverflow, however I think with this new version there may be a more elegant version to solve this problem.
I am using version 4.2.0 of chartJs.
Here is what I have done so far following the documentation :
const lineChartData = {
labels: [
'01/22',
'02/22',
'03/22',
'04/22',
'05/22',
'06/22',
'07/22',
'08/22',
],
datasets: [
{
label: 'Profit',
data: [2.4, 2.6, 2.23, 1.2, -2.2, -3.6, -1, 0.2],
borderColor: '#0B9564',
pointBackgroundColor: 'transparent',
pointBorderColor: 'transparent',
borderJoinStyle: 'bevel',
fill: {
target: 'origin',
above: 'rgba(11, 149, 100, 0.08)',
below: 'rgba(218, 96, 96, 0.08)',
},
},
],
};
And here is the actual result:
Finally, here is a preview of what I would like it to look like. This is a mock-up, so it's not quite accurate.
Do you have any idea how I could reproduce this? It doesn't seem to me that in the documentation this problem is mentioned.
Out of the Box you won't be able to do this, the best would be something like in the example below (using the segementation styling, and a linear color gradient).
If you really need this exact look, you could check if someone has created a plugin, or create your own plugin (or inline plugin), that would override the normal rendering. (link to plugin documentation).
Here a demo, how I would do this:
(based on the configuration, you posted)
const lineChartData = {
labels: [
'01/22',
'02/22',
'03/22',
'04/22',
'05/22',
'06/22',
'07/22',
'08/22',
],
datasets: [
{
label: 'Profit',
data: [2.4, 2.6, 2.23, 1.2, -2.2, -3.6, -1, 0.2],
borderColor: '#0B9564',
pointBackgroundColor: 'transparent',
pointBorderColor: 'transparent',
borderJoinStyle: 'bevel',
fill: {
value: -25,
above: 'rgba(11, 149, 100, 0.08)'
},
segment: {
borderColor: ctx => segmentColor(ctx, '#0B9564', 'red')
}
},
],
};
function segmentColor(ctx, color1, color2){
if(ctx.p0.parsed.y < 0 && ctx.p1.parsed.y < 0 ) {
return color2;
} else if (ctx.p0.parsed.y < 0){
var gradient = myChart.ctx.createLinearGradient(ctx.p0.x, ctx.p0.y, ctx.p1.x, ctx.p1.y);
gradient.addColorStop(.5, color2);
gradient.addColorStop(1, color1);
return gradient
} else if (ctx.p1.parsed.y < 0){
var gradient = myChart.ctx.createLinearGradient(ctx.p1.x, ctx.p1.y, ctx.p0.x, ctx.p0.y);
gradient.addColorStop(.5, color2);
gradient.addColorStop(1, color1);
return gradient
}
return color1
}
const config = {
type: 'line',
data: lineChartData,
options: {
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right',
labels: {
usePointStyle: true,
},
}
},
}
};
var myChart = new Chart(
document.getElementById('chart'),
config
);
<script src="//cdn.jsdelivr.net/npm/chart.js"></script>
<div class="chart" style="height:184px; width:350px;">
<canvas id="chart" ></canvas>
</div>
I am trying to achieve the Tooltip shown below in the first image. Inside of the tooltip I need to display the yAxes and xAxes data. The chart.js version I am using is 3.7.0
My tooltip looks like this:
The tooltip that I am trying copy:
The chart.js documentation is quite hard for me to understand. Is there any guru that can explain to me.
Question: Why is my tooltip returning the yAxes data, that I return as a variable(label) as undefined?
Are there any other options I can use to make my chart look like the chart in the second picture?
My Code:
tooltip: {
displayColors: false,
backgroundColor: 'rgba(45,132,180,0.8)',
bodyFontColor: 'rgb(255,255,255)',
callbacks: {
title: function(item, everything){
return;
},
label: function(item, everything){
//console.log(item);
//console.log(everything);
let first = item.yLabel;
let second = item.xLabel;
let label = first + ' ppm';
return label;
}
}
}
Thank you in advance for your time and efforts, please help me figure out what am I doing wrong!
yLabel and xLabel dont exist anymore on the tooltip, they are V2 syntax.
You can just axess the y object in the parsed section to get the y value. Then you can use the afterBody callback to show the x label like so:
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: {
displayColors: false,
backgroundColor: 'rgba(45,132,180,0.8)',
bodyFontColor: 'rgb(255,255,255)',
callbacks: {
title: () => {
return
},
label: (ttItem) => (`${ttItem.parsed.y} ppm`),
afterBody: (ttItems) => (ttItems[0].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.7.0/chart.js"></script>
</body>
I use chart.js and I would like to display labels at the right of each bar but I got a problem with the first label.
I use the plugin chartjs-plugin-datalabels it work but the first label is hidden.
Do you know how to fix this?
https://jsfiddle.net/rq78pg4j/1/
var ctx4 = $('#chart_choice');
var chart_market = new Chart(ctx4, {
type: 'horizontalBar',
data: {
labels: ['Legend 1', 'Legend 2'],
datasets: [{
data: [12, 10],
label: '# of Votes',
backgroundColor: [
'rgba(243,212,205,1)',
'rgba(243,212,205,1)'
],
borderColor: [
'rgba(223,142,123,1)',
'rgba(223,142,123,1)'
],
borderWidth: 1
}]
},
options: {
plugins: {
datalabels: {
align: 'end',
anchor: 'end',
color: '#0B4892',
font: function(context) {
var w = context.chart.width;
return {
size: w < 512 ? 12 : 14,
weight: 'bold',
};
},
formatter: function(value, context) {
return context.chart.data.labels[context.dataIndex];
}
}
}
}
});
The problem is that Chart.js is not aware of what chartjs-plugin-datalabels is doing. Therefore, it doesn't reserve enough space at the right of the chart, allowing the labels of the largest bars to appear on the canvas.
This can be fixed by defining extra padding at the right of the chart as follows.
options: {
layout: {
padding: {
right: 100
}
},
...
For further details, please consult the page Layout Configuration from the Chart.js documentation.
SOLVED
Solution: Changed the spelling of axis to axes
I have just begun working with Chart.js as an alternative to the Python Plot.ly library.
So far I have been able to get the chart formatted the way I would like but there are still a couple of nuances I cant get right.
The first of which is that I cannot get any solution for adding a $ before Y-Axis values.
Here is my chart followed by the chart's code:
<script>
var ctx = document.getElementById("myChart").getContext('2d');
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var O1 = [1000,2000,3000,4000,5000,6000,7000,8000,9000,10000,11000,12000];
var O2 = [3000,6000,5000,3000,8000,6000,4000,7000,8000,0000,3000,1000];
var mychart = new Chart(ctx, {
type: 'line',
options: {
title:{
text: 'Test Chart',
display: true,
fontStyle: 'bold',
fontSize: 16,
},
legend:{
position: 'right',
},
scales:{
yAxis:[{
scaleLabel:{
display: true,
labelString: 'Tester',
},
ticks:{
callback: function(value, index, values) {
if(parseInt(value) >= 1000){
return '$' + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
} else {
return '$' + value;
}
}
}
}]
},
tooltips:{
callbacks: {
label: function(tooltipItem, data){
var dataLabel = data.labels[tooltipItem.index];
var value = ': $ ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].toLocaleString();
if (Chart.helpers.isArray(dataLabel)) {
dataLabel = dataLabel.slice();
dataLabel[0] += value;
} else {
dataLabel += value;
}
return dataLabel1;
}
}
}
},
data: {
labels: months,
datasets: [
{
label: 'Officer1',
data: O1,
fill: false,
backgroundColor: 'rgba(255, 99, 132)',
borderColor: 'rgba(255, 99, 132)',
},
{
label: 'Officer2',
data: O2,
fill: false,
backgroundColor: 'rgba(0,0,255)',
borderColor: 'rgba(0,0,255)',
}
]
}
});
</script>
As you may be able to see I would simply like to add a $ before my Y-Axis data values. The last solution I tried also broke the data up by 1000s.
Additional:
The next few issues I've come across are very minor, which is why I chose to include them here.
First I would like a way to center my title over the chart itself, rather than centered over the whole chart+legend item.
Second is I would like to add some space to the left of my legend, as to separate it more from the chart.
Lastly, my Y-Axis title will not display. I would like it to display here while im testing in case I need it in the future.
This issue was solved by changing the spelling of axis to axes...subtle
Change the spelling of axis to axes
I am trying to remove the small rectangle box on the left of the "legend" text "Score List" in this case, of the chart. I can not find anything in the docs that shows how to do that. Yes, I found how to remove the "legend" entirely, but that would causes the graphs of the bars to go too high in my chart design. Here is a sample code I have:
<!DOCTYPE html>
<html>
<head>
<title>ChartJS - BarGraph</title>
<style type="text/css">
#chart-container {
width: 300px;
height: 150px;
}
</style>
<!-- javascript -->
<script type="text/javascript" src="jquery-1.11.min.js"></script>
<script type="text/javascript" src="Chart.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
//url: "test.html",
//method: "GET",
success: function(data) {
// test data
var data = [
{
"Serverid":"1",
"score":"37"
},
{
"Serverid":"2",
"score":"60"
},
{
"Serverid":"3",
"score":"35"
},
{
"Serverid":"4",
"score":"41"
},
{
"Serverid":"5",
"score":"50"
},
{
"Serverid":"6",
"score":"70"
},
{
"Serverid":"7",
"score":"70"
},
{
"Serverid":"8",
"score":"70"
},
// ... it can be more than that
];
var Server = [];
var score = [];
for(var i in data) {
Server.push("Server " + data[i].Serverid);
score.push(data[i].score);
}
var chartdata = {
labels: Server,
datasets : [
{
label: 'Score List',
backgroundColor: [
// even color
'rgba(255, 99, 132, 0.2)',
// odd color
'rgba(75, 192, 192, 0.2)'
],
borderColor: [
// even color
'rgba(255,99,132,1)',
// odd color
'rgba(153, 102, 255, 1)'
],
borderWidth: 1,
hoverBackgroundColor: 'rgba(200, 200, 200, 1)',
hoverBorderColor: 'rgba(200, 200, 200, 1)',
data: score
}
]
};
var ctx = $("#mycanvas");
var barGraph = new Chart(ctx, {
type: 'bar',
data: chartdata,
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var ttip_value = data.datasets[0].data[tooltipItem.index];
if(ttip_value == 31) {
return "DOWN";
}else {
return "UP";
}
}
}
}
}
});
}, // end success
error: function(data) {
console.log(data);
alert(data);
}
}); // end ajax
});
</script>
</head>
<body>
<br> Bar Chart <br>
<div id="chart-container">
<canvas id="mycanvas" width="200" height="100"></canvas>
</div>
</body>
</html>
Thank you!
The easiest way to remove the legend colored boxes is to use the legend.labels.boxSize property and set it to 0 (this is documented in the chart.js API here). Here is a codepen example.
legend: {
labels: {
boxWidth: 0,
}
}
Keep in mind that there are not very many options for configuring the embedded legend (since it is actually rendered directly in the canvas object). If you later decide you would like to change the legend look and feel in a more significant way then it is easiest to create your own legend using normal HTMl/CSS and style it accordingly. You can achieve this by using the .generateLegend() prototype method.
Here is an example of a chart that is using a custom external legend.