Graph 1 hangs when function called second time - javascript

I want to generate graphs dynamically when I click on a button. My problem is when I click the button second time, the first graphs blocks displaying data.
The problem is with setInterval used within addChart function but I can't figure out how to rectify the issue. Is there some sanity in my logic or not?
<script>
function addChart() {
chartCount++;
var name = document.getElementById("chartName").value;
chartDict[name] = chartCount;
chart[chartCount] = new CanvasJS.Chart("chartContainer" + chartCount, {
title: {
text: name
},
axisY: {
includeZero: false,
maximum: 70
},
axisX: {
valueFormatString: "hh:mm tt"
},
data: [{
type: "line",
dataPoints: dps[chartCount]
}]
});
updateChart[chartCount] = function(count) {
count = count || 1;
for (var j = 0; j < count; j++) {
dps[chartCount].push({
x: xVal[chartCount],
y: yVal[chartCount]
});
xVal[chartCount] = new Date()
//console.log(xVal)
//xVal++;
}
if (dps[chartCount].length > dataLength) {
dps[chartCount].shift();
}
chart[chartCount].render();
};
intervals[chartCount] = setInterval(updateChart[chartCount], 1000)
}
</script>

You can try below workaround :
Remove the chart's inner content from DOM before reassigning the new values to chart element
Below is link to use remove() method of jquery:
https://api.jquery.com/remove/

Related

How to draw a line on a highcharts graph from an AJAX call?

I have in my html page a highcharts graph that I want to update dynamically. I have some input boxes that once they get updated by the user, trigger an AJAX post request. The request does some calculations and I want the output to be used to re-draw the line of my chart's second serie . That line represents a simple y = x function, the 'x' variable being calculated during the AJAX call.
Here is my html/JS code for the chart:
<script type="text/javascript">
$(function () {
$(document).ready(function () {
Highcharts.setOptions({
global: {
useUTC: false
}
});
var chart;
$('#container').highcharts({
chart: {
type: 'line',
animation: Highcharts.svg,
marginRight: 10,
},
title: {
text: 'Strategy Payoff'
},
xAxis: {
//type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'PnL',
data: (function () {
var data = [],
time = (new Date()).getTime(),
i;
var V = document.getElementById('V').value;
var Q = document.getElementById('Q').value;
var S = document.getElementById('S').value;
var K = document.getElementById('K').value;
var Type = document.getElementById('Type').value;
if (Type == 'Call') {
direction = 1;
} else {
direction = -1;
}
if (S >= 5000) {
stepSize = 500;
} else if (S >= 500) {
stepSize = 50;
} else {
stepSize = 1;
}
for (i = 0; i <= S * 2; i+=stepSize) { // i+=stepSize
data.push({
x: i,
y: Math.max(-V * Q, -V * Q + Q * direction * (i-K))
});
}
return data;
})()
}, {
name: 'Current Option Strategy PnL',
data: (function pnl(value=10) {
var data2 = [],
time2 = (new Date()).getTime(),
i;
var S = document.getElementById('S').value;
if (S >= 5000) {
stepSize = 500;
} else if (S >= 500) {
stepSize = 50;
} else {
stepSize = 1;
}
for (i = 0; i <= S * 2; i+=stepSize) {
data2.push({
x: i,
y: value
});
}
return data2;
})()
}]
});
});
});
</script>
Here are the input boxes that trigger the AJAX request when updated by the user:
<div class="chart" id="container"></div>
<div class="slider-wrapper">
<span>Option 1 Imp. Vol.</span>
<input class="toChange" id="rangeInput" name="rangeInput" type="range" value="{{Sigma}}" min="0.1" max="150" lang="en_EN" step="0.1" oninput="amount.value=rangeInput.value" />
<input class="toChange" id="amount" type="number" value="{{Sigma}}" min="0.1" max="150" lang="en_EN" step="0.1"oninput="rangeInput.value=amount.value" />
</div>
Finally, here is the AJAX request itself:
<script type="text/javascript">
function inputChange () {
var Sigma = document.getElementById("rangeInput").value;
var Type = document.getElementById('Type').value;
var S = document.getElementById('S').value;
var K = document.getElementById('K').value;
var t = document.getElementById('t').value;
var r = document.getElementById('r').value;
var V = document.getElementById('V').value;
var Q = document.getElementById('Q').value;
$.ajax({
url: '/optionstrategies/',
type: 'POST',
data: {
'Type': Type,
'S': S,
'K': K,
'r': r,
't': t,
'Sigma': Sigma,
},
success: function(optionVal) {
alert((optionVal - V) * Q);
document.getElementById("oPrice").innerHTML = optionVal;
document.getElementById("PnL").innerHTML = (optionVal - V) * Q;
// pnl(12);
}
});
}
$(".toChange").change(inputChange);
</script>
The AJAX call works well as the alert shows the expected value. I now need to use that value to update my chart. So for instance, if the value is equal to 12, I need the second serie of my chart to draw a line representing the y = 12 function.
I've named the function dealing with my second serie 'pnl' as you can see. I've been trying to call that function in the 'success' part of my AJAX request by writing something like 'pnl(12);', but it didn't do anything. Could anybody please help?
Use the series.update feature inside the success call and set the new data on it. Please check the available demos under below link.
API: https://api.highcharts.com/class-reference/Highcharts.Series#update
If this clue wouldn't help, please reproduce a simplified version of your code on some online editor which I could work on.

