Related
i trying to create a chart when users search and it works but the problem when user search again it throw Uncaught Error: Canvas is already in use and when i try to destroy it it throw another error says that destroy is not function, I need a way to make the chart change when user serach without the need to reload the page
my code
var endpoint = "/api/chart/data";
myform.addEventListener("submit", function (e) {
e.preventDefault();
var name = document.querySelector("#name").value;
var amount = document.querySelector("#amount").value;
$.ajax({
method: "GET",
url: endpoint + "?name=" + name + "&amount=" + amount,
success: function (data) {
labels = data.labels;
data = data.data;
console.log("success");
console.log(name);
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, {
type: "bar",
data: {
labels:labels,
datasets: [
{
label: "# of Votes",
data: data,
backgroundColor: [
"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)",
],
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,
borderRadius: 5,
},
],
},
options: {
responsive: true,
scales: {
x: {
min: -100,
max: 100,
ticks: {
color: '#fff',
},
beginAtZero: true,
},
y: {
ticks: {
color: '#fff',
},
beginAtZero: true,
},
},
},
});
},
error:function(){
console.error('enter valid data')
}
});
});
The problem is that the myChart variable is declared inside the scope of the AJAX success function. The variable only exists within the function body during its execution. When the user performs a new search, the success function is invoked again but the initially created myChart variable does no longer exist.
You can solve your problem by creating myChart at the beginning in the global scope as follows.
var myChart = new Chart('myChart', {
type: "bar",
data: {
labels: [], // initialize with an empty array
datasets: [{
label: "# of Votes",
data: [], // initialize with an empty array
...
});
Your event listener and AJAX request would then look as shown below. Note that I set the labels and data on the existing chart and call myChart.update() afterwards. This is cleanest and the most efficient way to deal with new data. For further details, please consult Updating Charts from chart.js documentation.
var endpoint = "/api/chart/data";
myform.addEventListener("submit", function(e) {
e.preventDefault();
var name = document.querySelector("#name").value;
var amount = document.querySelector("#amount").value;
$.ajax({
method: "GET",
url: endpoint + "?name=" + name + "&amount=" + amount,
success: function(data) {
myChart.data.labels = data.labels;
myChart.data.datasets[0].data = data.data;
myChart.update();
},
error: function() {
console.error('enter valid data')
}
});
});
I tried nearly everything but i dont know anymore how to solve this
problem i get my datas from a api in php to javascript in this case
the times, i'm using a chart.js live chart where i want to apply the
times automatically to the labels, but i dont get it how to use the
variable of my map array in my chart.js labels
function drawChartHistoryTimelineGateWayAll_hours(dataFromAjax){
var time = dataFromAjax.data.data1.map(function(innerData) {
return innerData.map(function(row){
return moment(row[11], 'YYYY-MM-DD HH:mm:ss').format('HH:mm:ss');
});
});
var myChartObject = document.getElementById('myChartHistory');
var chart = new Chart(myChartObject,{
type: 'line',
data: {
labels: [timeDisplay],--------->I need to use the variable here
datasets: [{
label: "GATEWAY1",
fill: true,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255, 99, 132, 1)',
data: [25,45,65] //Daten müssen Konfiguriert werden
},
}
}
To Implement custom label there is a chartjs plugin called datalabels which can be imported using cdn
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#0.7.0"></script>
or using npm
npm i chartjs-plugin-datalabels
Refer the below code to which implement custom date as label
let x = [],
y = [];
data.forEach(z => {
let date = new Date(z.dateT)
x.push(date.toLocaleDateString());
});
var myLineChart = new Chart(ctx, {
plugins: [ChartDataLabels],
type: "bar",
data: {
labels: x,
datasets: [
{
data: y,
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(211, 84, 0,0.8)"
]
}
]
},
options: options
});
}
};
````
I'm trying to use Chart.js to generate a bar chart using dynamically generated data from Oracle DB. I'm having trouble getting the data in the right format, I think I'm close but I've been stuck for a while.
My JSON file:
[{"REGION":"Poland","REV_VALUE":"2263"},{"REGION":"United States","REV_VALUE":"1961"},{"REGION":"Spain","REV_VALUE":"555"},{"REGION":"United Kingdom","REV_VALUE":"380"},{"REGION":"Germany","REV_VALUE":"314"}]
And here is my barchar.js file:
$(document).ready(function(){
$.ajax({
url: "http://localhost/DWH/dataJSON.php",
method: "GET",
dataType : 'JSON',
success: function(data) {
console.log(data);
var region = [];
var value = [];
for(var i in data) {
region.push(data[i].REGION);
value.push(data[i].REV_VALUE);
}
var chartdata = {
labels: region,
datasets : [
{
label: 'Region',
backgroundColor: 'rgba(200, 200, 200, 0.75)',
borderColor: 'rgba(200, 200, 200, 0.75)',
hoverBackgroundColor: 'rgba(200, 200, 200, 1)',
hoverBorderColor: 'rgba(200, 200, 200, 1)',
data: value.map(function(x) {return x * 1;})
}
]
};
var ctx = $("#myChart");
var barGraph = new Chart(ctx, {
type: 'bar',
data: chartdata
});
},
error: function(data) {
console.log(data);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
I tried to implement a solution that I found in other topics, but still without success.
Any help would be very much appreciated!
I made this quickly to give you an example to help you out, you were in the right direction. I have the snippet using hardcoded data for example purposes, and then at the bottom I used the Ajax method.
Parsed the data as so, similar to what you were doing by using data.map().
let region = [];
let rev_value = [];
try {
data.map((item) => {
rev_value.push(item.REV_VALUE);
region.push(item.REGION);
});
} catch (error) {
console.log(error);
}
Then to use the data I just simply used a spread operator for the array contents [...].
labels: [...region],
data: [...rev_value],
Example 1 using Canvas.js simple example with your data hardcoded.
var ctx = document.getElementById('myChart').getContext('2d');
let data = [{
"REGION": "Poland",
"REV_VALUE": "2263"
}, {
"REGION": "United States",
"REV_VALUE": "1961"
}, {
"REGION": "Spain",
"REV_VALUE": "555"
}, {
"REGION": "United Kingdom",
"REV_VALUE": "380"
}, {
"REGION": "Germany",
"REV_VALUE": "314"
}];
let region = [];
let rev_value = [];
try {
data.map((item) => {
rev_value.push(item.REV_VALUE);
region.push(item.REGION);
});
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: [...region],
datasets: [{
label: 'Regions',
data: [...rev_value],
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
}
}]
}
}
});
} catch (error) {
console.log(error);
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<canvas id="myChart" width="400" height="400"></canvas>
Example 2 using your template and an Ajax call, change the URL for the request.
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<canvas id="myChart" width="400" height="400"></canvas>
<script>
function grab() {
/* Promise to make sure data loads */
return new Promise((resolve, reject) => {
$.ajax({
url: "/data.json",
method: "GET",
dataType: 'JSON',
success: function(data) {
resolve(data)
},
error: function(error) {
reject(error);
}
})
})
}
$(document).ready(function() {
grab().then((data) => {
console.log('Recieved our data', data);
let regions = [];
let value = [];
try {
data.forEach((item) => {
regions.push(item.REGION)
value.push(item.REV_VALUE)
});
let chartdata = {
labels: [...regions],
datasets: [{
label: 'Region',
backgroundColor: 'rgba(200, 200, 200, 0.75)',
borderColor: 'rgba(200, 200, 200, 0.75)',
hoverBackgroundColor: 'rgba(200, 200, 200, 1)',
hoverBorderColor: 'rgba(200, 200, 200, 1)',
data: [...value]
}]
};
let ctx = $("#myChart");
let barGraph = new Chart(ctx, {
type: 'bar',
data: chartdata
});
} catch (error) {
console.log('Error parsing JSON data', error)
}
}).catch((error) => {
console.log(error);
})
});
</script>
You can try something like this :
dataPoints: variable ? variable.map((v) => ({x: (v.region), y: v.value})) : []
I have almost everything I need to get everything working just as I want it, I’m only missing one thing.
This is my get request:
app.get('/:username/tasks', function (req, res) {
if (req.session.user === req.params.username) {
var photo;
countList = [],
categoryList = [];
db.User.findOne({
where: {
username: req.session.user
}
}).then(function (info) {
console.log(info.dataValues.picURL);
photo = info.dataValues.picURL
})
db.Tasks.findAndCountAll({
attributes: ['category'],
where: {
UserUsername: req.session.user
},
group: 'category'
}).then(function (result) {
for (var i = 0; i < result.rows.length; i++) {
categoryList.push(result.rows[i].dataValues.category);
countList.push(result.count[i].count);
}
console.log(categoryList);
console.log(countList);
})
db.Tasks.findAll({
where: {
UserUsername: req.params.username
}
}).then(function (data) {
res.render('index', {
data: data,
helpers: {
photo: photo,
countList: countList,
categoryList: categoryList
}
})
});
} else {
res.redirect('/');
}
})
The “findAndCountAll” function gives me this in return:
[ 'Health', 'Other', 'Recreational', 'Work' ] [ 5, 1, 1, 1 ]
Which are exactly the two arrays I need.
The problem is that I need to pass these values into a javascript script tag.
When I send them to index.handlebars with the helper function in “Tasks.findAll” I get the values. The problem is that if I add a script tag and pass the values into that script tag, it doesn’t work.
How else can I get these values into that script tag?
That’s the last piece of the puzzle.
Here is the js file I'm trying to put the data into:
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: [MISSING DATA HERE],
datasets: [{
label: '# of Votes',
data: [MISSING DATA HERE],
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)',
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
],
borderWidth: 1
}]
},
});
I wrote in caps where the missing data is in the file.
Any help is much obliged.
You should run all those queries in parallel using Promise.all and when all of them done render chart
const userPromise = db.User.findOne({
where: {
username: req.session.user
}
});
const tasksWithCountPromise = db.Tasks.findAndCountAll({
attributes: ['category'],
where: {
UserUsername: req.session.user
},
group: 'category'
}).then(function (result) {
for (var i = 0; i < result.rows.length; i++) {
categoryList.push(result.rows[i].dataValues.category);
countList.push(result.count[i].count);
}
return { countList, categoryList };
});
const allTasksPromise = db.Tasks.findAll({
where: {
UserUsername: req.params.username
}
});
Promise.all(userPromise, tasksWithCountPromise, allTasksPromise)
.then(([user, tasksWithCount, allTasks]) => {
res.render('index', {
data: allTasks,
helpers: {
photo: user.dataValues.picURL,
countList: tasksWithCount.countList,
categoryList: tasksWithCount.categoryList
}
})
});
I am using Chart.js and am trying to change the y-axis (see screen shot below). I tried filling the yLabels property with an array of strings. But that didn't work. Any help would be appreciated!
jQuery(document).ready(function($) {
'use strict ';
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["HTML", "CSS", "SCSS", "JavaScript"],
yLabels: [
'newb',
'codecademy',
'code-school',
'bootcamp',
'junior-dev',
'mid-level',
'senior-dev',
'full-stack-dev',
'famous-speaker',
'unicorn'
],
datasets: [{
data: [12, 19, 3, 10],
backgroundColor: [
'rgba(255, 159, 64, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(255, 206, 86, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)'
],
borderWidth: 1
}]
},
options: {
legend: {
display: false
},
// scales: {
// yAxes: [{
// ticks: {
// beginAtZero: true
// }
// }]
// },
title: {
display: true,
text: 'Shameless Bar Graph to show proficency in skills'
}
}
});
});
For version 2.x, yAxes labels are actually stored in the options of the chart, and not its data as you did.
If you take a look at the docs, you'll see that you have to edit the callback attributes of the ticks in options.scales.yAxes .
To do what you want, I just added a JS object in your code :
// Replace the value with what you actually want for a specific key
var yLabels = {
0 : 'newb', 2 : 'codecademy', 4 : 'code-school', 6 : 'bootcamp', 8 : 'junior-dev',
10 : 'mid-level', 12 : 'senior-dev', 14 : 'full-stack-dev', 16 : 'famous-speaker',
18 : 'unicorn', 20 : 'harambe'
}
And then in the callback :
options: {
scales: {
yAxes: [{
ticks: {
callback: function(value, index, values) {
// for a value (tick) equals to 8
return yLabels[value];
// 'junior-dev' will be returned instead and displayed on your chart
}
}
}]
}
}
Take a look at this jsFiddle for the result.
Update for the 3.9.1 version (see https://www.chartjs.org/docs/latest/axes/labelling.html#creating-custom-tick-formats). It's quite similar but you will need to change to syntax to get :
options: {
scales: {
y: {
ticks: {
// Include a dollar sign in the ticks
callback: function(value, index, ticks) {
return '$' + value;
}
}
}
}
}