I'm newbie in Angular and I want to show charts with dynamic data.
I'm trying with Chart.js I've made the import and examples works.
So basically the system recieves from PHP JSON data and I show the data.
`<div *ngFor="let i of idspreguntas; let f = index">
<canvas id="{{i}}"></canvas>
<span *ngIf="f == max2-1" id="inservible">
{{loadGraphics()}}
</span>
</div>`
But here is a problem the HTML code executes after I set the Chart properties and doesn't work.
My solution was check the last position of Array (Previously transformed from JSON) and execute loadGraphics() I gave more time adding timeout per Chart.
loadGraphics() {
$('#inservible').remove();
let index = 0;
console.log(this.lista);
for (const i of this.lista) {
setTimeout(this.cargaChart(i, index), 2000);
index++;
}
}
I know this is a very bad practice but I don't know how to make it.
Finally here is the cargaChart function
cargaChart(i, u) {
const respu = [];
const cont = [];
if (i.Respuesta1 !== '') {
respu.push(i.Respuesta1);
cont.push(i.Contador1);
}
if (i.Respuesta2 !== '') {
respu.push(i.Respuesta2);
cont.push(i.Contador2);
}
if (i.Respuesta3 !== '') {
respu.push(i.Respuesta3);
cont.push(i.Contador3);
}
if (i.Respuesta4 !== '') {
respu.push(i.Respuesta4);
cont.push(i.Contador4);
}
if (i.Respuesta5 !== '') {
respu.push(i.Respuesta5);
cont.push(i.Contador5);
}
if (i.Pregunta !== '') {
const myChart = new Chart($('#' + i.idPregunta)[0].getContext('2d'), {
type: 'bar',
data: {
labels: respu,
datasets: [{
label: i.Pregunta,
data: cont,
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1,
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
}
}]
}
},
});
}
}
This is de unique method that is worked for me. (Almost)
The last dataof array doesn't work console said 'TypeError: Cannot read property 'getContext' of undefined'
But only in the last position, others positions works well.
Here the JSON
[{"idPregunta":"04QLDT5S","NumeroPregunta":"3","Nombre":"¿Quién eres?","Pregunta":"¿Quién eres?","Respuesta1":"Yo","Contador1":"0","Respuesta2":"Tú","Contador2":"1","Respuesta3":"Ella","Contador3":"0","Respuesta4":"","Contador4":0,"Respuesta5":"","Contador5":0},{"idPregunta":"0Z000BZ8","Pregunta":"Qué hace","Respuesta1":"Nada","Contador1":"0","Respuesta2":"Llorando","Contador2":"0","Respuesta3":"Triste","Contador3":"0","Respuesta4":"","Contador4":"0","Respuesta5":"","Contador5":"0"},{"idPregunta":"0Y2FG4XL","Pregunta":"¿Qué duces=","Respuesta1":"Nada","Contador1":"0","Respuesta2":"Algo","Contador2":"0","Respuesta3":"Simbólico","Contador3":"0","Respuesta4":"Majestuoso","Contador4":"0","Respuesta5":"Brilante","Contador5":"0"}]
Sorry for all.. I'm learning.
Related
This is my callback function and i have getData(data); to get all JSON data ,
And created dataset = [ ]; (for get some specific properties from my all JSON data)
function call_some_api(getData){
request('https://someUrl..........',{json:true},(err,res,data) => {
if (err) {
console.log(err);
}
if (res.statusCode === 200){
var dataset = [];
data.forEach((value, key)=>{
dataset.push(value.close);
});
getData(data);
}
});
};
And use callback and pass my all JSON data in res.render it works normally.
But i want add dataset variable from my callback into res.render to page know variable dataset
app.get('/chart',function(req,res){
call_some_api(function(getAPI_data){
res.render('chart',{
dataChart: getAPI_data,
});
});
});
I just need to my /chart page (handlebars template) know my variable from callback function. (for build chart)
This my /chart (handlebars template)
<canvas id="myChart" width="400" height="400"></canvas>
<br><br>
<script>
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['Jan', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
// I just want add in this line below.
data: dataset,
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
stacked: true
}
}
}
});
</script>
This error
You mean like a second argument, analog to getAPI_data ?
function call_some_api(getData){
request('https://someUrl..........',{json:true},(err,res,data) => {
if (err) {
console.log(err);
}
if (res.statusCode === 200){
var dataset = [];
// BTW this can be better/cleaner done with `.map` ;)
data.forEach((value, key)=>{
dataset.push(value.close);
});
getData(data, dataset);
}
});
};
And in your render/http endpoint
app.get('/chart',function(req,res){
call_some_api(function(getAPI_data, dataset){
res.render('chart',{
dataChart: getAPI_data,
dataset
});
});
});
NOTE: Code not tested, inline edited.
Hey I have only been javascript for a little bit but I am trying to get user input so that it can split up that number into 50% 30% and 20% which will also display the percentages in a chart using chart.js. Now I have tried many different ways which either result in no chart, no output of the numbers in the div elements, or just nothing at all. I assume it has to deal with scope issues on the perfifty variables being in the function but then getDocumentById is not retrieving them when they are global and I still can't get those variables to be part of the chart. Sorry if this is a simple fix I have just been on this for too many days and I still cant figure it out. Thank you.
function calculate(){
var user_input = document.getElementById("monthlyincome").value;
var percentages = {
perfifty: (50 / 100) * user_input,
perthirty: (30 / 100) * user_input,
pertwenty: (20 / 100) * user_input
};
document.getElementById("50%").innerHTML = percentages.perfifty;
document.getElementById("30%").innerHTML = percentages.perthirty;
document.getElementById("20%").innerHTML = percentages.pertwenty;
};
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: ['Red', 'Blue', 'Yellow'],
datasets: [{
label: '',
data: [percentages.perfifty, percentages.perthirty, percentages.pertwenty],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
I assume you call calculate when the user has given input and you create the chart outside of any function. This would mean you create the chart immediately when loading the script, when the user has not given any input yet. you want to create the chart inside calculate or if you want to see the canvas before user input, you can update the chart.
Here is an example:
function handleInput() {
let text = document.getElementById("uInput");
var num = Number(text.value);
if (isNaN(num)) {
alert("bad input!");
return;
}
var percentages = {
perfifty: (50 / 100) * num,
perthirty: (30 / 100) * num,
pertwenty: (20 / 100) * num
};
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: ['Red', 'Blue', 'Yellow'],
datasets: [{
label: '',
data: [percentages.perfifty, percentages.perthirty, percentages.pertwenty],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
}
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.5.1/dist/chart.min.js"></script>
<label for="uInput">Input:</label>
<input type="text" id="uInput">
<button onclick="handleInput()"> Submit </button>
<canvas id="myChart"></canvas>
I have a dynamic data that is need to be put inside a for loop in order to display the data of interest. I tested putting animation into 0 from this issue and also try the same update() function.
This is my code below
barChartMonth() {
let backgroundColor: any = [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)',
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
];
let borderColor: any = [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)',
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
];
this.barChart = new Chart(this.barCanvas.nativeElement, {
type: 'bar',
data: {
labels: this.monthcostlabor,
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
for(let bard = 0; bard < this.monthcostlabor.length; bard++){
this.barChart.data.datasets.push({ label: this.monthcostlabor[bard], backgroundColor: backgroundColor[bard], borderColor: borderColor[bard], borderWidth: 1 });
}
this.barChart.data.datasets.forEach(element => {
element.data.push(this.monthcostglobal)
});
this.barChart.update();
}
The code above dynamically choose color, hover and based on the data recorded. See for loop. Is there any other way to solve this issue?
A few of the glaring problems is how the length of backgroundColor and borderColor could be less than this.monthcostlabor leading to undefined values when loaded through the bard iterator.
Also, why cannot you loop within the constructor?
this.barChart = new Chart(this.barCanvas.nativeElement, {
type: 'bar',
data: {
labels: this.monthcostlabor,
datasets: this.monthcostlabor.map((elem,i) => ({
label: elem,
backgroundColor: backgroundColor[(i % backgroundColor.length)],
borderColor: borderColor[(i % borderColor.length)],
borderWidth: 1,
data:[this.monthcostglobal] })); // the second push() can be included here?
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
/*
for(let bard = 0; bard < this.monthcostlabor.length; bard++){
this.barChart.data.datasets.push({ label: this.monthcostlabor[bard], backgroundColor: backgroundColor[bard], borderColor: borderColor[bard], borderWidth: 1 });
}
this.barChart.data.datasets.forEach(element => {
element.data.push(this.monthcostglobal)
});
this.barChart.update(); */
I guess the problem is related to async api calls
I solved it with :
async setChart () {
this.myChart = await this.apiService.setChartData(this.myChart, this.myCanvas);
this.myChart.update();
}
async this.apiService.setChartData(mChart, mCanvas) {
mChart.data = this.getChrData(mLabel, dtSets, this.colourList, this.colourBordList, cType);
mChart.data.labels = mLabel;
return mChart;
}
Same issue was happened to me. I resolved it using a setTimeout(function(){chart.update()},50) but your solution is more elegant.
Nice
I'm writing code to read in values from my Firebase database, store them into an array, and then plug my array into the Chart.js code to display my data in the graph. But my graph is coming up empty.
First, I create a snapshot of the values in the database, and push them to the new array genderData. I then confirmed that the array was populated with a console.log(genderData) (see below). As far as I can tell, the array was populated:
My console log:
I then console logged outside of my ref call to the database, and it looks like this:
My code to pull data from the database:
var rootRef = firebase.database().ref().child('counters');
// Get counter values.
var genderData = [];
rootRef.once('value').then(function(snapshot){
genderData.push(snapshot.val()['Male']);
genderData.push(snapshot.val()['Female']);
genderData.push(snapshot.val()['Nonbinary']);
genderData.push(snapshot.val()['Other']);
genderData.push(snapshot.val()["Didn't Say"]);
console.log(genderData);
})
console.log(genderData);
Then, I created a regular bar graph with Chart.js, and tried to plug in genderData into the graph:
// Bar graph displaying the total number of students by gender.
var ctx = document.getElementById("myChart4").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["Male", "Female", "Non-Binary", "Other", "Unspecified"],
datasets: [{
data: genderData,
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)',
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
title: {
display: true,
text: 'Total Students by Time Taken to Complete Degree'
},
legend:{
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
But my graph is empty:
EDIT:
Upon further inspection, I noticed that the values are showing up... kind of.
So it seems that my data just isn't creating the "bar" of the graph? And my y values start at 0.0 and end at 1.0, and I have no idea why.
I'm new to Chart.js and I've been trying to get all the snippets I've found to work together to get my labels and tool-tips to display correctly. I thought I would post my working script to show how I managed to get my values displayed with the thousand separator, a currency symbol added to the tool-tips and to the scales, and to have labels on the X and Y axes. Some of the posts I saw didn't have examples on where to place the relevant code.
Please note, I did not write all this code. This has been compiled from multiple Stack searches and multiple attempts to get some of it to work together.
Here's the code I used...
<canvas id="myChart"></canvas>
<script>
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["July", "August", "September", "October", "November", "December", "January", "February", "March", "April", "May", "June"],
datasets: [{
label: 'YTD 2017/18',
data: ["12000, 11250, 10000, 2000, 3000, 6000,12000, 11250, 10000, 2000, 3000, 6000"],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)',
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)',
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
scaleLabel: {
display: true,
labelString: 'Total Sales',
fontStyle: 'bold',
fontSize: 20
},
ticks: {
beginAtZero: true,
callback: function(value, index, values) {
if(parseInt(value) >= 1000){
return '$' + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
} else {
return '$' + value;
}
}
}
}],
xAxes: [{
scaleLabel: {
display: true,
labelString: 'Months of the Year',
fontStyle: 'bold',
fontSize: 20
}
}],
},
tooltips: {
callbacks: {
// this callback is used to create the tooltip label
label: function(tooltipItem, data) {
// get the data label and data value to display
// convert the data value to local string so it uses a comma seperated number
var dataLabel = data.labels[tooltipItem.index];
// add the currency symbol $ to the label
var value = ': $ ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].toLocaleString();
// make sure this isn't a multi-line label (e.g. [["label 1 - line 1, "line 2, ], [etc...]])
if (Chart.helpers.isArray(dataLabel)) {
// show value on first line of multiline label
// need to clone because we are changing the value
dataLabel = dataLabel.slice();
dataLabel[0] += value;
} else {
dataLabel += value;
}
// return the text to display on the tooltip
return dataLabel;
}
}
},
}
});
</script>