ChartDirector 6.0 (Perl Edition)

Realtime Chart with Snapshot




The example extends the Simple Realtime Chart example by adding buttons to download the chart in PNG and PDF formats.

When the button is pressed, the URL of the web page will be modified by appending an extra query parameter specifying the download format. On the server side, the charting code will check for this parameter. If the parameter exists, it will send the chart as an attachment. When the browser receives the attachment, instead of displaying it, it should save it as a file. The exact behaviour depends on the browser. Some browsers may immediately save the attachment as a file in a download directory; some browsers may prompt the user for the filename and directory; some browsers that do not support downloading files may ignore the content.

NOTE: This sample script uses "cdjcv.js". When developing your own script using this sample script as a template, please ensure you copy "cdjcv.js" to the proper directory and reference it using the proper path.

Source Code Listing

[CGI Version] perldemo_cgi\realtimesnapshot.pl
#!/usr/bin/perl

# In the sample code, the ChartDirector for Perl module is assumed to be in "../lib"
use File::Basename;
use lib (dirname($0)."/../lib") =~ /(.*)/;

use perlchartdir;

#
# In this demo, the generated web page needs to load the "cdjcv.js" Javascript file. For ease of
# installation, we put "cdjcv.js" in the same directory as this script. However, if this script is
# installed in a CGI only directory (such as cgi-bin), the web server would not allow the browser to
# access this non-CGI file.
#
# To get around this potential issue, a special load resource script is used to load these files.
# Instead of using:
#
#    <SCRIPT SRC="cdjcv.js">
#
# we now use:
#
#    <SCRIPT SRC="loadresource.pl?file=cdjcv.js">
#
# If this script is not in a CGI only directory, you may replace the following loadResource string
# with an empty string "" to improve performance.
#
my $loadResource = "loadresource.pl?file=";

print "Content-type: text/html\n\n";
print <<EndOfHTML
<!DOCTYPE html>
<html>
<head>
    <title>Realtime Chart with Snapshot</title>
    <script type="text/javascript" src="${loadResource}cdjcv.js"></script>
</head>
<body style="margin:0px">
<table cellspacing="0" cellpadding="0" style="border:black 1px solid;">
    <tr>
        <td align="right" colspan="2" style="background:#000088; color:#ffff00; padding:0px 4px 2px 0px;">
            <a style="color:#FFFF00; font:italic bold 10pt Arial; text-decoration:none" href="http://www.advsofteng.com/">
                Advanced Software Engineering
            </a>
        </td>
    </tr>
    <tr valign="top">
        <td style="width:130px; background:#c0c0ff; border-right:black 1px solid; border-bottom:black 1px solid;">
            <br />
            <br />
            <div style="font:12px Verdana; padding:10px;">
                <b>Update Period</b><br />
                <select id="UpdatePeriod" style="width:110px">
                    <option value="5">5</option>
                    <option value="10" selected="selected">10</option>
                    <option value="20">20</option>
                    <option value="30">30</option>
                    <option value="60">60</option>
                </select>
                <br /><br /><br />
                <b>Time Remaining</b><br />
                <div style="width:108px; border:#888888 1px inset;">
                    <div style="margin:3px" id="TimeRemaining">0</div>
                </div>
            </div>
            <br />
            <br />
            <br />
            <br />
            <div style="text-align:center">
                <input type="button" value="Download PDF" onclick="download('pdf')" style="width:112px; font:10pt Arial" /><br />
                <input type="button" value="Download PNG" onclick="download('png')" style="width:112px; font:10pt Arial" />
            </div>
        </td>
        <td style="border-left:black 1px solid; padding:5px 0px 0px 5px;" >
            <!-- ****** Here is the image tag for the chart image ****** -->
            <img id="ChartImage1" src="realtimesnapshotchart.pl?chartId=demoChart1">
        </td>
    </tr>
</table>
<script type="text/javascript">

//
// Executes once every second to update the countdown display. Updates the chart when the countdown reaches 0.
//
function timerTick()
{
    // Get the update period and the time left
    var updatePeriod = parseInt(document.getElementById("UpdatePeriod").value);
    var timeLeft = Math.min(parseInt(document.getElementById("TimeRemaining").innerHTML), updatePeriod) - 1;

    if (timeLeft == 0)
        // Can update the chart now
        JsChartViewer.get('ChartImage1').streamUpdate();
    else if (timeLeft < 0)
        // Reset the update period
        timeLeft += updatePeriod;

    // Update the countdown display
    document.getElementById("TimeRemaining").innerHTML = timeLeft;
}
window.setInterval("timerTick()", 1000);

//
// Send a request to the server with the query parameter "download=xxx". The server should handle this
// as a download request.
//
function download(format)
{
    var imageURL = document.getElementById("ChartImage1").src;
    imageURL += ((imageURL.indexOf('?') == -1) ? '?' : '&') + "download=" + format;

    // Download as an attachment to the current window
    location.href = imageURL;
}

</script>
</body>
</html>
EndOfHTML
;

[CGI Version] perldemo_cgi\realtimesnapshotchart.pl
#!/usr/bin/perl