Highcharts sparklines from ajax-inserted data

You have a html table and you want to show sparkline charts from your data, exactly as in this example (from highcharts demos):
https://codepen.io/_dario/pen/rNBOGVR
Highcharts suggested code follows:
/**
* Create a constructor for sparklines that takes some sensible defaults and merges in the individual
* chart options. This function is also available from the jQuery plugin as $(element).highcharts('SparkLine').
*/
Highcharts.SparkLine = function(a, b, c) {
var hasRenderToArg = typeof a === 'string' || a.nodeName,
options = arguments[hasRenderToArg ? 1 : 0],
defaultOptions = {
chart: {
renderTo: (options.chart && options.chart.renderTo) || this,
backgroundColor: null,
borderWidth: 0,
type: 'area',
margin: [2, 0, 2, 0],
width: 120,
height: 20,
style: {
overflow: 'visible'
},
// small optimalization, saves 1-2 ms each sparkline
skipClone: true
},
title: {
text: ''
},
credits: {
enabled: false
},
xAxis: {
labels: {
enabled: false
},
title: {
text: null
},
startOnTick: false,
endOnTick: false,
tickPositions: []
},
yAxis: {
endOnTick: false,
startOnTick: false,
labels: {
enabled: false
},
title: {
text: null
},
tickPositions: [0]
},
legend: {
enabled: false
},
tooltip: {
hideDelay: 0,
outside: true,
shared: true
},
plotOptions: {
series: {
animation: false,
lineWidth: 1,
shadow: false,
states: {
hover: {
lineWidth: 1
}
},
marker: {
radius: 1,
states: {
hover: {
radius: 2
}
}
},
fillOpacity: 0.25
},
column: {
negativeColor: '#910000',
borderColor: 'silver'
}
}
};
options = Highcharts.merge(defaultOptions, options);
return hasRenderToArg ?
new Highcharts.Chart(a, options, c) :
new Highcharts.Chart(options, b);
};
var start = +new Date(),
$tds = $('td[data-sparkline]'),
fullLen = $tds.length,
n = 0;
// Creating 153 sparkline charts is quite fast in modern browsers, but IE8 and mobile
// can take some seconds, so we split the input into chunks and apply them in timeouts
// in order avoid locking up the browser process and allow interaction.
function doChunk() {
var time = +new Date(),
i,
len = $tds.length,
$td,
stringdata,
arr,
data,
chart;
for (i = 0; i < len; i += 1) {
$td = $($tds[i]);
stringdata = $td.data('sparkline');
arr = stringdata.split('; ');
data = $.map(arr[0].split(', '), parseFloat);
chart = {};
if (arr[1]) {
chart.type = arr[1];
}
$td.highcharts('SparkLine', {
series: [{
data: data,
pointStart: 1
}],
tooltip: {
headerFormat: '<span style="font-size: 10px">' + $td.parent().find('th').html() + ', Q{point.x}:</span><br/>',
pointFormat: '<b>{point.y}.000</b> USD'
},
chart: chart
});
n += 1;
// If the process takes too much time, run a timeout to allow interaction with the browser
if (new Date() - time > 500) {
$tds.splice(0, i + 1);
setTimeout(doChunk, 0);
break;
}
// Print a feedback on the performance
if (n === fullLen) {
$('#result').html('Generated ' + fullLen + ' sparklines in ' + (new Date() - start) + ' ms');
}
}
}
doChunk();
However, in my use case, the data in the table (and the data-sparkline attribute) are not hard-coded like in the example, but loaded and displayed via an AJAX call, similar to below.
//here a table row gets compiled
var tableRow = '<tr id="row_' + word.id + '">';
//this is where the sparkline data go
tableRow += '<td class="has-sparkline"></td></tr>';
//the row gets appended to tbody
$('#wordstable tbody').append(tableRow);
//finally the sparkline data are attached
//data are a simple string such as "1,2,3,4,5"
var rowId = '#row_'+word.id;
var rowIdTd = rowId + ' td.has-sparkline';
$(rowIdTd).data('sparkline',word.sparkline);
This breaks the example logic and I can't have Highcharts "see" the data.
No particular error is returned (as the data, as far as Highcharts is concerned, just isn't there, so there's nothing to do).
The doChunk bit just does all the processing in advance, and when you add your row it is no longer processing. One way of dealing with this is pulling out the part that creates a single chart into a separate function (makeChart) and when you are doing your processing you use that part directly to create your sparkline.
For example, doChunk with split out makeChart:
function makeChart(td) {
$td = td;
stringdata = $td.data('sparkline');
arr = stringdata.split('; ');
data = $.map(arr[0].split(', '), parseFloat);
chart = {};
if (arr[1]) {
chart.type = arr[1];
}
$td.highcharts('SparkLine', {
series: [{
data: data,
pointStart: 1
}],
tooltip: {
headerFormat: '<span style="font-size: 10px">' + $td.parent().find('th').html() + ', Q{point.x}:</span><br/>',
pointFormat: '<b>{point.y}.000</b> USD'
},
chart: chart
});
}
// Creating 153 sparkline charts is quite fast in modern browsers, but IE8 and mobile
// can take some seconds, so we split the input into chunks and apply them in timeouts
// in order avoid locking up the browser process and allow interaction.
function doChunk() {
var time = +new Date(),
i,
len = $tds.length,
$td,
stringdata,
arr,
data,
chart;
for (i = 0; i < len; i += 1) {
makeChart($($tds[i]));
n += 1;
// If the process takes too much time, run a timeout to allow interaction with the browser
if (new Date() - time > 500) {
$tds.splice(0, i + 1);
setTimeout(doChunk, 0);
break;
}
// Print a feedback on the performance
if (n === fullLen) {
$('#result').html('Generated ' + fullLen + ' sparklines in ' + (new Date() - start) + ' ms');
}
}
}
And then a basic example of your ajax-code:
function ajaxIsh() {
var word = {
name: 'Bird', // is the word
id: 'bird',
sparkline: '1, 2, 3, 4, 5'
};
//here a table row gets compiled
var tableRow = '<tr id="row_' + word.id + '">';
//this is where the sparkline data go
tableRow += '<th>'+word.name+'</th><td class="has-sparkline"></td></tr>';
//the row gets appended to tbody
$('#table-sparkline tbody').append(tableRow);
//finally the sparkline data are attached
//data are a simple string such as "1,2,3,4,5"
var rowId = '#row_'+word.id;
var rowIdTd = rowId + ' td.has-sparkline';
$(rowIdTd).data('sparkline',word.sparkline);
makeChart($(rowIdTd));
}
See this JSFiddle demonstration of it in action.

