How can I add white spaces/margin between bars with Chart.js 3.0 ? I didn't find anything to process like the image
What I want
My code looks like this and makes this :
What I have
datasets: [{
categoryPercentage: 1.0,
barPercentage: 0.8,
}]
},
options: {
onHover() {},
indexAxis: 'y',
maintainAspectRatio: false,
}
full code here : https://codepen.io/mateofaivre/pen/zYdYgmB
You should set the categoryPercentage to lower value like 0.8 and barPercentage to 1.
Graphical info about categoryPercentage vs barPercentage:
// categoryPercentage: 1.0
// barPercentage: 1.0
Bar: | 1.0 | 1.0 |
Category: | 1.0 |
Sample: |===========|
// categoryPercentage: 1.0
// barPercentage: 0.5
Bar: |.5| |.5|
Category: | 1.0 |
Sample: |==============|
// categoryPercentage: 0.5
// barPercentage: 1.0
Bar: |1.0||1.0|
Category: | .5 |
Sample: |==================|
EDIT:
You can get the bar width from the metasets of the chart and use that to draw it on the chart like so:
const plugin = {
id: 'background',
beforeDraw: (chart, args, opts) => {
if (!opts.color) {
return;
}
const {
ctx,
chartArea,
_metasets
} = chart;
ctx.fillStyle = opts.color;
_metasets.forEach(meta => {
meta.data.forEach(data => {
if (data.horizontal) {
ctx.fillRect(chartArea.left, (data.y - (data.height / 2)), chartArea.width, data.height)
} else {
ctx.fillRect((data.x - (data.width / 2)), chartArea.top, data.width, chartArea.height)
}
})
});
}
}
Chart.register(plugin);
var colors = [];
for (var i = 0; i < 5; i++) {
colors.push('#5671DB');
}
var config = {
type: 'bar',
data: {
labels: ['Commerce, vente', 'Transport', 'Bureautique', 'Accueil', 'Santé', 'Secrétariat', 'Nettoyage', 'Sécurité', 'Mécanique', 'Agro-alimentaire'],
datasets: [{
data: [23.8, 17.7, 13, 9.5, 7.8, 7, 5.5, 5, 4.5, 3.5],
backgroundColor: colors,
hoverBackgroundColor: colors,
borderColor: colors,
}],
},
options: {
onHover() {},
indexAxis: 'y',
barPercentage: 0.8,
//barThickness: 60,
// maxBarThickness: 60,
categoryPercentage: 1.0,
maintainAspectRatio: true,
responsive: true,
plugins: {
background: {
color: '#CDECEF'
},
title: {
display: false,
text: "Les 10 principaux domaines d'emploi",
align: 'start',
fullSize: true,
color: '#324488',
font: {
size: 24,
family: 'Arial',
}
},
legend: {
display: false
},
tooltip: {
backgroundColor: 'rgba(255,255,255,0)',
displayColors: false,
titleFont: {
size: 0,
},
titleMarginBottom: 0,
titleSpacing: 0,
bodyFont: {
size: 25,
weight: 700
},
xAlign: 'right',
callbacks: {
label: (item) => (`${item.parsed.x} %`),
},
},
},
scales: {
y: {
beginAtZero: true,
ticks: {
color: "#34478B",
font: {
size: 18,
},
stepSize: 1,
beginAtZero: true
},
},
x: {
ticks: {
color: "#25C8C9",
font: {
size: 14
},
stepSize: 1,
beginAtZero: true
},
}
}
},
};
var ctx = document.getElementById('myChart').getContext('2d');
new Chart(ctx, config);
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<canvas id="myChart"></canvas>
codePen
If reducing the bar size is not a problem you could add barPercentage to your options.
Like this:
const config = {
type: 'bar',
data,
options: {
indexAxis: 'y',
barPercentage: 0.8
}
};
Bar Chart | Charts.js
Related
Following on from the answer in this post
I have the following chart which can also be found here
const d0 = new Date("2023-02-15T00:00:00.721Z").getTime()
const d1 = new Date("2023-02-15T01:00:00.721Z").getTime()
const d2 = new Date("2023-02-15T02:30:00.721Z").getTime()
const d3 = new Date("2023-02-15T03:20:00.721Z").getTime()
const d4 = new Date("2023-02-15T05:05:00.721Z").getTime()
let values = [d0, d1, d2, d3, d4];
let data = {
labels: [''],
datasets: [{
label: 'up',
axis: 'y',
data: [d1],
backgroundColor: 'red',
},{
label: 'down',
axis: 'y',
data: [d2],
backgroundColor: 'yellow',
},{
label: 'out',
axis: 'y',
data: [d3],
backgroundColor: 'green',
},{
label: 'up',
axis: 'y',
data: [d4],
backgroundColor: 'red',
}
]
};
const config = {
data,
type: 'bar',
options:{
elements: {
bar: {
borderWidth: 0
}
},
ticks: {
display: true
},
interaction: {
mode: 'dataset'
},
tooltip: {
mode: 'dataset'
},
hover: {
mode: 'dataset'
},
onClick: function (e) {
// debugger;
var activePointLabel =
this.getElementsAtEventForMode(e, 'dataset', { intersect: true }, false)
alert(activePointLabel[0].datasetIndex);
}
,
plugins: {
legend: {
display: false,
},
title: {
display: false,
},
},
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
grid: {
display: true
},
min: d0,
ticks: {
callback: function(value, index, ticks) {
return moment(value).format('HH:mm');
}
},
// afterBuildTicks: axis => axis.ticks = values.map(v => ({ value: v }))
},
y: {
grid: {
display: false
},
stacked: true
},
}
}};
new Chart(document.getElementById("chart"), config);
This produces this...
]1
I would like to get rid of all the grids lines , except the ticks, but if I set the gird displays false the tick also disappear, and it also leave a border around the chart, etg something like
Is there a way to do this?
Just add border: {display: false}, to the scales configuration. (here is the link to the documentation)
...
scales: {
x: {
border: {
display: false,
},
...
},
...
}
...
Update added full running example:
const d0 = moment.duration('07:00:00').asMinutes();
const d1 = moment.duration('09:00:00').asMinutes();
const d2 = moment.duration('10:45:00').asMinutes();
const d3 = moment.duration('17:35:00').asMinutes();
const d4 = moment.duration('19:00:00').asMinutes();
let values = [d0, d1, d2, d3, d4];
let data = {
labels: [''],
datasets: [{
label: 'up',
axis: 'y',
data: [d1],
backgroundColor: 'red',
},{
label: 'down',
axis: 'y',
data: [d2],
backgroundColor: 'yellow',
},{
label: 'out',
axis: 'y',
data: [d3],
backgroundColor: 'green',
},{
label: 'up',
axis: 'y',
data: [d4],
backgroundColor: 'red',
}
]
};
const config = {
data,
type: 'bar',
options:{
plugins: {
tooltip: {
mode: 'dataset',
callbacks: {
label: function(item){
return moment().startOf('day').add({ minute: item.raw}).format('HH:mm');
}
}
},
legend: {
display: false,
},
title: {
display: false,
},
},
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
min: d0,
border: { display: false },
ticks: {
callback: function(value, index, ticks) {
return moment().startOf('day').add({ minute: value}).format('HH:mm');
}
},
afterBuildTicks: axis => axis.ticks = values.map(v => ({ value: v }))
},
y: {
stacked: true,
grid: { display: false },
},
}
}};
new Chart(document.getElementById("chart"), config);
<script src="//cdn.jsdelivr.net/npm/chart.js"></script>
<script src="//cdn.jsdelivr.net/npm/moment#^2"></script>
<script src="//cdn.jsdelivr.net/npm/chartjs-adapter-moment#^1"></script>
<div class="chart" style="height:84px; width:350px;">
<canvas id="chart" ></canvas>
</div>
use tickColor (see below config) for v 3.8.2
scales: {
x: {
...
grid: {
display: true,
drawTicks: true, //show ticks
borderColor: "transparent", //horizontal line color above ticks (x-axis)
color: "transparent", //grid lines color
tickColor: "#868e96" //ticks color (little line above points)
},
},
...
}
I'm working with chart.js and I can't seem to be able to change the scale of the Y axis to show whole numbers, in this example I would like to have just round numbers in the scale (1,2,3,4,5) instad of the decimal (0 -0,5 - 1,0 - 1,5 - 2,0 - etc)
I'm using a vertical Bar chart from here: https://www.chartjs.org/docs/latest/samples/bar/vertical.html
and my current setup is this:
var setVirtualBarChart = function (element, viewModel) {
var chArea = element.getContext("2d");
var chartConfig = {
type: 'bar',
data: {
labels: ['Categories'],
datasets: [
{
minBarLength: 2,
label: '0-7 days',
barPercentage: 0.75,
categoryPercentage: 0.75,
data: viewModel.ZeroToSevenDaysUser(),
backgroundColor: window.chartColors.BrightVisibleGreen
},
{
minBarLength: 2,
label: '8-30 days',
barPercentage: 0.75,
categoryPercentage: 0.75,
data: viewModel.SevenToThirtyDaysUser(),
backgroundColor: window.chartColors.Orange
},
{
minBarLength: 2,
label: '30+ test days',
barPercentage: 0.75,
categoryPercentage: 0.75,
data: viewModel.ThirtyPlusDaysUser(),
backgroundColor: window.chartColors.BrightRed
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [
{
stacked: false,
display: true,
scaleLabel: {
display: true,
//labelString: 'Categories',
gridLines: {
offsetGridLines: true
}
}
}
],
yAxes: [
{
stacked: false,
display: true,
scaleLabel: {
display: true,
labelString: 'Number of invoices'
},
ticks: {
precision: 0,
min: 0
}
}
]
}
}
};
VirtualBarChart = new Chart(chArea, chartConfig);
};
You are using v2 syntax while using v3, in v3 all scales are objects and no arrays anymore. For all changes please read the migration guide
Exaple:
const options = {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow"],
datasets: [{
label: '# of Votes',
data: [1, 2.5, 1.5],
backgroundColor: ["Red", "Blue", "Yellow"]
}]
},
options: {
scales: {
y: {
ticks: {
stepSize: 1
},
}
}
}
}
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'm trying to create a scatter plot with Chartjs.
I want to have few datasets centered around one X value, and three Y values.
When I can't set the custom X labels for my dataset, and also can't set a fixed range for X axes.
This is how I generate the data:
function generateData(n, xCenter, yCenter) {
var data = [];
var spread = 0.2
for (var i = 0; i < n; i++) {
data.push({
x: (Math.random() - 0.5)*spread + xCenter,
y: (Math.random() - 0.5)*spread + yCenter
})
}
return data
}
var scatterChartData = {
datasets: [
{
label: 'My First dataset',
backgroundColor: "#0000FF",
data: generateData(100, 1, 2)
},
{
label: 'My Second dataset',
backgroundColor: "#00FF00",
data: generateData(50, 1, 3)
},
{
label: 'My Second dataset',
backgroundColor: "#00FF00",
data: generateData(50, 1, 4)
},
]
}
Here are the scatter options:
var scatterOptions = {
tooltips: {
enabled: true
},
responsive: true, // Instruct chart js to respond nicely.
maintainAspectRatio: false, // Add to prevent default behaviour of full-width/height
responsive: true,
legend: {
display: false
},
scales: {
xAxes: [{
gridLines: {
display: false,
ticks: {
min: 0,
max: 10,
stepSize: 0.01
}
}
}],
yAxes: [{
gridLines: {
display: true,
ticks: {
stepSize: 0.01,
suggestedMin: 0.5,
suggestedMax: 5
}
}
}]
}
}
And this is the plot:
var myChart = new Chart(ctx, {
showTooltips: false,
type: 'scatter',
data: scatterChartData,
options: scatterOptions
});
I'm currently working with ChartJS.
It works fine on Firefox and Chrome.
On Safari there is horizontal lines which appear. (here there is one good on orange and two others unwanted )
I have a lot of datapoint (2 lines of 1600 data point). I don't know if it could be a cause.
My code is here.
In some other part, I update time uni and time min.
_displayChart: function(label1, label2){
var timeFormat = 'DD/MM/YYYY HH:mm';
var ctx = document.getElementById(this.heading).getContext('2d');
const data = {
// Labels should be Date objects
//labels:this._stats[1],
datasets: [{
fill: false,
label: label1,
data: this._stats[2],
borderColor: '#fe8b36',
pointRadius: 0,
backgroundColor: [
'#fe8b36'
]
},{
label: label2,
fill: false,
data: this._stats[3],
borderWidth: 1,
pointRadius: 0,
borderColor: 'rgba(99, 100, 200, 1)',
backgroundColor: [
'rgba(99, 100, 200, 0.2)'
]
}]
}
const options = {
type: 'line',
data: data,
options: {
responsive: false,
fill: false,
responsive: true,
maintainAspectRatio:!this._isMobile(),
max: this.max,
hover: {
// Overrides the global setting
mode: 'index'
},
annotation: {
drawTime: 'beforeDatasetsDraw',
events: ['click'],
annotations: []
},
legend: {
labels: {
filter: function(legendItem, chartData) {
if(legendItem.datasetIndex == 2 || legendItem.datasetIndex == 3 ){
return false;
}
return true;
}
}
},
tooltips: {
mode:'index',
intersect : false,
callbacks: {
title: function(tooltipItems, data) {
return tooltipItems[0].xLabel.format(timeFormat);
},
label: function(tooltipItems, data) {
return tooltipItems.yLabel+'%';
}
}
},
scales: {
xAxes: [{
type: 'time',
display: true,
time:{
unit:'day',
min:moment(Date.now()-this.monthTs),
max:this._stats[1][this._stats[1].length]
}
}],
yAxes: [{
ticks: {
beginAtZero: true,
},
display: true
}]
}
}
}
this._chart = new Chart(ctx, options);
},
When I'm applying this, I have no problem:
this._chart.options.scales.xAxes[0].time.unit = 'month';
this._chart.options.scales.xAxes[0].time.stepSize = 1;
this._chart.options.scales.xAxes[0].time.min = this._stats[1][0];
this._chart.options.scales.xAxes[0].time.max = this._stats[1][this._stats[1].length-1];
Thanks
I am trying to align the generated time scale labels using Chart.js v2.2 with the centre of the bars of a bar chart. I have tried the offsetGridLines option but this seems to have no effect when using Xaxis scale type time.
Here is an example, maybe I have missed something:
<div id="container" style="width: 75%;">
<canvas id="canvas"></canvas>
</div>
<script>
var barChartData = {
labels: ["2015-01-01", "2015-02-01", "2015-03-01", "2015-04-01", "2015-05-01", "2015-07-01"],
datasets: [{
label: 'Dataset 1',
backgroundColor: "rgba(220,220,220,0.5)",
data: [10, 4, 5, 7, 2, 3]
}]
};
window.onload = function() {
var ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
elements: {
rectangle: {
borderWidth: 2,
borderColor: 'rgb(0, 255, 0)',
borderSkipped: 'bottom'
}
},
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: 'Chart.js Bar Chart'
}
,
scales: {
xAxes: [{
categoryPercentage: .5,
barPercentage: 1,
type: 'time',
scaleLabel: {
display: true,
labelString: 'Year-Month'
},
time: {
min: '2014-12-01' ,
max: '2015-12-01',
unit: 'month',
displayFormats: {
month: "MMM YY"
}
},
gridLines: {
offsetGridLines: false,
drawTicks: true,
display: true
},
stacked: true
}],
yAxes: [{
ticks: {
beginAtZero: true
},
stacked: true
}]
}
}
});
};
</script>
This fiddle may help to place the data label in the center of the bar
https://jsfiddle.net/tea8dhgy/
<div id="container" style="width: 75%;">
<canvas id="canvas"></canvas>
</div>
var barChartData = {
labels: ["2015-01-01", "2015-02-01", "2015-03-01", "2015-04-01", "2015-05-01", "2015-07-01"],
datasets: [{
label: 'Dataset 1',
backgroundColor: "rgba(220,220,220,0.5)",
data: [10, 4, 5, 7, 2, 3]
}]
};
var ctx = document.getElementById("canvas").getContext("2d");
new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
elements: {
rectangle: {
borderWidth: 2,
borderColor: 'rgb(0, 255, 0)',
borderSkipped: 'bottom'
}
},
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: 'Chart.js Bar Chart'
},
scales: {
xAxes: [{
categoryPercentage: .5,
barPercentage: 1,
type: 'time',
scaleLabel: {
display: true,
labelString: 'Year-Month'
},
time: {
// min: '2014-12-01' ,
// max: '2015-12-01',
unit: 'month',
displayFormats: {
month: "MMM YY"
}
},
gridLines: {
offsetGridLines: false,
drawTicks: true,
display: true
},
stacked: true
}],
yAxes: [{
ticks: {
beginAtZero: true
},
stacked: true
}]
},
animation: {
onComplete: function() {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(10, "bold", Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'center';
this.data.datasets.forEach(function(dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function(bar, index) {
//var data = dataset.data[index];
var data = dataset.data[index];
console.log(bar);
if (data > 0) {
ctx.fillText(data, bar._model.x, bar._model.base - (bar._model.base - bar._model.y) / 2 - 5);
}
});
});
}
}
}
});
I was able to get a working chart by removing the min and max values set.
Here is the JSFiddle
Was the following image the desired outcome?