Chart not rendering with pug/jade and nodejs - javascript

I'm trying (about a week!!) to render a chart that works totally fine with hardcoded labels, but with my labels (data) from MySQL it shows nothing but a blank page.
However, if I console.log my labels, it shows me all the data sent from my DB which I want to put as labels to my chart.
In my index.js:
router.get('/api', function (req, res) {
axios.get('http://localhost:3000/projetos/quantos/ci')
.then(dados =>{
const d = dados.data;
var labelsx = [];
for(var i = 0; i < d.length; i++){
labelsx.push(d[i].Nome);
}
console.log(labelsx);
var datax = [];
for(var j = 0; j < d.length; j++){
datax.push(d[j].QuantosHa)
}
console.log(datax);
res.render('chart',
{title: "chart",
datai: JSON.stringify(datax),
labeli: labelsx
})
})
.catch(erro => {e: erro});
});
My chart.pug:
extends layout
block content
script(src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js")
div
each l in labeli
ul=l
div
.chart-container
canvas#chartPic
script.
var ctx = document.getElementById("chartPic").getContext('2d');
ctx.canvas.parentNode.style.width = '50%';
var idata = #{datai};
var chart = new Chart(ctx, {
type: 'pie',
data: {
labels: [],
datasets: [{
data: idata,
backgroundColor: ['red', 'green', 'blue', 'pink', 'black'],
borderColor: ['green', 'blue', 'red', 'black', 'pink'],
borderWidth: 1
}]
},
options: {
title: {
display: true,
text: "top 5 centros com mais projetos"
},
legend: {
position: 'bottom'
}
}
});
If i put, for example ["one", "two", "three", "four", "five"] in my chart's labels field it render with no problem and also that "each l in labeli" works just fine, but everytime I try to pass it to my chart, page goes blank like this:
If i put it like its showing the pug code I get the chart:
Can someone help me? Thanks in advance for any suggestion you may have!

Inside index.js, you should not convert datax to a string but simply pass the original array. Remove JSON.stringify from the code block below.
res.render('chart',
{ title: "chart",
datai: JSON.stringify(datax),
labeli: labelsx
})
It should looks as follows.
res.render('chart',
{ title: "chart",
datai: datax,
labeli: labelsx
})
UPDATE
In chart.pug you forgot to define the labels. Instead of an empty array, you should change the code as follows.
var chart = new Chart(ctx, {
type: 'pie',
data: {
labels: #{labeli}, // <- make this change

It might be to late to answer this question but I was also facing the same issue and couldn't find any answer. The following steps did the trick.
Remove JSON stringify before sending the response
res.render('chart',
{
title: "chart",
datai: datax,
labeli: labelsx
}
)
And Data is returned in a single comma separated string. So I use the String.split function to create an array.
{
//...
datasets: [{
data: ('#{datai}').split(','),
backgroundColor: ['red', 'green', 'blue', 'pink', 'black'],
borderColor: ['green', 'blue', 'red', 'black', 'pink'],
borderWidth: 1
}],
//...
}

Related

Set a limit / max number for legends

Lets say I have a Donut chart with 5 items in data like this
const data = {
labels: ['E-commerce', 'Enterprise', 'Green', 'Grey', 'Purple'],
datasets: [
{
label: '# of Votes',
data: [12, 19, 3, 5, 3],
backgroundColor: ['#C07CC3', '#9C3848', '#9DDBAD', '#ADA8B6', '#606EDA'],
borderWidth: 1,
},
],
}
I don't want it to show all the legends as I don't have space or whatever reason
How can I hide the Green and purple in this example?
I mean only from legends not from chart
I see two easy ways, how you could approach this problem:
(I personally I would use the second option below, it is more configurable, but it needs just abit of coding)
You can simply delete the labels you want to delete from the labels- array, and they won't show up in the legend.
But keep in mind you would have to change the order of the data and backgroundColor arrays, to match this change.
Here a short demo:
const data = {
labels: ['E-commerce', 'Enterprise', 'Grey'], // <-- just remove the unwanted labels
datasets: [{
data: [12, 19, 5, 3, 3], // <-- reorder
backgroundColor: ['#C07CC3', '#9C3848', '#ADA8B6', '#9DDBAD', '#606EDA'], // <-- reorder
borderWidth: 1,
}],
};
const config = {
type: 'doughnut',
data: data,
options: {
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right',
labels: {
usePointStyle: true,
},
}
},
}
};
new Chart(
document.getElementById('chart'),
config
);
<script src="//cdn.jsdelivr.net/npm/chart.js"></script>
<div class="chart" style="height:184px; width:350px;">
<canvas id="chart" ></canvas>
</div>
Better and cleaner (but some coding is needed), you can filter out label-items, you don't want to display, with the function array filter. (details can be found in the documentation)
UPDATED Alternative Version Demo:
here only the Top 3 labels (limiting the amount of labels with the variable maxLabelsToShow) will be shown (sort order is descending, but changing this is would be easy)
function getLabelsOnlyTopX(num, data, labels){
let selectedLabels = []
//we don't want to alter the order
let helperData = [...data];
//sort in descending order
helperData.sort( (a,b) => b-a);
//get top X Values
helperData = helperData.slice(0, num);
//get index for the data
let indexes = data.map( (value, index) => ({value,index}) ).filter(item => helperData.some(n1 => n1 == item.value))
//slecet only labels with the correct index
selectedLabels = labels.filter((value, index) => indexes.some( n => n.index == index))
// just be sure that a maximum of num labels are sent
return selectedLabels.slice(0, num);
}
let maxLabelsToShow = 3;
let serverData = [12, 19, 3, 5, 3]
let labels = ['E-commerce', 'Enterprise', 'Green', 'Grey', 'Purple'];
// Calling the newly created function
let showOnly = getLabelsOnlyTopX(maxLabelsToShow, serverData, labels);
const data = {
labels: labels,
datasets: [{
data: serverData,
backgroundColor: ['#C07CC3', '#9C3848',
'#9DDBAD', '#ADA8B6', '#606EDA'],
borderWidth: 1,
}],
};
const config = {
type: 'doughnut',
data: data,
options: {
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right',
labels: {
usePointStyle: true,
/* FILTER function */
filter: function(item, chart) {
return showOnly.indexOf( item.text) > -1;
}
},
}
},
}
};
new Chart(
document.getElementById('chart'),
config
);
<script src="//cdn.jsdelivr.net/npm/chart.js"></script>
<div class="chart" style="height:184px; width:350px;">
<canvas id="chart" ></canvas>
</div>

