How to make a dynamic scrolling Line chart

Share RGraph:   Share or Like RGraph on Facebook!

A guide for how you can easily make a dynamic scrolling Line chart. It can be made to be smooth by minimising the delay between requests giving the appearance of a continuously updating line.

[No canvas support]

Creating a scrolling Line chart is not an entirely simple affair if you're new to RGraph but this explanation should help to make everything clear. The code that generates the chart above is shown and documented below. Browser timings are not perfect so the chart ay not show exactly the amount of points that you want - an important thing to take into consideration is the the amount of time required to draw the chart - which may be 5 to 10ms.

    window.onload = (function ()
        * Define the varibles that we're going to use

        // Refresh rate (in milliseconds - 1000 per second)
        var delay = 40;
        // Number of points shown on the chart
        var points = 1200;
        // Number of points shown on the chart
        var data = new Array(points);
        // A shortcut reference to the global RGraph object
        var RG = RGraph;
        // A shortcut reference to the global Math object
        var ma = Math;
        // Max Y value on the chart
        var max = 100;
        // min Y value on the chart
        var min = 0;
        // Halfway between the min and max
        var num = (( (max - min) / 2) + min);

        // Generate the labels that are across the X axis. Hard-coded sadly...
        var labels = ['60s', '55s','50s', '45s','40s','35s','30s','25s','20s','15s','10s','5s','0s'];
        // The increase/decrease of each iteration
        var delta = 2;

        * Draw the chart. On subsequent draws this chart is updated with new data and
        * redrawn This is faster than creating a whole new object and drawing that.
        var obj = new RGraph.Line({
            id: 'cvs',
            data: data,
            options: {
                ymax: max,
                tickmarks: null,
                linewidth: 1,
                shadow: null,
                backgroundGridVlines: false,
                backgroundGridBorder: false,
                backgroundGridColor: '#eee',
                color: 'black',
                numxticks: 5,
                axisColor: '#666',
                textColor: '#666',
                colors: ['red'],
                labels: labels,
                noxaxis: true,
                textAccessible: true,
                textSize: 14

        * This is the main draw function that is called multiple times per
        * second to update the chart with new data. It:
        * 1. Clears the canvas so that it's ready to be drawn on again
        * 2. .shift()s a piece of data off of the rear of the Line chart internal data
        *    variable
        * 3. .push()s  a new piece of data on to the end of the same array
        * 4. Draws the chart again
        function draw()
            // Clear (NOT reset) the canvas

            // Generate a random number between -5 and 5 and add it to the num
            // variable. Adding asmall change instead of generating a whole new
            // number result in a gentler change.
            num += RG.random(-1 * delta, delta);

            // Limit the num variable to min - max
            num = ma.max(min, num);
            num = ma.min(max, num);

            // Remove a number from the front of the data array

            // Add the new number on to end of the data array
            // Draw the chart
            // Call this function again after the delay (using setTimeout NOT setInterval)
            setTimeout(draw, delay);


Fetching new data using AJAX

Fetching new data by AJAX is dependent on network speed and the responsiveness of the computer providing the data - amongst other things. So as a result of this if you go down the route of an updating chart that fetches new data via AJAX you will need to reduce the frequency of updates (eg 1 per second).

Taking this into consideration though - it is feasible to make a queue like system, where the AJAX requests happen independently of the chart update and put data into an array (a queue) and the chart updates take data from this array every time its drawn.

Or perhaps something like this:

Another option is to use WebSockets to spawn a seperate process - which again could update a queue. Though is adding needless complexity to the whole thing.

Using colors to indicate a threshold

In the demos there's a demo of a scrolling chart that shows different colors above/below a threshold. The method used in this demo is quite involved and requires two charts to be created along with the clipping feature of canvas. A much simpler option is to use gradients with (for example) 10 instances of the first colour and then 10 instances of the second colour. With this many colours the vertical space allocated to each indiviual colour is small - and the change from on colour to the next will be small too. The more colours that you use the smaller the graduation will be. It comes across as a bit of a kludge, but because it's much simpler than using two charts/canvas tags and clipping its worthy of trying first.

    fillstyle: 'Gradient(green:green:green:green:green:green:green:green:green:green:rgba(255,0,0,0.75):rgba(255,0,0,0.75):rgba(255,0,0,0.75):rgba(255,0,0,0.75):rgba(255,0,0,0.75):rgba(255,0,0,0.75):rgba(255,0,0,0.75):rgba(255,0,0,0.75):rgba(255,0,0,0.75):rgba(255,0,0,0.75))'

Use the button below to set the colour of the chart above to an example of this.

Another way by creating the gradient manually

An alternative is to creat the gradient manually - using the canvas gradient functionality directly. Similarly to CSS gradients it allows you to set the color stop positions precisely - affording you a little extra control. By using this method the change from red to green is a little more defined. As an aside - with this method you don't need to call the RGraph internal method .parseGradients().

var gradient = obj.context.createLinearGradient(0,0,0,250);
obj.set('fillstyle', gradient);



© Copyright Richard Heyes 2008-2017