Due to very poor documentation (https://www.chartjs.org/docs/latest/) I decided to ask Chart.js community this question.
How can I change the angle of the scale label?
This is my actual view
I would like to make those labels horizontal (see red labels how it should be).
The config is:
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: [this.label, this.valueUnit],
fontSize: 14,
},
afterFit: function(scaleInstance) {
scaleInstance.width = 120;
}
}]
You can define a second y-axis that is responsible for drawing the scale label horizontally.
The single yAxis.ticks label can be left aligned by defining mirror: true together with some padding.
ticks: {
mirror: true,
padding: 60,
...
To make the tick label visible on the chart area, the same padding needs to be defined left of the chart layout.
layout: {
padding: {
left: 60
}
},
Please take a look on the runnable code below and see hot it works.
new Chart(document.getElementById('myChart'), {
type: 'line',
data: {
labels: ['A', 'B', 'C', 'D'],
datasets: [{
data: [10, 12, 8, 6],
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgb(255, 99, 132)',
borderWidth: 1,
fill: false
}]
},
options: {
layout: {
padding: {
left: 60
}
},
legend: {
display: false
},
scales: {
yAxes: [{
},
{
ticks: {
stepSize: 0.5,
mirror: true,
padding: 60,
fontColor: 'red',
callback: v => v == 0.5 ? ['Horizontal', 'Label'] : undefined
},
gridLines: {
display: false
}
}
]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas id="myChart" height="50"></canvas>
The Plugin Core API offers a range of hooks that may be used for performing custom code. You can use the afterDraw hook to draw the scale label yourself directly on the canvas using CanvasRenderingContext2D.fillText().
afterDraw: chart => {
var ctx = chart.chart.ctx;
ctx.save();
let yAxis = chart.scales['y-axis-0'];
let y = yAxis.bottom / 2;
ctx.textAlign = 'left';
ctx.font = "14px Arial";
ctx.fillStyle = "gray";
ctx.fillText('Horizontal', 0, y - 8);
ctx.fillText('Label', 0, y + 8);
ctx.restore();
}
You'll also have to define some extra padding at the left of the chart to make sure, the scale label does not overlap the chart area.
options: {
layout: {
padding: {
left: 70
}
},
Please take a look at the following runnable code and see how it works.
new Chart(document.getElementById('myChart'), {
type: 'line',
plugins: [{
afterDraw: chart => {
var ctx = chart.chart.ctx;
ctx.save();
let yAxis = chart.scales['y-axis-0'];
let y = yAxis.bottom / 2;
ctx.textAlign = 'left';
ctx.font = "14px Arial";
ctx.fillStyle = "gray";
ctx.fillText('Horizontal', 0, y - 8);
ctx.fillText('Label', 0, y + 8);
ctx.restore();
}
}],
data: {
labels: ['A', 'B', 'C', 'D'],
datasets: [{
data: [10, 12, 8, 6],
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgb(255, 99, 132)',
borderWidth: 1,
fill: false
}]
},
options: {
layout: {
padding: {
left: 70
}
},
legend: {
display: false
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas id="myChart" height="50"></canvas>
There is no build in way to do this. If you want to achieve this behaviour you will have to draw it on the canvas yourself with an custom plugin
Related
I'm using the Datalabels plugin to provide labels to points on a Chart.js scatter graph.
My Chart.js / Datalabels configuration looks like this:
(Full example: https://codepen.io/LondonAppDev/pen/oNyReVr)
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'scatter',
data: {
datasets: [{
label: '# of Votes',
data: [
{x: 10, y: 10},
{x: 100, y: 100},
{x: 50, y: 50},
{x: 51, y: 51},
]
}]
},
plugins: [ChartDataLabels],
options: {
elements: {
point: {
radius: 5,
hoverRadius: 8
}
},
plugins: {
tooltip: {
enabled: false
},
datalabels: {
labels: {
value: {
align: 'top',
color: '#000',
borderColor: '#000',
borderWidth: 1,
offset: 20,
padding: 10,
backgroundColor: '#fff',
}
}
}
}
}
});
The default behaviour is that labels will overlap. I want to make the labels come to the forefront when they are hovered over. So if I hover over a label or point, it comes to the foreground.
I attempted to add this to options.plugins.datalabels.labels.value:
listeners: {
enter: function(context) {
context.dataIndex = 999;
context.datasetIndex = 999;
return true;
},
leave: function(context) {
context.dataIndex = 0;
context.datasetIndex = 0;
return true;
}
}
However it doesn't have the desired effect.
Anyone know how I can make the label come to the foreground on hover?
I am setting the startAngle on my polar chart so the first category starts on the -180 degrees.
But I can't figure out why the data point labels don't correspondingly adjust and rotate. As a result, they show up incorrectly against the wrong data. As you can see in the image, Question 6 still appears where Question 1 should be. The tooltips on each section do appear correctly.
Note: When I use the datalabels plugin, it does show the label correctly. But I am not using it because it does not wrap the labels and also it cuts off the labels if they become too big. In addition I had responsiveness problems with it.
So please suggest a solution without that plugin if possible.
Thank you very much for helping me out.
const mydata = {
labels: [
'Question1',
'Question2',
'Question3',
'Question4',
'Question5',
'Question6'
],
datasets: [{
label: 'Data labels don't move',
data: [5, 8, 6, 6, 7, 8],
backgroundColor: [
'rgb(255, 99, 132)',
'rgb(75, 192, 192)',
'rgb(255, 205, 86)',
'rgb(201, 203, 207)',
'rgb(255, 99, 132)',
'rgb(201, 203, 207)'
]
}]
};
var myChart = new Chart('mychartId'),
{
type: "polarArea",
data: mydata,
options:
{
responsive: true,
cutoutPercentage: 20,
startAngle: -1 * Math.PI,
legend: {
display: false
},
layout: {
padding: 20
},
scale: {
ticks: {
max: 10,
beginAtZero: true,
min: 1,
stepSize: 1,
display: false
},
angleLines: {
display: false
},
pointLabels: {
display: true
}
}
}
}
sample image showing the problem
Update to V3, there they do turn with the chart if you adjust the startAngle
var options = {
type: 'polarArea',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [2, 9, 3, 5, 2, 3],
borderWidth: 1
}]
},
options: {
scales: {
r: {
startAngle: 180,
ticks: {
display: false
},
pointLabels: {
display: true
}
}
}
}
}
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.6.0/chart.js"></script>
</body>
V3 has some breaking changes over V2, for all of them you can read the migration guide
I have the below Chart implemented using chart.js version 3.x.
https://jsfiddle.net/Lxya0u98/12/
I have multiple datasets in my charts to achieve the behavior I want.
I am facing an issue with the datasets overlapping. In the chart, I have end of the blue color line overlapping with the green color dot dataset. Is there a way to avoid this issue?
I have the below two datasets:
// Data set for the Big Dot
{
showLine: false,
borderWidth: 0,
lineTension: 0,
borderColor: colorVal,
backgroundColor: colorVal,
pointBackgroundColor: colorVal,
pointBorderColor: colorVal,
pointBorderWidth: 2,
pointRadius: 15,
};
// Data set for the Connecting Lines
{
showLine: true,
lineTension: 0,
borderWidth: 5,
borderColor: colorVal,
pointRadius: 0,
pointBorderWidth: 0,
spanGaps: true,
};
Is there a Z-Index for the Datasets so that they appear on top of the previous one in the stack?
The option dataset.order has similar effect as the z-index.
Datasets with higher order are drawn first
Datasets with no or lower order are drawn last, hence appear on top
Therefore, adding order: 1 to your line datasets should solve the problem.
var newDataLine = {
...
order: 1
};
Instead of defining multiple datasets, you could proceed as follows:
First convert your line chart into a scatter chart.
Then draw the lines directly on the canvas using the Plugin Core API. The API offers a range of hooks that may be used for performing custom code. You can use the beforeDraw hook to draw connection lines of different colors between data points and to the open end of the chart.
Note that you have to define xAxes.ticks.max in order to obtain the open end line at the right of the chart.
Please take a look at below runnable code snippet and see how it works.
new Chart('line-chart', {
type: "scatter",
plugins: [{
beforeDraw: chart => {
var ctx = chart.chart.ctx;
ctx.save();
var xAxis = chart.scales['x-axis-1'];
var yAxis = chart.scales['y-axis-1'];
var dataset = chart.data.datasets[0];
var y = yAxis.getPixelForValue(0);
dataset.data.forEach((value, index) => {
var xFrom = xAxis.getPixelForValue(value.x);
var xTo;
if (index + 1 < dataset.data.size) {
xTo = xAxis.getPixelForValue(dataset.data[index + 1].x);
} else {
xTo = xAxis.right;
}
ctx.strokeStyle = dataset.backgroundColor[index];
ctx.lineWidth = 4;
ctx.beginPath();
ctx.moveTo(xFrom, y);
ctx.lineTo(xTo, y);
ctx.stroke();
});
ctx.restore();
}
}],
data: {
datasets: [{
data: [
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 2, y: 0 }
],
backgroundColor: ['red', 'blue', 'green'],
borderColor: ['red', 'blue', 'green'],
pointRadius: 8,
pointHoverRadius: 8,
}],
},
options: {
layout: {
padding: {
left: 10,
right: 10
}
},
legend: {
display: false
},
tooltips: {
enabled: false
},
scales: {
yAxes: [{
ticks: {
display: false
},
gridLines: {
display: false,
}
}],
xAxes: [{
ticks: {
display: false,
max: 3
},
gridLines: {
display: false
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas id="line-chart" height="30"></canvas>
I'm trying to recreate this below chart with a stacked option on my background lines
But my attempts were unsuccessful with this image below as result
$(function() {
var areaChartCanvas = $('#areaChart').get(0).getContext('2d')
var areaChartData = {
labels: ['', '', ''],
datasets: [{
backgroundColor: 'transparent',
borderColor: 'black',
pointRadius: false,
data: [32, 12, 28],
type: 'line'
}, {
backgroundColor: 'red',
pointRadius: false,
data: [20, 20, 20]
}, {
backgroundColor: 'orange',
pointRadius: false,
data: [40, 40, 40]
}, {
backgroundColor: 'cyan',
pointRadius: false,
data: [60, 60, 60]
}]
}
var areaChartOptions = {
maintainAspectRatio: false,
responsive: true,
legend: {
display: false
},
scales: {
xAxes: [{
gridLines: {
display: true,
}
}],
yAxes: [{
gridLines: {
display: true,
},
stacked: true
}]
}
}
var areaChart = new Chart(areaChartCanvas, {
type: 'line',
data: areaChartData,
options: areaChartOptions
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<canvas id="areaChart" style="height:250px"></canvas>
ideally, I want to be able to create 'AREAS' with different colors that will be stacked according to the interval I pass to it.
e.g:
cyan - 20
orange - 20
red - 20
but currently, I'm doing
cyan - 60
orange - 40
red - 20
If I understand you correctly, I thought about different approach and extends the chart with Plugin[1] (Inspired by https://stackoverflow.com/a/49303362/863110)
Chart.pluginService.register({
beforeDraw: function (chart, easing) {
if (chart.config.options.fillColor) {
var ctx = chart.chart.ctx;
var chartArea = chart.chartArea;
ctx.save();
let delta = 0;
const chartHeight = chartArea.bottom - chartArea.top;
const bottomBarHeight = chart.height - chartHeight - chartArea.top;
chart.config.options.fillColor.map(color => {
const colorHeight = chartHeight * (color[0] / 100);
const colorBottom = chartArea.bottom + colorHeight;
ctx.fillStyle = color[1];
const x = chartArea.left,
y = chart.height - bottomBarHeight - colorHeight - delta,
width = chartArea.right - chartArea.left,
height = colorHeight;
delta += height;
ctx.fillRect(x, y, width, height);
ctx.restore();
})
}
}
});
var chartData = {
labels: ['a', 'b', 'c', 'd'],
datasets: [{
label: 'value',
borderColor: 'blue',
data: [30, 50, 25, 10]
}]
};
var ctx = document.getElementById("myChart").getContext("2d");
var myBar = new Chart(ctx, {
type: 'line',
data: chartData,
options: {
scales: {
yAxes: [{ ticks: { max: 60 } }]
},
legend: { display: false },
fillColor: [
[20, 'red'],
[20, 'blue'],
[20, 'green'],
[20, 'pink'],
[20, 'yellow'],
]
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="myChart" height="300" width="500"></canvas>
https://jsbin.com/lisuvuq/2/edit?js,output
[1] - With Plugin you can custom the chart's behaviour. When you use Plugin you get an API so you can "listen" to life cycle events of the chart (beforeDraw for example) and call your own code. The API calls your function and gives you data about the chart so you can use it in your code.In this example, we're using the API to (1) Run a code before the chart been drawing (2) Using the data to calculate the areas of the different colors. (3) Draw additional shapes (ctx.fillRect) based on the calculation.
I have a graph with multiple data points / lines. Currently, if you hover near a data point, it will display the label/value for that point.
What I'd like is the following: when you hover anywhere on the chart, it will display the labels + values for all data points at that x-value simultaneously in a single label.
For example, let's take the given datasets:
Date (x-labels): ['Jan 01','Jan 02','Jan 03']
Apples Sold: [3,5,1]
Oranges Sold: [0,10,2]
Gallons of Milk Sold: [5,7,4]
When you hover over the middle of the graph, above the 'Jan 02' vertical space, the label should display:
Jan 02
-----------------------
Apples Sold: 5
Oranges Sold: 10
Gallons of Milk Sold: 7
Is there a simple way to accomplish this?
Thanks.
Is there a simple way to accomplish this?
YES !! There is a quite straightforward way to accomplish this. If you would have read the documentation, you could have found that pretty easily.
Anyway, basically you need to set the tooltips mode to index in your chart options, in order to accomplish the behavior you want.
...
options: {
tooltips: {
mode: 'index'
}
}
...
Additionally, you probably want to set the following:
...
options: {
tooltips: {
mode: 'index',
intersect: false
},
hover: {
mode: 'index',
intersect: false
}
}
...
This will make it so all of the expected hover/label interactions will occur when hovering anywhere on the graph at the nearest x-value.
From the Documentation :
# index
Finds item at the same index. If the intersect setting is true, the
first intersecting item is used to determine the index in the data. If
intersect false the nearest item, in the x direction, is used to
determine the index.
Here is a working example :
var ctx = document.getElementById('canvas').getContext('2d');
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: ['Jan 01', 'Jan 02', 'Jan 03'],
datasets: [{
label: 'Apples Sold',
data: [3, 5, 1],
borderColor: 'rgba(255, 99, 132, 0.8)',
fill: false
}, {
label: 'Oranges Sold',
data: [0, 10, 2],
borderColor: 'rgba(255, 206, 86, 0.8)',
fill: false
}, {
label: 'Gallons of Milk Sold',
data: [5, 7, 4],
borderColor: 'rgba(54, 162, 235, 0.8)',
fill: false
}]
},
options: {
tooltips: {
mode: 'index',
intersect: false
},
hover: {
mode: 'index',
intersect: false
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="canvas"></canvas>
For Chart.js 3.3.2, you can use #baburao's approach with a few changes. You can check the documentation. Put tooltip in plugins. Example:
...
options: {
plugins: {
tooltip: {
mode: 'nearest',
intersect: false
}
}
}
...
I know this is an old post, but in a time I needed to divide a bar on multiple datasets, but the labels to be keeped as original values:
eg:
dataset 1: Totals: 10 15 10
dataset 2: Red: 4 5 9
dataset 3: Blue: 4 2 1
In my chart I want to show the "Totals" bar and to collor a part of it in red/blue or "the rest" (which is Totals color). I'll don't write the code to modify the datasets, but I'll complete #busterroni answer for chartjs v3+
plugins: {
tooltip: {
mode: 'index',
intersect: false,
callbacks: {
label: (item) => item.dataset.label + ': ' +
this.originalValues[item.datasetIndex].data[item.dataIndex]
}
}
}
You can achieve this after plotting the data like this:
Html
<div class="container">
<h2>Chart.js — Line Chart Demo</h2>
<div>
<canvas id="myChart"></canvas>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.4/Chart.min.js">
</script>
CSS
.container {
width: 80%;
margin: 15px auto;
}
Javascript
var ctx = document.getElementById('myChart').getContext('2d');
function convert(str) {
var date = new Date(str),
mnth = ("0" + (date.getMonth() + 1)).slice(-2),
day = ("0" + date.getDate()).slice(-2);
return [date.getFullYear(), mnth, day].join("-");
}
var date = ["Tue Jun 25 2019 00:00:00 GMT+0530 (India Standard Time)"];
var y1 = [12];
var y2 = [32];
var y3 = [7];
var dataPoints1 = [], dataPoints2 = [], dataPoints3 = [], datep=[];
console.log(date.length)
if(date.length=="1"){
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["",convert(date[0]),""],
datasets: [{
label:"Tweets",
backgroundColor: "rgba(153,255,51,0.4)",
fill:false,
borderColor:"rgba(153,255,51,0.4)",
data: [null,y1[0],null]
}, {
label:"Retweets",
backgroundColor: "rgba(255,153,0,0.4)",
fill:false,
borderColor:"rgba(255,153,0,0.4)",
data: [null,y2[0],null]
},{
label:"Favourites",
backgroundColor: "rgba(197, 239, 247, 1)",
fill:false,
borderColor:"rgba(197, 239, 247, 1)",
data:[null,y3[0],null]
}
]
},
options: {
scales: {
xAxes: [{
gridLines: {
display: false
}
}],
yAxes: [{
ticks: {
display: true
},
gridLines: {
display: false,
// drawBorder: false //maybe set this as well
}
}]
},
}
});}
else{
for (var i = 0; i < date.length; i++) {
datep.push(convert(date[i]))
dataPoints1.push(y1[i]);
dataPoints2.push(y2[i]);
dataPoints3.push(y3[i]);
}
console.log(datep)
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: datep,
datasets: [{
label:"Tweets",
backgroundColor: "rgba(153,255,51,0.4)",
fill:false,
borderColor:"rgba(153,255,51,0.4)",
data: dataPoints1
}, {
label:"Retweets",
backgroundColor: "rgba(255,153,0,0.4)",
fill:false,
borderColor:"rgba(255,153,0,0.4)",
data: dataPoints2
},{
label:"Favourites",
backgroundColor: "rgba(197, 239, 247, 1)",
fill:false,
borderColor:"rgba(197, 239, 247, 1)",
data:dataPoints3
}
]
},
options: {
scales: {
xAxes: [{
gridLines: {
display: false
}
}],
yAxes: [{
ticks: {
display: true
},
gridLines: {
display: false,
// drawBorder: false //maybe set this as well
}
}]
},
}
});
}
or chk this fiddle https://jsfiddle.net/gqozfb4L/
You could try using JavaScript to track the users mouse and based on the position, return the data at that vertice.
document.querySelector('.button').onmousemove = (e) => {
const x = e.pageX - e.target.offsetLeft
const y = e.pageY - e.target.offsetTop
e.target.style.setProperty('--x', `${ x }px`)
e.target.style.setProperty('--y', `${ y }px`)
}