I want to add flag icons under the country code labels but am completely stuck.
Image of the chart with my current code
The images are named BR.svg, FR.svg and MX.svg and are located under #/assets/icons/flags/
I am using vue#2.6.12 and vue-chartjs#3.5.1 in my project. This is my Chart.vue component:
<script>
import { Bar } from 'vue-chartjs'
export default {
extends: Bar,
data: () => ({
chartdata: {
labels: ['BR', 'FR', 'MX'],
datasets: [
{
label: 'Lorem ipsum',
backgroundColor: '#AF78D2',
data: [39, 30, 30],
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
legend: {
display: false,
},
tooltips: {
"enabled": false
},
scales : {
xAxes : [ {
gridLines : {
display : false
}
} ],
yAxes: [{
ticks: {
beginAtZero: true,
suggestedMin: 0,
suggestedMax: 40,
stepSize: 5,
}
}]
},
"hover": {
"animationDuration": 0
},
"animation": {
"duration": 1,
"onComplete": function() {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function(dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function(bar, index) {
var data = dataset.data[index] + '%';
ctx.fillText(data, bar._model.x, bar._model.y - 5);
});
});
}
},
}
}),
mounted () {
this.renderChart(this.chartdata, this.options)
}
}
</script>
This runnable code below is the closest to a solution I have come by hours of searching. But it still won't do the trick because I don't know how to integrate it with what I have.
const labels = ['Red Vans', 'Blue Vans', 'Green Vans', 'Gray Vans'];
const images = ['https://i.stack.imgur.com/2RAv2.png', 'https://i.stack.imgur.com/Tq5DA.png', 'https://i.stack.imgur.com/3KRtW.png', 'https://i.stack.imgur.com/iLyVi.png'];
const values = [48, 56, 33, 44];
new Chart(document.getElementById("myChart"), {
type: "bar",
plugins: [{
afterDraw: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['y-axis-0'];
xAxis.ticks.forEach((value, index) => {
var x = xAxis.getPixelForTick(index);
var image = new Image();
image.src = images[index],
ctx.drawImage(image, x - 12, yAxis.bottom + 10);
});
}
}],
data: {
labels: labels,
datasets: [{
label: 'My Dataset',
data: values,
backgroundColor: ['red', 'blue', 'green', 'lightgray']
}]
},
options: {
responsive: true,
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}],
xAxes: [{
ticks: {
padding: 30
}
}],
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="90"></canvas>
When I have added the plugin code into my own code I get an error message saying 'plugins' is already defined in props, but I can't manage to use it somehow.
Anyone who knows how to implement this afterDraw plugin into my code? I appreciate any input.
Thanks a lot in advance! :)
In the mounted of your vue component you can call the addPlugin (has to be done before the renderChart method) like this:
this.addPlugin({
id: 'image-label',
afterDraw: (chart) => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['y-axis-0'];
xAxis.ticks.forEach((value, index) => {
var x = xAxis.getPixelForTick(index);
var image = new Image();
image.src = images[index],
ctx.drawImage(image, x - 12, yAxis.bottom + 10);
});
}
})
Documentation: https://vue-chartjs.org/api/#addplugin
It works in ChartJS version 4.0.1. data needs to return 'plugins':
data() {
return {
plugins: [{
afterDraw: chart => {
const ctx = chart.ctx;
const xAxis = chart.scales['x'];
const yAxis = chart.scales['y'];
xAxis.ticks.forEach((value, index) => {
let x = xAxis.getPixelForTick(index);
ctx.drawImage(images[index], x - 12, yAxis.bottom + 10)
});
}
}],
data: {...
Please note that ctx should be chart.ctx and NOT chart.chart.ctx.. Similarly, it should be chart.scales['x'] and NOT chart.scales['x-axis-0'].
After you return plugins, this needs to be referenced in your Bar component like so..
<Bar :data="data" :options="options" :plugins="plugins"/>
var ctx = document.getElementById('myChart').getContext('2d');
var labels = ["Mar-2019","Apr-2019","May-2019","Jun-2019","Jul-2019","Aug-2019","Sep-2019","Oct-2019","Nov-2019","Dec-2019","Jan-2020","Feb-2020","Mar-2020"];
var dataSet = {"ADVERTS_PUBLISHED":["0","0","1","0","4","0","2","0","1","0","1","1","1"],"ADVERT_ACTIONS":["5","1","2","1","2","0","1","0","1","2","1","0","0"],"VIEWS":["34","1","4","3","5",0,"1",0,"2","5","6",0,0],"CLICKS":["13","0","3","3","3",0,"1",0,"2","4","6",0,0],"SUBMITTED":["3",0,"2","2","2",0,"1",0,"7","3","2",0,0],"PENDING":["0",0,"2","0","0",0,"0","2","0","1","0",0,0],"FILTERED":["3",0,"1","2","2",0,"1","0","7","3","0",0,0],"SHORTLISTED":["0",0,"0","2","0",0,"0","5","0","0","0",0,0],"REGRETTED":["0",0,"0","0","0",0,"0","1","0","0","0",0,0],"INTERVIEWED":["0",0,"0","2","0",0,"0","1","0","0","0",0,0],"OFFERED":["1",0,"0","0","1",0,"11","0","0","0","0",0,0],"OFFERED_AND_DECLINED":["0",0,"0","0","0",0,"0","1","0","0","0",0,0],"REGRETTED_AND_COMM":["0",0,"0","0","0",0,"0","1","0","0","2",0,0],"ACTUAL_HIRED":["0",0,"0","0","0",0,"0","0","0","1","0",0,0]};
myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: labels,
datasets: [{
label: 'Adverts Published',
data: dataSet.ADVERTS_PUBLISHED,
backgroundColor: function() {
return getRandomColorHex()
},
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
// onClick: graphClickEvent,
hover: {
onHover: function (e, el) {
$("#myChart").css("cursor", el[0] ? "pointer" : "default");
}
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
function getRandomColorHex() {
var hex = "0123456789ABCDEF",
color = "#";
for (var i = 1; i <= 6; i++) {
color += hex[Math.floor(Math.random() * 16)];
}
return color;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="">
<canvas class="chart__graph" id="myChart"></canvas>
</div>
I am creating a pie using chartjs, the data set is dynamically generate from a php back end and could be of any size so i cant set fixed colors for the pie chart.
I have managed to get the pie chart generating with a random background color for each section but the legend is not taking on the background color. Another issue is that if I use the legend to hide a slice of the pie the colors randomly generate again. I don't want this to to happen.
Send array (["red", "blue","orange"] as value for backgroundColor.
Simple forEach example:
var colors = [];
labels.forEach((element) => {
var hex_color = getRandomColorHex();
colors.push(hex_color);
})
console.log(colors) /* ["#5076FA", "#2832C4", "#36DEA3", "#7A940B", "#FD8E0D", "#6214DF", "#9CF566", "#71459C", "#98F6B5", "#B111A4", "#AAB800", "#D8DA57", "#836BD9"] */
And use this array as a value for backgroundColor:
backgroundColor: colors,
Working example:
var ctx = document.getElementById('myChart').getContext('2d');
var labels = ["Mar-2019","Apr-2019","May-2019","Jun-2019","Jul-2019","Aug-2019","Sep-2019","Oct-2019","Nov-2019","Dec-2019","Jan-2020","Feb-2020","Mar-2020"];
var dataSet = {"ADVERTS_PUBLISHED":["0","0","1","0","4","0","2","0","1","0","1","1","1"],"ADVERT_ACTIONS":["5","1","2","1","2","0","1","0","1","2","1","0","0"],"VIEWS":["34","1","4","3","5",0,"1",0,"2","5","6",0,0],"CLICKS":["13","0","3","3","3",0,"1",0,"2","4","6",0,0],"SUBMITTED":["3",0,"2","2","2",0,"1",0,"7","3","2",0,0],"PENDING":["0",0,"2","0","0",0,"0","2","0","1","0",0,0],"FILTERED":["3",0,"1","2","2",0,"1","0","7","3","0",0,0],"SHORTLISTED":["0",0,"0","2","0",0,"0","5","0","0","0",0,0],"REGRETTED":["0",0,"0","0","0",0,"0","1","0","0","0",0,0],"INTERVIEWED":["0",0,"0","2","0",0,"0","1","0","0","0",0,0],"OFFERED":["1",0,"0","0","1",0,"11","0","0","0","0",0,0],"OFFERED_AND_DECLINED":["0",0,"0","0","0",0,"0","1","0","0","0",0,0],"REGRETTED_AND_COMM":["0",0,"0","0","0",0,"0","1","0","0","2",0,0],"ACTUAL_HIRED":["0",0,"0","0","0",0,"0","0","0","1","0",0,0]};
var colors = [];
labels.forEach((element) => {
var hex_color = getRandomColorHex();
console.log("hello" + hex_color);
colors.push(hex_color);
})
var myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: labels,
datasets: [{
label: 'Adverts Published',
data: dataSet.ADVERTS_PUBLISHED,
backgroundColor: colors,
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
// onClick: graphClickEvent,
hover: {
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
function getRandomColorHex() {
var hex = "0123456789ABCDEF",
color = "#";
for (var i = 1; i <= 6; i++) {
color += hex[Math.floor(Math.random() * 16)];
}
return color;
}
div{
border: 1px solid red;
}
<div id="">
<canvas class="chart__graph" id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I have two doughnut charts written in Chart JS with labels that would specify dollar amounts as well as percentages.
<canvas id="ikeBudgetR1" width="400px" height="400px;"></canvas>
<canvas id="ikeBudgetR2" width="400px" height="400px;"></canvas>
Javascript
<script>
var ctx = document.getElementById("ikeBudgetR1").getContext('2d');
var ikeBudgetR1 = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["Administration", "Project Delivery", "Multifamily", "Homebuyers Assistance Program", "Single Family Home Repair Program"],
datasets: [{
backgroundColor: [
"#00558C",
"#64A70B",
"#DA291C",
"#DE7C00",
"#9B26B6"
],
data: [4362828, 1787858, 57682924, 10108500, 13314455]
}]
},
options: {
title: {
display: true,
text: 'Round 1'
},
legend: {
display: false,
},
tooltips: {
callbacks: {
title: function(tooltipItem, data) {
return data['labels'][tooltipItem[0]['index']];
},
label: function(tooltipItem, data) {
var value = data.datasets[0].data[tooltipItem.index];
value = value.toString();
value = value.split(/(?=(?:...)*$)/);
value = value.join(',');
return '$' + value;
},
afterLabel: function(tooltipItem, data) {
var dataset = data['datasets'][0];
var percent = Math.round((dataset['data'][tooltipItem['index']] / dataset["_meta"][0]['total']) * 100)
return percent + '%';
}
},
}
}
});
</script>
<script>
var ctx = document.getElementById("ikeBudgetR2").getContext('2d');
var ikeBudgetR2 = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["Multifamily", "Single Family Home Repair Program", "Infrastructure Projects"],
datasets: [{
backgroundColor: [
"#00558C",
"#64A70B",
"#DA291C",
"#DE7C00",
"#9B26B6"
],
data: [91400000, 63700000, 26100000]
}]
},
options: {
title: {
display: true,
text: 'Round 2'
},
legend: {
display: false,
},
tooltips: {
callbacks: {
title: function(tooltipItem, data) {
return data['labels'][tooltipItem[0]['index']];
},
label: function(tooltipItem, data) {
var value = data.datasets[0].data[tooltipItem.index];
value = value.toString();
value = value.split(/(?=(?:...)*$)/);
value = value.join(',');
return '$' + value;
},
afterLabel: function(tooltipItem, data) {
var dataset = data['datasets'][0];
var percent = Math.round((dataset['data'][tooltipItem['index']] / dataset["_meta"][0]['total']) * 100)
return '(' + percent + '%)';
}
},
}
}
});
</script>
I can only get the percentages to calculate for one of the charts. Is it possible to make a global label for these charts where I don't have to calculate the percentages for each chart?
My fiddle
I was able to solve this by using the following formula:
afterLabel : function(tooltipItem, data) {
var allData = data.datasets[tooltipItem.datasetIndex].data;
var tooltipData = allData[tooltipItem.index];
var total = 0;
for (var i=0; i<allData.length; i++) {
total += allData[i];
}
var tooltipPercentage = Math.round((tooltipData / total) * 100);
return tooltipPercentage + '%';
},
It's not a global formula but it works on each chart I add to the page.