chart.js dynamically adjust gap between vertical bars - javascript

I am working on a webpage that presents dashboard on th basis of invoice processing project.
using below code i am populating bar chart.
function loadVolumeChart()
{
var pieChartContent = document.getElementById('chartAreaWrapper');
pieChartContent.innerHTML = '';
$('#chartAreaWrapper').append('<canvas id="line-chart" height="300" width="1500px"><canvas>');
//getData For Volume Analysis Chary
var url_string = document.referrer;;
var url = new URL(url_string);
var name = url.searchParams.get("name");
var user=url.searchParams.get("user");
var team=url.searchParams.get("team");
var date=url.searchParams.get("date");
var dates = [];
var count = [];
var from = date.split("-")[0];
var to = date.split("-")[1];
var re=$.ajax({
url: 'getTotalCounts.php',
type: 'POST',
data: {
from:from,
to:to,
team:team,
totalVolume: '00'
},
async:false,
success: function(data) {
var result =data;
var json = JSON.parse(result);
dates=json[0].data;//json[0].data;
count=json[1].data;
//alert(dates);
}
}).done(function(data){
// openPage(data);
}).fail(function(data){
alert(data.responseText);
});
//volume chart
new Chart(document.getElementById("line-chart"), {
type: 'bar', //line
data: {
labels:dates,
datasets: [{
data:count,
label: "Total Inward",
backgroundColor: "#0E6655", //borderColor
fill: true
},
]
},
options: {
responsive:false,
maintainAspectRatio: true,
legend: {
display: false
},
tooltips: {
enabled: true
},
scales: {
xAxes: [{
gridLines: {
display:false
},
barThickness: 15,
}],
yAxes: [{
barPercentage: 1.0,
categoryPercentage: 1.0,
gridLines: {
display:false
},
ticks: {
min: 0,
max:10,
stepSize: 1
}
}]
},
}
});
//end of volume chart
}
But the problem is when data is low, means if the x axis data contains only 2 dates, then the gap between two bars is too large, like the image below,
but if i add more dates then the gap reduces.i want to set gap between two bars even if their are only two bars. the gap between both should not increase if the dates (bars) according to the size of x axis data. if the data is large then it should only scroll. thats why i have added scroll bar.
the div of chart is as:
<div class="parentDiv" >
<div class="chartAreaWrapper" id="chartAreaWrapper" style="height:80%;width:70%;margin-left: 20px; margin-top: 10px;float: left;">
<canvas id="line-chart" height="300" width="1500px"></canvas>
</div>
</div>

In your code, the option xAxis.barThickness defines that the width of individual bars has to be of 15 pixels. Simply remove this option.
You should also consider to use the latest stable version of Chart.js (currently v2.9.3) where the option xAxis.barThickness is deprecated. The options barThickness, barPercentage and categoryPercentage are now part of the dataset configuration.

Related

Chart.JS: How to make sharp lines to smooth curved lines

Hi I'm new at charts and this is my chartjs chart, it's working currently, but it's showing in sharp lines and I want to make it smooth curve lines on this chart. Any ideas?
function statistics(data) {
if ($('#stats-currency').length > 0) {
if (typeof(stats_currency) !== 'undefined') {
stats_currency.destroy();
}
if (typeof(data) == 'undefined') {
var currency = $('select[name="currency"]').val();
$.get(admin_url + 'home/stats_currency/' + currency, function(response) {
stats_currency = new Chart($('#stats-currency'), {
type: 'line',
data: response,
options: {
responsive:true,
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
}
}]
},
},
});
}, 'json');
} else {
stats_currency = new Chart($('#stats-currency'), {
type: 'line',
data: data,
options: {
responsive: true,
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
}
}]
},
},
});
}
This can be done through the option lineTension that needs to be defined on your dataset. Choose a value below 1.
datasets: [{
...
lineTension: 0.8
}]
By default, you should however already see curved smooth lines since accoring to Chart.js documentation, the default value is 0.4.
lineTension: Bezier curve tension of the line. Set to 0 to draw straight lines.
Please note that if the steppedLine value is set to anything other than false, lineTension will be ignored.
you can do it by adding tension value to your charts options
<canvas id="myChart"></canvas>
JS
const config = {
type: 'line', // your chart type
data: data, // pass here your data
options: {
elements: {
line: {
tension : 0.4 // smooth lines
},
},
},
};
// pass it like
const myChart = new Chart(
document.getElementById('myChart'),
config
);

