Home

Thu, May. 8th, 2008, 01:37 am
Using libchart as a cakephp vendor application

First off, in cake 1.2, you vendor() is depreciated, so you'll have to use App::import('Vendor', ... ); A link on its usage can be found <a href="http://cakebaker.42dh.com/2008/03/26/loading-vendor-files/">http://cakebaker.42dh.com/2008/03/26/loading-vendor-files/</a>
First off, we want to unpack libchart tarball, and put the libchart directory in /app/webroot/vendors/.
The basic steps for creating a graph are:
  1. Create an action that will *just* fetch data
  2. hand the data over in a predetermined fashion to the view.
  3. Then the view will call a helper function which will do the actual graphing (libchart calls). 
So for example, I created an action in my controller which displays a number of fruits. Important things to note are the first three lines, this turns off all verbose debugging, and default layouts which will get in the way of the PNG. The "predetermined" fashion is that my helper is going to accept a chart title, and an array of data in the form of x-labels => y-vals.

class FruitsController extends AppController {
    var $helpers = array('Html', 'Form', 'Javascript', 'Graph');
...
    function chartFruitTotals($id = null, $rndm = null) {
        $this->layout = null;
        $this->autoLayout = false;
        Configure::write('debug', '0');

        // do some database stuff here to get data. I'll use a prefilled array
        $chartData = array ('apples' => 3, 'pears' => 4, 'oranges => '1', 'peaches' => '2');
        $chartTitle = 'Fruit Totals';
        $chartData = $alertTotals;
        $this->set(compact('chartTitle', 'chartData'));
    }
...
}


The view is rather simple. Just call the GraphHelper's method which will do the charting.
<?php
    $graph->showChart($chartTitle, $chartData);
?>


The helper method is where the magic will be. Since libchart.php in its own directory (two directories deep) we'll be using the following syntax: App::import('Vendor', 'libchart', array('file'=>'libchart'.DS.'classes'.DS.'libchart.php')); where DS is the directory separator. I just ended up copying a barchart demo file that came with libchart and just slightly modifying it.
<?php
    App::import('Vendor', 'libchart', array('file'=>'libchart'.DS.'classes'.DS.'libchart.php'));
    class GraphHelper extends AppHelper {
...
        function showChart($chartTitle, $chartData)
        {
            header("Content-type: image/png");
            $chart = new HorizontalBarChart(300, 250);

            $dataSet = new XYDataSet();

            foreach ($chartData as $xLabel => $yValue) {
                $dataSet->addPoint(new Point($xLabel, $yValue));
             }

            $chart->setDataSet($dataSet);
            $chart->getPlot()->setGraphPadding(new Padding(5, 15, 15, 100));
            $chart->getPlot()->setLogoFileName(null); // get rid of the annoying logo

            $chart->setTitle($chartTitle);
            $chart->render();
        }
...
?>

Now, what that will do is spit out a raw PNG file to that particular view. If you would like the chart to appear as an <IMG> anywhere in your pages, you probably want to do a component or something similar that does the same as the helper and just $chart->render($tmpfile) it out to "tempnam", or "tmpfile", and a wrapper in the img/ directory @readfile's the tmpfile/tempnam. To be safe, make sure any reads are escaped correctly. There are other ways to skin that cat, but at this point it's just plain ol' php.