Changing Tables in Highcharts Missing Row

I have an HTML table with some data, from that table I'm creating a chart:
var chart = Highcharts.chart('graph_user_1', {
data: {
table: 'table_user_1',
startColumn: 0,
endColumn: 1
},
chart: {
type: 'column'
},
title: {
text: 'Coverage'
},
yAxis: {
allowDecimals: true,
title: {
text: 'Hours'
}
},
tooltip: {
formatter: function() {
return '<b>' + this.series.name + '</b><br/>' +
this.point.y + ' Points - ' + this.point.name.toLowerCase();
}
},
plotOptions: {
column: {
colorByPoint: true
}
},
series: [{
id: 'series1'
}],
colors: [
'#ff0000',
'#00ff00',
'#0000ff',
'#3A8BEE',
'#F9B342',
'#DC4008'
]
});
I also have a filter, it lets me select some dates and filter the table, these rows of data that are not hidden, are appended to a hidden table on the page:
$("#to_date").on("change", function() {
var from = parseDate($('#from_date').val());
var to = parseDate($('#to_date').val());
var loop_count = 0;
var hidden_count = 0;
$("#body tr").each(function() {
var row = $(this);
var date_from = parseDate(row.find("td").eq(7).text());
var date_to = parseDate(row.find("td").eq(8).text());
var show = true;
show = isContained(date_from, date_to, from, to);
if (show) {
row.show();
legendArray.push(row); //pushes row to array
} else {
row.hide();
hidden_count++;
}
loop_count++;
});
if (hidden_count === loop_count) {
warning.prop("hidden", false);
warning.append("<strong>No results.</strong>");
}
restore(legendArray, chart);
});
The restore function at the end gets the array with rows and a chart reference, it appends the rows from the array to the new table, then changes the source of the data from the original to the hidden table (id="aux") and redraws it.
function restore(array) {
var table = document.getElementById('auxBody');
for (var i = 0; i <= array.length - 1; i++) {
table.appendChild(array[i][0].cloneNode(true));
}
var complete = function(options) {
var chart = $('#graph_user_1').highcharts();
var series1 = chart.get('series1');
series1.setData(options.series[0].data, false);
chart.redraw();
};
Highcharts.data({
table: 'aux',
complete: complete
});
}
After this, the graph IS updated, but it's always missing one row, the last one. I've printed the array, the new table, the nodes that are being appended, inspected, etc. All of this show the table with all the rows, but the graph is always missing the last one, I thought it was an index problem in the loop that adds the nodes but that doesn't seems to be the case.
As I posted earlier, it was a header issue with the table.
At creation I was appending the outerHTML of the copied table head:
newTable.append(newTHead[0].outerHTML);
Of course this caused an issue and the table had no headers, (even though it still showed on inspect) solution was removing the outerHTML and just appending the node, just a dumb conceptual mistake.
newTable.append(newTHead[0]);