What kind of graph could I use to achieve this with ChartJS (or similar)?

I'm trying to make a deciBel-frequency chart like this in javascript:
[X axis is frequency domain (red, blue and yellow are 4G bands), Y axis is power in dB]
However, the classic bar chart that I find in every library cannot fix the bottom of the bars below 0. I'm trying to find another kind of chart that I could use to achieve this. Orange color is the noise floor power.
Thank you in advance.
No way to create "range" only by one value.
For example, the data for the red bar in your example is not only 20 -or- -180 but -180 to 20 = nested array (Multidimensional Array)
data = [[-180,20]];
snippet:
labels1 = ["a","b","c","d"];
data = [[20,-180],[40,-160],[20,-120]];
var data = {
labels: labels1,
datasets: [
{
label: "hello",
data: data,
backgroundColor: ["yellow", "blue", "orange"],
borderWidth: 5
}
]
}
var options = {
responsive: true,
scales: {
xAxes: [{
stacked: false,
}],
yAxes: [{
stacked: false,
ticks: {
gridLines: {
drawOnChartArea: true
},
max: 100,
min: -180,
}
}]
},
title: {
display: true,
text: name
},
tooltips: {
mode: 'index',
intersect: false,
},
};
/*for(let i = 0; i<10; i++)
{
let labels2 = [];
let datos2 = [];
labels2.push(i);
datos2.push(-120);
}*/
var ctx = document.getElementById("myChart");
var chartInstance = new Chart(ctx, {
type: 'bar',
data: data,
options:options
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<h2>
Hello World!
</h2>
<canvas id='myChart'/>

Chart.js not showing dynamically populated data

I was having some trouble when trying to dynamically populate bar chart in chart.js. I have two arrays, one for label, one for its price and both of them are already populated with the sorted data from firebase. Here is my code:
var ctx = document.getElementById('brandChart').getContext("2d");
var data = {
labels: [],
datasets: [{
data: [],
backgroundColor: [
"#424242",
]
}]
};
var options = {
layout: {
padding: {
top: 5
}
},
responsive: true,
legend: {
display: true,
position: 'bottom',
// disable legend onclick remove slice
onClick: null
},
animation: {
animateScale: true,
animateRotate: true
},
};
var opt = {
type: "horizontalBar",
data: data,
options: options
};
if (brandChart) brandChart.destroy();
brandChart = new Chart(ctx, opt);
// dynamically populate chart
for(var i = 0; i < labelData.length; i++){
brandChart.config.data.labels.push(labelData[i]);
}
for(var i = 0; i < priceData.length; i++){
brandChart.config.data.datasets[0].data.push(priceData[i]);
}
brandChart.update();
I managed to show all of them in bar chart, however, the result as such:
It is kind of squeeze between each labels if there are too many categories. Also, only the first bar has the color & the legends shown undefined. Any ideas how to solve these?
ɪꜱꜱᴜᴇ #1 - ꜱᴏʟᴜᴛɪᴏɴ
Add a callback for y-axis ticks, in your chart options :
options: {
scales: {
yAxes: [{
ticks: {
callback: function(t, i) {
if (!(i % 2)) return t;
}
}
}]
},
...
}
this will only show every other label on y-axis.
ɪꜱꜱᴜᴇ #2 - ꜱᴏʟᴜᴛɪᴏɴ
This is because, you have only one color in your backgroundColor array. If you want different color for each bar, then you need to populate this array with multiple color values.
Edit: as it seems form your updated question, you already kind of got the idea.
ɪꜱꜱᴜᴇ #3 - ꜱᴏʟᴜᴛɪᴏɴ
Define the label property for your dataset , like so :
datasets: [{
label: 'Legend Title', //<- define this
data: [],
backgroundColor: ["#424242", ]
}]

Single bar with background Chart.js [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 months ago.
Improve this question
I want to paint a horizontal bar with Chart.js, but i want a default background color (Which is the max value) and paint the current value with another color. Just like the image below. How can i do this?
There is no easy way to do this in Chart.js (such as a specific "100% stacked bar" type). What you need is two stacked horizontal bars.
First, define your chart-type as a horizontalBar
// html
<canvas id="chart" height="20"></canvas>
// javascript
var ctx = document.getElementById('chart');
var bar_chart = new Chart(ctx, {
type: 'horizontalBar' // this will give you a horizontal bar.
// ...
};
In order to have a single bar instead of two, they need to be stacked. You also need to hide the scales. Optionally, you can hide the legend and the tooltip. This is all configured in the options:
var bar_chart = new Chart(ctx, {
// ...
options: {
legend: {
display: false // hides the legend
},
tooltips: {
enabled: false // hides the tooltip.
}
scales: {
xAxes: [{
display: false, // hides the horizontal scale
stacked: true // stacks the bars on the x axis
}],
yAxes: [{
display: false, // hides the vertical scale
stacked: true // stacks the bars on the y axis
}]
}
}
};
As stacked bars are placed on top of each other, your first dataset contains your value (57.866), and the second dataset corresponds to max - value. Here's an example considering value = 57866 and max = 80000:
var value = 57866; // your value
var max = 80000; // the max
var bar_chart = new Chart(ctx, {
// ...
datasets: [{
data: [value],
backgroundColor: "rgba(51,230,125,1)"
}, {
data: [max - value],
backgroundColor: "lightgrey"
}]
};
Here's the jsfiddle with the full code.
In addition to #Tarek's answer,
If you need to get the percentage value in the bar,
https://jsfiddle.net/akshaykarajgikar/bk04frdn/53/
Dependensies:
https://www.chartjs.org/
https://chartjs-plugin-datalabels.netlify.app/
var bar_ctx = document.getElementById('bar-chart');
var bar_chart = new Chart(bar_ctx, {
type: 'horizontalBar',
data: {
labels: [],
datasets: [{
data: [57.866],
backgroundColor: "#00BC43",
datalabels: {
color: 'white' //Color for percentage value
}
}, {
data: [100 - 57.866],
backgroundColor: "lightgrey",
hoverBackgroundColor: "lightgrey",
datalabels: {
color: 'lightgray' // Make the color of the second bar percentage value same as the color of the bar
}
}, ]
},
options: {
legend: {
display: false
},
tooltips: {
enabled: false
},
scales: {
xAxes: [{
display: false,
stacked: true
}],
yAxes: [{
display: false,
stacked: true
}],
}, // scales
plugins: { // PROVIDE PLUGINS where you can specify custom style
datalabels: {
align: "start",
anchor: "end",
backgroundColor: null,
borderColor: null,
borderRadius: 4,
borderWidth: 1,
font: {
size: 20,
weight: "bold", //Provide Font family for fancier look
},
offset: 10,
formatter: function(value, context) {
return context.chart.data.labels[context.dataIndex]; //Provide value of the percentage manually or through data
},
},
},
}, // options
});
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#0.7.0"></script>
<canvas id="bar-chart" height="20"></canvas>

Hide Y-axis labels when data is not displayed in Chart.js

I have a Chart.js bar graph displaying two sets of data: Total SQL Queries and Slow SQL Queries. I have Y-axis labels for each respective set of data. The graph can be seen below:
When I toggle one of the sets of data to not display, the corresponding Y-axis labels still display. When interpreting the graph, this is a bit confusing. As seen below:
My question: How can I hide the Y-axis labels of any set of data that is currently not being displayed?
This is how I currently have my chart set up:
<canvas id="SQLPerformanceChart" minHeight="400"></canvas>
<script type="text/javascript">
...
var data = {
labels: labelArray,
datasets: [{
label: "Total SQL Queries",
fill: false,
borderWidth: 1,
borderColor: "green",
backgroundColor: "rgba(0, 255, 0, 0.3)",
yAxisID: "y-axis-0",
data: totalQueriesArray
}, {
label: "Slow SQL Queries",
fill: false,
borderWidth: 1,
borderColor: "orange",
backgroundColor: "rgba(255, 255, 0, 0.3)",
yAxisID: "y-axis-1",
data: slowQueriesArray,
}]
};
var options = {
animation: false,
scales: {
yAxes: [{
position: "left",
ticks: {
beginAtZero: true
},
scaleLabel: {
display: true,
labelString: 'Total SQL Queries'
},
id: "y-axis-0"
}, {
position: "right",
ticks: {
beginAtZero: true
},
scaleLabel: {
display: true,
labelString: 'Slow SQL Queries'
},
id: "y-axis-1"
}]
},
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
title: function(tooltipItem, data) {
return data.label;
},
beforeLabel: function(tooltipItem, data) {
if (tooltipItem.index == 24) {
return data.labels[tooltipItem.index] + " - Now";
} else {
return data.labels[tooltipItem.index] + " - " + data.labels[(tooltipItem.index) + 1];
}
}
}
}
}
var ctx = document.getElementById("SQLPerformanceChart");
var SQLPerformanceChart = new Chart(ctx, {
type: 'bar',
data: data,
options: options
});
</script>
You can add a callback function to legends onClick:
var options = {
animation: false,
scales: {
yAxes: [{
position: "left",
ticks: {
beginAtZero: true
},
scaleLabel: {
display: true,
labelString: 'Total SQL Queries'
},
id: "y-axis-0"
}, {
position: "right",
ticks: {
beginAtZero: true
},
scaleLabel: {
display: true,
labelString: 'Slow SQL Queries'
},
id: "y-axis-1"
}]
},
legend: {
onClick: function(event, legendItem) {
//get the index of the clicked legend
var index = legendItem.datasetIndex;
//toggle chosen dataset's visibility
SQLPerformanceChart.data.datasets[index].hidden =
!SQLPerformanceChart.data.datasets[index].hidden;
//toggle the related labels' visibility
SQLPerformanceChart.options.scales.yAxes[index].display =
!SQLPerformanceChart.options.scales.yAxes[index].display;
SQLPerformanceChart.update();
}
}
}
This solution applies if you are using angular-chartjs, and if you want to apply this behaviour to all displayed charts.
If you want to skip to the code, check this fiddlejs.
You can also check this other fiddlejs to check the default Angular-Chartjs behaviour.
Step by step:
I use the first chart example in angular-chart.js, so this will be the final result after clicking:
<div ng-app="app" ng-controller="MainController as mainCtrl">
<canvas id="line" class="chart chart-line" chart-data="data"
chart-labels="labels" chart-series="series" chart-options="options"
chart-dataset-override="datasetOverride" chart-click="onClick">
</canvas>
</div>
Replace the handler of the global Chart:
Chart.defaults.global.legend.onClick = function (e, legendItem) {
var idx = legendItem.datasetIndex;
// IMPORTANT charts will be created in the second and third step
var chart = charts[e.srcElement.id];
chart.options.scales.yAxes[idx].display = !chart.options.scales.yAxes[idx].display;
var meta = chart.getDatasetMeta(idx);
// See controller.isDatasetVisible comment
meta.hidden = meta.hidden === null ? !chart.data.datasets[idx].hidden : null;
chart.update();
};
Create a global variable charts so we can get access each of the charts with the canvas id:
var charts = {};
Fill up the charts variables using the chart-create event:
angular.module("app", ["chart.js"]).controller("MainController", function ($scope) {
$scope.$on('chart-create', function (event, chart) {
charts[chart.chart.canvas.id] = chart;
});
$scope.labels = ["January", "February", "March", "April", "May", "June", "July"];
$scope.series = ['Series A', 'Series B'];
$scope.data = [...
I wish there would be a better way of getting a chart from the canvas id, but as far as I know this is the suggested way by the developers.
This solution applies if you are using ng2-charts with chart.js and Angular 7^ and if you want to apply this behavior to all displayed charts.
import Chart from chart.js
Chart.defaults.global.legend.onClick = function (e: MouseEvent, chartLegendLabelItem: ChartLegendLabelItem) {
const idx: number = chartLegendLabelItem.datasetIndex;
const chart = this.chart;
chart.options.scales.yAxes[idx].display = !chart.options.scales.yAxes[idx].display;
const meta = chart.getDatasetMeta(idx);
meta.hidden = meta.hidden === null ? !chart.data.datasets[idx].hidden : null;
chart.update();
};
or for local configuration
legend: <ChartLegendOptions>{
onClick: function (e: MouseEvent, chartLegendLabelItem:ChartLegendLabelItem) {
const idx: number = chartLegendLabelItem.datasetIndex;
const chart = this.chart;
chart.options.scales.yAxes[idx].display =
!chart.options.scales.yAxes[idx].display;
const meta = chart.getDatasetMeta(idx);
meta.hidden = meta.hidden === null ?
!chart.data.datasets[idx].hidden : null;
chart.update();
}
}
I came along this problem using v3.8.0, none of the obove worked for me.
This code works for me.
Note I'm storing all my chart instances in a Map because I have multiple charts on the same page.
var instances = new Map();
When createing the incances I put them there.
and now the hiding of the y axis label and data on legend click:
onClick: function (event, legendItem) {
var instance = instances.get(event.chart.id);
var meta = instance.getDatasetMeta(legendItem.datasetIndex);
var newValue = !meta.yScale.options.display;
meta.hidden = meta.yScale.options.display;
meta.yScale.options.display = newValue;
instance.update();
}

Categories