prevent axis label rotation in Chart.js [duplicate] - chart.js

I'm trying to rotate the title of the y axis 90 degrees clockwise in chart.js but I couldn't find any way to do this.
This question chartjs: trying to rotate the y-Axis label only rotates the ticks/labels not the y axis title itself.
The only related post I can find is this Ability to rotate axis title and the response was from Jan 26, 2021 saying there was no way to do this.
I have attached my javascript and html code below.
Any help would be greatly appreciated.
The y axis title I would like to rotate is highlighted in red and called: Number of defects. Ideally I'd like to rotate it 90 degrees clockwise.
const labels = ['2021-06-07 00:00:00', '2021-06-08 00:00:00', '2021-06-09 00:00:00'];
const data = {
labels: labels,
datasets: [
{
label: 'Fixed defects',
backgroundColor: 'rgb(0, 255, 0)',
borderColor: 'rgb(0, 255, 0)',
data: ['2', '73', '34'],
barThickness: 5
}, {
label: 'Open defects',
backgroundColor: 'rgb(255, 0, 0)',
borderColor: 'rgb(255, 0, 0)',
data: ['0', '5', '2'],
barThickness: 5
}]
};
const config = {
type: 'bar',
data: data,
options: {
scales: {
x: {
min: '2021-06-07 00:00:00',
max: '2021-09-10 00:00:00',
type: 'time',
time: {
unit: 'week'
},
stacked: true,
title: {
text: 'Dates (weeks)',
display: true
}
},
y: {
stacked: true,
title: {
text: 'Number of defects',
display: true
}
}
}
}
};
const myChart = new Chart(
document.getElementById('myChart'),
config
);
<!DOCTYPE html>
<meta charset="utf-8">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/moment#^2"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment#^1"></script>
<link rel="stylesheet" type="text/css" href="../styles.css">
<body>
<div>
<canvas height="100px" id="myChart"></canvas>
</div>
<script>
</script>
</body>

You can use a custom plugin, to make space you first need to increase the padding on the left, after that you can calculate the correct position by taking the average of the top and bottom y's of the chart area.
Also you should not include chart.js 2 times. When chart.js updates to V4 you will have V4 and V3 installed which will give unwanted behaviour.
Example:
const customTitle = {
id: 'customTitle',
beforeLayout: (chart, args, opts) => {
const {
display,
font
} = opts;
if (!display) {
return;
}
const {
ctx
} = chart;
ctx.font = font || '12px "Helvetica Neue", Helvetica, Arial, sans-serif'
const {
width
} = ctx.measureText(opts.text);
chart.options.layout.padding.left = width * 1.1;
},
afterDraw: (chart, args, opts) => {
const {
font,
text,
color
} = opts;
const {
ctx,
chartArea: {
top,
bottom,
left,
right
}
} = chart;
if (opts.display) {
ctx.fillStyle = color || Chart.defaults.color
ctx.font = font || '12px "Helvetica Neue", Helvetica, Arial, sans-serif'
ctx.fillText(text, 3, (top + bottom) / 2)
}
}
}
const labels = ['2021-06-07 00:00:00', '2021-06-08 00:00:00', '2021-06-09 00:00:00'];
const data = {
labels: labels,
datasets: [{
label: 'Fixed defects',
backgroundColor: 'rgb(0, 255, 0)',
borderColor: 'rgb(0, 255, 0)',
data: ['2', '73', '34'],
barThickness: 5
}, {
label: 'Open defects',
backgroundColor: 'rgb(255, 0, 0)',
borderColor: 'rgb(255, 0, 0)',
data: ['0', '5', '2'],
barThickness: 5
}]
};
const config = {
type: 'bar',
data: data,
options: {
scales: {
x: {
min: '2021-06-07 00:00:00',
max: '2021-09-10 00:00:00',
type: 'time',
time: {
unit: 'week'
},
stacked: true,
},
y: {
stacked: true,
}
},
plugins: {
customTitle: {
display: true,
text: 'Number of defects',
color: 'blue'
}
}
},
plugins: [customTitle]
};
const myChart = new Chart(
document.getElementById('myChart'),
config
);
<!DOCTYPE html>
<meta charset="utf-8">
<script src="https://cdn.jsdelivr.net/npm/chart.js#^3"></script>
<script src="https://cdn.jsdelivr.net/npm/moment#^2"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment#^1"></script>
<body>
<div>
<canvas height="100px" id="myChart"></canvas>
</div>
</body>