Chart won't draw. Returning a string value not a Number value - Meteor - Chartjs

So I'm trying to build a pie chart using chartjs in meteor.
I'm pretty sure the problem is that the order of precedence is talking over here.
I need the object in this order
{
value: 900.65,
color:"#red",
highlight: "#FF5A5E",
label: "income"
}
but i get it in this order
{
color: "#red"
highlight: "#FF5A5E"
label: "income"
value: 900.65
}
This is my loop
function drawExpPie(){
data = [];
var Task = Tasks.find({},{fields:{value:1,text:1}}).fetch();
for(var i = 0; i < Task.length; i++) {
var newdataset = {
label:Task[i].text,
highlight: "#FCA456",
color: "red",
value:Task[i].value,
};
data.push(newdataset);
}
console.log(data);
var context = document.getElementById('myExpChart').getContext('2d');
var myPieChart = new Chart(context).Pie(data);
}
Template.exp.helpers({
exp: function() {return Session.get("exp");}
});
Template.exp.rendered = function(){
drawExpPie();
};
Any help is appreciated. Thanks
Change value:Task[i].value to
value:Task[i].value || 0,
This fixed it...
for(var i = 0; i < Task.length; i++) {
data.push({
label: Task[i].text,
highlight: "#FF5A5E",
color:"#F7464A",
value: Number(Task[i].value)
});
}
Keynote : value: Number(Task[i].value) would likely work as well.

Canvas.js slows down

The problem:
The problem I am encountering is that for each "JQuery event" click, the canvas.js diagram slows down proporsjonal to the click? I believe $(document).ready(function(){ is responsible.
That is to say 10 clicks slows down the applciation 10 times. Keep in mind that I have five canvas.js diagrams (tables). Canvas.js
Table1.js (The same code structure goes for the other diagrams, table2,table3 etc).
(function table1(){
$(document).ready(function(){
var dps = []; // data
var chart = new CanvasJS.Chart("table1",
{
title:{
text: "Exhaust Temperature"
data: [
{
type: "spline",
name: "Temp Cylinder 1",
showInLegend: "true",
legendText: "Temp Cylinder 1",
dataPoints: dps1
}
});
var xVal = 0;
var updateInterval = 50;
var dataLength = 50;
var updateChart = function (count) {
count = count || 1;
// count is number of times loop runs to generate random dataPoints.
for (var j = 0; j < count; j++) {
dps.push({
x: xVal,
y: EXTS[1]
});
xVal++;
};
if (dps.length > dataLength )
{
dps.shift();
}
chart.render();
};
// generates first set of dataPoints
updateChart(dataLength);
// update chart after specified time.
setInterval(function(){updateChart()}, updateInterval);
});
}());
This is JQuery event that is responsible for showing and hiding the diagrams, keep in mind that the user can only view one diagram at time.
$('[data-row]').on('click', function() {
var row = $(this).attr('data-row');
$('.active').removeClass('active');
$('#table' + row).addClass('active');
if (row == 1){
$.getScript("table1.js", function(){});
table1();
} else if (row == 2) {
$.getScript("table2.js", function(){});
table2();
} else if (row == 3) {
$.getScript("table3.js", function(){});
table3();
}
});

Categories

Resources