Multiple dynamic vertical lines on a chart with Chart.js

I am trying to create multiple vertical lines on a single chart, these represent treatment dates. each line is to have a different value (date) and possibly different colour (depending on the treatment type) currently I have multiple lines but these are hard coded like below:
var Line = "25/03/2018";
var Line2 = "13/07/2018";
var treatments = [{
type: 'line',
mode: 'vertical',
scaleID: 'x-axis-0',
value: Line,
borderColor: '#007e24',
borderWidth: 4,
label: {
enabled: true,
content: '13/07/2018'
}
},
{
type: 'line',
mode: 'vertical',
scaleID: 'x-axis-0',
value: Line2,
borderColor: '#000',
borderWidth: 4,
label: {
enabled: true,
content: '13/07/2018'
}
}
];
As data will be coming in from a CSV Is it possible to add something like below and create the number of treatments equalled to the number of items in the arrays and change the values and colours accordingly? So using below I would end up with 3 lines with the values and colours that are in the arrays?
var dates = ["01/03/2018", "01/05/2018", "09/10/2018"];
var colours= ["#000", "#000", "#fff"];
var treatments = [{
type: 'line',
mode: 'vertical',
scaleID: 'x-axis-0',
value: DYNAMIC VALUE,
borderColor: 'DYNAMIC VALUE',
borderWidth: 4,
label: {
enabled: true,
content: '13/07/2018'
}
}
];
Or if there is any other workaround that may be possible to create this?
Thanks! Hope this makes sense! :-)
If I understand it right, you can loop through the dates array and build the treatments array with a for loop.
I've not run it, but the below should at least point you in the right direction - it assumes there are the same number of colours as dates.
var dates = ["01/03/2018", "01/05/2018", "09/10/2018"];
var colours = ["#000", "#000", "#fff"];
var treatments = [];
var i;
for (i = 0; i < dates.length; i++) {
treatments.push({
type: 'line',
mode: 'vertical',
scaleID: 'x-axis-0',
value: dates[i],
borderColor: colours[i],
borderWidth: 4,
label: {
enabled: true,
content: '13/07/2018'
}
});
}

Chart.js dinamically populate data in Oracle Application Express

