0

I am trying to load data from the server-side and displaying them in Highcharts one by one.

But before displaying them on the Highchart, I am doing some processing on the data and then rendering it into the Highcharts.

I am using AJAX so that I can get data every single time without refreshing the page and reloading the chart.

The chart is working good for the first set of data and then it shows undefined and the chart not showing any next set of data.

Here I have random.php file that I use to get the data :

header("Content-type: text/json");

$data = [];
for($i=0; $i<500; $i++)
{
    $data[] = rand(0,10);  
}

$into_mysql = json_encode($data);

echo $into_mysql;

Now I am fetching the data in the chart in other page:

var chart;
// Prototype to Request Data using `AJAX`
function requestData() {
    $.ajax({
        url: 'random.php',
        async: false,
        success: function (data) {
            y = data;
            console.log(y);
            return (y);
        }
    });
}


// Fetch the data from the `requestData` and process it.
function fetch() {
    requestData();
    var divisor = 2;
    var count = 0;
    for (var i = 0, length = y.length; i < length; i++) {
        y[i] /= divisor;
    }
    console.log(y);
    return (y);
    setInterval(function () { requestData }, 1000);
}

var json_array = fetch();

var i = 0;
function next() {

    return json_array[i++];
    // i++;

}

Highcharts.chart('container', {
    chart: {
        type: 'line',
        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],
                    chart = this;
                var count = 0;
                setInterval(function () {
                    var x = (new Date()).getTime(), // current time
                        y = next();
                    console.log(y);
                    series.addPoint([x, y], false, true);
                    chart.redraw(false);
                }, 1000 / 130);
            }
        }
    },

    time: {
        useUTC: false
    },

    title: {
        text: 'ECG Graph Plot From MySQl Data'
    },
    xAxis: {
        type: 'datetime',
        labels: {
            enabled: false
        },
        tickPixelInterval: 150
    },
    yAxis: {
        //max: 1.5,
        //min: -1.5,
        title: {
            text: 'Value'
        },
        plotLines: [{
            value: 0,
            width: 1,
            color: '#808080'
        }]
    },
    tooltip: {
        headerFormat: '<b>{series.name}</b><br/>',
        pointFormat: '{point.x:%Y-%m-%d %H:%M:%S}<br/>{point.y:.2f}'
    },
    legend: {
        enabled: false
    },
    exporting: {
        enabled: false
    },
    series: [{
        animation: false,
        name: 'ECG Graph Plot From MySQl Data',
        dataGrouping: {
            enabled: false
        },
        data: (function () {
            // generate an array of random data
            var data = [],
                time = (new Date()).getTime(),
                i;

            for (i = -1000; i <= 0; i += 1) {
                data.push([
                    time + i * 10,
                    null
                ]);
            }
            return data;
        }())
    }]
});   

So what I require is to render the data one by one without breaking it. when the One dataset from the random.php gets over. the next data should start in continuation of that.

Update:

Consider a scenario where an array of 500 data is generated every few second. what I want is to show the array points in one highcharts one by one. but only first set of array data is being displayed and the rest of the array data is not showing.

9
  • Could you reproduce your issue in an online code editor like jsfiddle? Instead of real data use fake static data with the same structure. And please try to be more precise of what you're going to achieve. Commented Nov 7, 2019 at 13:26
  • I am not able to produce the same in online code editor. as I need the data from AJAX call every time. @WojciechChmiel. Commented Nov 11, 2019 at 4:43
  • I tried to make the question more clear. please see the update section a the bottom of the question Commented Nov 11, 2019 at 5:06
  • This is the reproduction of your code: jsfiddle.net/BlackLabel/defm0qLc/1. You don't need AJAX to reproduce it use static data and setTimeout. Commented Nov 11, 2019 at 7:27
  • that's so nice of you to do that :) .. now According to your fiddle, the array data is only producing one time on Highcharts. now what I need is that the next array data should be printed in continuation of the previous data. it's just showing one array data. I tried many things. but not able to accomplish that. @WojciechChmiel Commented Nov 11, 2019 at 8:43

