bar chart animation in descending order - javascript

I have a PHP search page where union members can check their seniority level. The results page displays their stats along with a chart.js horizontal bar chart showing their seniority level. all works great except the bar animates from the right.
I want the bar to animate from the left, from 397 up to their seniority level.
<script type="text/javascript">
$('#details').on('shown.bs.collapse', function () {
Chart.pluginService.register({
beforeRender: function (chart) {
if (chart.config.options.showAllTooltips) {
// create an array of tooltips
// we can't use the chart tooltip because there is only one tooltip per chart
chart.pluginTooltips = [];
chart.config.data.datasets.forEach(function (dataset, i) {
chart.getDatasetMeta(i).data.forEach(function (sector, j) {
chart.pluginTooltips.push(new Chart.Tooltip({
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options.tooltips,
_active: [sector]
}, chart));
});
});
// turn off normal tooltips
chart.options.tooltips.enabled = false;
}
},
afterDraw: function (chart, easing) {
if (chart.config.options.showAllTooltips) {
// we don't want the permanent tooltips to animate, so don't do anything till the animation runs at least once
if (!chart.allTooltipsOnce) {
if (easing !== 1)
return;
chart.allTooltipsOnce = true;
}
// turn on tooltips
chart.options.tooltips.enabled = true;
Chart.helpers.each(chart.pluginTooltips, function (tooltip) {
tooltip.initialize();
tooltip.update();
// we don't actually need this since we are not animating tooltips
tooltip.pivot();
tooltip.transition(easing).draw();
});
chart.options.tooltips.enabled = false;
}
}
});
Chart.plugins.register({
beforeDraw: function(chartInstance, easing) {
var ctx = chartInstance.chart.ctx;
ctx.fillStyle = 'rgba(89,105,255,.15)'; // your color here
var chartArea = chartInstance.chartArea;
ctx.fillRect(chartArea.left, chartArea.top, chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
}
});
var ctx = document.getElementById("chartjs_bar").getContext('2d');
var data = myChart = new Chart(ctx, {
type: 'horizontalBar',
data: {
datasets: [{
backgroundColor: [
"#5969ff",
"#ff407b",
"#25d5f2",
"#ffc750",
"#2ec551",
"#7040fa",
"#ff004e"
],
data:<?php echo json_encode($ChartRank); ?>,
}]
},
options: {
showAllTooltips: true,
tooltips: {
displayColors:false,
custom: function(tooltip) { },
callbacks: {
// use label callback to return the desired label
label: function(tooltipItem, data) {
return "Your Seniority : " + tooltipItem.xLabel;
},
// remove title
title: function(tooltipItem, data) {
return;
}
}
},
title: {
display: true,
padding: 5,
text: 'Seniority level'
},
scales: {
xAxes: [{
display: true,
gridLines: {
display:false,
drawBorder:false
},
ticks: {
reverse:true,
min:1,
stepSize: 50,
max: 397
}
}],
yAxes: [{
display: true,
gridLines: {
display:false,
drawBorder:false
}
}]
},
responsive: true,
legend: {
display:false,
padding:0,
labels: {
fontColor: '#71748d',
fontFamily: 'Circular Std Book',
fontSize: 14,
}
},
}
});
});
</script>

Related

Chart.js StackedBar doesn't show labels on bar and maximum y-value

I saw this other post on Stackoverflow and it is what I want to do. I have my awesome graph in my ASP.NET Core web application by Chart.js#2.9.4. I read the data from an API.
As I read, I added chartjs-plugin-datalabels on my project and add the script to the page.
$.ajax({
url: 'myapi',
dataType: 'json'
})
.fail(function (err) {
alert(err);
})
.done(function (data) {
$("#chart").html('');
$("#chart").html('<canvas id="barChart" style="min-height: 300px; height: 3000px; max-height: 300px; max-width: 100%;"></canvas>');
var stackedBarChartCanvas = $('#barChart').get(0).getContext('2d')
var stackedBarChartData = $.extend(true, {}, data)
var temp0 = data.datasets[0]
var temp1 = data.datasets[1]
stackedBarChartData.datasets[0] = temp1
stackedBarChartData.datasets[1] = temp0
var stackedBarChartOptions = {
responsive: true,
maintainAspectRatio: false,
tooltips: {
mode: 'label',
callbacks: {
label: function (tooltipItem, data) {
return data.datasets[tooltipItem.datasetIndex].label + ": " + numberWithCommas(tooltipItem.yLabel);
}
}
},
scales: {
xAxes: [{
stacked: true,
}],
yAxes: [{
stacked: true,
max: 100,
ticks: {
callback: function (value) {
return numberWithCommas(value);
},
},
}]
},
plugins: {
datalabels: {
display: true,
align: 'center',
anchor: 'center',
display: function (context) {
return context.dataset.data[context.dataIndex] > 15;
},
font: {
weight: 'bold'
},
formatter: Math.round
}
}
}
var stackedBarChart = new Chart(stackedBarChartCanvas, {
type: 'bar',
data: stackedBarChartData,
options: stackedBarChartOptions,
onAnimationComplete: function () {
var ctx = this.chart.ctx;
ctx.font = this.scale.font;
ctx.fillStyle = this.scale.textColor
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
this.datasets.forEach(function (dataset) {
dataset.bars.forEach(function (bar) {
ctx.fillText(bar.value, bar.x, bar.y - 5);
});
})
}
})
})
If I move the mouse over the graph, nothing happens but in the Console I have this error
Uncaught TypeError: Cannot read property 'r' of null (Chart.js:1655)
Also, I want to fix the maximum value in the y-axis must be 100 because there are only percentage. Although, I set the y-axis to 100, the chart displays 120.
Chart.js doesn't show the data because it is required to set some parameters:
HoverBackgroundColor
HoverBorderWidth
HoverBorderColor
After settings them, the chart is working.

Chart js legend are being cut off if the bar height is equal to port height - chart js

I am using chart js to display barchart as :
$(function(){
let aid;
let $radio_input;
let none_obs;
let display = true;
let $js_dom_array = ["76.44", "120.00"];
let $js_am_label_arr = ["None $0", "Terrace - Large $2000"];
if($js_am_label_arr.length > 20){
display = false;
}
let $js_backgroundColor = ["rgba(26,179,148,0.5)", "rgba(26,179,148,0.5)"];
// let $div = document.getElementById("barChart");
// $div.height="140";
let ctx2 = document.getElementById("barChart").getContext("2d");
let chart = new Chart(ctx2, {
type: 'bar',
data: {
labels: $js_am_label_arr,
datasets: [{
label: 'DOM',
data: $js_dom_array,
backgroundColor: $js_backgroundColor,
barPercentage: 0.4,
maxBarThickness: 50,
// maxBarLength: 5,
}]
},
options: {
legend: {
display: false
},
responsive: true,
maintainAspectRatio: false,
legendCallback: function(chart) {
var text = [];
for (var i=0; i<chart.data.datasets.length; i++) {
text.push(chart.data.labels[i]);
}
return text.join("");
},
tooltips: {
mode: 'index',
callbacks: {
// Use the footer callback to display the sum of the items showing in the tooltip
title: function(tooltipItem, data) {
let title_str = data['labels'][tooltipItem[0]['index']];
// let lastIndex = title_str.lastIndexOf(" ");
// return title_str.substring(0, lastIndex);
return title_str;
},
label: function(tooltipItem, data) {
return 'Avg. DOM: '+data['datasets'][0]['data'][tooltipItem['index']];
},
},
},
scales: {
xAxes: [{
stacked: false,
beginAtZero: true,
// scaleLabel: {
// labelString: 'Month'
// },
ticks: {
display: display,
min: 0,
autoSkip: false,
maxRotation: 60,
callback: function(label, index, labels) {
// let lastIndex = label.lastIndexOf(" ");
// let avg_amount = label.split(" ").pop();
// let am_name = label.substring(0, lastIndex);
// let truncated_am_name = am_name.length > 30 ? (am_name.substring(0, 30)+'...') : am_name;
// return truncated_am_name+' '+avg_amount;
return label;
}
}
}]
},
layout: {
margin: {
top: 5
}
},
},
plugins:[{
afterDatasetsDraw: function(chart,options) {
// var chartInstance = chart,
let ctx = chart.ctx;
ctx.font = Chart.defaults.global.defaultFontStyle;
ctx.fillStyle = Chart.defaults.global.textColor;
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
chart.data.datasets.forEach(function (dataset, i) {
var meta = chart.controller.getDatasetMeta(i);
meta.data.forEach(function (bar, index) {
ctx.fillText(Math.round(dataset.data[index]), bar._model.x, bar._model.y); //bar._model.y - 5
});
})
}
}]
});
document.getElementById('barChart').innerHTML = chart.generateLegend();
})
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.3"></script>
<div style="height:400px;">
<canvas id="barChart" xheight="140px"></canvas>
</div>
If you need jsfiddle
Here, the value of second barchart is 120 and it is being cut off. I could pull text little down as: ctx.fillText(Math.round(dataset.data[index]), bar._model.x, bar._model.y + 5); But I don't wat the value to be overlapped with the bar. I have also tried with following options
layout: {
margin: {
top: 5
}
},
and
axisY:{
viewportMaximum: 130
},
But, none of these seems to work. Is there any way to increase the height or viewport of the chart js? It would be helpful if you could provide the js fiddle as well.
Instead of layout.margin.top, you need to define layout.padding.top as follows:
layout: {
padding: {
top: 20
}
},

How to display different tooltip based on data values in ChartJS v2?

I’m using ChartJs, to display a Line chart and I’m trying to do 2 things :
The first one is to display different colors based on the tooltip’s value. Highest value vs Medium value
The second one is to display a different tooltip if the tooltips value is the lowest. Minimun value
I’ve tried to use a custom plugins to do this, but It didn’t work
This is the code I've managed to do so far :
Chart.plugins.register({
beforeRender: function(chart) {
if (chart.config.options.showAllTooltips) {
chart.pluginTooltips = [];
chart.config.data.datasets.forEach(function(dataset, i) {
chart.getDatasetMeta(i).data.forEach(function(sector, j) {
console.log(j, sector);
chart.pluginTooltips.push(
new Chart.Tooltip(
{
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options.tooltips,
_active: [sector],
},
chart
)
);
});
});
// turn off normal tooltips
chart.options.tooltips.enabled = false;
}
},
afterDraw: function(chart, easing) {
if (chart.config.options.showAllTooltips) {
if (!chart.allTooltipsOnce) {
if (easing !== 1) return;
chart.allTooltipsOnce = true;
}
// turn on tooltips
chart.options.tooltips.enabled = true;
Chart.helpers.each(chart.pluginTooltips, function(tooltip) {
tooltip.initialize();
tooltip._options.bodyFontFamily = "Visby";
// Change color based on value
tooltip._options.bodyFontColor = '#FEB122';
// Change tooltip's html if minimun value of dataset
// Values .datapoints[0].value
// console.log(tooltip._model);
tooltip._options.displayColors = false;
tooltip._options.bodyFontSize = tooltip._chart.height * 0.05;
tooltip._options.yPadding = 0;
tooltip._options.xPadding = 0;
tooltip.update();
tooltip.pivot();
tooltip.transition(easing).draw();
});
chart.options.tooltips.enabled = false;
}
}
});
let canvas = document.getElementById("myLineChart");
Chart.defaults.global.defaultFontFamily = "Visby";
const ctx = canvas.getContext('2d');
const labels = JSON.parse(ctx.canvas.dataset.dates);
const prices = JSON.parse(ctx.canvas.dataset.prices);
const myLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: "Prix du billet",
data: prices,
backgroundColor: [
'rgba(0, 0, 0, 0)',
],
borderColor: [
'#F2F2F2',
],
pointBackgroundColor:
'#FEB122',
pointBorderColor:
'#FEB122',
borderWidth: 3,
}]
},
options: {
showAllTooltips: true, // call plugin we created
responsive: true,
cutoutPercentage: 60,
legend: {
position: "bottom"
},
animation: {
animateScale: true,
animateRotate: true
},
tooltips: {
enabled: false,
backgroundColor:"rgba(0,0,0,0)",
callbacks: {
title: function(tooltipItems, data) {
return "";
},
label: function(tooltipItem, data) {
var datasetLabel = "";
var label = data.labels[tooltipItem.index];
return data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index] + '€';
},
labelColor: function(tooltipItem, data) {
// console.log(data);
}
}
},
legend: {
display: false
},
layout: {
padding: {
left: 32,
right: 32,
top: 32,
bottom: 32
}
},
scales: {
xAxes: [{
gridLines: {
display: false,
drawBorder: false,
},
}],
yAxes: [{
display: false
}]
}
}
});
How could I make this work ?
I've managed to do that by using the plugin Chartjs Datalabels.
And using the scriptable colors options.

