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')
}
});
});
Related
I've been using ChartJS with PrimeNG, in Angular. Need to make a doughnut chart with i believe one dataset. I need to make it so each value has a different thickness, like this
So far I've tried a lot of things and read a lot of ChartJS documentation on Doughnut charts, but none of the options have helped me.
Here's how I implement my chart in HTML
<p-chart type="doughnut" [data]="donutData" [options]="donutChartOptions" class="h-10 my-4"></p-chart>
And here's the .ts to it
this.donutData = {
labels: ['A', 'B', 'C'],
datasets: [
{
data: [300, 50, 100],
backgroundColor: ['#F36F56', '#FFC300', '#B8A3FF'],
hoverBackgroundColor: ['#F36F56', '#FFC300', '#B8A3FF'],
},
],
};
this.donutChartOptions = {
cutout: 50,
plugins: {
legend: {
display: false,
labels: {
color: '#ebedef',
},
},
},
};
Here you can find the answer of your question: https://github.com/chartjs/Chart.js/issues/6195
I transferred the answer of "ex47" to chart.js 3
I put the constant "data" into the html file just to have less double code, it should better be in the javascript file.
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.9.1/dist/chart.min.js"></script>
<script>
const data = {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [
{
label: "# of Votes",
data: [12, 19, 3, 5, 2, 3],
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
}
]
}
</script>
<style>
#chartWrapper {
width: 400px;
height: 400px;
}
</style>
</head>
<body>
<div id="chartWrapper">
<canvas id="myChart" width="400" height="400"></canvas>
</div>
</body>
<script src="myChart.js"></script>
</html>
myChart.js
var thickness = {
id: "thickness",
beforeDraw: function (chart, options) {
let thickness = chart.options.plugins.thickness.thickness;
thickness.forEach((item,index) => {
chart.getDatasetMeta(0).data[index].innerRadius = item[0];
chart.getDatasetMeta(0).data[index].outerRadius = item[1];
});
}
};
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, {
type: "doughnut",
plugins: [thickness],
data: data,
options: {
plugins: {
thickness: {
thickness: [[100,130],[80,150],[70,160],[100,130],[100,130],[100,130]],
}
},
}
});
"Spirit04eK"'s solution sets the thickness in descending order of the magnitude of the value
myChart.js
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, {
type: 'doughnut',
plugins: [
{
beforeDraw: function (chart) {
const datasetMeta = chart.getDatasetMeta(0);
const innerRadius = datasetMeta.controller.innerRadius;
const outerRadius = datasetMeta.controller.outerRadius;
const heightOfItem = outerRadius - innerRadius;
const countOfData = chart.getDatasetMeta(0).data.length;
const additionalRadius = Math.floor(heightOfItem / countOfData);
const weightsMap = datasetMeta.data
.map(v => v.circumference)
.sort((a, b) => a - b)
.reduce((a, c, ci) => {
a.set(c, ci + 1);
return a;
}, new Map());
datasetMeta.data.forEach(dataItem => {
const weight = weightsMap.get(dataItem.circumference);
dataItem.outerRadius = innerRadius + additionalRadius * weight;
});
}
}
],
data: data,
options: {
layout: {
padding: 10,
},
plugins: {
legend: false,
datalabels: {
display: false
},
},
maintainAspectRatio: false,
responsive: true,
}
});
I was able to create this doughnut chart that displays data. However, now that I look at it, I would like add the number value of the foods (100,200,300) below, on a second line, instead of having next to the food item itself. Is there a way to do this? I was thinking that since this is a nested array, looping through it may work? Any thoughts?
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
label1: [["Pizza: 100"], ["Hot Dogs: 200"], ["Burgers:300"]],
datasets: [{
label: '# of Votes',
data: [12, 19, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)'
],
borderWidth: 1
}]
},
options: {
tooltips: {
callbacks: {
title: function(tooltipItem, data, label1, label2) {
return data ['label1'][tooltipItem[0]['index']];
},
label: function(tooltipItem, data) {
return data['datasets'][0]['data'][tooltipItem['index']];
},
afterLabel: function(tooltipItem, data) {
var dataset = data['datasets'][0];
var percent = Math.round((dataset['data'][tooltipItem['index']] / dataset["_meta"][0]['total']) * 100)
return '(' + percent + '%)';
}
},
backgroundColor: '#FFF',
titleFontSize: 16,
titleFontColor: '#0066ff',
bodyFontColor: '#000',
bodyFontSize: 14,
displayColors: false
}
}
});
<div>
<canvas id="myChart" height="100"></canvas>
<div id="chartjs-tooltip">
<table></table>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js">
</script>
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 am having some issues trying to update my Chartjs doughnut chart using data pulled from my database.
I have the following ajax call which is successful:
$.ajax({
url: "<!--#include virtual="../include/env"-->/data",
type: "GET",
cache: "false",
success: function(value) {
update_doughnut(value);
},
dataType: "json"
});
This pulls in 2 values [used and free]
The JS for my chart looks like this currently:
var ctx = document.getElementById('myDoughnutChart').getContext('2d');
var myDoughnutChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['Used', 'Free'],
datasets: [{
data: [0, 0],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(75, 192, 192, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(75, 192, 192, 1)'
],
borderWidth: 2
}]
},
options: {
responsive: true,
legend: {
display: false
}
},
});
I have tried creating this function which the ajax calls to update the data:
function table_space(value) {
myDoughnutChart.data.datasets[0].data = [value[0].USED, value[0].FREE]
myDoughnutChart.update();
};
But I keep getting a "Cannot read property '0' of undefined" error message. It is worth noting that the query that the ajax call runs can take up 40secs; could this be why?
Thanks for the response. But managed to figure it out. I need to make changes to my Ajax call to update the values of my doughnuts directly and get rid of my table_space function:
$.ajax({
url: "<!--#include virtual="../include/env"-->/data",
type: "GET",
cache: "false",
success: function(value) {
Doughnut1.data.datasets[0].data = [value[0].USED, value[0].FREE]
Doughnut2.data.datasets[0].data = [value[1].USED, value[1].FREE]
Doughnut3.data.datasets[0].data = [value[2].USED, value[2].FREE]
Doughnut1.update();
Doughnut2.update();
Doughnut3.update();
},
dataType: "json"
});
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})) : []