Amélioration : camembert

Soyez le premier à donner votre avis sur cette source.

Snippet vu 5 964 fois - Téléchargée 16 fois

Contenu du snippet

Bonjour à tous

Je viens de développer un camembert 2D dans le but de m'entrainer, mais aussi de ressembler au mieux à celui généré par Flex 4 (j'ai un projet sous Flex 4 et j'ai un module d'impression PDF qui doit rendre le même résultat que Flex 4, d'où la nécessité de coder le mien, les autres ayant à chaque fois au moins un détail gênant qui diffère).

J'aimerais vos avis et suggestions sur ce qui a été fait. :)

Il s'agit d'une version 1, et plusieurs améliorations sont à venir:
- explodeSlice(): pour détacher un morceau du reste du camembert (mise en retrait)
- drawVLegend(): contrairement à drawHLegend() qui dessine la légende horizontalement à la base, celui-ci les dessinera à gauche ou à droite et verticalement
- set3D(): pour une version 3D du camembert
- et d'autres encore

Le point où j'aimerais aussi avoir part de vos idées, c'est celui pour rendre le graphique plus joli (éviter de voir les pixels).
J'ai essayé d'appliquer l'antialiasing, mais soit je ne m'en sers pas correctement, soit il est inefficace ici...

Ci-dessous:
- AKPie.php : la classe du graphique
- test.php : un exemple d'utilisation
- et il faudra inclure "font.ttf" qui n'est autre que la police courrier par défaut dans C:\Windows\Font\ (pour windows)

Voilà :)

Et merci à ceux qui auront le courage de lire, voire de tester ;)

Source / Exemple :


// --- test.php -----------------------------------------------
include 'AKPie.php';

// --- Call example 
// test.php?seriesX=a:11:{s:10:%22Logistique%22;s:2:%2216%22;s:18:%22Cabinet%20de%20conseil%22;s:1:%227%22;s:14:%22Pharmaceutique%22;s:1:%227%22;s:10:%22Automobile%22;s:1:%227%22;s:28:%22SSII%20et%20Conseil%20Informatique%22;s:1:%227%22;s:8:%22T%E9l%E9coms%22;s:1:%227%22;s:55:%22Administration%20d%27Etat,%20Poste,%20Collectivit%E9%20Territoriale%22;s:1:%224%22;s:8:%22B%E2timent%22;s:1:%223%22;s:6:%22M%E9dias%22;s:1:%223%22;s:9:%22Industrie%22;s:1:%223%22;s:5:%22Autre%22;s:1:%227%22;}
// test.php?seriesX=a:3:{i:0;i:2009;i:1;i:2010;i:2;i:2011;}&seriesY=a:3:{i:0;i:118;i:1;i:218;i:2;i:780;}

// --- Data retrieving
$seriesX = (!empty($_GET['seriesX'])) 
	? unserialize(stripslashes($_GET['seriesX']))
	: array();
$seriesY = (!empty($_GET['seriesY']))
	? unserialize(stripslashes($_GET['seriesY']))
	: array(); 

// --- Class instanciation
$pie = new AKPie($seriesX, $seriesY);
$pie->draw();

// --- AKPie.php ---------------------------------------------------------------------------------------
<?php
/* ------------------------------------------------------------ *

  • ___ ___ *
  • / // / *
  • / // / __ __ *
  • / // \ / /__ __ __ __/ /_ _ _ _ __ ____ *
  • / /| |\ \ __ __ / //_/ _//_ |/_ __/_/ \/ _ |/ _/ *
  • / /_| | \ \ . \ . \ // / /_/ . | / / / / / / / | /\_ \ *
  • /________| \__\ _/ _///_/\__/\__|_\\_//_/\__/_/ /_/____/ *
  • / / / / *
  • /_/ /_/ *
  • *
  • ------------------------------------------------------------ *
  • Class: AKPie *
  • *
  • @author: Asph@tor (under Advanced Partner's project) *
  • @date: 2011-05-17 *
  • @version: v1.0.0 *
  • @compatible: PHP >= 4.2 *
  • @dependancies: GD2 *
  • font.ttf *
  • @license: free of use, of modifications and of *
  • commercialization. Just past this header *
  • at the begining of your code *
  • @contact: akpplications@gmail.com *
  • ------------------------------------------------------------ */