Always show doughnut Chart tooltip in Angular 5

I need to always show tooltip for a doughnut Chart so I need to add this:
Chart.pluginService.register({
beforeRender: function(chart) {
if (chart.config.options.showAllTooltips) {
// create an array of tooltips
// we can't use the chart tooltip because there is only one tooltip per chart
chart.pluginTooltips = [];
chart.config.data.datasets.forEach(function(dataset, i) {
chart.getDatasetMeta(i).data.forEach(function(sector, j) {
chart.pluginTooltips.push(new Chart.Tooltip({
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options.tooltips,
_active: [sector]
}, chart));
});
});
// turn off normal tooltips
chart.options.tooltips.enabled = false;
}
},
afterDraw: function(chart, easing) {
if (chart.config.options.showAllTooltips) {
// we don't want the permanent tooltips to animate, so don't do anything till the animation runs atleast once
if (!chart.allTooltipsOnce) {
if (easing !== 1)
return;
chart.allTooltipsOnce = true;
}
// turn on tooltips
chart.options.tooltips.enabled = true;
Chart.helpers.each(chart.pluginTooltips, function(tooltip) {
tooltip.initialize();
tooltip.update();
// we don't actually need this since we are not animating tooltips
tooltip.pivot();
tooltip.transition(easing).draw();
});
chart.options.tooltips.enabled = false;
}
}
});
https://jsfiddle.net/suhaibjanjua/qz3es03j/
In Angular 5 and I don't really know how to translate that code inside a component.ts.
I also need to add a small black border to each tooltips. I know how to do that in css but I don't know how to add it to chart tooltips.
this is my current component.ts code:
doughnutChartData: any[] = [0,18,26,16, 40];
doughnutChartLabels: any[] = ['NA', 'NE', 'NO', 'C', 'S'];
doughnutChartOptions: any = {
responsive: true,
maintainAspectRatio: false,
cutoutPercentage: 80,
tooltips: {
enabled: true,
backgroundColor: 'white',
titleFontColor: 'black',
bodyFontColor: 'black',
xPadding: 20,
yPadding: 20,
displayColors: false,
callbacks: {
label: function(tooltipItem, data) {
var allData = data.datasets[tooltipItem.datasetIndex].data;
var tooltipLabel = data.labels[tooltipItem.index];
var tooltipData = allData[tooltipItem.index];
var total = 0;
for (var i in allData) {
total += allData[i];
}
var tooltipPercentage = Math.round((tooltipData / total) * 100);
return tooltipLabel + ': ' + tooltipPercentage + '%';
}
}
}
};
doughnutChartColors: any[] = [{
borderWidth: 3,
backgroundColor: ['#ffffff', '#e827d3', 'black', 'rgb(104, 104, 104)', 'gray']
}];
And the html:
<mat-card class="charts-npls first-chart">
<canvas baseChart
[data]="doughnutChartData"
[labels]="doughnutChartLabels"
[options]="doughnutChartOptions"
[colors]="doughnutChartColors"
[legend]="false"
chartType="doughnut">
</canvas>
</mat-card>
Ok I was able to find an answer by using this as an example:
https://embed.plnkr.co/opFmFg34AyqVwgvdda0Z?show=preview
declare var Chart: any;
ngOnInit() : void{
Chart.pluginService.register({
beforeDraw: (chart) => {
if (chart.config.options.showAllTooltips) {
// create an array of tooltips
// we can't use the chart tooltip because there is only one tooltip per chart
chart.pluginTooltips = [];
chart.config.data.datasets.forEach(function(dataset, i) {
chart.getDatasetMeta(i).data.forEach(function(sector, j) {
chart.pluginTooltips.push(new Chart.Tooltip({
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options.tooltips,
_active: [sector]
}, chart));
});
});
// turn off normal tooltips
chart.options.tooltips.enabled = false;
}
},
afterDraw: (chart, easing) => {
if (chart.config.options.showAllTooltips) {
// we don't want the permanent tooltips to animate, so don't do anything till the animation runs atleast once
if (!chart.allTooltipsOnce) {
if (easing !== 1)
return;
chart.allTooltipsOnce = true;
}
// turn on tooltips
chart.options.tooltips.enabled = true;
Chart.helpers.each(chart.pluginTooltips, function(tooltip) {
tooltip.initialize();
tooltip.update();
// we don't actually need this since we are not animating tooltips
tooltip.pivot();
tooltip.transition(easing).draw();
});
chart.options.tooltips.enabled = false;
}
}
});
}
And I added:
showAllTooltips: true,
to the doughnutChartOptions
Ok, to add a border to tooltips just add:
borderColor: 'rgba(0,0,0,1)',
borderWidth: 1,
caretSize: 0,
carterSize 0 will also remove the carter so that you will get a nice rectangle.

