all,
I'm working with the following HTML/Javascript code:
<!doctype html>
<html>
<head>
<script type="text/javascript" src="//ajax.googleapis/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<!-- google fonts from CDN -->
<link href='+Sans:400,300,600' rel='stylesheet' type='text/css'>
<!-- highcharts -->
<script src=".js"></script>
<style>
html, body {
width: 95%;
margin: auto;
font-family: 'Open Sans',sans-serif;
}
#chart_container {
width:100%;
height:500px;
}
</style>
</head>
<body>
<h1>Live Data</h1>
<div id="chart_container">
</div>
</body>
<script type="text/javascript">
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'chart_container',
defaultSeriesType: 'line',
events: {
load: getBirds
}
},
title: {
text: 'DRHW Live Data Stream'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150,
maxZoom: 20 * 1000
},
yAxis: {
title: {
text: 'Count Observed'
}
},
series: [
],
legend: {
layout: 'horiztonal',
align: 'center'
}
});
function getBirds() {
var now = new Date();
var et = now.getTime() / 1000; //PHP TS
var st = et - 10; //30 seconds prior in PHP
console.log(chart);
if (chart.series.length > 0) {
var series = chart.series[0];
var length = series.length + 1;
var shift = series.data.length > 20;
}
$.getJSON("https://path/to/json&callback=?", function(result) {
var data = result.data;if (data.length == 0) {
return;
} else {
additions = new Array();
for (i=0;i<data.length;i++) {
if (data[i].qstype != "1") {
species = data[i].answers[0]['answer'];
scode = species.substring(0,species.search(" - ")).trim()
count = (data[i].answers[1]['answer'] * 1);
newdata = new Object();
newdata['name'] = species;
newdata['count'] = count;
additions.push(newdata);
}
}
//now, for each addition, you need to loop through the existing data structures, and see if the thing exists. if it does, add the data; if not, add the thing, then add the data.
var existingdata = chart.series;
for (i=0;i<additions.length;i++) {
isnewpoint = true;
for (j=0;j<existingdata.length;j++) {
if (existingdata[j].name == additions[i].name) {
isnewpoint = false
count = additions[i].count;
point = [now.getTime(),count];
chart.series[j].addPoint(point, true, shift);
shift = false; //this way, only one shift occurs - the first time through adding a new point to an existing data set. this will control against future shifting, either from other datapoints having new points added,
}
}
if (isnewpoint) {
newseries = new Object();
count = additions[i].count;
newseries['name'] = additions[i].name;
for (j=0;j<length;j++) {
newseries['data'].push(0);
}
newseries['data'].push(count);
chart.series.push(newseries);
}
}
//we have now looped through and added a new data point to all species where new data was created in this pull. We still need to add a new point to those that were not affected.
existingdata = chart.series;
for (i=0;i<existingdata.length;i++) {
getname = existingdata[i].name;
getlength = existingdata[i].data.length;
if (getlength<length) { //which we established earlier as one MORE than existed previously, prior to the addition
point = [now.getTime(),0]
chart.series[i].addPoint(point, true, shift);
}
}
}
setTimeout(getBirds,10000);
});
}
});
</script>
</html>
The problem that I'm having is pretty straightforward (but driving me nuts!), and early on in the js block. Though I'm defining the variable 'chart' as the new Highcharts chart, and I'm setting 'getBirds' as the function to load once that's loaded, the console.log line tells me that the chart is undefined, and the line below it throws an error (Uncaught TypeError: Cannot read property 'series' of undefined
).
I've checked the following:
- The Highcharts reference (), which suggests a setup similar to mine;
- I've tried defining the
chart
variable on its own line (which of course defines chart for my console.log, but does not define thechart.series
required on the next line); - I've researched stackoverflow and other docs for variable scope, but I think I'm handling it properly based on my research.
- I've tried reversing the order - putting the
getBirds()
function above thechart
definition.
I'm at a loss. Any help provided is much appreciated; thanks in advance!
all,
I'm working with the following HTML/Javascript code:
<!doctype html>
<html>
<head>
<script type="text/javascript" src="//ajax.googleapis./ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<!-- google fonts from CDN -->
<link href='http://fonts.googleapis./css?family=Open+Sans:400,300,600' rel='stylesheet' type='text/css'>
<!-- highcharts -->
<script src="http://code.highcharts./highcharts.js"></script>
<style>
html, body {
width: 95%;
margin: auto;
font-family: 'Open Sans',sans-serif;
}
#chart_container {
width:100%;
height:500px;
}
</style>
</head>
<body>
<h1>Live Data</h1>
<div id="chart_container">
</div>
</body>
<script type="text/javascript">
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'chart_container',
defaultSeriesType: 'line',
events: {
load: getBirds
}
},
title: {
text: 'DRHW Live Data Stream'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150,
maxZoom: 20 * 1000
},
yAxis: {
title: {
text: 'Count Observed'
}
},
series: [
],
legend: {
layout: 'horiztonal',
align: 'center'
}
});
function getBirds() {
var now = new Date();
var et = now.getTime() / 1000; //PHP TS
var st = et - 10; //30 seconds prior in PHP
console.log(chart);
if (chart.series.length > 0) {
var series = chart.series[0];
var length = series.length + 1;
var shift = series.data.length > 20;
}
$.getJSON("https://path/to/json&callback=?", function(result) {
var data = result.data;if (data.length == 0) {
return;
} else {
additions = new Array();
for (i=0;i<data.length;i++) {
if (data[i].qstype != "1") {
species = data[i].answers[0]['answer'];
scode = species.substring(0,species.search(" - ")).trim()
count = (data[i].answers[1]['answer'] * 1);
newdata = new Object();
newdata['name'] = species;
newdata['count'] = count;
additions.push(newdata);
}
}
//now, for each addition, you need to loop through the existing data structures, and see if the thing exists. if it does, add the data; if not, add the thing, then add the data.
var existingdata = chart.series;
for (i=0;i<additions.length;i++) {
isnewpoint = true;
for (j=0;j<existingdata.length;j++) {
if (existingdata[j].name == additions[i].name) {
isnewpoint = false
count = additions[i].count;
point = [now.getTime(),count];
chart.series[j].addPoint(point, true, shift);
shift = false; //this way, only one shift occurs - the first time through adding a new point to an existing data set. this will control against future shifting, either from other datapoints having new points added,
}
}
if (isnewpoint) {
newseries = new Object();
count = additions[i].count;
newseries['name'] = additions[i].name;
for (j=0;j<length;j++) {
newseries['data'].push(0);
}
newseries['data'].push(count);
chart.series.push(newseries);
}
}
//we have now looped through and added a new data point to all species where new data was created in this pull. We still need to add a new point to those that were not affected.
existingdata = chart.series;
for (i=0;i<existingdata.length;i++) {
getname = existingdata[i].name;
getlength = existingdata[i].data.length;
if (getlength<length) { //which we established earlier as one MORE than existed previously, prior to the addition
point = [now.getTime(),0]
chart.series[i].addPoint(point, true, shift);
}
}
}
setTimeout(getBirds,10000);
});
}
});
</script>
</html>
The problem that I'm having is pretty straightforward (but driving me nuts!), and early on in the js block. Though I'm defining the variable 'chart' as the new Highcharts chart, and I'm setting 'getBirds' as the function to load once that's loaded, the console.log line tells me that the chart is undefined, and the line below it throws an error (Uncaught TypeError: Cannot read property 'series' of undefined
).
I've checked the following:
- The Highcharts reference (http://www.highcharts./docs/working-with-data/preprocessing-live-data), which suggests a setup similar to mine;
- I've tried defining the
chart
variable on its own line (which of course defines chart for my console.log, but does not define thechart.series
required on the next line); - I've researched stackoverflow and other docs for variable scope, but I think I'm handling it properly based on my research.
- I've tried reversing the order - putting the
getBirds()
function above thechart
definition.
I'm at a loss. Any help provided is much appreciated; thanks in advance!
Share Improve this question edited Nov 23, 2013 at 19:18 kcbaker asked Nov 23, 2013 at 18:27 kcbakerkcbaker 1082 gold badges2 silver badges8 bronze badges 9-
2
Why do you have--->
$(function() { $(document).ready(function() {
– Blue Skies Commented Nov 23, 2013 at 18:39 -
Yes, OP,
$(function(){})
and$(document).ready(function(){})
are the same thing. – Andy Commented Nov 23, 2013 at 18:43 -
Regarding your issue, if the
chart.events.load
handler is for waiting until the DOM is ready, then why use it? You're already doing that (twice). – Blue Skies Commented Nov 23, 2013 at 18:44 -
I didn't think I needed both, but I wanted to follow the syntax I've seen elsewhere as exactly as possible. I'll edit and remove the
$function() {}
declaration at top, for clarity. – kcbaker Commented Nov 23, 2013 at 19:16 -
1
@PawełFus: My point was that it seems clear that the
events.load
handler is firing immediately, and synchronously, which means that there's no chance for the object to be returned to thechart
variable before the handler fires. If this is the case, then that means the chart is rendered immediately, and there's no need for an event handler. If so, OP should just run the code directly after thechart
assignment. That waychart
will be instantiated and fully usable. – Blue Skies Commented Nov 25, 2013 at 15:41
4 Answers
Reset to default 2The reason is likely that you cannot refer to a variable during its stages of declaration. I'm guessing that the load function is being called as it's being declared. Luckily, you can refer to the object during the function declaration. Try the following block of code.
function getBirds(e) {
var now = new Date(),
et = now.getTime() / 1000, //PHP TS
st = et - 10, //30 seconds prior in PHP
chart = this;
if (chart.series.length > 0) {
...declaring the chart
variable in the var block inside.
Trying out examples from highchart page I found out that variable chart
is available only after $.json()
or $ajax()
call. If you try to use chart
before that it returns undefined
. Because it is and it is set only after $.json().
Their examples with json or ajax are set this way:
var chart;
function requestData() {...}
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'chart_container',
defaultSeriesType: 'spline',
events: {
load: requestData
}
...
});
I did similarly with your example. From getBirds()
I mented out some lines before json call:
console.log(chart);
if (chart.series.length > 0) {
var series = chart.series[0];
var length = series.length + 1;
var shift = series.data.length > 20;
}
and moved them after json call.
And changed this line:
//newdata['name'] = species;
newdata['name'] = scode;
And stop here:
for (j=0;j<length;j++) {
because of error:
Uncaught TypeError: Cannot call method 'push' of undefined
at line
newseries['data'].push(count);
It fails because there is no array. Hope this help.
You should check two solution :
series variable property Shouldn't be empty array maybe its ok to enter series: null;
replace your script with this code and check it again :
http://notepad/share/3TwgCoEano
<script type="text/javascript">
$(function() {
$(document).ready(function() {
var chart = new Highcharts.Chart({
chart: {
renderTo: 'chart_container',
defaultSeriesType: 'line',
events: {
load: getBirds
}
},
title: {
text: 'DRHW Live Data Stream'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150,
maxZoom: 20 * 1000
},
yAxis: {
title: {
text: 'Count Observed'
}
},
series: null,
legend: {
layout: 'horiztonal',
align: 'center'
}
});
function getBirds() {
var now = new Date();
var et = now.getTime() / 1000; //PHP TS
var st = et - 10; //30 seconds prior in PHP
console.log(chart);
if (chart.series.length > 0) {
var series = chart.series[0];
var length = series.length + 1;
var shift = series.data.length > 20;
}
$.getJSON("https://path/to/json&callback=?", function(result) {
var data = result.data;if (data.length == 0) {
return;
} else {
additions = new Array();
for (i=0;i<data.length;i++) {
if (data[i].qstype != "1") {
species = data[i].answers[0]['answer'];
scode = species.substring(0,species.search(" - ")).trim()
count = (data[i].answers[1]['answer'] * 1);
newdata = new Object();
newdata['name'] = species;
newdata['count'] = count;
additions.push(newdata);
}
}
//now, for each addition, you need to loop through the existing data structures, and see if the thing exists. if it does, add the data; if not, add the thing, then add the data.
var existingdata = chart.series;
for (i=0;i<additions.length;i++) {
isnewpoint = true;
for (j=0;j<existingdata.length;j++) {
if (existingdata[j].name == additions[i].name) {
isnewpoint = false
count = additions[i].count;
point = [now.getTime(),count];
chart.series[j].addPoint(point, true, shift);
shift = false; //this way, only one shift occurs - the first time through adding a new point to an existing data set. this will control against future shifting, either from other datapoints having new points added,
}
}
if (isnewpoint) {
newseries = new Object();
count = additions[i].count;
newseries['name'] = additions[i].name;
for (j=0;j<length;j++) {
newseries['data'].push(0);
}
newseries['data'].push(count);
chart.series.push(newseries);
}
}
//we have now looped through and added a new data point to all species where new data was created in this pull. We still need to add a new point to those that were not affected.
existingdata = chart.series;
for (i=0;i<existingdata.length;i++) {
getname = existingdata[i].name;
getlength = existingdata[i].data.length;
if (getlength<length) { //which we established earlier as one MORE than existed previously, prior to the addition
point = [now.getTime(),0]
chart.series[i].addPoint(point, true, shift);
}
}
}
setTimeout(getBirds,10000);
});
}
});
});
</script>
the function declaration is interpreted before the chart object exists in the global namespace.
If you change the syntax to a function expression instead
var getBirds=function() {
....
};
it won't be evaluated until you call it.
However, you might want to add chart as a parameter for getBirds(), it's a little cheaper than getting a variable from the global namespace.
EDIT
This might require a bit of debugging, but it's worth a try
var getBirds = function(chart) {
...
};
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'chart_container',
defaultSeriesType: 'line',
events: {
load: function() {
getBirds(this);
}
}
}
...
});
setTimeout(getBirds,10000);
});
}
});