Below is my code ,Firstly i had fetched data from database using JSON,after that i binded initial 15 rows to chart,and in setInterval function i am continually binding 1 row after interval of 1 second ,My question is without alert i.e alert("hi") i am not getting initial result,how can i get result without alert?
$(function () {
$(document).ready(function () {
var Data = "";
var dataarray = [];
var IdArray = [];
var counter = 0;
var chart;
$('#container').highcharts({
chart: {
type: 'spline',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function () {
var series = this.series[0];
setInterval(function () {
var i = 16 + counter;
var x = IdArray[i], // current time
y = dataarray[i];
series.addPoint([x, y], true, true);
counter = counter + 1;
}, 1000);
}
}
},
title: {`enter code here`
text: 'Live HighChart From Database'
},
xAxis: {
type: 'decimal'
},
yAxis: {
title: {
text: 'Value'
}
},
series: [{
name: 'Data from database',
data: (function () {
// generate an array of random data
$.ajax({
type: 'POST',
dataType: 'json',
contentType: 'application/json',
url: 'LiveHighchart.aspx/GetData',
data: '{}',
success:
function (response) {
Data = response.d;
for (var i = 0; i < Data.length; i++) {
dataarray[i] = Data[i].random;
IdArray[i] = Data[i].Id;
}
}
});
var data = [];
alert("hi");
for (var i = 0; i < 15; i++) {
data.push({
x: IdArray[i],
y: dataarray[i]
});
}
return data;
})()
}]
});
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto">
</div>
</div>
</form>
</body>
</html>
I think it's because the query hasn't return the result yet - the alert is causing a pause in your app that means the result can be delivered in time. You should think about using callbacks - functions that only run when the data from your AJAX call is returned.
I Solved it myself ,code after ajax request was executing before ajax request loads data:
this line (async: false) in ajax request forced code after ajax to pause until ajax loads data
Related
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.
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/
I'm currently trying to get a chart I have as drilldown remove all series data previously and redraw with new data. Below I've added the ajax calls and the html/javascript for the chart. The problem was that everytime I called the chart, it would rebuild the chart and double call. So I've been trying to get it to simply remove the data and redraw with new data from the ajax call.
AJAX & SetData call:
self.drilldownLoad = (year: number) => {
self.isDrilldownLoading(true);
self.isDrilldownLoaded(false);
$.ajax({
xhrFields: { withCredentials: true },
url: areaUrl + "api/Incident/IncidentDrilldown?year=" + year,
success: data => {
self.isDrilldownLoading(false);
self.data(data);
self.setDrilldownPlotData(data);
self.isDrilldownLoaded(true);
},
error: data => {
self.loadingError(true)
}
});
}
self.setDrilldownPlotData = (data: any) => {
while (self.drilldownPlotData().length) {
self.drilldownPlotData().pop();
}
while (self.drilldownPlotDataLabels().length) {
self.drilldownPlotDataLabels().pop();
}
var len = data.List.length,
i;
var criticalData = [];
for (i = 0; i < len; i++) {
criticalData.push(
data.List[i].Critical
)
}
var highData = [];
for (i = 0; i < len; i++) {
highData.push(
data.List[i].High
)
}
var mediumData = [];
for (i = 0; i < len; i++) {
mediumData.push(
data.List[i].Medium
)
}
var lowData = [];
for (i = 0; i < len; i++) {
lowData.push(
data.List[i].Low
)
}
for (i = 0; i < len; i++) {
self.drilldownPlotDataLabels.push(
data.List[i].IncidentMonth
)
}
self.drilldownPlotData.push(
{
name: 'Critical',
data: criticalData,
color: '#fa5a5a',
},
{
name: 'High',
data: highData,
color: '#fea156',
},
{
name: 'Medium',
data: mediumData,
visible: false,
color: '#b191c3',
},
{
name: 'Low',
data: lowData,
visible: false,
color: '#83bfd1',
}
)
}
This creates the initial chart. Once the chart is initialized, I set it to not be recreated every time I have data load from this particular ajax call. I can't seem to get it load the series data in correctly and redraw the chart.
var = subchartCreated = false;
viewModel.isDrilldownLoaded.subscribe(function () {
if (!subchartCreated) {
specificChart();
subchartCreated = true;
}
if (subchartCreated === true)
{
for (var i = 0; i < specificChart.series.length; i++) {
specificChart.series[i].remove(true); //forces the chart to redraw
}
}
});
I have two charts, one chart is the initial chart and that one is loading just fine. The second chart is the one of interest and I would like to have it load once and then simply load the series data, remove it from the second chart and then redraw with the new data. This is the click function that I have in the first chart to load the second chart. Currently, it works on the first load, but will not update data beyond that.
point: {
events: {
click: function () {
viewModel.drilldownLoad(this.category);
$('#drilldownButton').removeClass('hidden');
$('#yearlyincident-container').addClass('hidden');
$('#drilldown-container').removeClass('hidden');
$('#incidentInfoGrid').addClass('hidden');
$('#incidentDrillDownGrid').removeClass('hidden');
getDrilldownData(this.category);
}
}
}
I feel like its a relatively easy fix, but I'm just not getting it right. My initial attempts only removed the click functionality of the first chart. Any help with this would be greatly appreciated. Thanks!
I created a minimal reproduction of this problem, so as to make it easy for someone to help me figure this out.
This is what I have:
http://jsfiddle.net/tDW7e/1/
$(function () {
$(document).ready(function () {
Highcharts.setOptions({
global: {
useUTC: false
}
});
var chart;
$('#container').highcharts({
chart: {
type: 'spline',
//animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function () {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function () {
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], true, true);
document.getElementById('dbg').innerHTML = series.toString();
}, 1000);
}
}
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
series: [{
name: 'Random data',
data: (function () {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i++) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
})()
}]
});
});
});
HTML:
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
<div id="dbg" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
I edited the Live Chart demo, to write the value of the data to a second div. I am trying to perform a check to make sure that the most recent DateTime value in the graph is not the most recent in my database. I cannot perform this check because what should be an array of [DateTime, Int] becomes an array of [Object].
Any help is appreciated!
First of all, in your example you are using series which always is array of objects.
Second thing, each of points is also object, otherwise you couldn't use for example point.update() to update new options etc.
Third thing, in your example you are creating points as:
data.push({
x: time + i * 1000,
y: Math.random()
});
Which obviously is an object, not an array.
If you want to get actual point, use: series.options.data, and if using proper format (as you said) use this: http://jsfiddle.net/tDW7e/4/
Maybe something like this will be helpful.
setInterval(function () {
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], true, true);
var lastIndex = series.data.length - 1;
document.getElementById('dbg').innerHTML = 'x : ' + series.data[lastIndex].x + ' y: ' + series.data[lastIndex].y;
}, 1000);
Your series object contains points which are objects containing x and y values. Of you want to print it out, consider using JSON.stringify e.g.
document.getElementById('dbg').innerHTML = JSON.stringify(series.data);
I need to loop thru div's and load them using the promise pattern but apparently only the data from the last call gets displayed.
Here is my code
$('div[class=ceTable]').each(function () {
var position = $(this).position();
gridID = $(this).attr('id')
tableID = $(this).attr("data-tableid")
docId = $(this).attr("data-docid")
headerFound = $(this).data("headerFound")
headerArray = $(this).data("headerArray")
columnCount = $(this).data("columnCount")
$.ajax({
type: "GET",
dataType: "json",
url: "ajaxGetTableData",
data: {
'docID': docId,
'tableID': tableID
},
beforeSend: function () {
$('#' + gridID).block({
css: {
border: 'none',
padding: '15px',
backgroundColor: '#36a9e1',
'-webkit-border-radius': '10px',
'-moz-border-radius': '10px',
opacity: 5,
color: '#fff'
},
message: 'Loading Grid'
});
}
}).done(function (data) {
console.log(data, "ajaxGetTableData")
ceFeature.generateGridFromJSONObject({
tabledata: data,
columnCount: columnCount,
gridID: gridID,
headerArray: headerArray,
headerFound: headerFound
})
$('#' + gridID).unblock();
})
Your variables are implicitly global (as you forgot the var keyword) so each iteration will overwrite the previous values. The async callbacks will only access the last one then - the typical creating functions in a loop problem.
To fix this, make the variables local to the function (the each callback) so that it makes the success callback a closure with the respective variables in its scope:
$('div[class=ceTable]').each(function () {
var position = $(this).position(),
gridID = $(this).attr('id'),
tableID = $(this).attr("data-tableid"),
docId = $(this).attr("data-docid"),
headerFound = $(this).data("headerFound"),
headerArray = $(this).data("headerArray"),
columnCount = $(this).data("columnCount");
…
Using a closure:
$('div[class=ceTable]').each(function () {
var position = $(this).position();
gridID = $(this).attr('id')
tableID = $(this).attr("data-tableid")
docId = $(this).attr("data-docid")
headerFound = $(this).data("headerFound")
headerArray = $(this).data("headerArray")
columnCount = $(this).data("columnCount")
(function (columnCount, gridID, headerArray, headerFound) {
$.ajax().done();
}(columnCount, gridID, headerArray, headerFound));
});