# In the sample code, the ChartDirector for Perl module is assumed to be in "../lib"
use File::Basename;
use lib (dirname($0)."/../lib") =~ /(.*)/;

use perlchartdir;

# Get HTTP query parameters
use CGI;
my $query = new CGI;

#
# Data to draw the chart. In this demo, the data buffer will be filled by a random data generator.
# In real life, the data is probably stored in a buffer (eg. a database table, a text file, or some
# global memory) and updated by other means.
#

# We use a data buffer to emulate the last 240 samples.
my $sampleSize = 240;
my $dataSeries1 = [(0) x $sampleSize];
my $dataSeries2 = [(0) x $sampleSize];
my $dataSeries3 = [(0) x $sampleSize];
my $timeStamps = [(0) x $sampleSize];

# Our pseudo random number generator
my $firstDate = perlchartdir::chartTime2(time()) - scalar(@$timeStamps);
for(my $i = 0; $i < scalar(@$timeStamps); ++$i) {
    my $p = $firstDate + $i;
    $timeStamps->[$i] = $p;
    $dataSeries1->[$i] = cos($p * 2.1) * 10 + 1 / (cos($p) * cos($p) + 0.01) + 20;
    $dataSeries2->[$i] = 100 * sin($p / 27.7) * sin($p / 10.1) + 150;
    $dataSeries3->[$i] = 100 * cos($p / 6.7) * cos($p / 11.9) + 150;
}

# Create an XYChart object 600 x 320 pixels in size
my $c = new XYChart(600, 320);

# Set the plotarea at (55, 60) and of size 520 x 235 pixels with transparent background and border.
# Enable both horizontal and vertical grids by setting their colors to grey (cccccc). Set clipping
# mode to clip the data lines to the plot area.
$c->setPlotArea(55, 60, 520, 235, -1, -1, $perlchartdir::Transparent, 0xcccccc, 0xcccccc);
$c->setClipping();

# Add a title to the chart using dark grey (0x333333) 20pt Arial Bold font
$c->addTitle("Realtime Chart with Snapshot", "arialbd.ttf", 20, 0x333333);

# Add a legend box at the top of the plot area using horizontal layout. Use 10pt Arial Bold font,
# transparent background and border, and line style legend icon.
my $b = $c->addLegend(55, 30, 0, "arialbd.ttf", 10);
$b->setBackground($perlchartdir::Transparent, $perlchartdir::Transparent);
$b->setLineStyleKey();

# Set the x and y axis stems to transparent and the label font to 10pt Arial
$c->xAxis()->setColors($perlchartdir::Transparent);
$c->yAxis()->setColors($perlchartdir::Transparent);
$c->xAxis()->setLabelStyle("arial.ttf", 10);
$c->yAxis()->setLabelStyle("arial.ttf", 10);

# Add y-axis title using 12pt Arial font
$c->yAxis()->setTitle("Y-Axis Title Placeholder", "arial.ttf", 12);

# For the automatic x and y axis labels, set the minimum spacing to 75 and 30 pixels.
$c->xAxis()->setTickDensity(75);
$c->yAxis()->setTickDensity(30);

# Set the x-axis label format
$c->xAxis()->setLabelFormat("{value|hh:nn:ss}");

# Create a line layer to plot the lines
my $layer = $c->addLineLayer2();

# The x-coordinates are the timeStamps.
$layer->setXData($timeStamps);

# The 3 data series are used to draw 3 lines. Here we put the latest data values as part of the data
# set name, so you can see them updated in the legend box.
$layer->addDataSet($dataSeries1, 0xff0000, $c->formatValue($dataSeries1->[scalar(@$dataSeries1) - 1
    ], "Alpha: {value|2}"));
$layer->addDataSet($dataSeries2, 0x00cc00, $c->formatValue($dataSeries2->[scalar(@$dataSeries2) - 1
    ], "Beta: {value|2}"));
$layer->addDataSet($dataSeries3, 0x0000ff, $c->formatValue($dataSeries3->[scalar(@$dataSeries3) - 1
    ], "Gamma: {value|2}"));

# Check if is download request
my $downloadFormat = $query->param("download");
if (!((!defined($downloadFormat) || $downloadFormat eq ""))) {
    my $fname = sprintf("demo_%s", $c->formatValue($timeStamps->[scalar(@$timeStamps) - 1],
        "yyyymmddhhnnss"));
    if ($downloadFormat eq "pdf") {
        # Output in PDF and stream as attachment
        binmode(STDOUT);
        print "Content-Disposition: attachment; filename=\"$fname.pdf\"\n";
        print "Content-type: application/pdf\n\n";
        print $c->makeChart2($perlchartdir::PDF);
        exit;
    } else {
        # Output in PNG and stream as attachment
        binmode(STDOUT);
        print "Content-Disposition: attachment; filename=\"$fname.png\"\n";
        print "Content-type: image/png\n\n";
        print $c->makeChart2($perlchartdir::PNG);
        exit;
    }
}

# Output the chart
binmode(STDOUT);
print "Content-type: image/png\n\n";
print $c->makeChart2($perlchartdir::PNG);