supermikenews

My views on software, programming, Linux, the Internet, government, taxation, working, and life.

Sunday, October 22, 2006

Drawing PNG Piecharts in Linux-based PHP

After a lot of work and articles on the web, I figured out how to draw PNG piecharts in PHP without needing anything more than ImageMagick to be installed on the Linux web server. (You might also need to change file permissions or use a sticky bit here or there to get this going in your environment.) The following code uses the SVG XML standard to create a plain text XML file with the vector description in it. Then, we feed it to ImageMagick to convert the SVG to a PNG. (Remember, ImageMagick is a package of graphical tools, and one of those is the 'convert' command.) The following code is Public Domain. You may redistribute it freely without my permission, and I hope you do pass it on to your friends. I hope that people take this code and make it do all sorts of things like 3D charts and so on. It's just my way of giving back to the PHP programmer community which has been generous to me. If you find a way to compress the logic somewhat or you want to share links to where you have 3D variations of this, please do drop me a comment because I could use that if you're willing to share it. My original intent was to use the function in the reports section of a call tracking system I was writing.

<?php
function DrawPieChart(&$anSlices, &$asLabels, $sFileName) {
$sFileName = ($sFileName == '') ? 'tmp' : $sFileName;
$nTotal = 0; $i = 0; $nSegment = 0; $nRadius = 150; $nStartx = 158;
$nStarty = 158; $nLastx = $nRadius; $nLasty = 0; $sRectX = 378;
$sRectY = 8; $sTextX = 428; $sTextY = 28;
$asColors = array('#ffe700','#429e29','#39aace','#de0000','#101073',
'#f782bd','#ff8200','#d6d6d6');
$nCountedColors = count($asColors); $sBordercolor = 'black';
$nTotal = array_sum($anSlices);
$H = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
$H .= "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n";
$H .= "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n";
$H .= "<svg width=\"32cm\" height=\"15cm\"
xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n";
$H2 = '';
foreach ($anSlices as $n) {
    $nArc = "0";
$nSegment = $n / $nTotal * 360 + $nSegment;
    if (($n / $nTotal * 360) > 180) {
        $nArc = 1;
    }
    $nNextx = intval(cos(deg2rad($nSegment)) * $nRadius);
    $nNexty = intval(sin(deg2rad($nSegment)) * $nRadius);
 $H .= ' <path d="M ' . $nStartx . ',' . $nStarty . ' l ' .
$nLastx . ',' . (-($nLasty)) . ' a '  . $nRadius . ',' . $nRadius .
 ' 0 '  . $nArc . ',0 ' . ($nNextx - $nLastx) . ',' .
(-($nNexty - $nLasty)) .  ' z"' . " \n";
 $H .= ' fill="' . $asColors[$i]  . '" stroke="' .
$sBordercolor  . '" stroke-width="2" stroke-linejoin="round" />' .
"\n";
 $H2 .= " <rect x=\"$sRectX\" y=\"$sRectY\" width=\"30\"
height=\"20\" style=\"stroke-width: 2; stroke: black; fill: "
. $asColors[$i] . "\"/>\n";
 $H2 .= " <text x=\"$sTextX\" y=\"$sTextY\"
style=\"font-family:arial, sans-serif, sans; font-size: 70pt; fill: black; stroke: none\">\n";
 $H2 .= $asLabels[$i] . ' : ' . $n . "%\n</text>\n";
$nLastx = $nNextx; $nLasty = $nNexty; $sRectY += 41; $sTextY += 41.3; ++$i;
$i = ($i > $nCountedColors) ? 0 : $i;
}
$H .= "$H2</svg>\n"; $sSVG = $sFileName . '.svg';
$sPNG = $sFileName . '.png';
$fh = fopen ("/tmp/$sSVG",'wb'); fwrite($fh, $H); fclose($fh);
$sCmd = "/usr/bin/convert -density 30 /tmp/$sSVG $sPNG; rm -f '/tmp/$sSVG'";
`$sCmd`;
echo "<img src='$sPNG'>";
}
$anSlices = array(5, 20, 10, 25, 10, 15, 10, 5);
$asLabels = array('Jeff Henderson', 'Cathy Carson', 'Mike Margula',
'Derek Domino', 'Kim Kanders', 'Tony Tenneson', 'Darweep Kilugiliniasko',
'Hasken Parda');
echo "<h2>Sales Volume</h2>";
DrawPieChart($anSlices, $asLabels, 'sales');
?>