1 Answer 1

1
+50

I think I found a possible work around your code. First of all there are some missconceptions in your current approach:

  • There is nothing that gets done after return statement. Yes, as you point out in your comment, after doing return in a function nothing gets done

  • In your high charts your data depends on json_array (basically you read the X element of the array), but you actually never update json_array with more information.

Ok... what should I do?

Let's see. First of all, you should make sure you are fetching data in an interval after the first fetch. How to do that:

function fetch() {
    requestData();
    var divisor = 2;
    var count = 0;
    for (var i = 0, length = y.length; i < length; i++) {
        y[i] /= divisor;
    }
    console.log(y);
    // Create the interval before returning, and actually calling the function
    setInterval(function () { requestData() }, 1000);
    return (y);
}

Second, you need that each requestData updates the array you are reading from: Disclaimer, I am using the jsfiddle of your comments to create an easy example


  var json_array = fetch();

  function requestData() {
    var data = [];

    for (var i = 0; i < 500; i++) {
      data.push(Math.random() * 10);
    }

    y = data;

    // Check that json_array have been initialized and after add the data that we fetched in it (so from [1, 2, 3] to... [1, 2, 3, 4, 5, 6]
    if (Array.isArray(json_array)) {
      json_array = json_array.concat(data);
    }
  }

Using your ajax code it should look like

function requestData() {
    $.ajax({
        url: 'random.php',
        async: false,
        success: function (data) {
         /// you can skip this check... I just do it for safety
         if (Array.isArray(json_array)) {
           json_array = json_array.concat(data);
         }
        }
    });
}

And basically that is all, as long as your request is faster than the speed you are reading X in the graph it should work just fine.

I have here the working demo

Extra This is not needed, as in the solution i tried to modify as little as possible your code and mainly point out what was wrong with your approach but I will consider the next improvements to your code:

  • Abstract data fetching in a service. Basically you could create a class/prototype that will fetch data once you instanciate it and keep fetching data and adding it
  • This class will also check how many indexes of your data you can access currently, and give you the next element.
  • Modify your highcharts to use it.

Here is an abstraction of the implementation

class DataFetcher {
constructor() {
   this.currentDataPoint = 0
   this.data = fetch(...)
   this.keepFetching()
}
keepFetching() {
   fetchMoreData().onSuccess((data) => { this.data = data }
}

getNext() {
   if (this.isThereData) {
// Return data point and increase pointer
     dataPoint = this.data[this.currentDataPoint]
     this.currentDataPoint =+ 1
     return dataPoint
   }
// Return nothing because there is no more data points
   return null
}

isThereData() { 
  return this.data.length >= this.currentDataPoint + 1
}

}

Lastly you could abstract the division of this data using a map function:

function fetch() {
    requestData();
    y = y.map(value => value/2);
    console.log(y);
    // Create the interval before returning, and actually calling the function
    setInterval(function () { requestData() }, 1000);
    return (y);
}

// Also the other function
function requestData() {
    var data = [];

    for (var i = 0; i < 500; i++) {
      data.push(Math.random() * 10);
    }

    y = data.map(dataPoint => dataPoint/2);

    // Check that json_array have been initialized and after add the data that we fetched in it (so from [1, 2, 3] to... [1, 2, 3, 4, 5, 6]
    if (Array.isArray(json_array)) {
      json_array = json_array.concat(data);
    }
  }

Hope this help you to refine your solution!

Sign up to request clarification or add additional context in comments.

9 Comments

wow. Perfectly explained and done. I will implement your approach and will get back to you shortly.
only one thing. the divisor is not working from the second set of data.
the logic under fetch() function is only called once. and from the next time it just displaying the random data without dividing by 2. as in fetch().
Opps, i will update it, but it should be as simple as adding /2 inside the for loop. I hope it help you, if so you can mark it as resolved
Yes I can manually divide the question by 2 in the loop. but I want the fetch functioning to be called automatically. but still, the answer you provided is very much perfect. That's why I am marking it as resolved. I appreciate your effort. :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.