Hi I am suing the library chart.js 2.7 with Oracle application express and I am facing issue with passing data array.
I set up same variable fields to store the the array for the chart, but the chart is not displayed/rendered.
note: P79_.. are item of the page (text field) containing the array from ad hoc queries.
Any suggestions? thanks in advance
here's my code
<script>
var BUDGET1 =[document.getElementById("P79_BUDGET1_AC").value]
var BUDGET2 =[document.getElementById("P79_BUDGET2_AC").value]
var ACTUAL1 =[document.getElementById("P79_ACTUAL1_AC").value]
var ACTUAL2 =[document.getElementById("P79_ACTUAL2_AC").value]
new Chart(document.getElementById("mixed-chart"), {
type: 'bar',
data: {
labels: ["P01", "P02", "P03", "P04","P05", "P06", "P07", "P08", "P09", "P10", "P11", "P12"],
datasets: [{
label: "Plan1",
type: "line",
borderColor: "#c45850",
data: BUDGET1,
fill: false
}, {
label: "Plan2",
type: "line",
borderColor: "#3e95cd",
data: BUDGET2,
fill: false
}, {
label: "Actual1",
type: "bar",
backgroundColor: "#ffbb99",
backgroundColorHover: "#ff9933",
data: ACTUAL1,
}, {
label: "Actual2",
type: "bar",
backgroundColor: "#99ffbb",
backgroundColorHover: "#00ff40",
data: ACTUAL2
}
]
},
options: {
title: {
display: true,
text: 'Plan Trend'
},
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];
var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].toLocaleString();
// make 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;
}
}
},
legend: { display: true}
}
});
</script>
I do not know if these instructions to create these arrays works. Could try to use console.log in these values to check if works?
var BUDGET1 =[document.getElementById("P79_BUDGET1_AC").value]
var BUDGET2 =[document.getElementById("P79_BUDGET2_AC").value]
console.log(BUDGET1);
console.log(BUDGET2);
var ACTUAL1 =[document.getElementById("P79_ACTUAL1_AC").value]
var ACTUAL2 =[document.getElementById("P79_ACTUAL2_AC").value]
console.log(ACTUAL1);
console.log(ACTUAL2);
*You can execute this code on console. On chrome press F12, go to console.
Look at this post to see how convert a string with commas to array. Convert string with commas to array

Pushing data from json to Chart.js labels and data

I am using the Chart.js lib to make charts.
I have a json array that I am getting from a database.
Here is the console log of it: Data
I need to get the address, speed, and speed limit for every element in the list and use it in a chart.
My current code is as follows:
function ShowChart() {
var popCanvas = document.getElementById("speedLimitsChart");
console.dir(speeddata);
var labels = speeddata.map(function (e) {
return e.Adress;
});
var speed = speeddata.map(function (e) {
return e.Speed;
});
var speedlimits = speeddata.map(function (e) {
return e.SpeedLimits;
});
console.dir(labels);
var barChart = new Chart(popCanvas, {
type: 'bar',
data: {
datasets: [{
label: 'Speed',
data: speed,
backgroundColor: '#1E90FF'
}, {
label: 'Speed Limits',
data: speedlimits,
backgroundColor: '#B22222',
type: 'line'
}],
},
labels: labels
});
}
But in the result I only have the first element in my chart, and there are no labels.
Here is the output screen: Chart
I checked speed, speedlimits and labels and all of them have 2 elements. Can you please advise where my problem might be?
I found where is my problem
I need to write labels inside of data
Like this
var barChart = new Chart(popCanvas, {
type: 'bar',
data: {
labels: labels ,
datasets: [{
label: 'Speed',
data: speed,
backgroundColor: '#1E90FF'
}, {
label: 'Speed Limits',
data: speedlimits,
backgroundColor: '#B22222',
type: 'line'
}],
},
});

Flotr2 different colors for two sets of data

I've merged positive and negative data to one data set called yAxis (multiple columns for both positive and negative). Here's the code:
//...
var yAxis = [wololoTotalValues];
var xAxis = wololoTotalKeys;
window.onload = function () {
Flotr.draw(document.getElementById("chart"), yAxis, {
title: "wololo",
bars: {
show: true,
barWidth: 0.8
},
yaxis: {
min: 0,
max: wololoMaxValue + 10,
tickDecimals: 0
},
xaxis: {
ticks: xAxis
}
});
};
//...
<div id='chart' style="width:1200px;height:500px;"></div>
I would like 'bad' and 'ble' to be red. I found some manuals how to handle this problem with flot, but not flotr(flotr2).
Is there any way to make it somehow like below? Or maybe I must split the data like here?
colors: (yAxis[0-lastGood] : "#0000FF"), (yAxis[lastGood+1-lastBad] : "#FF0000")
Okay, found the solution, splitting the data into two arrays helped. Code is below:
var gud = [];
for(i=0; i<wololoLengthGood; i++){
gud.push([i, wololoValuesGood[i]]);
}
var bad = [];
for(i=wololoLengthGood; i<wololoLengthGood+wololoLengthBad; i++){
bad.push([i, wololoValuesBad[i-wololoLengthGood]]);
}
window.onload = function () {
Flotr.draw(document.getElementById("chart"),
[{ // replacement of 'yAxis' from here
data: gud,
color: "#0000FF"
},{
data: bad,
color: "#FF0000"
}], // till here.
//...

Categories

Resources