This question has been asked many times and I went through most of them but non of them helped me finding a solution.
I am generating couple of bar charts using a for loop as a part of reporting functionality.
I am using node.js with Express Handlebars.
My page looks like:
<div class="row report-charts">
<div class="col-md-12">
{{#buildings}}
<div class="col-md-6">
<h4>{{Name}}</h4>
<canvas id="{{idBuildings}}" width="200" height="80"></canvas>
</div>
{{/buildings}}
</div>
</div>
My js code looks like:
$('.case-report-btn').click(function(){
$.ajax({
type: 'post',
url: '/reports/cases/filter',
data : {
StartDate : $('.start-ms-time-hidden').val(),
EndDate : $('.end-ms-time-hidden').val(),
ReportKey : $('.cases-filter-type').val()
},
dataType: 'json',
success: function(res) {
$('.report-charts').show();
for(key in res) {
var innerObj = res[key]; //gives the inner obj
var ctx = document.getElementById(key); //the idBuildings
var labels = [];
var data = [];
var buildingName = innerObj.Name;
for(innerKey in innerObj) {
if(innerKey != 'Name' && innerKey != 'Total') {
labels.push(innerKey);
data.push(innerObj[innerKey]);
}
}
var options = {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: buildingName,
data: data,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255,99,132,1)',
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true,
fixedStepSize: 1
}
}]
}
}
}
var myChart = new Chart(ctx, options);
}
$('#pleaseWaitDialog').modal('hide');
},
error: function(err) {
$('#pleaseWaitDialog').modal('hide');
bootbox.alert('Error: ' + err);
}
});
});
So basically, I am using for loop to generate multiple charts on the page. Inside the loop I declared the chart variable, every time I change the report parameters and hit the button, the new chart is generated. But when I hover over it, the old one still shows up.
Now I am not sure where I should be putting the myChart.destroy() or myChart.clear() methods. I also tried moving the myChart declaration outside the for loop but it didn't help either.
Any suggestions on how to handle this?
I think there are a few ways to do it. You can update your chart data if the chart already exist. Here two functions you can use:
function removeData(chart) {
chart.data.labels.pop();
chart.data.datasets.forEach((dataset) => {
dataset.data.pop();
});
chart.update();
}
function addData(chart, label, data) {
chart.data.labels.push(label);
chart.data.datasets.forEach((dataset) => {
dataset.data.push(data);
});
chart.update();
}
First you have to remove all your data and then add the new data.
If you want to destroy the chart and create it again you have to save your variable as global. To do this you have yo declare your variable like window.myChart and then before create the new chart, something like this:
if (window.myChart) window.myChart.destroy();
window.myChart = new Chart(ctx, options);
Another way you can try is removing your canvas and creating another one. Something like this:
$('#your_canvas').remove();
$('#your_canvas_father').append('<canvas id="your_canvas"></canvas>');
Related
I am trying to make a button that clears/destroys the chart in the canvas so that i can make a new one on the same canvas, but i keep on getting that my function is declared but its value is never read. How can i fix this? I will share alot of my code under so its easier to help me, but the code messy.
HTML:
<!--Canvas for chart-->
<canvas id="chart"></canvas>
<!-- https://www.chartjs.org/docs/latest/ -->
<script id="graph1" type="text/JavaScript" src="js/Main.js"></script>
<button type="button" id="generate" onclick="generateGraph()">Generate</button>
<button type="button" id="clear" onclick="clearCanvas()">Clear</button>
JavaScript:
//Url for JSON-file
var url = "";
//The labels for the chart
var graphLabels = [];
var generateButton = document.getElementById("generate");
//When a checkbox is checked (function)
function generateGraph(url) {
var arrayTheta = [];
var arrayRange = [];
var mcsArray = [];
var channelArray = [];
//Getting the data from json-file (function) {NOTE: gotta figure out a way to get data from multible JSON-files}
async function getData(arrayRange, arrayTheta, url, graphLabels, mcsArray, channelArray) {
//Gets data from the JSON-file, were the url is the box that is checked
const response = await fetch(url);
const productData = await response.json();
for (let index = 0; index < productData.length; index++) {
arrayTheta.push(productData[index].theta);
arrayRange.push(productData[index].Range);
}
//The graph, copied from Chart.js, but changed for our prefrence
const ctx = document.getElementById('chart').getContext('2d');
const myChart = new Chart(ctx,{
type: 'line',
data: {
labels: arrayTheta,
datasets: [{
label: graphLabels,
data: arrayRange,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255, 99, 132, 1)',
pointRadius: 0,
tension: 0.4
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
,x: {
display: true,
type: 'linear'
}
}
}
});
}
getData(arrayRange, arrayTheta, url, graphLabels, mcsArray, channelArray)
//Trying to make a clear button, but does not work (Remove this comment when it works)
var clearButton = document.getElementById("clear")
function clearCanvas() {
console.log("DETROYINGG")
myChart.destroy()
}
}
I hope this code is enough to help me, but if you need more i can send that too.
your const myChart declaration is inside generateGraph function, only the code inside generateGraph has access to const myChart
what you could do is to use window.myChart instead of const myChart so that the variable is globally available and you clearCanvas() function can access it also using window.myChart.destroy()
This question already has an answer here:
Retrieving JSON data for Highcharts with multiple series?
(1 answer)
Closed 2 years ago.
I have been trying to display the second value of my json file in highcharts for two days.
my json file:
[[1591518187000,17.3,12.7],[1591518135000,17.2,12.7]...[1591518074000,17.2,12.6],[1591518020000,17.2,12.7]]
The time and the first value are displayed correctly.
my script in php file:
<script type="text/javascript">
var chart;
function requestData() {
$.getJSON('../****json.php',
function (data) {
var series = chart.series[0];
series.setData(data);
}
);
}
(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
defaultSeriesType: 'line',
marginRight: 10,
marginBottom: 25,
events: { load: requestData }
},
.....
series: [{
name: 'Temperatur',
data: []
},
{
name: "Taupunkt",
data: []
......
</script>
Does anyone happen to have a way of drawing the second values as a line?
You could process your data and make two data sets for both series. Both data sets will have the same x values, but different y values. The code could look something like this:
$.getJSON('../****json.php',
function (data) {
var dataSetOne = [],
dataSetTwo = [];
data.forEach(function(point) {
dataSetOne.push([point[0], point[1]);
dataSetTwo.push([point[0], point[2]);
});
chart.series[0].setData(dataSetOne);
chart.series[1].setData(dataSetTwo);
}
);
On my chart using Chart.js I have an annotation created with the chartjs-plugin-annotation. I would like the annotation label to be visible on hover over the line. But I can't get it to work. I have the following code:
//define ChartOneData
var ctx = document.getElementById("chart").getContext("2d");
var chartOne = new Chart(ctx, {
type: 'line',
data: chartOneData,
options: {
annotation: {
events: ["mouseenter", "mouseleave"],
annotations: [{
type: 'line',
mode: 'vertical',
scaleID: 'x-axis-0',
value: 1,
label: {
enabled: false,
content: "Text Label",
},
onMouseenter: function(e) {
var element = this;
element.options.label.enabled = true;
element.chartInstance.update();
},
onMouseleave: function(e) {
var element = this;
element.options.label.enabled = false;
element.chartInstance.update();
}]
}
}
}
}
The events fire and change the attribute 'enabled' (visible in console testing) but the chart, and visuals, do not update.
In fact I receive the error in the console:
Unable to preventDefault inside passive event listener invocation.
dispatcher # chartjs-plugin-annotation.js:261
I don't understand this, can anyone help?
So it turned out that this was an issue with the underlying pluging. The code was correct and worked with chart.js versions 2.5 and 2.6 but not with 2.7. An issue was added to the chart-annotations github repository.
The solution was to downgrade to 2.6 and await a fix in the next version of charts.js
I have a line graph generated with c3.js with json data
the current chart is very simple
var chart = c3.generate({
bindto: '.balanceChart',
data: {
url: '/data',
mimeType:'json'
}
});
json data:
{
data1: [1000,1240,1270,1250,1280]
data2: [1000,240,30,-20,30]
}
chart looks good and is there
but it is currently plotting both sets of data
what i would like is for data2 to be the tooltip value of the plot
You can hide data2 from displaying like so
data: {
...
hide: ['data2']
}
From http://c3js.org/reference.html#data-hide
And use tooltip.format.value to change the tooltip display
tooltip: {
format: {
value: function (value, ratio, id, index) {
// return chart.data.values("data2")[index]; // if still wanting to use data2
// or get rid of data2 completely using this
var vals = chart.data.values(id); // id will be 'data1', vals will then be data1 array
return vals[index] - (index === 0 ? 0 : vals[index - 1]);
}
}
}
http://c3js.org/reference.html#tooltip-format-value
tooltip.format.title and tooltip.format.name will also be useful here to communicate to a user the value isn't actually that of data1 (maybe just changing the title to "Delta Data1")
I am working on a project using Syncfusion Javascript gauge control to display a weekly pay bonus. The data is stored on a SharePoint list. I wrote a javascript to convert the sharepoint list from XML to JSON.
<script type="text/javascript">
$ajax({
url: "/_api/web/lists/GetByTitle('bonusEntry')/items?$orderby=Date desc&$filter=Department eq 'Meltshop'&$top=1",
type: "GET",
headers: {
"accept":"application/json;odata=verbose",
},
success: function (data) {
var newMsBonus = "";
for(i=0; i < data.d.results.length; i++){
newMsBonus = newMsBonus + "<div>" + data.d.results[i].ACrew + "</div>";
}
$('#oDataanalysisScoreBoard').html(newMsBonus);
},
error: function (error) {
alert("error: " + JSON.stringify(error));
}
})
Then the value is placed in this Div.
<div id="oDataanalysisScoreBoard"></div>
Basically what I would like to do is bind the data to the Syncfusion control which is set up like this:
$("#CircularGauge1").ejCircularGauge({
width: 500,
height: 500,
backgroundColor: "#3D3F3D",
readOnly: false,
scales: [{
ticks: [{
type: "major",
distanceFromScale: 70,
height: 20,
width: 3,
color: "#ffffff"
}, {
type: "minor",
height: 12,
width: 1,
distanceFromScale: 70,
color: "#ffffff"
}],
}]
});
Then the gauge is created inside this:
<div id="CircularGauge1"></div>
The gauge will build but I cannot get the gauge to recieve the value.
If anyone has any ideas on how I can make this work or things I'm doing I would greatly appreciate any input! Thanks everyone!
EDIT:
The synfusion software creates a gauge and changes the needle based on a number value thats given to it. My ajax call pulls a number entered into a Sharepoint list and then displays that in a div.
In the above code snippet you mentioned the passing value as “String”. If you pass the string value to the loop it will concatenate as string value only. But we need to pass the integer value to the Circular Gauge properties(width, height, distancefromscale) to take effect. Hence, change the code snippet with the following.
$.ajax({
url: "/Gauge/GetData",
type: "POST",
success: function (data) {
var newMsBonus = 0;
for (i = 0; i < data.length; i++) {
newMsBonus = newMsBonus + data[i].MajorDistanceFromScale; // Here i have used the MajorScale distanceFromScale value for the demo
}
$('#oDataanalysisScoreBoard').html(newMsBonus);
},
failure: function (error) {
alert("no data available");
}
});
And we have prepared the sample to meet your requirement with the MVC application including the “.mdf” database. We have created the table called “GaugeData” and added the two record. And using the “$.ajax” called the action method “GetData” and received the “JSON” data from the controller. Refer the following code snippet.
View Page:
$.ajax({
url: "/Gauge/GetData",
type: "POST",
success: function (data) {},
failure: function (error) {
}
});
Controller Page:
public class GaugeController : Controller
{
GaugeDataDataContext db = new GaugeDataDataContext();
public JsonResult GetData()
{
IEnumerable data = db.GaugeDatas.Take(500);
return Json(data, JsonRequestBehavior.AllowGet);
}
}
And then assigned the calculated value to the gauge property. Here, I have used the “MajorDistanceFromScale” value read from the database record and assigned to the gauge properties. Refer the following coding snippet.
var distanceValue = parseInt($("#oDataanalysisScoreBoard")[0].innerHTML);
$("#CircularGauge1").ejCircularGauge({
width: 500,
height: 500,
backgroundColor: "#3D3F3D",
readOnly: false,
scales: [{
ticks: [{
type: "major",
distanceFromScale: distanceValue,
height: 20,
width: 3,
color: "#ffffff"
}, {
type: "minor",
height: 12,
width: 1,
distanceFromScale: 70,
color: "#ffffff"
}],
}]
});
And also please refer the below attached sample for more reference.
GaugeListSample