DEV Community

Tib
Tib

Posted on • Edited on

Simple live chart using Mojolicious

Live

In this blog post, I will show how easy it is to write a live chart with Perl, Mojolicious::Lite and some javascript (mainly Highcharts).

Mojolicious

The code

The Mojolicious::Lite very small webapp. With routes and get/set urls:

use Mojolicious::Lite;

my $datfile = "/tmp/values.txt";

# Answer to /
get '/' => sub {
    my $c = shift;
    $c->render(template => 'live', format => 'html');
};

# Set value from GET call
get '/setvalue/:value' => sub { 
    my $c   = shift;
    my $value = $c->param('value');
    open(my $fh, '>', $datfile) or die "Could not open $datfile $!";
    print $fh "$value\n";
    close $fh;
    $c->render(text => "You set the value to $value");
};

# Get value from GET call
get '/getvalue' => sub { 
    my $c   = shift;
    open(my $fh, '<:encoding(UTF-8)', $datfile) or die "Could not open '$datfile' $!";
    my $value = <$fh>;
    chomp $value;
    $c->render(text => "$value");
};
Enter fullscreen mode Exit fullscreen mode

Right below, I start the application:

app->start;
Enter fullscreen mode Exit fullscreen mode

And open the __DATA__ section (where falls the template/view in Mojolicious::Lite applications):

__DATA__
Enter fullscreen mode Exit fullscreen mode

And the view, with jquery and highcharts to make it "live".... Yes it is a bit a big blob since there is all configs for the chart, but it's not that complicated !

The view is a big chunk of javascript and an almost empty piece of html (just one div to make room to chart):

@@ live.html.ep
<html lang="us">
<head>
  <meta charset="utf-8">
  <title>Dynamic Live Chart</title>
  <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
  <script src="http://code.highcharts.com/highcharts.js"></script>
  <script>
    $(document).ready(function() {
        Highcharts.setOptions({
            global: {
                useUTC: false
            }
        });

        var chart;
        chart = new Highcharts.Chart({
            chart: {
                renderTo: 'container',
                type: 'spline',
                marginRight: 10,
                events: {
                    load: function() {

                        // set up the updating of the chart each second
                        var series = this.series[0];
                        var y = 0; 
                        setInterval(function() {
                            var x = (new Date()).getTime(); // current time
                            $.get('/getvalue', function(data) {
                              var oldy = y;
                              y = parseInt(data);
                              series.addPoint([x, y], true, true);
                            });
                        }, 1000);
                    }
                }
            },
            title: {
                text: 'Dynamic Chart live'
            },
            xAxis: {
                type: 'datetime',
                tickPixelInterval: 150
            },
            yAxis: {
                title: {
                    text: 'Values'
                },
                plotLines: [{
                    value: 0,
                    width: 1,
                    color: '#808080'
                }]
            },
            plotOptions: {
                line: {
                    marker: {
                        enabled: false
                    }
                }
            },
            tooltip: {
                formatter: function() {
                        return '<b>'+ this.series.name +'</b><br/>'+
                        Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) +'<br/>'+
                        Highcharts.numberFormat(this.y, 2);
                }
            },
            legend: {
                enabled: false
            },
            exporting: {
                enabled: false
            },
            series: [{
                name: 'Value',
                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: 0,
                        });
                    }
                    return data;
                })()
            }]
        });
    });
  </script>
</head>
<body> 
<div id="container"></div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

We have our application, now we are ready to feed and test 😃

Feed with random data

Feed me

As you can see, the data source is a flat /tmp/values.txt file that can be fed by http GET call or manually (this is what we will do right now):

$ while true; do echo `shuf -i 0-20 -n 1` > /tmp/values.txt; sleep 1; done
Enter fullscreen mode Exit fullscreen mode

Start it and test

I start it with development server morbo (but could be something else):

$ morbo live.pl
Enter fullscreen mode Exit fullscreen mode

We can access value with:

$ curl http://127.0.0.1:3000/getvalue
12
Enter fullscreen mode Exit fullscreen mode

Or set value to 100 for instance with the endpoint /setvalue/100:

$ curl http://127.0.0.1:3000/setvalue/100
You set the value to 100
Enter fullscreen mode Exit fullscreen mode

The result

Open your favorite browser and you will get this beautiful live chart:
Live

You can also get an overview here

Top comments (9)

Collapse
 
jonasbn profile image
Jonas Brømsø •

Great article

Both Mojolicious and Highcharts are awesome, we use both at work, but the license for Highcharts is a bit restricted. Recommendations for a freely distributable open source charting library would be most welcome... 😜

Collapse
 
robianc profile image
Roberto •

I use Apache Echarts
echarts.apache.org/en/index.html

Collapse
 
thibaultduponchelle profile image
Tib •

Thank you for the tip, Echarts looks very nice !! But can you create live charts with it ?

Thread Thread
 
robianc profile image
Roberto •

Here is an example from the documentation:
echarts.apache.org/examples/en/edi...

Collapse
 
jonasbn profile image
Jonas Brømsø •

Hi Roberto

I heard about echarts on a podcast, it just seemed a bit overkill compared to what I need to implement, I will give it a second look.

Take care

Thread Thread
 
robianc profile image
Roberto •

Hi,
In Mojolicious i have a html with echarts js code and I fill in the data variable and few others I need, through the stash. Very efficient in my use case.
By the way, in my opinion, Echarts can be an interesting solution for a Perl programmer to create high quality plots. Unfortunately a good/modern and complete plotting module is one of the things that Perl lacks.
Best regards

Thread Thread
 
jonasbn profile image
Jonas Brømsø •

Hi Roberto, you mean as in server side rendering. I must admit I am not to the approach your outline of having the rendering done by the client, having the Mojolicious (or similar) service only deliver the raw data.

Guess I have been in the MVC-sphere for too long :-)

Thread Thread
 
robianc profile image
Roberto •

No, no sorry :) I meant that I have a template I fill on server with data for Echarts. The data are then embedded in the html. So all is done server side and I serve a self standing html

Collapse
 
simeoreig profile image
Simeo Reig •

$ while true; do echo shuf -i 0-20 -n 1 > /tmp/values.txt; sleep 1; done

Should be

$ while true; do echo shuf -i 0-20 -n 1 >> /tmp/values.txt; sleep 1; done

Note double > (>>)