class AKPie { protected $img; // The chart instance (true colors) protected $antialias; // Antialiasing protected $backgroundColor; // Background color behind the chart protected $borderColor; // Chart border's color protected $pieBorderColor; // Pie border's color protected $pieDelta; // Distance between pie and legend's labels protected $piePadding; // Chart's padding protected $pieX; // Chart's origin x value protected $pieY; // Chart's origin y value protected $pieSize; // Chart's size protected $width; // Display area width protected $height; // Display area height protected $title; // Chart's title protected $titleColor; // Chart title's color protected $titleFont; // Chart title's font to use protected $titlePadding; // Chart title's distance from the nearest side protected $titleSize; // Chart title's size protected $legendLabelColor; // Legend item label's color protected $legendLabelGap; // Gap between legend's labels protected $legendLabelSize; // Legend item label's size protected $legendPadding; // Legend box's distance from the nearest side protected $legendPosition; // Legend position (left, bottom, right, top) protected $legendWidth; // Legend width protected $guidLabelSize; // Legend guid label's size protected $guidLinesColor; // Legend guid line's color protected $guidLabelsColor; // Legend guid label's color protected $seriesX; // Data keys' label protected $seriesY; // Data values' label protected $seriesZ; // Data values in percents protected $precision; // Percents precision protected $showBorder; // Show chart's borders protected $showLegend; // Show legend protected $showLegendBorder; // Show legend's border protected $showPieBorder; // Show pie's and slices' border protected $showShadow; // Show pie's shadow protected $showGuidLines; // Show lines between slices and slices' label protected $showGuidLabels; // Show slices' labels protected $titleY; // First free y after title's drawing protected $legendY; // Last free y after legend's drawing protected $slicesColors; // Chart's color range protected $shadowColor; // Pie shadow's color protected $shadowLagX; // Pie shadow's x distance from pie protected $shadowLagY; // Pie shadow's y distance from pie // --------------------------------------------------------- // --- CONSTRUCTOR --- // --------------------------------------------------------- function __construct($seriesX=array(), $seriesY=array()) { if (count($seriesY) == 0) { $this->seriesX = array_keys($seriesX); $this->seriesY = array_values($seriesX); } else if (count($seriesX) == 0 || count($seriesY) != count($seriesX)) { echo "ERROR: incorrect parameters - size of each parameters should be the same!"; } else { $this->seriesX = array_values($seriesX); $this->seriesY = array_values($seriesY); } $this->width = 800; $this->height = 600; $this->precision = 2; $this->antialias = true; $this->title = 'My Pie Chart'; $this->titleColor = '333333'; $this->titleFont = 'font.ttf'; $this->titlePadding = 40; $this->titleSize = 16; $this->titleY = 0; $this->backgroundColor = '#FFFFFF'; $this->borderColor = '0x444444'; $this->legendY = $this->height; $this->legendLabelColor = 'ff0'; $this->legendLabelSize = 8; $this->legendLabelGap = $this->legendLabelSize*3/4; $this->legendPadding = 20; $this->legendPosition = 'bottom'; $this->legendWidth = 250; $this->guidLabelSize = 8; $this->guidLinesColor = '0x444444'; $this->guidLabelsColor = '0x444444'; $this->pieBorderColor = 'ccc'; $this->pieDelta = 20; $this->piePadding = 0; $this->showBorder = true; $this->showLegend = true; $this->showLegendBorder = true; $this->showPieBorder = true; $this->showShadow = true; $this->showGuidLines = true; $this->showGuidLabels = true; $this->shadowColor = '444'; $this->shadowLagX = 3; $this->shadowLagY = 3; $this->slicesColors = array( '0xE48701', '0x1B85D9', '0xA5BC4E', '0xFFFC93', '0x7ECFE1', '0xFF84BC', '0xC5F57E', '0x7EA6CE', '0xFF7E9F', '0x7EC29B', '0x7E83BB', '0xFFB17E', '0x7EC9BD', '0xC57EBF', '0xFFBD8A'); } // --------------------------------------------------------- // --- SETTERS --- // --------------------------------------------------------- function setAntialias($antialias) { $this->antialias = $antialias; } function setBackgroundColor($color) { $this->backgroundColor = $color; } function setBorderColor($color) { $this->borderColor = $color; } function setPieBorderColor($color) { $this->pieBorderColor = $color; } function setPieDelta($delta) { $this->pieDelta = $delta; } function setPiePadding($padding) { $this->piePadding = $padding; } function setWidth($width) { $this->width = $width; } function setHeight($height) { $this->height = $height; } function setTitle($title) { $this->title = $title; } function setTitleFont($font) { $this->titleFont = $font; } function setTitleColor($color) { $this->titleColor = $color; } function setTitleSize($size) { $this->titleSize = $size; } function setTitlePadding($padding) { $this->titlePadding = $padding; } function setLabelFunction($function) { $this->labelFunction = $function; } function setLegendWidth($width) { $this->legendWidth = $width; } function setLegendLabelColor($color) { $this->legendLabelColor = $color; } function setLegendLabelGap($gap) { $this->legendLabelGap = $gap; } function setLegendLabelSize($size) { $this->legendLabelSize = $size; $this->legendLabelGap = $size*3/4; } function setLegendPadding($padding) { $this->legendPadding = $padding; } function setLegendPosition($position) { $this->legendPosition = $position; } function setGuidLabelSize($size) { $this->guidLabelSize = $size; } function setGuidLabelsColor($color) { $this->guidLabelsColor = $color; } function setGuidLinesColor($color) { $this->guidLinesColor = $color; } function setPrecision($precision) { $this->precision = $precision; } function showBorder() { $this->showBorder = true; } function showLegend() { $this->showLegend = true; } function showLegendBorder() { $this->showLegendBorder = true; } function showPieBorder() { $this->showPieBorder = true; } function showShadow() { $this->showShadow = true; } function showGuidLines() { $this->showGuidLines = true; } function showGuidLabels() { $this->showGuidLabels = true; } function setSlicesColors($colors) { $this->slicesColors = $colors; } function setShadowColor($color) { $this->shadowColor = $color; } function setShadowLagX($lag) { $this->shadowLagX = $lag; } function setShadowLagY($lag) { $this->shadowLagY = $lag; } // --------------------------------------------------------- // --- PUBLIC METHODS --- // --------------------------------------------------------- function draw() { $this->img = imagecreatetruecolor($this->width, $this->height); imageantialias($this->img, $this->antialias); $this->drawBackground(); $this->drawBorder(); $this->drawTitle(); $this->drawHLegend(); $this->drawPie(); $this->drawGuidLines(); header('Content-Type: image/png'); imagepng($this->img); imagedestroy($this->img); } // --------------------------------------------------------- // --- PRIVATE METHODS --- // --------------------------------------------------------- protected function calculatePercents($data) { $percents = array(); $len = count($data); $total = 0; foreach ($data as $v) $total+=$v; foreach ($data as $v) $percents[] = round($v * 100 / $total, $this->precision); return $percents; } protected function formatGuidLabel($label, $width) { $str = explode(' ', $label); $len = count($str); $line = 1; $txt = $str[0]; $label = ''; $maxWidth = 0; for ($i=1; $i<$len; $i++) { if (strlen($txt.' '.$str[$i])*$this->guidLabelSize*3/4 < $width) $txt .= ' '.$str[$i]; else { $w = strlen($txt)*$this->guidLabelSize*3/4; if ($maxWidth < $w) $maxWidth = $w; $label .= $txt."\n"; $txt = $str[$i]; $line++; } } $label .= $txt; return array($label, $line, $maxWidth); } protected function drawBackground() { list($r, $g, $b) = $this->html2rgb($this->backgroundColor); $bgcolor = imagecolorallocate($this->img, $r, $g, $b); imagefilledrectangle($this->img, 0, 0, $this->width-1, $this->height-1, $bgcolor); } protected function drawBorder() { if ($this->showBorder) { list($r, $g, $b) = $this->html2rgb($this->borderColor); $bgcolor = imagecolorallocate($this->img, $r, $g, $b); imagerectangle($this->img, 0, 0, $this->width-1, $this->height-1, $bgcolor); } } protected function drawTitle() { // POSSIBLE OPTIMIZATION: word wrapping $x = ($this->width - (strlen($this->title) * $this->titleSize*5/6)) / 2; $y = $this->titlePadding; list($r, $g, $b) = $this->html2rgb($this->titleColor); $titleColor = imagecolorallocate($this->img, $r, $g, $b); imagettftext($this->img, $this->titleSize, 0, $x, $y, $titleColor, $this->titleFont, $this->title); $this->titleY = $y + $this->titlePadding; } protected function drawHLegend() { if ($this->showLegend) { // box sizes and paddings $cellSize = $this->legendLabelSize * 0.75; $textSize = $this->legendLabelSize; $cellPadding = ($textSize - $cellSize) / 2; // lengths and item/line numbers $len = count($this->seriesX); $max = 0; $nb = 0; $flag = $this->width - 2*$this->legendPadding; // colors $slices = count($this->slicesColors); list($r, $g, $b) = $this->html2rgb($this->borderColor); $borderColor = imagecolorallocate($this->img, $r, $g, $b); // longest label width for ($i=0; $i<$len; $i++) if (strlen($this->seriesX[$i]) > strlen($this->seriesX[$max])) $max = $i; $wordWidth = strlen($this->seriesX[$max]) * $textSize; // number of lines and items per line $cellWidth = 3*$cellSize + $wordWidth; $cellHeight = $textSize + $cellSize; while ($flag > 0 && $nb < $len) { $flag -= $cellWidth; $nb++; } if ($cellWidth * $nb > $this->width - $this->legendPadding*2) $nb--; $line = ceil($len / $nb); // positions switch ($this->legendPosition) { case "top": $x = ($this->width - $nb*$cellWidth) / 2; $y = $this->titleY; $this->legendY = $this->height; break; case "bottom": default: $x = ($this->width - $nb*$cellWidth) / 2 ; $y = $this->height - ($textSize+$this->legendLabelGap)*$line - $this->legendPadding; $this->legendY = $y - $this->legendPadding; break; } // draw items for ($i=0; $i<$line; $i++) { for ($j=0; $j<$nb && $j<$len-$i*$nb; $j++) { // draw color cell list($r, $g, $b) = $this->html2rgb($this->slicesColors[($i*$nb+$j)%$slices]); $legendColor = imagecolorallocate($this->img, $r, $g, $b); imagefilledrectangle( $this->img, $x+1+$j*$cellWidth, $y+$cellPadding+1+$i*$cellHeight, $x+$cellSize-2+$j*$cellWidth, $y+$cellPadding+$cellSize-2+$i*$cellHeight, $legendColor); imagerectangle( $this->img, $x+$j*$cellWidth, $y+$cellPadding+$i*$cellHeight, $x+$cellSize-1+$j*$cellWidth, $y+$cellPadding+$cellSize-1+$i*$cellHeight, $borderColor); // draw label imagettftext( $this->img, $textSize, 0, $x+2*$cellSize+$j*$cellWidth, $y+$textSize-1+$i*$cellHeight, $titleColor, $this->titleFont, $this->seriesX[$i*$nb+$j]); } } // draw border if ($this->showLegendBorder) imagerectangle( $this->img, $x-$this->legendPadding/2, $y-$this->legendPadding/2, $x+$nb*$cellWidth, $y+$line*$cellHeight, $borderColor); if ($this->legendPosition == 'top') $this->titleY = $y+$line*$cellHeight+$this->legendPadding; } } protected function drawPie() { // position $x = $this->width / 2; $y = ($this->titleY + $this->legendY) / 2; $pieSize = $this->height - ($this->titleY + $this->height - $this->legendY + 2*$this->piePadding); $pieSize *= 3/5; $this->pieX = $x; $this->pieY = $y; $this->pieSize = $pieSize; // shadow if ($this->showShadow) { list($r, $g, $b) = $this->html2rgb($this->shadowColor); $color = imagecolorallocate($this->img, $r, $g, $b); imagefilledarc($this->img, $x+$this->shadowLagX, $y+$this->shadowLagY, $pieSize, $pieSize, 0, 360, $color, IMG_ARC_PIE); } // calculate percents $this->seriesZ = $this->calculatePercents($this->seriesY); // slices drawing $len = count($this->seriesX); $slen = count($this->slicesColors); list($r, $g, $b) = $this->html2rgb($this->pieBorderColor); $borderColor = imagecolorallocate($this->img, $r, $g, $b); $deg = 0; for ($i=0; $i<$len; $i++) { list($r, $g, $b) = $this->html2rgb($this->slicesColors[$i%$slen]); $color = imagecolorallocate($this->img, $r, $g, $b); $end = ($i==$len-1) ? 360 : $deg + $this->seriesZ[$i] * 360 / 100; imagefilledarc($this->img, $x, $y, $pieSize, $pieSize, $deg, $end, $color, IMG_ARC_PIE); if ($this->showPieBorder) imagefilledarc($this->img, $x, $y, $pieSize, $pieSize, $deg, $end, $borderColor, IMG_ARC_EDGED | IMG_ARC_NOFILL); $deg = $end; } // IMG_ARC_PIE | IMG_ARC_EDGED | IMG_ARC_NOFILL | IMG_ARC_CHORD } protected function drawGuidLines() { if ($this->showGuidLabels) { // data retrieving $x = $this->pieX; $y = $this->pieY; $d = $this->pieSize/2; $xl = $x - ($d + $this->pieDelta); $xr = $x + ($d + $this->pieDelta); list($r, $g, $b) = $this->html2rgb($this->guidLinesColor); $color = imagecolorallocate($this->img, $r, $g, $b); // drawing $deg = 0; $v = $this->seriesZ[0]; foreach ($this->seriesZ as $k => $v) { $tmp = ($v*2*pi()/100); // lines $xx = ($x + ($d + $this->pieDelta)*cos($deg + $tmp/2)) > $x ? $xr : $xl; if ($this->showGuidLines) { imageline( $this->img, $x + ($d - $this->pieDelta)*cos($deg + $tmp/2), $y + ($d - $this->pieDelta)*sin($deg + $tmp/2), $x + ($d + $this->pieDelta)*cos($deg + $tmp/2), $y + ($d + $this->pieDelta)*sin($deg + $tmp/2), $color); imageline( $this->img, $x + ($d + $this->pieDelta)*cos($deg + $tmp/2), $y + ($d + $this->pieDelta)*sin($deg + $tmp/2), $xx, $y + ($d + $this->pieDelta)*sin($deg + $tmp/2), $color); } // labels if ($xx == $xr) { list($txt, $nb, $w) = $this->formatGuidLabel($this->seriesX[$k], $this->width - $xr - $this->pieDelta); $xx = $xr + $this->pieDelta; } else { $width = strlen($this->seriesX[$k])*$this->guidLabelSize*3/4; list($txt, $nb, $w) = $this->formatGuidLabel($this->seriesX[$k], $xl - $this->pieDelta); $xx = $xl - $this->pieDelta - ($nb > 1 ? $w : $width); } imagettftext( $this->img, $this->guidLabelSize, 0, $xx, $y + ($d+$this->pieDelta)*sin($deg+$tmp/2) + $this->guidLabelSize/2 - ($nb-1)*$this->guidLabelSize/2, $this->guidLabelsColor, $this->titleFont, $txt); $deg += $tmp; } } } // --------------------------------------------------------- // --- STATIC METHODS --- // --------------------------------------------------------- static function html2rgb($color) { if ($color[0] == '#') $color = substr($color, 1); if ($color[0] == '0' && $color[1] == 'x') $color = substr($color, 2); if (strlen($color) == 6) return array( hexdec($color[0].$color[1]), hexdec($color[2].$color[3]), hexdec($color[4].$color[5])); elseif (strlen($color) == 3) return array( hexdec($color[0].$color[0]), hexdec($color[1].$color[1]), hexdec($color[2].$color[2])); else return false; } static function rgb2html($r, $g=-1, $b=-1) { if (is_array($r) && sizeof($r) == 3) list($r, $g, $b) = $r; $r = intval($r); $g = intval($g); $b = intval($b); $r = dechex($r < 0 ? 0 : ($r > 255 ? 255 : $r)); $g = dechex($g < 0 ? 0 : ($g > 255 ? 255 : $g)); $b = dechex($b < 0 ? 0 : ($b > 255 ? 255 : $b)); $color = (strlen($r) < 2 ? '0' : '').$r; $color .= (strlen($g) < 2 ? '0' : '').$g; $color .= (strlen($b) < 2 ? '0' : '').$b; return '#'.$color; } } ?>

A voir également

Ajouter un commentaire

Commentaires

Bonjour à tous, pourriez vous m'expliquer comment remplacer les infos de $seriesY et $seriesX avec des éléments de tableau tirés d'une base de données merci ...
Messages postés
239
Date d'inscription
vendredi 20 octobre 2006
Statut
Membre
Dernière intervention
20 avril 2009

Bonjour,

Ton code est tres clair, mais pourquoi ne pas utiliser une methode de sérialization un peu plus standard, comme JSON par exemple ? Ca permettrait de créer plus facilement les séries à partir de JavaScript.

Pour ton probleme d'anti-alias, tu peux essayer de générer une image 4 fois plus grande, puis d'utiliser imagecopyresampled() pour la rammener a la résolution voulue.

Ca devrait ne pas consommer trop de mémoire vue la taille des camembert.

Par contre tu devras peut-etre ne pas aliaser les textes (trace les après le imagecopyresampled() ).

Eric

PS: Peut-etre une petite note sur le format a utiliser pour les series serait plus simple que de devoir "reverse-engineerer" les exemples fournis :o)
Profil bloqué
asphator bo travail et merci a zoulou93 pour la modif ça Fonctionne me sera très utile Merci
Messages postés
2
Date d'inscription
jeudi 11 décembre 2003
Statut
Membre
Dernière intervention
7 mars 2006