Related

ChartJs line chart time cartesian axis number of ticks and wierd offset

I am trying to make a chart to show data for the last 7 days.
My x axis - is a time cartesian axis and time unit is set to 'day' but the chart shows me only 6 ticks and I want to show 7 ticks, one tick for every day.
Also the ticks are offset to the chart points, I want the points be exactly align with the ticks
let [priceData, scoreData] = generateFakeData(7);
// max price to show on the chart is max price + 1000
const maxPrice = Math.max(...priceData.map(data => data.y)) + 1000;
//console.log(data);
console.log(priceData[0].x);
console.log(priceData[scoreData.length - 1].x);
function generateRandomNumber(min, max) {
return Math.floor(Math.random() * max) + min;
}
const ctx = document.getElementById('chart').getContext('2d');
const myChart = new Chart(ctx, {
type: 'line',
pointRadius: 0,
options: {
elements: {
point: {
pointRadius: 0,
pointHoverRadius: 3
}
},
interaction: {
mode: 'nearest',
intersect: false,
axis: 'x'
},
plugins: {
legend: {
labels: {
// This more specific font property overrides the global property
color: '#fff',
font: {
size: 14,
}
}
}
},
scales: {
x: {
type: 'time',
beginAtZero: true,
ticks: {
color: "white",
autoSkip: false,
maxTicksLimit: 7,
count: 7,
},
time: {
displayFormats: {
month: 'dd MMM yy'
},
unit: 'day'
},
gridLines: {
offsetGridLines: true,
},
offset: false,
},
y: {
type: 'linear',
min: 0,
max: maxPrice,
ticks: {
color: "white"
}
},
y1: {
type: 'linear',
min: 0.5,
max: 10.5,
display: true,
position: 'right',
ticks: {
color: "white",
autoSkip: false,
maxTicksLimit: 12,
callback: function (val, index) {
// Hide first and last tick label
return val === 0.5 || val === 10.5 ? '' : this.getLabelForValue(val);
},
},
// grid line settings
grid: {
drawOnChartArea: false, // only want the grid lines for one axis to show up
},
},
}
},
data: {
datasets: [
{
label: 'price',
data: priceData,
borderColor: [
'#ffb800'
],
borderWidth: 1
},
{
label: 'score',
data: scoreData,
borderColor: [
'#00ff00'
],
borderWidth: 1,
yAxisID: 'y1',
}
]
}
});
function generateFakeData(numOfDays) {
const priceData = [];
const scoreData = [];
let today = new Date();
priceData.unshift({ x: new Date(today), y: generateRandomNumber(1000, 2500) });
scoreData.unshift({ x: new Date(today), y: generateRandomNumber(1, 10) });
for (let i = 0; i < numOfDays - 1; i++) {
const newDate = today.setDate(today.getDate() - 1);
priceData.unshift({ x: new Date(newDate), y: generateRandomNumber(1000, 2500) });
scoreData.unshift({ x: new Date(newDate), y: generateRandomNumber(1, 10) });
}
return [priceData, scoreData];
}
html {
background-color: black
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.7.1/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
</head>
<body>
<canvas id="chart"></canvas>
</body>
</html>
Link to jsBin: https://jsbin.com/viduman/5/edit?html,js,output
I only needed to set the hour of each day to (0,0,0,0)
let today = new Date();
today.setHours(0, 0, 0, 0);

ChartJS multiple X axis and extra labels in y axis

I have a graph using ChartJS latest version 3.3.2. My code is as below:
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<title>OCA-Test</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.3.2/chart.min.js"></script>
</head>
<body>
<canvas id="chartJSContainer"></canvas>
<script>
const labels = ["A","B","C","D","E","F","G","H","I","J"];
const data = {
labels: labels,
datasets: [
{
label: 'Dataset 1',
data: [-92, -100, -99, -86, 8, 56, -94, -89, -92, -24],
borderColor: 'transparent',
backgroundColor: 'transparent',
order: 1
},
{
label: 'Dataset 2',
data: [-92, -100, -99, -86, 8, 56, -94, -89, -92, -24],
borderColor: 'black',
backgroundColor: 'blue',
type: 'line',
order: 0
}
]
};
const config = {
type: 'bar',
data: data,
options: {
responsive: true,
plugins: {
legend: {
display: false
},
title: {
display: false
}
},
scales: {
y: {
min: -100,
max: 100
}
}
}
};
var chart = new Chart(document.getElementById('chartJSContainer'), config);
</script>
</body>
</html>
How can I add the same x-axis labels on the top of the graph too and add new labels on the left of the graph too. See capture attached. Thanks.
What I'm looking for
For the X axis on top you can just add another X axis and set position to top, for the labels between the Y axis best is to write a custom plugin for that.
Example:
var options = {
type: 'line',
data: {
labels: ["A", "B", "C", "D", "E", "F"],
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: {
scales: {
x: {
position: 'bottom',
grid: {
offset: true // offset true to get labels in between the lines instead of on the lines
}
},
x2: {
position: 'top',
grid: {
offset: true // offset true to get labels in between the lines instead of on the lines
}
},
y: {
ticks: {
count: (context) => (context.scale.chart.data.labels.length + 1)
}
}
},
plugins: {
labelsY: {
font: 'Arial',
size: '14px',
color: '#666',
align: 'right',
reverseLabels: false // true to make A start at top and F at bottom
}
}
},
plugins: [{
id: 'labelsY',
afterDraw: (chart, args, options) => {
const {
ctx,
scales: {
y,
x
},
data: {
labels
}
} = chart;
let dupLabels = JSON.parse(JSON.stringify(labels)); // remove pointer to internal labels array so you dont get glitchy behaviour
if (options.reverseLabels) {
dupLabels = dupLabels.reverse();
}
dupLabels.forEach((label, i) => {
ctx.save();
ctx.textAlign = options.align || 'right';
ctx.font = `${options.size || '20px'} ${options.font || 'Arial'}`;
ctx.fillStyle = options.color || 'black'
let xPos = x.getPixelForValue(labels[0]) - ctx.measureText(label).width;
let yPos = (y.getPixelForValue(y.ticks[i].value) + y.getPixelForValue(y.ticks[i + 1].value)) / 2;
ctx.fillText(label, xPos, yPos)
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.3.0/chart.js"></script>
</body>

ChartJS adding shadow color to grid and custom x-axis labels

I'm using chartJS 2.6.0 with scatter. The code I use is as below:
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link rel="stylesheet" href="css/960.css" />
<title>OCA-Test</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
</head>
<body>
<div class="container_12">
<canvas id="linechart"></canvas>
<script>
var linedata = {
datasets: [{
fill: false,
lineTension: 0,
borderColor: "black",
borderWidth: [2,2,2,2,2,2,2,2,2,2],
pointBackgroundColor: ["blue", "blue","blue", "blue","blue", "blue","blue", "blue","blue", "blue"],
pointRadius: [5,5,5,5,5,5,5,5,5,5],
pointStyle: ["rect","rect","rect","rect","rect","rect","rect","rect","rect","rect"],
data: [
{x: 0.25, y: 80},
{x: 0.75, y: -14},
{x: 1.25, y: -46},
{x: 1.75, y: 30},
{x: 2.25, y: 14},
{x: 2.75, y: -20},
{x: 3.25, y: -72},
{x: 3.75, y: -56},
{x: 4.25, y: -24},
{x: 4.75, y: -52}
]
}]
};
var chartOptions = {
responsive: true,
maintainAspectRatio: true,
legend: {display: false},
gridLines :{
},
scales: {
yAxes: [{
ticks: {
beginAtZero: false,
max: 100,
min: -100
}
}],
xAxes: [{
ticks: {
display: false
}
}]
}
};
var lineID = document.getElementById("linechart").getContext("2d");
var lineChart = new Chart(lineID, {
type: "scatter",
data: linedata,
options: chartOptions
});
</script>
</body>
</html>
What I'm trying to do is to display some texts in the x-axis in the middle of every grid column like what the bar graph does see image Bar graph image
Also, I would like to add a color to the grid just between y-axis -30 and 20 like in the capture below HTML workaround
All I could do is do it in HTML by displaying tags below the graph and using margins and by also placing an image in the background to get what shows in image 2 but it is an ugly solution.
Any help would be appreciated thanks.
For both requirements you can write custom inline plugins.
Example:
var options = {
type: 'scatter',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [{
x: 0.25,
y: 80
},
{
x: 0.75,
y: -14
},
{
x: 1.25,
y: -46
},
{
x: 1.75,
y: 30
},
{
x: 2.25,
y: 14
},
{
x: 2.75,
y: -20
},
{
x: 3.25,
y: -72
},
{
x: 3.75,
y: -56
},
{
x: 4.25,
y: -24
},
{
x: 4.75,
y: -52
}
],
borderWidth: 1
}]
},
options: {
plugins: {
customText: {
text: ['hi', 'this', 'is', 'text', 'in', 'Mid', '!', ':)'],
size: '20px',
color: 'red',
font: 'Arial black'
},
backgrounds: {
hbars: [{
from: -28,
to: -80,
color: "rgb(195, 230, 195)"
},
{
from: 20,
to: 28,
color: "rgb(230, 220, 195)"
},
{
from: 0,
to: 20,
color: "rgb(230, 195, 195)"
}
]
}
}
},
plugins: [{
id: 'backgrounds',
beforeDraw: (chart, args, options) => {
const {
ctx,
chartArea,
scales
} = chart;
const y = scales['y-axis-1'];
const x = scales['y-axis-1'];
options.hbars.forEach((hBar) => {
ctx.save();
ctx.fillStyle = hBar.color;
ctx.fillRect(chartArea.left, y.getPixelForValue(hBar.from), chartArea.right - chartArea.left, y.getPixelForValue(hBar.to) - y.getPixelForValue(hBar.from));
ctx.restore();
})
}
},
{
id: 'customText',
afterDraw: (chart, args, options) => {
const {
ctx,
chartArea,
scales
} = chart;
const y = scales['y-axis-1'];
const x = scales['x-axis-1'];
options.text.forEach((text, i) => {
ctx.save();
ctx.textAlign = 'center';
ctx.font = `${options.size || '20px'} ${options.font || 'Arial'}`;
ctx.fillStyle = options.color || 'black'
ctx.fillText(text, x.getPixelForValue((Number(x.ticks[0]) + Number(x.ticks[1])) / 2), y.getPixelForValue((Number(y.ticks[i]) + Number(y.ticks[i + 1])) / 2))
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/2.9.4/Chart.js"></script>
</body>

charts js have a bar spanning negative/positive on y-axis

Is there a way in chartjs to have a bar span across the zero line? As an example,
lets say I have a bar with
data:[x:1, y:100]
How do I tell it to span the y-axis from -100 to 100 (instead of from 0 to 100)?
I have sort of a playground here where I can do either negative or positive per bar, but not both for one bar.
https://jsbin.com/dufonoceja/1/edit?js,output
This can be done since Chart.js v2.9.0, which now supports floating bars. Individual bars can now be specified with the syntax [min, max].
<html>
<head>
<title>Floating Bars</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<style>
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
</style>
</head>
<body>
<div>
<canvas id="canvas" height="120"></canvas>
</div>
<script>
var chartData = {
labels: [1,2,3,4,5,6],
datasets: [{
type: 'bar',
label: 'Red Bar',
borderColor: 'black',
borderWidth: 1,
backgroundColor: 'rgba(128,0,0,0.2)',
data: [[0, 100], [-100, 100], [-30, 40], 0, 0, 0],
}, {
type: 'bar',
label: 'Green Bar',
backgroundColor: 'rgba(0,128,0,0.2)',
borderColor: 'black',
borderWidth: 1,
data: [0, 0, 0, 0, [-50, 70], 100],
}
]
};
window.onload = function() {
var ctx = document.getElementById('canvas').getContext('2d');
window.myBar = new Chart(ctx, {
type: 'bar',
data: chartData,
options: {
scaleBeginAtZero: false,
responsive: true,
spanGaps: true,
tooltips: {
mode: 'index',
intersect: true
},
scales: {
xAxes: [{
gridLines: {
display: false
},
}],
yAxes: [{
type: 'linear',
ticks: {
beginAtZero: false,
min:-100,
max:100,
stepSize:30
}
}],
}
}
});
};
</script>
</body>
</html>

Adding line over stacked line chart with ChartJS

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.