I'm passing the following config to Chart.js:
{
type: 'doughnut',
data: {
labels: ['a', 'b', 'c'],
datasets: [{
data: [878, 19020, 100412286],
backgroundColor: [
'rgb(255, 99, 132)',
'rgb(54, 162, 235)',
'rgb(255, 205, 86)'
],
hoverOffset: 4
}]
}
}
But because of the huge difference between all three (given how much bigger c is), c ends up "overlapping" everything else and I just get a doughnut with only one color, showing only c.
If I try a smaller value for c all three sectors show up fine.
But I don't understand, Chart.js should've been able to show all pieces (set a minimum size for the smallest sector etc.)
Is there some parameter I can pass to the config to fix this ?
You can use a logarithmic scale but only for lines. A donut is not a good choice for your use case
https://www.chartjs.org/docs/latest/samples/scales/log.html
Config:
const config = {
type: 'line',
data: data,
options: {
responsive: true,
plugins: {
title: {
display: true,
text: 'Chart.js Line Chart - Logarithmic'
}
},
scales: {
x: {
display: true,
},
y: {
display: true,
type: 'logarithmic',
}
}
},
};
Setup:
const DATA_COUNT = 7;
const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};
const labels = Utils.months({count: 7});
const data = {
labels: labels,
datasets: [
{
label: 'Dataset 1',
data: logNumbers(DATA_COUNT),
borderColor: Utils.CHART_COLORS.red,
backgroundColor: Utils.CHART_COLORS.red,
fill: false,
},
]
};
Action
const logNumbers = (num) => {
const data = [];
for (let i = 0; i < num; ++i) {
data.push(Math.ceil(Math.random() * 10.0) * Math.pow(10, Math.ceil(Math.random() * 5)));
}
return data;
};
const actions = [
{
name: 'Randomize',
handler(chart) {
chart.data.datasets.forEach(dataset => {
dataset.data = logNumbers(chart.data.labels.length);
});
chart.update();
}
},
];
One alternative is using 3 datasets, one for each data.
labels: ['a', 'b', 'c'],
datasets: [
{
label: "My First Dataset",
data: [878,0,0],
backgroundColor: [
"rgb(255, 205, 86)",
"rgb(255, 99, 132)",
"rgb(54, 162, 235)",
],
offset:0,
hoverOffset: 0,
},
{
label: "My First Dataset2",
data: [0,19020,0],
backgroundColor: [
"rgb(255, 205, 86)",
"rgb(255, 99, 132)",
"rgb(54, 162, 235)",
],
offset:0,
hoverOffset: 0,
},
{
label: "My First Dataset2",
data: [0,0,100412286],
backgroundColor: [
"rgb(255, 205, 86)",
"rgb(255, 99, 132)",
"rgb(54, 162, 235)",
],
offset:0,
hoverOffset: 0,
},
],
I hope this help.
Related
I am starting to learn the chart.js library.
I drew a pie chart (like "pie"). When you hover over the slices of the diagram, a number appears in the pop-up window that sets the size of the sector.
new chart(
document.getElementById('diagram_1').getContext('2d'), {
type: 'pie',
data: {
labels: [
'Завершенная задача',
'Новая задача',
'Ошибка выполнения'
],
datasets: [{
label: '# of Votes',
data: [#successful_tasks, #new_tasks, #error_tasks],
backgroundColor: [
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(255, 99, 132, 0.2)'
],
borderColor: [
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(255, 99, 132, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
},
responsive: false
}
}
)
How can you make this number still displayed at the top, where the sectors are listed (I marked this place with a red circle in the picture)?
I can add the required number to the labels array
...
data: {
labels: [
'Завершенная задача: ' + #successful_tasks,
'Новая задача: ' + #new_tasks,
'Ошибка выполнения: ' + #error_tasks
],
...
But then this number will appear twice in the tooltip
You can use the plugin system for this:
var options = {
type: 'pie',
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: {
customNumber: {
textColor: 'red',
xOffset: 10,
yOffset: 0,
font: '24px Comic Sans MS'
}
}
},
plugins: [{
id: 'customNumber',
afterDraw: (chart, args, opts) => {
const hoveredSlice = chart._active[0];
const {
ctx,
chartArea: {
right
}
} = chart;
if (!hoveredSlice) {
return;
}
ctx.font = opts.font || '24px verdana, sans-serif'
ctx.fillStyle = opts.textColor || 'black'
const val = chart.data.datasets[hoveredSlice.datasetIndex].data[hoveredSlice.index];
const meassures = ctx.measureText(val);
const height = ctx.measureText('M').width;
ctx.fillText(val, (right - meassures.width - (opts.xOffset || 0)), height + (opts.yOffset || 0))
}
}]
}
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>
I found the answer. My project is written in CoffeeScript, but I think it would be more useful for the StackOverflow community to post the code in JS.
options: {
legend: {
labels: {
generateLabels: function(chart) {
var data = chart.data;
if (data.labels.length && data.datasets.length) {
return data.labels.map(function(label, i) {
var meta = chart.getDatasetMeta(0);
var ds = data.datasets[0];
var arc = meta.data[i];
var custom = arc && arc.custom || {};
var getValueAtIndexOrDefault = Chart.helpers.getValueAtIndexOrDefault;
var arcOpts = chart.options.elements.arc;
var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
var value = chart.config.data.datasets[arc._datasetIndex].data[arc._index];
return {
text: label + ": " + value,
fillStyle: fill,
strokeStyle: stroke,
lineWidth: bw,
hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
index: i
};
});
} else {
return [];
}
}
}
}
}
I am trying to make a bar chart in chart.js I found some ready-made example and I am trying to adapt it for my requirements.
I don't know how to remove the double Y axis.
var densityCanvas = document.getElementById("densityChart");
Chart.defaults.global.defaultFontFamily = "Lato";
Chart.defaults.global.defaultFontSize = 18;
var densityData = {
label: 'Density of Planet (kg/m3)',
data: [5427, 5243, 5514, 3933, 1326, 687, 1271, 1638],
backgroundColor: 'rgba(0, 99, 132, 0.6)',
borderWidth: 0,
yAxisID: "y-axis-density"
};
var gravityData = {
label: 'Gravity of Planet (m/s2)',
data: [5427, 5243, 5514, 3933, 1326, 687, 1271, 1638],
backgroundColor: 'rgba(99, 132, 0, 0.6)',
borderWidth: 0,
yAxisID: "y-axis-gravity"
};
var planetData = {
labels: ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"],
datasets: [densityData, gravityData]
};
var chartOptions = {
scales: {
xAxes: [{
barPercentage: 1,
categoryPercentage: 0.6
}],
yAxes: [{
id: "y-axis-density"
}, {
id: "y-axis-gravity"
}]
}
};
var barChart = new Chart(densityCanvas, {
type: 'bar',
data: planetData,
options: chartOptions
});
The code above provides this result.
checkout this example [JSFIDDLE](http://jsfiddle.net/p3g07d09/)
I'm trying to visualize the following dataset with chart.js
var data =
{
"count": 2,
"result": {
"2020-01-22": {
"confirmed": 12,
"deaths": 5,
"recovered": 4
},
"2020-01-23": {
"confirmed": 20,
"deaths": 3,
"recovered": 2
}
}
}
So far I've figured out how to use the dates as label.
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'line',
data: { // mapping the dates as labels
labels: Object.entries(data.result).map( (item) => item[0]),
datasets: [{
label: 'My First dataset',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: ??
},{
label: 'My Second dataset',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: ??
},{
label: 'My Third dataset',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: ??
}]
}, // Configuration options go here
options: {}
});
I'd like to display the values of 'confirmed', 'deaths' and 'recovered' as three lines within this chart. Therefore I would include three different datasets right? How would I access the required information from json as array to populate the data arrays?
Thanks for your support
just map the key and values to appropriate arrays and consume them as datasets and labels.
var data = {
"count": 2,
"result": {
"2020-01-22": {
"confirmed": 12,
"deaths": 5,
"recovered": 4
},
"2020-01-23": {
"confirmed": 20,
"deaths": 3,
"recovered": 2
}
}
}
var dates = Object.keys(data["result"]).map(x => x);
var confirm = Object.values(data.result).map(x => x.confirmed);
var deaths = Object.values(data.result).map(x => x.deaths);
var recovered = Object.values(data.result).map(x => x.recovered);
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: dates,
datasets: [{
label: 'confirmed',
data: confirm,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 1
},
{
label: 'Deaths',
data: deaths,
backgroundColor: 'rgba(54, 162, 235, 0.2)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1
}, {
label: 'recovered',
data: recovered,
backgroundColor: 'rgba(255, 206, 86, 0.2)',
borderColor: 'rgba(255, 206, 86, 1)',
borderWidth: 1
}
]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" width="100" height="50"></canvas>
I'm a bit stuck on adding conditional background colours to a row in ChartJS, based on numbers on the vertical axis.
Eg.
If the vertical axis is between 0 - 6, background colour for those rows is green.
If the vertical axis is between 6 - 12 background colour for those rows is grey
If the vertical axis is > 12 background colour for those rows is red
Has anyone done something like this before?
I've attached a picture that roughly describes the functionality.
Cheers!
There is no option to do this with chartjs. However you can write your own plugin and draw the background by yourself in the beforeDraw hook for example.
var chart = new Chart(ctx, {
plugins: [{
beforeDraw: function(chart) {
//..
}
}]
});
You can get all the information to calculate the height of an y-axis-segment from the chart parameter.
I've included a snippet below how this could be implemented. Note however that this is more a proof of concept than a proper implementation:
var canvas = document.getElementById('myChart');
window.chartColors = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(51, 204, 51)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
var myLineChart = new Chart(canvas,
{
type: 'line',
data: {
labels: ['1', '2', '3', '4', '5'],
datasets: [
{
label: '# of Votes',
fill: false,
backgroundColor: window.chartColors.blue,
borderColor: window.chartColors.blue,
data: [2, 5, 12.5, 9, 6.3]
}
]
},
options: {
responsive: true,
title: {
display: true,
text: 'Conditional Background'
},
backgroundRules: [{
backgroundColor: window.chartColors.green,
yAxisSegement: 6
}, {
backgroundColor: window.chartColors.grey,
yAxisSegement: 12
}, {
backgroundColor: window.chartColors.red,
yAxisSegement: Infinity
}],
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: 1
}
}]
}
},
plugins: [{
beforeDraw: function (chart) {
var ctx = chart.chart.ctx;
var ruleIndex = 0;
var rules = chart.chart.options.backgroundRules;
var yaxis = chart.chart.scales["y-axis-0"];
var xaxis = chart.chart.scales["x-axis-0"];
var partPercentage = 1 / (yaxis.ticksAsNumbers.length - 1);
for (var i = yaxis.ticksAsNumbers.length - 1; i > 0; i--) {
if (yaxis.ticksAsNumbers[i] < rules[ruleIndex].yAxisSegement) {
ctx.fillStyle = rules[ruleIndex].backgroundColor;
ctx.fillRect(xaxis.left, yaxis.top + ((i - 1) * (yaxis.height * partPercentage)), xaxis.width, yaxis.height * partPercentage);
} else {
ruleIndex++;
i++;
}
}
}
}]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
<canvas id="myChart" width="400" height="250"></canvas>
Shiffty's answer is right on point, however it only works if the background values are present on the yAxis, which is not always the case... depends on what fits. A more generic solution is to calculate the actual values:
var canvas = document.getElementById('myChart');
window.chartColors = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(51, 204, 51)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
var myLineChart = new Chart(canvas,
{
type: 'line',
data: {
labels: ['1', '2', '3', '4', '5'],
datasets: [
{
label: '# of Votes',
fill: false,
backgroundColor: window.chartColors.blue,
borderColor: window.chartColors.blue,
data: [2, 5, 12.5, 9, 6.3]
}
]
},
options: {
responsive: true,
title: {
display: true,
text: 'Conditional Background'
},
backgroundRules: [{
backgroundColor: window.chartColors.green,
yAxisSegement: 6
}, {
backgroundColor: window.chartColors.grey,
yAxisSegement: 12
}, {
backgroundColor: window.chartColors.red,
yAxisSegement: 999999
}],
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: 1
}
}]
}
},
plugins: [{
beforeDraw: function (chart) {
var rules = chart.chart.options.backgroundRules;
var ctx = chart.chart.ctx;
var yAxis = chart.chart.scales["y-axis-0"];
var xaxis = chart.chart.scales["x-axis-0"];
for (var i = 0; i < rules.length; ++i) {
var yAxisSegement = (rules[i].yAxisSegement > yAxis.ticksAsNumbers[0] ? yAxis.ticksAsNumbers[0] : rules[i].yAxisSegement);
var yAxisPosStart = yAxis.height - ((yAxisSegement * yAxis.height) / yAxis.ticksAsNumbers[0]) + chart.chart.controller.chartArea.top;
var yAxisPosEnd = (i === 0 ? yAxis.height : yAxis.height - ((rules[i - 1].yAxisSegement * yAxis.height) / yAxis.ticksAsNumbers[0]));
ctx.fillStyle = rules[i].backgroundColor;
ctx.fillRect(xaxis.left, yAxisPosStart, xaxis.width, yAxisPosEnd - yAxisPosStart + chart.chart.controller.chartArea.top);
}
}
}]
});
Good evening,
I'm trying to build a line chart that represents API response time. The problem is that I didn't find any solution in Chart.JS documentation. Is there any native solution or any solution using canvas api?
I want to get the chart looking like this:
Here is the code that I've used to generate the chart
<script>
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: hoursArrFirst,
datasets: [{
label: 'First Brand API',
data: timeArrProftit,
borderWidth: 1,
backgroundColor: [
'rgba(255, 99, 132, 0.05)',
'rgba(255, 159, 64, 0.05)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(255, 59, 64, 1)'
]
},{
label: 'Second Brand API',
data: timeArrSecond,
borderWidth: 1,
backgroundColor: [
'rgba(132, 255, 99, 0.05)',
'rgba(64, 255, 159, 0.05)'
],
borderColor: [
'rgba(32,155,99,1)',
'rgba(64,155, 59, 1)'
]
},{
label: 'Third Brand API' ,
data: timeArrThird,
borderWidth: 1,
backgroundColor: [
'rgba(32, 99, 255, 0.05)',
'rgba(64, 59, 255, 0.05)'
],
borderColor: [
'rgba(32, 99, 120, 1)',
'rgba(64, 59, 120, 1)'
]
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
</script>
Call a function during and after animation
var options = {
onAnimationProgress: function() { drawDatasetPointsLabels() },
onAnimationComplete: function() { drawDatasetPointsLabels() }
}
function drawDatasetPointsLabels() {
ctx.font = '.9rem sans-serif';
ctx.fillStyle = '#AAA';
ctx.textAlign="center";
$(Trends.datasets).each(function(idx,dataset){
$(dataset.points).each(function(pdx,pointinfo){
// First dataset is shifted off the scale line.
// Don't write to the canvas for the null placeholder.
if ( pointinfo.value !== null ) {
ctx.fillText(pointinfo.value,pointinfo.x,pointinfo.y - 15);
}
});
});
}