bonjour,

beau travail d'entraînement (comme tu le dis !).
Dans mon entreprise nous utilisons la bibliothèque JP_GRAPH , pour ne pas tout (ré)écrire . voir http://www.aditus.nu/jpgraph .
Tu peux y jeter un coup d'oeil et t'en inspirer?

cordialement,
Michel
Messages postés
1654
Date d'inscription
dimanche 7 septembre 2008
Statut
Membre
Dernière intervention
11 septembre 2013
12
bonjour
j'ai du rajouté une font.ttf dans le repertoire +
ligne 333 $titleColor="123456",
et ça tourne ...

mon appel test

$_GET['seriesX']='a:3:{i:0;i:2009;i:1;i:2010;i:2;i:2011;}&seriesY=a:3:{i:0;i:118;i:1;i:218;i:2;i:780;}';
//$_GET['seriesY']='a:3:{i:0;i:2009;i:1;i:2010;i:2;i:2011;}&seriesY=a:3:{i:0;i:118;i:1;i:218;i:2;i:780;}';
// --- Data retrieving
$seriesX = (!empty($_GET['seriesX']))
? unserialize(stripslashes($_GET['seriesX']))
: array();
$seriesY = (!empty($_GET['seriesY']))
? unserialize(stripslashes($_GET['seriesY']))
: array();

// --- Class instanciation
$pie = new AKPie($seriesX, $seriesY);
$pie->draw();

autrement bien ta source
merci encore comme j'ai un projet de sondage elle tombe bien
a++

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.