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 > (>>)