How can I show only one x-axis in synchronous chart highchart

$('#container').bind('mousemove touchmove touchstart', function (e) {
var chart,
point,
i,
event;
for (i = 0; i < Highcharts.charts.length; i = i + 1) {
chart = Highcharts.charts[i];
event = chart.pointer.normalize(e.originalEvent);
point = chart.series[0].searchPoint(event, true);
if (point) {
point.highlight(e);
}
}
});
Highcharts.Pointer.prototype.reset = function () {
return undefined;
};
Highcharts.Point.prototype.highlight = function (event) {
event = this.series.chart.pointer.normalize(event);
this.onMouseOver(); // Show the hover marker
this.series.chart.tooltip.refresh(this); // Show the tooltip
this.series.chart.xAxis[0].drawCrosshair(event, this); // Show the crosshair
};
function syncExtremes(e) {
var thisChart = this.chart;
if (e.trigger !== 'syncExtremes') { // Prevent feedback loop
Highcharts.each(Highcharts.charts, function (chart) {
if (chart !== thisChart) {
if (chart.xAxis[0].setExtremes) { // It is null while updating
chart.xAxis[0].setExtremes(
e.min,
e.max,
undefined,
false,
{ trigger: 'syncExtremes' }
);
}
}
});
}
}
// Get the data. The contents of the data file can be viewed at
$.getJSON(
'https://cdn.rawgit.com/highcharts/highcharts/v6.0.4/samples/data/activity.json',
function (activity) {
$.each(activity.datasets, function (i, dataset) {
// Add X values
dataset.data = Highcharts.map(dataset.data, function (val, j) {
return [activity.xData[j], val];
});
$('<div class="chart">')
.appendTo('#container')
.highcharts({
chart: {
marginLeft: 40, // Keep all charts left aligned
spacingTop: 20,
spacingBottom: 20
},
title: {
text: dataset.name,
align: 'left',
margin: 0,
x: 30
},
credits: {
enabled: false
},
legend: {
enabled: false
},
xAxis: {
crosshair: true,
events: {
setExtremes: syncExtremes
},
labels: {
format: '{value} km'
}
},
yAxis: {
title: {
text: null
}
},
tooltip: {
positioner: function () {
return {
// right aligned
x: this.chart.chartWidth - this.label.width,
y: 10 // align to title
};
},
borderWidth: 0,
backgroundColor: 'none',
pointFormat: '{point.y}',
headerFormat: '',
shadow: false,
style: {
fontSize: '18px'
},
valueDecimals: dataset.valueDecimals
},
series: [{
data: dataset.data,
name: dataset.name,
type: dataset.type,
color: Highcharts.getOptions().colors[i],
fillOpacity: 0.3,
tooltip: {
valueSuffix: ' ' + dataset.unit
}
}]
});
});
}
);
Any help will be appreciated
You can hide unwanted x axes using visible property:
xAxis: {
visible: i === 2,
(...)
},
Live demo: http://jsfiddle.net/BlackLabel/abf07jgc/
API reference: https://api.highcharts.com/highcharts/xAxis.visible

Categories

Resources