Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

SMOOTH 3D CAMEMBERT


Information sur la source

Catégorie :Graphique Classé sous : camembert, 3d, antialiasing, bresenham, statistiques Niveau : Initié Date de création : 27/08/2006 Date de mise à jour : 29/09/2008 01:35:37 Vu / téléchargé: 13 294 / 1 495

Note :
9,54 / 10 - par 26 personnes
9,54 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (100)
Ajouter un commentaire et/ou une note

Description

Cliquez pour voir la capture en taille normale
Suite à la remarque de BADOUX concernant le "camembert" de la source N°34131 d'adresse :
http://www.phpcs.com/codes/CAMEMBERTS-3D_34131.aspx
et dont les bords lui semblaient "un peux pixellisé", j'ai décidé de revoir tout le code avec la ferme intention de faire disparaître ces vilains petits défauts (d'où cette nouvelle publication et non pas une simple mise à jour).
Un mot-clé à retenir : Anti-Aliasing (AA pour les connaisseurs)
Sa définition : "algorithme appliqué sur le contour des formes pour en rendre l'aspect plus agréable, et éviter de voir la structure grillagée de l'image."

La méthode "bourrin" consiste à créer une image plus grande (par exemple 3 fois plus grande)que l'on réduit à la bonne taille une fois le travail effectué. L'AA est réalisé par la fonction de réduction "ImageCopyResampled()", qui se charge de trouver un compromis satisfaisant entre les pixels constituant chaque carré de 3x3. Cette technique est efficace, l'image finale qu'elle produit acceptable (pour un camembert!), le code l'implémentant court et facile à comprendre, son seul défaut est de requérir un temps d'exécution important (que je n'ai pas mesuré, mais bon...). On peut trouver un code de ce type en allant sur "http://www.phpclasses.org" (y rechercher quelque chose comme "EQ_Smooth_3D_Pie_Graph").

On peut aussi attaquer le problème par la face nord, en partant d'une image à l'échelle 1, et gérer les transitions entre les zones de couleurs différentes.
Cette technique suppose en fait la réécriture des fonctions de gd2 impliquées dans l'image, et l'utilisation intensive d'algorithmes qui ont pour nom : Bresenham, Gupta-Sproull, point-milieu, ainsi que la mise à contribution de la transparence alpha.

C'est cette deuxième méthode qui est traitée ici.
Le code ci-dessous est entièrement fonctionnel, on peut donc en faire un copier-coller et l'exécuter immédiatement (php5 et gd2 requis).
Pour ceux qui veulent approfondir, ils trouveront dans le zip une version plus aboutie utilisant une véritable police de caractères et donnant le choix entre trois tailles de camembert différentes et trois types de fonds différents.

La démo en ligne :
http://michel.vanthodiep.free.fr/smooth3dcamembert/

 

Source

  • <?php
  • header ('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
  • header ('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
  • header ('Cache-Control: no-cache, must-revalidate');
  • header ('Pragma: no-cache');
  • /*
  • - Date de création : 27/01/2008
  • - Nom : aacamembert.php, version simplifiée à "copier-coller"
  • - Auteur : opossum_farceur
  • - Object : Camembert, 3D, Antialiasing, Bresenham, Statistiques
  • */
  • define('coef',M_PI/180);
  • class aacamembert
  • {
  • private $img;
  • private $a,$b,$cx,$cy,$aa,$bb,$aabb; /* ellipse */
  • private $data,$sort,$ellipse; /* tableaux */
  • private $quarter,$pivot; /* autres */
  • private $num,$linecolor; /* algorithme de Gupta-Sproull */
  • /* constructeur ---------------------------------------------------------------------------------------*/
  • function __construct($title,$arr)
  • {
  • $width=500;
  • $head=35; /* 15+15+5 : réservés pour le titre */
  • $height=300;
  • $w=240; /* grand axe horizontal */
  • $h=$w/2; /* 120 : petit axe vertical */
  • $thickness=$w/4; /* 60 : "épaisseur" du camembert */
  • $topcolor=0xFFFF00; /* dégradé : couleur du haut */
  • $bottomcolor=0x00FFFF; /* dégradé : couleur du bas */
  • $fontsize=3;
  • /* attributs calculés */
  • $this->a=$w/2; /* 1/2 grand axe : 120 */
  • $this->b=$h/2; /* 1/2 petit axe : 60 */
  • $this->cx=$width/2; /* abscisse et ordonnée du "centre" du camembert */
  • $this->cy=($height+$head-$thickness)/2;
  • $this->aa=$this->a*$this->a;
  • $this->bb=$this->b*$this->b;
  • $this->aabb=$this->aa*$this->bb;
  • /* attributs renseignés en cours de route */
  • $this->data=array();
  • $this->sort=array();
  • $this->ellipse=array();
  • /* antialiasing ligne droite */
  • $this->num=10; /* à choisir pair */
  • $this->linecolor=array(); /* taille du tableau : 1+3/2*$this->num, soit 16 (suffisant) */
  • /* préliminaires */
  • $this->img=imagecreatetruecolor($width,$height);
  • $this->mybackground($width-1,$height-1,$topcolor,$bottomcolor);
  • $textcolor=imagecolorallocate($this->img,0x00,0x00,0x00);
  • imagestring($this->img,5,($width-imagefontwidth(5)*strlen($title))/2,15,$title,$textcolor);
  • $this->aaellipse();
  • $this->gupta_sproull();
  • $specialcase=$this->init($arr,$thickness);
  • /* tracés */
  • $this->aadraw($thickness,$fontsize,$textcolor,$specialcase);
  • /* affichage */
  • header('Content-type: image/png');
  • imagepng($this->img);
  • imagedestroy($this->img);
  • }
  • /* "splite" une couleur en ses 3 composantes ----------------------------------------------------------*/
  • private function hex2rgb($hex)
  • {
  • return array(($hex>>16)& 0xFF,($hex>>8)& 0xFF,$hex & 0xFF);
  • }
  • /* mise en place du fond ------------------------------------------------------------------------------*/
  • private function mybackground($w,$h,$topcolor,$bottomcolor)
  • {
  • list($red,$green,$blue)=$this->hex2rgb($topcolor);
  • $bc=$this->hex2rgb($bottomcolor);
  • $incr=($bc[0]-$red)/$h;
  • $incg=($bc[1]-$green)/$h;
  • $incb=($bc[2]-$blue)/$h;
  • for($j=0;$j<=$h;$j++,$red+=$incr,$green+=$incg,$blue+=$incb)
  • imageline($this->img,0,$j,$w,$j,imagecolorallocate($this->img,$red,$green,$blue));
  • }
  • /* à partir de l'angle donné en argument retourne l'index correspondant du tableau de l'ellipse -------*/
  • private function index($v)
  • { /* formulation du sinus à partir du cosinus, en principe + rapide */
  • $cosv=cos(coef*$v);
  • $sinv= ($v>180)? -sqrt(1-$cosv*$cosv) : sqrt(1-$cosv*$cosv);
  • $x=round($this->a*abs($cosv));
  • $y=round($this->b*abs($sinv));
  • $case=floor($v/90);
  • $p=($case+$case%2)*$this->quarter;
  • $sign= ($case%2)? -1 : 1;
  • $q= ($this->aa*$y-$this->bb*$x<0)? $y : $this->quarter-$x;
  • return $p+$sign*$q;
  • }
  • /* traitement des données fournies dans le tableau ----------------------------------------------------*/
  • private function init($arr,$e)
  • { /* calcul de la somme des données */
  • for ($j=$sum=0,$n=count($arr);$j<$n;$j++) $sum+=$arr[$j][0];
  • /* analyse du tableau */
  • for ($j=$k=$v1=0;$j<$n;$j++) if ($arr[$j][0]) { /* cas non traité si donnée nulle */
  • /* extraction des composantes red, green et blue */
  • list($red,$green,$blue)=$this->hex2rgb($arr[$j][1]);
  • $this->data[$k]['color']=imagecolorallocate($this->img,$red,$green,$blue);
  • /* traitement des angles */
  • $v2=$v1+$arr[$j][0]*360/$sum;
  • if ($v1<=270 && $v2>=270) $first=$k;
  • if ($v1<=90 && $v2>=90) $last=$k;
  • $this->data[$k]['v']=$v2;
  • /* détermine la couleur ombrée */
  • $this->data[$k]['shade']=imagecolorallocate($this->img,max(0,$red-50),max(0,$green-50),max(0,$blue-50));
  • /* préparation du texte */
  • $this->data[$k]['legend']=$arr[$j][2];
  • $this->data[$k]['value']=number_format(100*$arr[$j][0]/$sum,2,',','').'%';
  • $this->data[$k]['xploded']=$arr[$j][3];
  • $v1=$v2;
  • $k++;
  • }
  • $m=count($this->data); /* différent de $n si une ou plusieurs donnée(s) sont nulles */
  • if ($first!=$last) {
  • for ($j=0,$k=$first;$k!=$last;$j++,$k=($k+1)%$m) $this->sort[$j]=$k;
  • $this->pivot=$j;
  • for ($k=$first-1;$k>=$last;$j++,$k--) $this->sort[$j]=$k;
  • return false;
  • }
  • else { /* cas particulier préoccupant : une grosse portion présente à la fois à 12h et à 18h */
  • for ($j=0,$k=($first+1)%$m;$j<$m;$j++,$k=($k+1)%$m) $this->sort[$j]=$k;
  • $this->pivot=$m-1;
  • /* mise en place du 2ème panneau de la dernière portion (origine du code : méthode "aadraw()") */
  • $j=$this->sort[$m-1];
  • $xploded=$this->data[$j]['xploded'];
  • if ($this->data[$this->sort[0]]['xploded'] || $xploded) {
  • $shade=$this->data[$j]['shade'];
  • $v1= ($j)? $this->data[$j-1]['v'] : 0;
  • $v2=$this->data[$j]['v'];
  • $vm=($v1+$v2)/2;
  • if ($xploded) {
  • $ox=round($this->cx+$this->a*cos(coef*$vm)/6); /* a/6, b/6 : "offsets" des portions */
  • $oy=round($this->cy+$this->b*sin(coef*$vm)/6);
  • }
  • else {
  • $ox=$this->cx;
  • $oy=$this->cy;
  • }
  • $index2=$this->index($v2);
  • $x2=$ox+$this->ellipse[$index2]['x'];
  • $y2=$oy+$this->ellipse[$index2]['y'];
  • imageline($this->img,$ox,$oy,$ox,$oy+$e,$shade);
  • imageline($this->img,$x2,$y2,$x2,$y2+$e,$shade);
  • $this->aaborder($ox,$oy,$x2,$y2,0,$backup2,$shade); /* ligne du haut */
  • $this->aaborder($x2,$y2+$e,$ox,$oy+$e,1,$backup2,$shade);/* ligne du bas (attention à l'ordre!) */
  • if ($x2-$ox>1) imagefilltoborder($this->img,round(($ox+$x2)/2),round(($oy+$y2+$e)/2),$shade,$shade);
  • $this->aaborder($x2,$y2+$e,$ox,$oy+$e,2,$backup2); /* aa ligne du bas */
  • }
  • return true;
  • }
  • }
  • /* calcul des 16 tons de gris utiles au dessin des lignes droites antialiassées -----------------------*/
  • private function gupta_sproull()
  • { /* cette fonction crée une table allant de 0 à 1.5*$this->num */
  • $col=array();
  • $numdiv2=$this->num/2;
  • /* calcul du volume interceptant chaque colonne, i et j parcourent un quart du cône */
  • for ($i=$this->num,$total=0;$i>=0;$i--) {
  • for ($j=$this->num,$k=0,$ii=$i*$i;$j>=0;$j--) {
  • $d=sqrt($ii+$j*$j);
  • if ($d<$this->num) $k+=$this->num-$d;
  • }
  • $col[$this->num-$i]=2*$k;
  • $total+=4*$k;
  • }
  • /* calcul de la table : 1ere partie correspondant à une intersection d'épaisseur inférieure à 1 */
  • $max=$this->num+$numdiv2;
  • for ($i=$k=0;$i<=$this->num;$i++) {
  • $k+=$col[$i];
  • $this->linecolor[$max-$i]=imagecolorexactalpha($this->img,0,0,0,round(127*(1-$k/$total)));
  • }
  • /* calcul de la table : 2eme partie correspondant à une intersection d'épaisseur supérieure à 1 */
  • for ($i=1;$i<=$numdiv2;$i++) {
  • $k+=$col[$this->num-$i]-$col[$i];
  • $this->linecolor[$numdiv2-$i]=imagecolorexactalpha($this->img,0,0,0,round(127*(1-$k/$total)));
  • }
  • }
  • /* "allume" le pixel avec une intensité fonction de la distance à la droite ---------------------------*/
  • private function plot($x,$y,$d)
  • {
  • if ($d<0) $d=-$d;
  • if ($d>1.5) return; /* rien à allumer si le pixel est trop loin */
  • imagesetpixel($this->img,$x,$y,$this->linecolor[round($d*$this->num)]);
  • }
  • /* tracé de droite "antialiassée" ---------------------------------------------------------------------*/
  • private function aaline($x1,$y1,$x2,$y2)
  • {
  • $dx=abs($x2-$x1);
  • $dy=abs($y2-$y1);
  • $incj= (($x2-$x1)*($y2-$y1)>0)? 1 : -1;
  • $K=1/(2*sqrt($dx*$dx+$dy*$dy));
  • if ($dx>$dy) { /* tendance "horizontale" */
  • if ($x2>$x1) {
  • $y=$y1;
  • $begin=$x1;
  • $end=$x2;
  • }
  • else {
  • $y=$y2;
  • $begin=$x2;
  • $end=$x1;
  • }
  • $p=2*$dy;
  • $delta=$dx;
  • $incx=0;
  • $incy=$incj;
  • $i=&$x;
  • $j=&$y;
  • }
  • else { /* tendance "verticale" */
  • if ($y2>$y1) {
  • $x=$x1;
  • $begin=$y1;
  • $end=$y2;
  • }
  • else {
  • $x=$x2;
  • $begin=$y2;
  • $end=$y1;
  • }
  • $p=2*$dx;
  • $delta=$dy;
  • $incx=$incj;
  • $incy=0;
  • $i=&$y;
  • $j=&$x;
  • }
  • /* tronc commun */
  • for ($i=$begin,$e=$p-$delta,$q=$e-$delta,$D=0,$R=2*$K*$delta;$i<=$end;$i++) {
  • $this->plot($x,$y,$D);
  • $this->plot($x+$incx,$y+$incy,$R-$D);
  • $this->plot($x-$incx,$y-$incy,$R+$D);
  • if ($e>=0) {
  • $D=$K*($e-$delta);
  • $j+=$incj;
  • $e+=$q;
  • }
  • else {
  • $D=$K*($e+$delta);
  • $e+=$p;
  • }
  • }
  • }
  • /* traitement de l'aa des "bordures" ------------------------------------------------------------------*/
  • private function aaborder($x1,$y1,$x2,$y2,$mode,&$backup,$mycolor=0)
  • {
  • $dx=$x2-$x1;
  • $dy=$y2-$y1;
  • $incj= ($dx*$dy>0)? 1 : -1;
  • if ($mode==1) $backup=array();
  • elseif ($mode==2) $const=$dx*$y1-$dy*$x1;
  • if (abs($dx)>abs($dy)) { /* tendance "horizontale" */
  • if ($dx>0) {
  • $y=$y1;
  • $begin=$x1;
  • $end=$x2;
  • }
  • else {
  • $y=$y2;
  • $begin=$x2;
  • $end=$x1;
  • }
  • $p=2*abs($dy);
  • $e=$p-abs($dx);
  • $q=$e-abs($dx);
  • $i=&$x;
  • $j=&$y;
  • }
  • else { /* tendance "verticale" */
  • if ($dy>0) {
  • $x=$x1;
  • $begin=$y1;
  • $end=$y2;
  • }
  • else {
  • $x=$x2;
  • $begin=$y2;
  • $end=$y1;
  • }
  • $p=2*abs($dx);
  • $e=$p-abs($dy);
  • $q=$e-abs($dy);
  • $i=&$y;
  • $j=&$x;
  • }
  • /* tronc commun */
  • for ($i=$begin,$t=0;$i<=$end;$i++,$t++) {
  • if ($mode==1) $backup[]=imagecolorat($this->img,$x,$y); /* mode "sauvegarde" */
  • elseif ($mode==2) { /* mode "antialiasing" */
  • for ($f=$x-0.2,$g1=$y-0.2,$g3=$y+0.2,$alpha=0;$f<=$x+0.2;$f+=0.2) {
  • $k=$const+$dy*$f;
  • for ($g=$g1;$g<=$g3;$g+=0.2) if ($dx*$g>$k) $alpha++;
  • }
  • list($red,$green,$blue)=$this->hex2rgb($backup[$t]);
  • $mycolor=imagecolorexactalpha($this->img,$red,$green,$blue,11*$alpha+28);
  • }
  • imagesetpixel($this->img,$x,$y,$mycolor);
  • if ($e>=0) {
  • $j+=$incj;
  • $e+=$q;
  • }
  • else $e+=$p;
  • }
  • }
  • /* tracé du camembert ---------------------------------------------------------------------------------*/
  • private function aadraw($e,$fontsize,$textcolor,$specialcase)
  • {
  • $A=$this->a*21/16; /* 1/2 grand axe de l'ellipse "englobante" */
  • $B=3*$A/4; /* bien que dépendant de $e, mais bon... */
  • $dy=-$e/2; /* "centre" du camembert à celui de l'ellipse "englobante" */
  • $AA=$A*$A;
  • $BB=$B*$B;
  • $ifw=imagefontwidth($fontsize);
  • /* "grande boucle" */
  • for ($i=0,$m=count($this->data);$i<$m;$i++) {
  • $j=$this->sort[$i];
  • /* initialisations */
  • $color=$this->data[$j]['color'];
  • $shade=$this->data[$j]['shade'];
  • $v1= ($j)? $this->data[$j-1]['v'] : 0;
  • $v2=$this->data[$j]['v'];
  • $vm=($v1+$v2)/2;
  • $index1=$this->index($v1);
  • $index2=$this->index($v2);
  • $xploded=$this->data[$j]['xploded'];
  • $panel1=$panel2=false;
  • $flag=0;
  • if ($xploded) {
  • $px=$this->a*cos(coef*$vm);
  • $py=$this->b*sin(coef*$vm);
  • $ox=round($this->cx+$px/6); /* a/6, b/6 : "offsets" des portions */
  • $oy=round($this->cy+$py/6);
  • }
  • else {
  • $px=5*$this->a*cos(coef*$vm)/6;
  • $py=5*$this->b*sin(coef*$vm)/6;
  • $ox=$this->cx;
  • $oy=$this->cy;
  • switch ($i) { /* cumulations possibles */
  • case 0: $flag=$this->data[$this->sort[$this->pivot]]['xploded'];
  • case $this->pivot-1: $flag|=$this->data[$this->sort[$m-1]]['xploded'];
  • default: $flag|=$this->data[$this->sort[$i+1]]['xploded'];
  • }
  • }
  • $x1=$ox+$this->ellipse[$index1]['x'];
  • $y1=$oy+$this->ellipse[$index1]['y'];
  • $x2=$ox+$this->ellipse[$index2]['x'];
  • $y2=$oy+$this->ellipse[$index2]['y'];
  • $gx=round($this->cx+$px); /* sans arrondi, problème raccordement segment en size 1 */
  • $gy=round($this->cy+$py);
  • /* traitement secteur du bas + paravent vertical */
  • if ($v1<180) {
  • if ($v2<180) {
  • $indexmax=$index2;
  • $x=$x2;
  • $y=$y2;
  • }
  • else { /* le traitement s'arrête à 180° */
  • $indexmax=2*$this->quarter; /* aussi : $this->index(180); */
  • $x=$ox-$this->a; /* aussi : $ox+$this->ellipse[$indexmax]['x']; */
  • $y=$oy; /* aussi : $oy+$this->ellipse[$indexmax]['y'] */
  • }
  • /* dessin des secteurs hauts et bas de l'ellipse */
  • for ($k=$index1,$backup0=array();$k<=$indexmax;$k++) {
  • $xk=$ox+$this->ellipse[$k]['x'];
  • $yk=$oy+$this->ellipse[$k]['y'];
  • $backup0[]=imagecolorat($this->img,$xk,$yk+$e);
  • imagesetpixel($this->img,$xk,$yk,$shade);
  • imagesetpixel($this->img,$xk,$yk+$e,$shade);
  • }
  • /* lignes verticales */
  • imageline($this->img,$x1,$y1,$x1,$y1+$e,$shade);
  • imageline($this->img,$x,$y,$x,$y+$e,$shade);
  • /* "remplissage" peu optimisé mais valable dans tous les cas de figures */
  • if ($x1-$x>1) imagefilltoborder($this->img,$x+1,$y+$e/2,$shade,$shade);
  • /* antialiasing secteur ellipse du bas */
  • $this->aaarc($index1,$indexmax,$ox,$oy+$e,$backup0);
  • }
  • if ($xploded || $flag) { /* dessine les "panneaux" verticaux */
  • if ($v1>90 && $v1<270) {
  • imageline($this->img,$ox,$oy,$ox,$oy+$e,$shade);
  • imageline($this->img,$x1,$y1,$x1,$y1+$e,$shade); /* parfois inutile, mais bon... */
  • $this->aaborder($x1,$y1,$ox,$oy,0,$backup1,$shade); /* ligne du haut, backup inutile */
  • $this->aaborder($ox,$oy+$e,$x1,$y1+$e,1,$backup1,$shade);/* ligne du bas, backup parfois inutile */
  • if ($ox-$x1>1)
  • imagefilltoborder($this->img,round(($ox+$x1)/2),round(($oy+$y1+$e)/2),$shade,$shade);
  • $this->aaborder($ox,$oy+$e,$x1,$y1+$e,2,$backup1); /* aa ligne du bas */
  • if ($v1<180) imageline($this->img,$x1,$y1,$x1,$y1+$e,$color); /* séparation verticale */
  • $panel1=true;
  • }
  • if ($v2<90 ||($v2>270 &&!($specialcase && $i==$m-1))) { /* $specialcase n'apparait qu'ici */
  • imageline($this->img,$ox,$oy,$ox,$oy+$e,$shade);
  • imageline($this->img,$x2,$y2,$x2,$y2+$e,$shade);
  • $this->aaborder($ox,$oy,$x2,$y2,0,$backup2,$shade); /* ligne du haut, backup inutile */
  • $this->aaborder($x2,$y2+$e,$ox,$oy+$e,1,$backup2,$shade);/* ligne du bas */
  • if ($x2-$ox>1)
  • imagefilltoborder($this->img,round(($ox+$x2)/2),round(($oy+$y2+$e)/2),$shade,$shade);
  • $this->aaborder($x2,$y2+$e,$ox,$oy+$e,2,$backup2); /* aa ligne du bas */
  • if ($v2<90) imageline($this->img,$x2,$y2,$x2,$y2+$e,$color); /* séparation verticale */
  • $panel2=true;
  • }
  • if ($panel1 && $panel2) imageline($this->img,$ox,$oy,$ox,$oy+$e,$color);/* séparation verticale */
  • }
  • /* dessine le dessus de la portion */
  • for ($k=$index1,$backup0=array();$k<=$index2;$k++) {
  • $xk=$ox+$this->ellipse[$k]['x'];
  • $yk=$oy+$this->ellipse[$k]['y'];
  • $backup0[]=imagecolorat($this->img,$xk,$yk);
  • imagesetpixel($this->img,$xk,$yk,$color);
  • }
  • /* tracé des "rayons", sauvegarde parfois inutile, mais bon... */
  • $this->aaborder($ox,$oy,$x1,$y1,1,$backup1,$color); /* centre -> extrémité */
  • $this->aaborder($x2,$y2,$ox,$oy,1,$backup2,$color); /* extrémité -> centre */
  • /* "remplissage" du secteur en partant du "germe" */
  • imagefilltoborder($this->img,$gx,$gy,$color,$color);
  • /* correction du défaut du "secteur trop étroit" (pas toujours nécessaire) */
  • imageline($this->img,$ox,$oy,$gx,$gy,$color);
  • /* antialiasing secteur ellipse du haut */
  • $this->aaarc($index1,$index2,$ox,$oy,$backup0);
  • /* antialiasing des "rayons" du secteur elliptique */
  • if ($xploded || $flag) {
  • $this->aaborder($ox,$oy,$x1,$y1,2,$backup1); /* centre -> extrémité */
  • $this->aaborder($x2,$y2,$ox,$oy,2,$backup2); /* extrémité -> centre */
  • }
  • else if ($i) { /* centre -> extrémité */
  • if ($i<$this->pivot) $this->aaborder($ox,$oy,$x1,$y1,2,$backup1);
  • else { /* extrémité -> centre */
  • $this->aaborder($x2,$y2,$ox,$oy,2,$backup2);
  • if ($i==$m-1) $this->aaborder($ox,$oy,$x1,$y1,2,$backup1);
  • }
  • }
  • /* traitement des légendes */
  • $ka=$AA*$py*$py+$BB*$px*$px;
  • $kb=$AA*$dy*$px*$py;
  • $kc=$AA*$px*$px*($dy*$dy-$BB);
  • if ($vm<=90 || $vm>270) {
  • $root=(-$kb+sqrt($kb*$kb-$ka*$kc))/$ka;
  • $qx=round($this->cx+$root);
  • $qy=round($this->cy+$root*$py/$px);
  • $this->aaline($gx,$gy,$qx,$qy);
  • $this->aaline($qx+1,$qy,$qx+10,$qy);
  • imagestring($this->img,$fontsize,$qx+14,$qy-12,$this->data[$j]['legend'],$textcolor);
  • imagestring($this->img,$fontsize,$qx+14,$qy-2,$this->data[$j]['value'],$textcolor);
  • }
  • else {
  • $root=(-$kb-sqrt($kb*$kb-$ka*$kc))/$ka;
  • $qx=round($this->cx+$root);
  • $qy=round($this->cy+$root*$py/$px);
  • $this->aaline($gx,$gy,$qx,$qy);
  • $this->aaline($qx-1,$qy,$qx-10,$qy);
  • $legendposx=$qx-12-$ifw*strlen($this->data[$j]['legend']);
  • $valueposx=$qx-12-$ifw*strlen($this->data[$j]['value']);
  • imagestring($this->img,$fontsize,$legendposx,$qy-12,$this->data[$j]['legend'],$textcolor);
  • imagestring($this->img,$fontsize,$valueposx,$qy-2,$this->data[$j]['value'],$textcolor);
  • }
  • }
  • }
  • /* dessine un arc avec l'aa ---------------------------------------------------------------------------*/
  • private function aaarc($begin,$end,$dx,$dy,&$backup)
  • {
  • for ($j=$begin,$i=0;$j<=$end;$j++,$i++) {
  • list($red,$green,$blue)=$this->hex2rgb($backup[$i]);
  • $mix=imagecolorexactalpha($this->img,$red,$green,$blue,$this->ellipse[$j]['alpha']);
  • imagesetpixel($this->img,$dx+$this->ellipse[$j]['x'],$dy+$this->ellipse[$j]['y'],$mix);
  • }
  • }
  • /* calcul de la transparence du point, intégration de l'enregistrement au tableau ---------------------*/
  • private function add($x,$y)
  • { /* 9 échantillons sont suffisants */
  • for ($f=$x-0.2,$g1=$y-0.2,$g3=$y+0.2,$alpha=0;$f<=$x+0.2;$f+=0.2) {
  • $k=$this->aabb-$this->bb*$f*$f;
  • for ($g=$g1;$g<=$g3;$g+=0.2) if ($this->aa*$g*$g<$k) $alpha++;
  • }
  • return array('x'=>$x,'y'=>$y,'alpha'=>11*$alpha+28);
  • }
  • /* calcul d'un quart de l'ellipse, généralisation à l'ellipse entière ---------------------------------*/
  • private function aaellipse()
  • {
  • $temp=array();
  • /* algorithme volontairement non optimisé, pour ne pas le rendre encore plus hermétique ! */
  • for ($x=0,$y=$this->b,$e=4*$this->bb+$this->aa*(1-4*$y);$this->bb*$x<$this->aa*$y;$x++) {
  • $temp[2][]=$this->add($x,$y); /* octant n°2 */
  • $e+= ($e<0)? $this->bb*(8*$x+12) : $this->bb*(8*$x+12)+8*$this->aa*(1-$y--);
  • }
  • for ($x=$this->a,$y=0,$e=4*$this->aa+$this->bb*(1-4*$x);$this->aa*$y<$this->bb*$x;$y++) {
  • $temp[1][]=$this->add($x,$y); /* octant n° 1 */
  • $e+= ($e<0)? $this->aa*(8*$y+12) : $this->aa*(8*$y+12)+8*$this->bb*(1-$x--);
  • }
  • /* on remet tout dans l'ordre qui convient */
  • $this->ellipse=array_merge($temp[1],array_reverse($temp[2]));
  • unset($temp);
  • /* généralisation aux 3 autres quadrants */
  • for ($i=0,$n=count($this->ellipse),$p=2*$n-2,$q=4*$n-4;$i<$n;$i++) {
  • $x=$this->ellipse[$i]['x'];
  • $y=$this->ellipse[$i]['y'];
  • $alpha=$this->ellipse[$i]['alpha'];
  • $this->ellipse[$p-$i]=array('x'=>-$x,'y'=>$y,'alpha'=>$alpha);
  • $this->ellipse[$p+$i]=array('x'=>-$x,'y'=>-$y,'alpha'=>$alpha);
  • $this->ellipse[$q-$i]=array('x'=>$x,'y'=>-$y,'alpha'=>$alpha);
  • }
  • $this->quarter=(count($this->ellipse)-1)/4;
  • }
  • /* fin de la classe -----------------------------------------------------------------------------------*/
  • }
  • $title='CodeS-SourceS : 33620 sources publiées!';
  • $arr=array(
  • /* donnée couleur légende xploded */
  • array(2072, 0x969696, 'Divers', 0),
  • array(1003, 0xFF9900, 'JAVA/J2EE', 0),
  • array(1038, 0xFFCB03, 'C#', 0),
  • array(1623, 0x99CC00, 'Flash', 0),
  • array(1854, 0x339966, 'IRC', 0),
  • array(1873, 0x33CCCC, 'Javascript/DHTML', 0),
  • array(2208, 0x0091C3, 'PHP', 1),
  • array(2624, 0xAA44AA, 'Delphi', 0),
  • array(4971, 0xFF99CC, 'C/C++', 0),
  • array(14354, 0xFF4C4C, 'Visual Basic', 0)
  • );
  • $mon_caprice_des_dieux=new aacamembert($title,$arr);
  • ?>
<?php
header ('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header ('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header ('Cache-Control: no-cache, must-revalidate');
header ('Pragma: no-cache');

/*
 - Date de création : 27/01/2008
 - Nom : aacamembert.php, version simplifiée à "copier-coller"
 - Auteur : opossum_farceur
 - Object : Camembert, 3D, Antialiasing, Bresenham, Statistiques 
*/
define('coef',M_PI/180);

class aacamembert 
{
   private $img;
   private $a,$b,$cx,$cy,$aa,$bb,$aabb;       /* ellipse */
   private $data,$sort,$ellipse;              /* tableaux */
   private $quarter,$pivot;                   /* autres */
   private $num,$linecolor;                   /* algorithme de Gupta-Sproull */

/* constructeur ---------------------------------------------------------------------------------------*/

function __construct($title,$arr)
{
   $width=500;
   $head=35;                                 /* 15+15+5 : réservés pour le titre */
   $height=300;
   $w=240;                                   /* grand axe horizontal */
   $h=$w/2;                                  /* 120 : petit axe vertical */
   $thickness=$w/4;                          /* 60 : "épaisseur" du camembert */
   $topcolor=0xFFFF00;                       /* dégradé : couleur du haut */
   $bottomcolor=0x00FFFF;                    /* dégradé : couleur du bas */
   $fontsize=3;
   /* attributs calculés */
   $this->a=$w/2;                            /* 1/2 grand axe : 120 */
   $this->b=$h/2;                            /* 1/2 petit axe : 60 */
   $this->cx=$width/2;                       /* abscisse et ordonnée du "centre" du camembert */
   $this->cy=($height+$head-$thickness)/2;
   $this->aa=$this->a*$this->a;
   $this->bb=$this->b*$this->b;
   $this->aabb=$this->aa*$this->bb;
   /* attributs renseignés en cours de route */
   $this->data=array();
   $this->sort=array();
   $this->ellipse=array();
   /* antialiasing ligne droite */
   $this->num=10;                            /* à choisir pair */
   $this->linecolor=array();                 /* taille du tableau : 1+3/2*$this->num, soit 16 (suffisant) */

   /* préliminaires */
   $this->img=imagecreatetruecolor($width,$height);
   $this->mybackground($width-1,$height-1,$topcolor,$bottomcolor);
   $textcolor=imagecolorallocate($this->img,0x00,0x00,0x00);
   imagestring($this->img,5,($width-imagefontwidth(5)*strlen($title))/2,15,$title,$textcolor);
   $this->aaellipse();
   $this->gupta_sproull();
   $specialcase=$this->init($arr,$thickness);

   /* tracés */
   $this->aadraw($thickness,$fontsize,$textcolor,$specialcase);

   /* affichage */
   header('Content-type: image/png');
   imagepng($this->img);
   imagedestroy($this->img);
}

/* "splite" une couleur en ses 3 composantes ----------------------------------------------------------*/

private function hex2rgb($hex)
{
   return array(($hex>>16)& 0xFF,($hex>>8)& 0xFF,$hex & 0xFF);
}

/* mise en place du fond ------------------------------------------------------------------------------*/

private function mybackground($w,$h,$topcolor,$bottomcolor)
{
   list($red,$green,$blue)=$this->hex2rgb($topcolor);
   $bc=$this->hex2rgb($bottomcolor);
   $incr=($bc[0]-$red)/$h;
   $incg=($bc[1]-$green)/$h;
   $incb=($bc[2]-$blue)/$h;

   for($j=0;$j<=$h;$j++,$red+=$incr,$green+=$incg,$blue+=$incb)
      imageline($this->img,0,$j,$w,$j,imagecolorallocate($this->img,$red,$green,$blue));
}

/* à partir de l'angle donné en argument retourne l'index correspondant du tableau de l'ellipse -------*/

private function index($v)
{  /* formulation du sinus à partir du cosinus, en principe + rapide */
   $cosv=cos(coef*$v);
   $sinv= ($v>180)? -sqrt(1-$cosv*$cosv) : sqrt(1-$cosv*$cosv);
   $x=round($this->a*abs($cosv));
   $y=round($this->b*abs($sinv));

   $case=floor($v/90);
   $p=($case+$case%2)*$this->quarter;
   $sign= ($case%2)? -1 : 1;
   $q= ($this->aa*$y-$this->bb*$x<0)? $y : $this->quarter-$x;

   return $p+$sign*$q;
}

/* traitement des données fournies dans le tableau ----------------------------------------------------*/

private function init($arr,$e)
{  /* calcul de la somme des données */
   for ($j=$sum=0,$n=count($arr);$j<$n;$j++) $sum+=$arr[$j][0];
   /* analyse du tableau */
   for ($j=$k=$v1=0;$j<$n;$j++) if ($arr[$j][0]) { /* cas non traité si donnée nulle */
      /* extraction des composantes red, green et blue */
      list($red,$green,$blue)=$this->hex2rgb($arr[$j][1]);
      $this->data[$k]['color']=imagecolorallocate($this->img,$red,$green,$blue);
      /* traitement des angles */
      $v2=$v1+$arr[$j][0]*360/$sum;
      if ($v1<=270 && $v2>=270) $first=$k;
      if ($v1<=90 && $v2>=90) $last=$k;
      $this->data[$k]['v']=$v2;
      /* détermine la couleur ombrée */
      $this->data[$k]['shade']=imagecolorallocate($this->img,max(0,$red-50),max(0,$green-50),max(0,$blue-50));		
      /* préparation du texte */
      $this->data[$k]['legend']=$arr[$j][2];
      $this->data[$k]['value']=number_format(100*$arr[$j][0]/$sum,2,',','').'%';
      $this->data[$k]['xploded']=$arr[$j][3];

      $v1=$v2;
      $k++;
   }

   $m=count($this->data);     /* différent de $n si une ou plusieurs donnée(s) sont nulles */
   if ($first!=$last) {
      for ($j=0,$k=$first;$k!=$last;$j++,$k=($k+1)%$m) $this->sort[$j]=$k;
      $this->pivot=$j;
      for ($k=$first-1;$k>=$last;$j++,$k--) $this->sort[$j]=$k;

      return false;
   }
   else {   /* cas particulier préoccupant : une grosse portion présente à la fois à 12h et à 18h */
      for ($j=0,$k=($first+1)%$m;$j<$m;$j++,$k=($k+1)%$m) $this->sort[$j]=$k;
      $this->pivot=$m-1;
      /* mise en place du 2ème panneau de la dernière portion (origine du code : méthode "aadraw()") */
      $j=$this->sort[$m-1];
      $xploded=$this->data[$j]['xploded'];
      if ($this->data[$this->sort[0]]['xploded'] || $xploded) {
         $shade=$this->data[$j]['shade'];
         $v1= ($j)? $this->data[$j-1]['v'] : 0;
         $v2=$this->data[$j]['v'];
         $vm=($v1+$v2)/2;
         if ($xploded) {
            $ox=round($this->cx+$this->a*cos(coef*$vm)/6);        /* a/6, b/6 : "offsets" des portions */
            $oy=round($this->cy+$this->b*sin(coef*$vm)/6);
         }
         else {
            $ox=$this->cx;
            $oy=$this->cy;
         }
         $index2=$this->index($v2);
         $x2=$ox+$this->ellipse[$index2]['x'];
         $y2=$oy+$this->ellipse[$index2]['y'];

         imageline($this->img,$ox,$oy,$ox,$oy+$e,$shade);
         imageline($this->img,$x2,$y2,$x2,$y2+$e,$shade);
         $this->aaborder($ox,$oy,$x2,$y2,0,$backup2,$shade);      /* ligne du haut */
         $this->aaborder($x2,$y2+$e,$ox,$oy+$e,1,$backup2,$shade);/* ligne du bas (attention à l'ordre!) */

         if ($x2-$ox>1) imagefilltoborder($this->img,round(($ox+$x2)/2),round(($oy+$y2+$e)/2),$shade,$shade);
         $this->aaborder($x2,$y2+$e,$ox,$oy+$e,2,$backup2);       /* aa ligne du bas */
      }
      return true;
   }
}

/* calcul des 16 tons de gris utiles au dessin des lignes droites antialiassées -----------------------*/

private function gupta_sproull()
{  /* cette fonction crée une table allant de 0 à 1.5*$this->num */
   $col=array();
   $numdiv2=$this->num/2;
   /* calcul du volume interceptant chaque colonne, i et j parcourent un quart du cône */
   for ($i=$this->num,$total=0;$i>=0;$i--) {
      for ($j=$this->num,$k=0,$ii=$i*$i;$j>=0;$j--) {
         $d=sqrt($ii+$j*$j);
         if ($d<$this->num) $k+=$this->num-$d;
      }
      $col[$this->num-$i]=2*$k;
      $total+=4*$k;
   }
   /* calcul de la table : 1ere partie correspondant à une intersection d'épaisseur inférieure à 1 */
   $max=$this->num+$numdiv2;
   for ($i=$k=0;$i<=$this->num;$i++) {
      $k+=$col[$i];
      $this->linecolor[$max-$i]=imagecolorexactalpha($this->img,0,0,0,round(127*(1-$k/$total)));
   }
   /* calcul de la table : 2eme partie correspondant à une intersection d'épaisseur supérieure à 1 */
   for ($i=1;$i<=$numdiv2;$i++) {
      $k+=$col[$this->num-$i]-$col[$i];
      $this->linecolor[$numdiv2-$i]=imagecolorexactalpha($this->img,0,0,0,round(127*(1-$k/$total)));
   }
}

/* "allume" le pixel avec une intensité fonction de la distance à la droite ---------------------------*/

private function plot($x,$y,$d)
{
   if ($d<0) $d=-$d;
   if ($d>1.5) return;                 /* rien à allumer si le pixel est trop loin */
   imagesetpixel($this->img,$x,$y,$this->linecolor[round($d*$this->num)]);
}


/* tracé de droite "antialiassée" ---------------------------------------------------------------------*/

private function aaline($x1,$y1,$x2,$y2)
{
   $dx=abs($x2-$x1);
   $dy=abs($y2-$y1);
   $incj= (($x2-$x1)*($y2-$y1)>0)? 1 : -1;
   $K=1/(2*sqrt($dx*$dx+$dy*$dy));

   if ($dx>$dy) {                      /* tendance "horizontale" */
      if ($x2>$x1) {
         $y=$y1;
         $begin=$x1;
         $end=$x2;
      }
      else {
         $y=$y2;
        $begin=$x2;
        $end=$x1;

      }

      $p=2*$dy;
      $delta=$dx;
      $incx=0;
      $incy=$incj;
      $i=&$x;
      $j=&$y;
   }
   else {                              /* tendance "verticale" */
      if ($y2>$y1) {
         $x=$x1;
         $begin=$y1;
         $end=$y2;
      }
      else {
         $x=$x2;
         $begin=$y2;
         $end=$y1;
      }

      $p=2*$dx;
      $delta=$dy;
      $incx=$incj;
      $incy=0;
      $i=&$y;
      $j=&$x;
   }
   /* tronc commun */
   for ($i=$begin,$e=$p-$delta,$q=$e-$delta,$D=0,$R=2*$K*$delta;$i<=$end;$i++) {
      $this->plot($x,$y,$D);
      $this->plot($x+$incx,$y+$incy,$R-$D);
      $this->plot($x-$incx,$y-$incy,$R+$D);
      if ($e>=0) {
         $D=$K*($e-$delta);
         $j+=$incj;
         $e+=$q;
      }
      else {
         $D=$K*($e+$delta);
         $e+=$p;
      }
   }
}

/* traitement de l'aa des "bordures" ------------------------------------------------------------------*/

private function aaborder($x1,$y1,$x2,$y2,$mode,&$backup,$mycolor=0)
{
   $dx=$x2-$x1;
   $dy=$y2-$y1;
   $incj= ($dx*$dy>0)? 1 : -1;
   if ($mode==1) $backup=array();
   elseif ($mode==2) $const=$dx*$y1-$dy*$x1;

   if (abs($dx)>abs($dy)) {            /* tendance "horizontale" */
      if ($dx>0) {
         $y=$y1;
         $begin=$x1;
         $end=$x2;
      }
      else {
         $y=$y2;
         $begin=$x2;
         $end=$x1;
      }

      $p=2*abs($dy);
      $e=$p-abs($dx);
      $q=$e-abs($dx);
      $i=&$x;
      $j=&$y;
   }
   else {                              /* tendance "verticale" */
      if ($dy>0) {
         $x=$x1;
         $begin=$y1;
         $end=$y2;
      }
      else {
         $x=$x2;
         $begin=$y2;
         $end=$y1;
      }


      $p=2*abs($dx);
      $e=$p-abs($dy);
      $q=$e-abs($dy);
      $i=&$y;
      $j=&$x;
   }
   /* tronc commun */
   for ($i=$begin,$t=0;$i<=$end;$i++,$t++) {
      if ($mode==1) $backup[]=imagecolorat($this->img,$x,$y);  /* mode "sauvegarde" */
      elseif ($mode==2) {                                      /* mode "antialiasing" */
         for ($f=$x-0.2,$g1=$y-0.2,$g3=$y+0.2,$alpha=0;$f<=$x+0.2;$f+=0.2) {
            $k=$const+$dy*$f;
            for ($g=$g1;$g<=$g3;$g+=0.2) if ($dx*$g>$k) $alpha++;
         }
         list($red,$green,$blue)=$this->hex2rgb($backup[$t]);
         $mycolor=imagecolorexactalpha($this->img,$red,$green,$blue,11*$alpha+28);
      }

      imagesetpixel($this->img,$x,$y,$mycolor);

      if ($e>=0) {

         $j+=$incj;
         $e+=$q;
      }
      else $e+=$p;
   }
}

/* tracé du camembert ---------------------------------------------------------------------------------*/

private function aadraw($e,$fontsize,$textcolor,$specialcase)
{
   $A=$this->a*21/16;               /* 1/2 grand axe de l'ellipse "englobante" */
   $B=3*$A/4;                       /* bien que dépendant de $e, mais bon... */
   $dy=-$e/2;                       /* "centre" du camembert à celui de l'ellipse "englobante" */
   $AA=$A*$A;
   $BB=$B*$B;
   $ifw=imagefontwidth($fontsize);

   /* "grande boucle" */
   for ($i=0,$m=count($this->data);$i<$m;$i++) {
      $j=$this->sort[$i];

      /* initialisations */
      $color=$this->data[$j]['color'];
      $shade=$this->data[$j]['shade'];
      $v1= ($j)? $this->data[$j-1]['v'] : 0;
      $v2=$this->data[$j]['v'];
      $vm=($v1+$v2)/2;
      $index1=$this->index($v1);
      $index2=$this->index($v2);
      $xploded=$this->data[$j]['xploded'];
      $panel1=$panel2=false;
      $flag=0;

      if ($xploded) {
         $px=$this->a*cos(coef*$vm);
         $py=$this->b*sin(coef*$vm);
         $ox=round($this->cx+$px/6);   /* a/6, b/6 : "offsets" des portions */
         $oy=round($this->cy+$py/6);
      }
      else {
         $px=5*$this->a*cos(coef*$vm)/6;
         $py=5*$this->b*sin(coef*$vm)/6;
         $ox=$this->cx;
         $oy=$this->cy;

         switch ($i) {                 /* cumulations possibles */
            case 0:              $flag=$this->data[$this->sort[$this->pivot]]['xploded'];
            case $this->pivot-1: $flag|=$this->data[$this->sort[$m-1]]['xploded'];
            default:             $flag|=$this->data[$this->sort[$i+1]]['xploded'];
         }
      }

      $x1=$ox+$this->ellipse[$index1]['x'];
      $y1=$oy+$this->ellipse[$index1]['y'];
      $x2=$ox+$this->ellipse[$index2]['x'];
      $y2=$oy+$this->ellipse[$index2]['y'];
      $gx=round($this->cx+$px);        /* sans arrondi, problème raccordement segment en size 1 */
      $gy=round($this->cy+$py);

      /* traitement secteur du bas + paravent vertical */
      if ($v1<180) {
         if ($v2<180) {
            $indexmax=$index2;
            $x=$x2;
            $y=$y2;
         }
         else {                                       /* le traitement s'arrête à 180° */
            $indexmax=2*$this->quarter;               /* aussi : $this->index(180); */
            $x=$ox-$this->a;                          /* aussi : $ox+$this->ellipse[$indexmax]['x']; */
            $y=$oy;                                   /* aussi : $oy+$this->ellipse[$indexmax]['y'] */
         }
         /* dessin des secteurs hauts et bas de l'ellipse */
         for ($k=$index1,$backup0=array();$k<=$indexmax;$k++) {
            $xk=$ox+$this->ellipse[$k]['x'];
            $yk=$oy+$this->ellipse[$k]['y'];
            $backup0[]=imagecolorat($this->img,$xk,$yk+$e);
            imagesetpixel($this->img,$xk,$yk,$shade);
            imagesetpixel($this->img,$xk,$yk+$e,$shade);
         }
         /* lignes verticales */
         imageline($this->img,$x1,$y1,$x1,$y1+$e,$shade);
         imageline($this->img,$x,$y,$x,$y+$e,$shade);
         /* "remplissage" peu optimisé mais valable dans tous les cas de figures */
         if ($x1-$x>1) imagefilltoborder($this->img,$x+1,$y+$e/2,$shade,$shade);
         /* antialiasing secteur ellipse du bas */
         $this->aaarc($index1,$indexmax,$ox,$oy+$e,$backup0);
      }

      if ($xploded || $flag) {   /* dessine les "panneaux" verticaux */
         if ($v1>90 && $v1<270) {
            imageline($this->img,$ox,$oy,$ox,$oy+$e,$shade);
            imageline($this->img,$x1,$y1,$x1,$y1+$e,$shade);         /* parfois inutile, mais bon... */
            $this->aaborder($x1,$y1,$ox,$oy,0,$backup1,$shade);      /* ligne du haut, backup  inutile */
            $this->aaborder($ox,$oy+$e,$x1,$y1+$e,1,$backup1,$shade);/* ligne du bas, backup parfois inutile */

            if ($ox-$x1>1)
               imagefilltoborder($this->img,round(($ox+$x1)/2),round(($oy+$y1+$e)/2),$shade,$shade);
            $this->aaborder($ox,$oy+$e,$x1,$y1+$e,2,$backup1);       /* aa ligne du bas */
            if ($v1<180) imageline($this->img,$x1,$y1,$x1,$y1+$e,$color);        /* séparation verticale */
            $panel1=true;
         }
         if ($v2<90 ||($v2>270 &&!($specialcase && $i==$m-1))) {     /* $specialcase n'apparait qu'ici */
            imageline($this->img,$ox,$oy,$ox,$oy+$e,$shade);
            imageline($this->img,$x2,$y2,$x2,$y2+$e,$shade);
            $this->aaborder($ox,$oy,$x2,$y2,0,$backup2,$shade);      /* ligne du haut, backup inutile */
            $this->aaborder($x2,$y2+$e,$ox,$oy+$e,1,$backup2,$shade);/* ligne du bas */

            if ($x2-$ox>1)
               imagefilltoborder($this->img,round(($ox+$x2)/2),round(($oy+$y2+$e)/2),$shade,$shade);
            $this->aaborder($x2,$y2+$e,$ox,$oy+$e,2,$backup2);       /* aa ligne du bas */
            if ($v2<90) imageline($this->img,$x2,$y2,$x2,$y2+$e,$color);         /* séparation verticale */
            $panel2=true;
         }
         if ($panel1 && $panel2) imageline($this->img,$ox,$oy,$ox,$oy+$e,$color);/* séparation verticale */
      }

      /* dessine le dessus de la portion */
      for ($k=$index1,$backup0=array();$k<=$index2;$k++) {
         $xk=$ox+$this->ellipse[$k]['x'];
         $yk=$oy+$this->ellipse[$k]['y'];
         $backup0[]=imagecolorat($this->img,$xk,$yk);
         imagesetpixel($this->img,$xk,$yk,$color);
      }
      /* tracé des "rayons", sauvegarde parfois inutile, mais bon... */
      $this->aaborder($ox,$oy,$x1,$y1,1,$backup1,$color);            /* centre -> extrémité */
      $this->aaborder($x2,$y2,$ox,$oy,1,$backup2,$color);            /* extrémité -> centre */
      /* "remplissage" du secteur en partant du "germe" */
      imagefilltoborder($this->img,$gx,$gy,$color,$color);
      /* correction du défaut du "secteur trop étroit" (pas toujours nécessaire) */
      imageline($this->img,$ox,$oy,$gx,$gy,$color);
      /* antialiasing secteur ellipse du haut */
      $this->aaarc($index1,$index2,$ox,$oy,$backup0);
      /* antialiasing des "rayons" du secteur elliptique */
      if ($xploded || $flag) {
         $this->aaborder($ox,$oy,$x1,$y1,2,$backup1);                /* centre -> extrémité */
         $this->aaborder($x2,$y2,$ox,$oy,2,$backup2);                /* extrémité -> centre */
      }
      else if ($i) {                                                 /* centre -> extrémité */
         if ($i<$this->pivot) $this->aaborder($ox,$oy,$x1,$y1,2,$backup1);
         else {                                                      /* extrémité -> centre */
            $this->aaborder($x2,$y2,$ox,$oy,2,$backup2);
            if ($i==$m-1) $this->aaborder($ox,$oy,$x1,$y1,2,$backup1);
         }
      }

      /* traitement des légendes */
      $ka=$AA*$py*$py+$BB*$px*$px;
      $kb=$AA*$dy*$px*$py;
      $kc=$AA*$px*$px*($dy*$dy-$BB);

      if ($vm<=90 || $vm>270) {
         $root=(-$kb+sqrt($kb*$kb-$ka*$kc))/$ka;
         $qx=round($this->cx+$root);
         $qy=round($this->cy+$root*$py/$px);

         $this->aaline($gx,$gy,$qx,$qy);
         $this->aaline($qx+1,$qy,$qx+10,$qy);
         imagestring($this->img,$fontsize,$qx+14,$qy-12,$this->data[$j]['legend'],$textcolor);
         imagestring($this->img,$fontsize,$qx+14,$qy-2,$this->data[$j]['value'],$textcolor);
      }
      else {
         $root=(-$kb-sqrt($kb*$kb-$ka*$kc))/$ka;
         $qx=round($this->cx+$root);
         $qy=round($this->cy+$root*$py/$px);

         $this->aaline($gx,$gy,$qx,$qy);
         $this->aaline($qx-1,$qy,$qx-10,$qy);
         $legendposx=$qx-12-$ifw*strlen($this->data[$j]['legend']);
         $valueposx=$qx-12-$ifw*strlen($this->data[$j]['value']);
         imagestring($this->img,$fontsize,$legendposx,$qy-12,$this->data[$j]['legend'],$textcolor);
         imagestring($this->img,$fontsize,$valueposx,$qy-2,$this->data[$j]['value'],$textcolor);
      }
   }
}

/* dessine un arc avec l'aa ---------------------------------------------------------------------------*/

private function aaarc($begin,$end,$dx,$dy,&$backup)
{
   for ($j=$begin,$i=0;$j<=$end;$j++,$i++) {
      list($red,$green,$blue)=$this->hex2rgb($backup[$i]);
      $mix=imagecolorexactalpha($this->img,$red,$green,$blue,$this->ellipse[$j]['alpha']);
      imagesetpixel($this->img,$dx+$this->ellipse[$j]['x'],$dy+$this->ellipse[$j]['y'],$mix);
   }
}

/* calcul de la transparence du point, intégration de l'enregistrement au tableau ---------------------*/

private function add($x,$y)
{  /* 9 échantillons sont suffisants */
   for ($f=$x-0.2,$g1=$y-0.2,$g3=$y+0.2,$alpha=0;$f<=$x+0.2;$f+=0.2) {
      $k=$this->aabb-$this->bb*$f*$f;
      for ($g=$g1;$g<=$g3;$g+=0.2) if ($this->aa*$g*$g<$k) $alpha++;
   }
   return array('x'=>$x,'y'=>$y,'alpha'=>11*$alpha+28);
}

/* calcul d'un quart de l'ellipse, généralisation à l'ellipse entière ---------------------------------*/

private function aaellipse()
{
   $temp=array();
   /* algorithme volontairement non optimisé, pour ne pas le rendre encore plus hermétique ! */
   for ($x=0,$y=$this->b,$e=4*$this->bb+$this->aa*(1-4*$y);$this->bb*$x<$this->aa*$y;$x++) {
      $temp[2][]=$this->add($x,$y);    /* octant n°2 */
      $e+= ($e<0)? $this->bb*(8*$x+12) : $this->bb*(8*$x+12)+8*$this->aa*(1-$y--);
   }

   for ($x=$this->a,$y=0,$e=4*$this->aa+$this->bb*(1-4*$x);$this->aa*$y<$this->bb*$x;$y++) {
      $temp[1][]=$this->add($x,$y);    /* octant n° 1 */
      $e+= ($e<0)? $this->aa*(8*$y+12) : $this->aa*(8*$y+12)+8*$this->bb*(1-$x--);
   }
   /* on remet tout dans l'ordre qui convient */
   $this->ellipse=array_merge($temp[1],array_reverse($temp[2]));
   unset($temp);
   /* généralisation aux 3 autres quadrants */
   for ($i=0,$n=count($this->ellipse),$p=2*$n-2,$q=4*$n-4;$i<$n;$i++) {
      $x=$this->ellipse[$i]['x'];
      $y=$this->ellipse[$i]['y'];
      $alpha=$this->ellipse[$i]['alpha'];
      $this->ellipse[$p-$i]=array('x'=>-$x,'y'=>$y,'alpha'=>$alpha);
      $this->ellipse[$p+$i]=array('x'=>-$x,'y'=>-$y,'alpha'=>$alpha);
      $this->ellipse[$q-$i]=array('x'=>$x,'y'=>-$y,'alpha'=>$alpha);
   }
   $this->quarter=(count($this->ellipse)-1)/4;
}

/* fin de la classe -----------------------------------------------------------------------------------*/

}

$title='CodeS-SourceS : 33620 sources publiées!';

$arr=array(
/*       donnée   couleur     légende              xploded */
   array(2072,    0x969696,   'Divers',            0),
   array(1003,    0xFF9900,   'JAVA/J2EE',         0),
   array(1038,    0xFFCB03,   'C#',                0),
   array(1623,    0x99CC00,   'Flash',             0),
   array(1854,    0x339966,   'IRC',               0),
   array(1873,    0x33CCCC,   'Javascript/DHTML',  0),
   array(2208,    0x0091C3,   'PHP',               1),
   array(2624,    0xAA44AA,   'Delphi',            0),
   array(4971,    0xFF99CC,   'C/C++',             0),
   array(14354,   0xFF4C4C,   'Visual Basic',      0)
);

$mon_caprice_des_dieux=new aacamembert($title,$arr);
?>

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

Historique

02 octobre 2006 00:40:41 :
Correction du bug signalé par CHPITIT01 (seulement dans le zip !) Optimisation du code
15 février 2007 20:44:52 :
correction d'un bug signalé par GUISMO1ER, CHRIS_TOPHE2, EZA, VISTUO, concernant la couleur des très petites portions qui pouvait dans certains cas envahir tout le camembert.
04 mars 2007 02:32:27 :
Ce nouveau code est une généralisation de "aacamembertplus" avec un camembert qui peut désormais interagir avec un fond "quelconque" : le dispositif est constitué d'une classe abstraite "phpmycamembert" dont dérivent les classes "aabasic" (fond uni), "aagradient" (dégradé entre 2 couleurs) et "aaimage" (image de fond). Note1 : le code est en php4 pour une compatibilité maximale. Note2 : j'ai supprimé du zip les documents récupérés sur internet; des liens vers leurs sites d'origine permettent cependant de les retrouver sans problèmes.
26 mars 2007 20:36:55 :
version 3.0 - Le constructeur de la classe de base "phpmycamembert" admet désormais un paramètre supplémentaire, le booléen "$xploded"; il suffira que ce paramètre soit à "true" pour éclater le camembert. - Regroupement de toutes les classes dans un fichier unique "camembert.php". Le dispositif, reposant désormais sur un "switch", est moins conventionnel, mais permet d'éviter la multiplication de fichiers avec 3 lignes de code dedans.
08 avril 2007 00:01:35 :
version 3.1 : correction bug signalé par SKALASKA, concernant les traits de légende des camemberts "condensés".
08 avril 2007 14:19:20 :
La mise à jour précédente n'ayant pas fonctionné (encore les mystères de l'informatique!), je l'exécute une deuxième fois...
02 février 2008 00:18:07 :
version 4.0 - traitement individuel de l'explosion de chaque part - migration vers php5 - adaptation du code à une page appelante en "ajax"
29 septembre 2008 01:35:38 :
version 4.1 : amélioration/consolidation/optimisation du code existant, ajout des dégradés dans les parties verticales courbes du camembert, simplification de l'exploitation "ajax" de la classe.

Commentaires et avis

signaler à un administrateur
Commentaire de wizad le 28/08/2006 13:36:49

Impressionant et en tout cas trés bon travail.

Juste un petit point à éventuellement améliorer/corriger : lors de l'appel de camembert.php sans aucun paramètre, l'image apparaissant et assez bizarre (marque noire sur fond gris). L'amélioration possiblie serait de détecter ce genre de détail et d'afficher une image grise avec un message du type : Paramètres de l'image non fournient.

En tout cas 10/10. Et je vais m'en inspiré pour me faire un librairie de graphique.

signaler à un administrateur
Commentaire de Rudy3212 le 29/08/2006 18:51:05

Whaou trop bien je ve voir sa

10/10

signaler à un administrateur
Commentaire de gagah1 le 31/08/2006 10:13:21

J'ai essayé de tester le script sur EasyPhp mais l'image n'apparait pas. Faut-il une librairie externe?

signaler à un administrateur
Commentaire de Rudy3212 le 31/08/2006 10:27:53

surement la librairie GD,
il faut l'activer dans easyphp

signaler à un administrateur
Commentaire de gagah1 le 31/08/2006 11:11:17

Comment l'activer?

signaler à un administrateur
Commentaire de Rudy3212 le 31/08/2006 11:13:44

Vous allez donc faire ceci :

   1. Vous rendre dans le dossier où Apache (le serveur Web) est installé. Si vous utilisez EasyPHP, rendez-vous dans le dossier où EasyPHP est installé. Vous devriez voir un sous-dossier "apache". C'est là :)
   2. Repérez un fichier appelé "php.ini" et ouvrez-le. C'est là-dedans que se trouvent toutes les options de configuration de PHP. Comme vous pouvez le voir, il y en a beaucoup.
   3. Il n'y a qu'une ligne qui nous intéresse. Elle contient le texte :
      ;extension=php_gd2.dll
      Faites une recherche pour repérer cette ligne, ça ira plus vite.
   4. Enlevez le point-virgule qui se trouve devant cette ligne. Vous devriez voir ceci :

      Image utilisateur


      En fait, le point-virgule sert de commentaire. Tant qu'il y a le commentaire, la ligne n'est pas lue et PHP "oublie" d'utiliser GD. Si vous enlevez le commentaire, alors PHP va "charger" la librairie GD, et vous allez pouvoir travailler avec des images !
   5. Enregistrez le fichier php.ini
   6. Redémarrez EasyPHP.


OUF ! C'est fini ! :D

Vous allez maintenant pouvoir utiliser GD sur votre ordinateur avec EasyPHP.
Normalement, si vous regardez les extensions chargées en cliquant sur le lien "Afficher", vous devriez avoir "gd" dans la liste :

Source : SiteduZero

signaler à un administrateur
Commentaire de gagah1 le 31/08/2006 11:18:35

C'est bon, j'ai trouvé. Merci.

signaler à un administrateur
Commentaire de Rudy3212 le 31/08/2006 11:19:13

Derien :)

signaler à un administrateur
Commentaire de Darigaaz81 le 27/09/2006 15:30:53

Impressionant !!!

signaler à un administrateur
Commentaire de Chpitit01 le 30/09/2006 22:26:42

Superbe travail, le rendu est impecable et le temps de génération de la page est impressionnante ;)
Félicitation!

Ya un léger bug quand même, lorsque l'une des "parts" atteint 50% et je ne sais pas comment résoudre ce bug :(

signaler à un administrateur
Commentaire de opossum_farceur le 02/10/2006 00:49:14

CHPITIT01, voilà ce bug (ô combien malicieux) enfin terrassé :
la ligne de "camembert.php" :
if ($w<90 || $w>270) {
à transformer en :
if ($w<=90 || $w>270) {
et roulez jeunesse !

Si tu trouves cette ligne dans ton fichier et que tu fais la correction, tu n'est pas obligé de recharger le zip.
Malgré tout, ce dernier contient un fichier "camembert.php" dans lequel j'ai incorporé quelques modifs satisfaisantes pour l'esprit, mais n'entraînant pas, à mon grand regret, d'amélioration notable en matière de performances.
Le code y a gagné en concision; quant à l'aspect visuel et la mise en oeuvre, c'est comme avant.

Pour répondre (un peu tardivement, je l'avoue!) à WIZAD :
La cohérence des données, c'est, à mon avis, du ressort de la page appelante.
Il y a en effet trop de choses imprévisibles!
Que tu fournisses un tableau vide, pourquoi pas!, mais on peut aussi fournir un tableau avec n'importe quoi dedans, ou alors des données situées dans des plages entraînant des débordements, des couleurs négatives, etc..., il n'y a pas de limites à ce genre de fantaisies!, et le code, que j'ai voulu utile à 100%, est suffisamment copieux comme çà pour ne pas être encombré de ce type de vérifications.

Amicalement.

signaler à un administrateur
Commentaire de Chpitit01 le 02/10/2006 13:14:21

Merci la modif marche niquelle :)!

Sinon il reste un léger bug. Rien de tel qu'un petit screen

http://www.ltdn.info/bug.jpg

Amicalement,

signaler à un administrateur
Commentaire de opossum_farceur le 02/10/2006 18:56:12

CHPITIT01, ton screen évite en effet un long discours. Il ne s'agit pas à proprement parler d'un bug : quand les données ne sont pas assez importantes (par rapport au total), il y a risque de chevauchement des légendes. J'avoue avoir été confronté à ce problème quand j'ai mis au point mon exemple des codes sources sur CSS; ma solution a été de créer une portion "divers" pour y fourrer les langages pas sufisamment représentés, et de ranger cette portion dans un coin qui m'arrange.
C'est un peu la solution de l'autruche, mais bon, j'avais pas envie à ce moment-là de me prendre la tête avec çà.
D'autres "techniques" sont également possibles, comme alterner les portions grosses et petites, je peux aussi revoir le code pour que la légende et le pourcentage soient sur la même ligne,
c'est pas vraiment un gros travail, mais çà réduira d'autant l'espace affecté à la légende, une solution que je ne veux pas envisager, par contre, c'est la technique "Excel", avec un tableau à côté du camembert, et où finalement le camembert, réduit de moitié, ne sert plus à rien.
Si quelqu'un a des idées, qu'il se manifeste, ce forum est là pour çà.
Un constat, derrière tout çà : le camembert n'est pas adapté pour représenter tous les types de données, et comme souvent ces données (quelque soit le sujet abordé d'ailleurs) se ressemblent, un gros poisson qui accapare la moitié des ressources, avec tout autour une multitude de "petits" qui se partagent les miettes, il peut être judicieux d'envisager des représentations plus traditionnelles comme les histogrammes.
Une autre idée comme çà, en passant : est-il vraiment nécessaire de créer une portion pour chaque version de FireFox?

Amicalement.

signaler à un administrateur
Commentaire de Chpitit01 le 03/10/2006 16:52:27

Bonjour,

Effectivement, je ne suis pas obligé de faire une part pour chaque version de firefox mais je préfére avoir tous les cas de figures possible :D!

En ce qui concerne la résolution de ce "bug", je pense qu'alterner les grosses parts et les petites serai peut être un bon point.
Mais n'y a t'il pas moyen de rallonger les traits pour les légendes par exemple?

Sinon je ferai une légende a coté en stockant la couleur, le navigateur et ainsi juste laisser sur les lignes du camembert le % et le nb d'utilisateur mais bon ca fait plus beau actuellement(surtout que le rendu est génial :D)

Merci en tout cas d'avoir soins de d'améliorer ta source, ce qui n'est pas donné a tout le monde ;)

Amicalement,

signaler à un administrateur
Commentaire de opossum_farceur le 03/10/2006 20:40:35

salut CHPITIT01,

1 : "je pense qu'alterner les grosses parts et les petites serai peut être un bon point."
Cà, c'est à toi de le gérer dans la page appelante, ainsi que trier les données dans un ordre qui te conviennes; le faire dans la classe "aacamembertplus" (dont le rôle est d'assurer le service "minimum") risque fort de ne pas plaire à d'autre utilisateurs.

2 : "n'y a t'il pas moyen de rallonger les traits pour les légendes"
Cà, c'est à "aacamembertplus" de le gérer, mais rallonger les traits (sans augmenter la taille de l'image container, et en réduisant éventuellement la taille de la police) ne permettra pas d'éviter le chevauchement des données telles qu'elles se présentent dans ton screen.

3 : "Sinon je ferai une légende a coté en stockant la couleur, le navigateur..."
Cà, c'est la solution "Excel" (dèjà évoquée plus haut), et là, tu touches où çà fait mal, mon idée d'origine était justement de faire quelque chose qui ne ressemble pas à çà. Donc si tu te sens capable de le faire, ok vas-y mais sans moi.

4 : tu n'as pas évoqué la solution qui est de mettre la légende et le pourcentage sur la même ligne, qui réduit la longueur allouée à la légende, mais permet d'éviter les chevauchements.
Rien de tel qu'un petit screen :
http://michel.vanthodiep.free.fr/camembert/test1.png
A noter que l'image n'a pas été élargie.

5 : "Merci en tout cas d'avoir soins de d'améliorer ta source"
Ma modeste expérience de développeur m'a fait comprendre une chose : les meilleurs logiciels sont ceux qui sont le fruit d'une collaboration étroite entre développeur(s) et utilisateur(s), et où, à la limite, l'utilisateur(s), de part sa capacité à poser des questions pertinentes et à exprimer des besoins concrets, a autant de mérite que le développeur(s).
Autant te dire, CHPITIT01, qu'avec tes problèmes de légendes qui se chevauchent, tu tombes à pic pour jouer le rôle de Candide!

Amicalement.

signaler à un administrateur
Commentaire de Chpitit01 le 03/10/2006 21:17:00

Excuse moi mais je n'avais pas bien compris ce que tu entandais par solution "excel" :(.

Bon sinon je crois que je vais faire un mixe de 2 solutions:
-Mettre le % sur la même ligne(avec ton screen c'est deja plus clair)
-Alterner les grosses parties et les petites

En tout cas merci beaucoup encre une fois pour cette formidable source :)!

signaler à un administrateur
Commentaire de guismo1er le 04/10/2006 17:16:42

Salut, ta source est excellente (javais l'ancienne version), mais j'ai une question comment faire au lieu d emettre array(12,couleur, ledende) avec une requete sql?

j'ai trouvé: en faisant ca:

$arr = array();
while($data=mysql_fetch_assoc($sql2))
{
    $arr[] = array($data['ville'], 0x969696,$data['loc']);
}

mais comment mettre une couleur différente pour chaque proportions, car là tout se met en une couleur, et le rendu est laid, car meme le fond est de la meme couleur :(

Merci de votre aide :)

guismo1er

signaler à un administrateur
Commentaire de opossum_farceur le 04/10/2006 18:31:01

CHPITIT01,
Ton intention est maintenant de te débrouiller tout seul : bravo et bonnes stats !

GUISMO1ER,
Le problème que tu évoques a déjà été traité :
http://www.phpcs.com/codes/CAMEMBERTS-3D_34131.aspx
Commentaire de : opossum_farceur le 11/02/2006 14:46:59

En résumé : tu te débrouilles pour mettre les couleurs dans un tableau à part.
Après, que le fond prenne la couleur du camembert, c'est une autre histoire : là, tu postes tes données, pour que je puisse reproduire le phénomène et (éventuellement) le débugger.

Amicalement.

signaler à un administrateur
Commentaire de Eza le 24/10/2006 23:17:33

Problème :'(

Call to undefined function: imagettfbbox

Dommage la version pixelisé marche et celle ci me prose problème sur mon serveur, n'y a t'il pas une solution pour contourner ce problème sans devoir installer FreeType ?

Merci d'avance,
Sinon excellent script!!!

signaler à un administrateur
Commentaire de opossum_farceur le 25/10/2006 02:16:21

EZA,

La version "pixellisée" marche parce qu'elle n'utilise pas le support FreeType. C'est le cas également de la source présente au début de cette page; moyennant quelques adaptations mineures, en prenant modèle sur la version du zip, elle peut très bien faire l'affaire!
Une question malgré tout me taraude : mais pourquoi donc désactiver le support FreeType?
Amicalement.

signaler à un administrateur
Commentaire de Eza le 25/10/2006 12:20:41

Merci pour ta réponse...
Le support FreeType n'est pas désactivé,
mais n'a pas été installer sur le serveur sur le quel je suis...

Donc le souci que j'ai je l'ai tester sur mon pc avec wamp serveur et il marche super bien, mais lorsque je l'ai uploader sur mon serveur j'ai l'erreur

Fatal error: Call to undefined function: imagettfbbox() in /home/ ... /camembert.php on line 92

Alors que l'autre script avec les "pixels" marche parfaitement...
étant nouveau dans les scripts php, je ne vois pas encore comment je peux m'y prendre pour remédier à ce problème,

Merci d'avance,
Ludovic

signaler à un administrateur
Commentaire de opossum_farceur le 25/10/2006 18:56:34

EZA, concrètement, voilà ce qu'il est possible de faire (je l'ai testé) :

1. dans "camembert.php", remplacer la classe "aacamembertplus" par la classe "aacamembert" présente au début de cette page (attention à l'accolade de fermeture de la classe!)

2. dans "camembert.php", remplacer :
$mon_caprice_des_dieux=new aacamembertplus($_GET['title'],str2arr($_GET['arr']),$_GET['size']);
par
$mon_caprice_des_dieux=new aacamembert($_GET['title'],str2arr($_GET['arr']));

3. dans "index.php", remplacer :
echo '<img src="camembert.php?title=',$title,'&arr=',arr2str($arr),'&size=',$size,'">';
par
echo '<img src="camembert.php?title=',$title,'&arr=',arr2str($arr),'">';

4. roulez jeunesse!

signaler à un administrateur
Commentaire de Eza le 25/10/2006 20:37:51

Je te remercie infiniment ...
C'est vraiment la classe, et un excellent script.

Merci beaucoup,
Ludovic

signaler à un administrateur
Commentaire de dadais le 01/11/2006 15:26:34

woaw !!!
absolument magnifique !

11/10 ^^

signaler à un administrateur
Commentaire de chris_tophe2 le 19/11/2006 18:21:01

Bon, au depart c'est pas mal cependant, il y a des gros bugs qui arrivent apres : Par Exemple : http://crazycms.info/index.php?mods=stats&navig.

signaler à un administrateur
Commentaire de opossum_farceur le 20/11/2006 20:10:37

CHRIS_TOPHE2
Le "bug" est dû à la trop grande disproportion entre la valeur la plus petite (1) et la valeur la plus grande (exprimée, il me semble, en hexa sur 15 octets !).
Un rapport de 2/100 entre ces 2 extrêmes semble être le minimum tolérable, puisque se manifeste à ce moment-là le problème du chevauchement des légendes évoqué plus haut avec CHPITIT01. Si l'on descend plus bas, vers quelque chose comme 0.5/100, un autre phénomène se produit, il n'est plus possible d'exprimer graphiquement un secteur, et sa couleur peut envahir alors toute
l'image.
Dans le code, un contrôle sommaire permet d'éluder les données strictement égales à 0, on peut "affiner" le filtrage pour que le camembert ne soit généré qu'à partir d'une certaine valeur
(paramétrable?) du rapport évoqué plus haut, sans quoi s'afficherait à la place un message, il n'empêche, le premier soucis, il est au niveau de la page appelante, c'est de fournir des données pas trop farfelues!
Amicalement.

signaler à un administrateur
Commentaire de opossum_farceur le 23/11/2006 00:16:28

Petite correction du texte précédent : remplacer "valeur la plus grande" par "somme de toutes les valeurs". Désolé pour la confusion éventuellement engendrée.

signaler à un administrateur
Commentaire de tazmania37 le 05/12/2006 16:27:04

J'ai mis 10 !
Excellent, je vais m'en servir pour mon site.
Vraiment du très bon boulot. Et le côté esthétique est impec aussi !
Vivement la prochaine source, bonne continuation !

signaler à un administrateur
Commentaire de misscam le 21/01/2007 00:25:10

Impeccable, c'est exactement ce que je cherchais ! Merci infiniment pour ce code de qualité :)

signaler à un administrateur
Commentaire de vistuo le 10/02/2007 18:32:43

Excellent code ! je l'utiliserais avec bien dans mes statistiques !
Juste une petite question , est-il possible de faire des parts éclaté !
Si oui comment faire ?

10/10

signaler à un administrateur
Commentaire de opossum_farceur le 11/02/2007 20:40:24

Par "éclaté", tu penses j'imagine à quelque chose qui ressemblerait à :
http://michel.vanthodiep.free.fr/camembert/Excel.gif
?

signaler à un administrateur
Commentaire de Eza le 12/02/2007 08:57:27

Bonjour,

Le script est simplement superbe, cependant j'ai un petit bug. Comme une image vaut mieux qu'un long discours... http://img385.imageshack.us/my.php?image=bugvo9.jpg . Si vous avez une idée d'ou vient le problème.

J'ai utiliser la solution de  opossum_farceur le 25/10/2006 18:56:34.

Car le support free type n'est pas activer sur mon serveur.

Je vous remercie d'avance,
Ludovic

signaler à un administrateur
Commentaire de vistuo le 12/02/2007 17:36:26

oui exactement !
Est-il possible de séparer de x pixel (comme $size) !!
Sa serait super simpa de me le dire !!!

signaler à un administrateur
Commentaire de opossum_farceur le 13/02/2007 02:13:03

Salut EZA,
Le bug que tu signales a déjà été évoqué :
Commentaire de : opossum_farceur le 20/11/2006 20:10:37
Ton image a été envahie par le jaune, qui est la couleur d'une portion représentant un pourcentage proche de zéro, sans pour autant être nul.
Le script ne traite pas les cas où le pourcentage est strictement égal à zéro, mais il est encore trop permissif : il devrait également rejeter tout ce qui est en dessous d'un seuil, que j'ai évalué un peu au pif à 0.5%, mais que je devrais quantifier avec plus de précision s'il s'avère nécessaire de faire une mise à jour.
Si une portion correspond à ce cas de figure, on peut envisager 2 scénarios :
1. Le script avorte en générant éventuellement un message.
2. Le script s'accomode de la situation et n'affiche pas la portion, au risque de fausser légèrement les pourcentages restants.
Je penche évidemment pour la deuxième solution, mais on peut en discuter...

Salut VISTUO,
Désolé, mais le code tel qu'il est n'est pas prévu pour ce type de représentation.
Faire un camembert "éclaté" et "antialiassé" représente d'ailleurs un véritable challenge et nécessite la réécriture de tout le code. Un compromis acceptable (pour se faire la main)pourrait consister déjà à "éclater" la version "pixellisée" du script (la source N°34131); çà représente déjà un gros effort, pour s'en faire une idée, on peut déjà aller voir le code source de JPGraph (travail assez impressionnant dû à Johan Persson) que l'on peut trouver, il me semble, sur ce site.

Amicalement.

signaler à un administrateur
Commentaire de vistuo le 13/02/2007 14:47:09

Merci c'est pas grave ! Pour info, en dessous de 1,56% (exactement) !, l'image prend la couleur de la part trop petite ! (je pense que cela change en fonction de la taille, c'est pour cela que j'ai l'ai cherché avec $size=1)

Voila

signaler à un administrateur
Commentaire de Eza le 13/02/2007 20:46:15

Je ne suis pas super douer pour ce script ...

$arr=array(
# donnée couleur légende
array($espace_libre, 0x0E6100, 'Libre'),
array($espace_script, 0xFC6500, 'Script'),
array($espace_page, 0xFFCB00, 'Pages'),
array($espace_image, 0x01547E, 'Images'),
array($espace_media, 0xFF0018, 'Medias'),
);

au début je me suis dit j'ai que mettre une condition genre

if($pourcent_libre >= 1,56)
{
array($espace_libre, 0x0E6100, 'Libre'),
}

Mais j'ai une erreur qui me dit que la syntaxe n'est pas correct.

Si vous pouviez m'aider je vous en serai très reconnaissant.
Eza

signaler à un administrateur
Commentaire de opossum_farceur le 14/02/2007 00:26:47

Merci VISTUO pour l'info

EZA,
peut-être que la syntaxe
if($pourcent_libre >= 1.56)
serait plus appropriée, mais franchement, avec ce test, je vois pas vraiment où tu vas...

Ce week-end, j'aurai plus de temps et je ferai une mise à jour.

Amicalement.


signaler à un administrateur
Commentaire de opossum_farceur le 15/02/2007 20:52:55

1. Finalement, la correction a été plus rapide que je croyais, j'ai réussi à traiter le problème à la racine, évitant par là les tests évoqués le 13/02. On peut exprimer désormais des portions de 0.1% (et même moins!), le seul problème est que celles-ci n'ont plus graphiquement grand intérêt étant donné qu'on ne les voit plus...

2. Pour ceux que çà peut intéresser, il n'y a qu'une ligne à modifier :

imagefilltoborder($this->img,round(($x1+$x2)/2),round(($y1+$y2+$this->d)/2),$shade,$shade);

à changer en :

if ($x1-$x2>1)
imagefilltoborder($this->img,round(($x1+$x2)/2),round(($y1+$y2+$this->d)/2),$shade,$shade);

3. Je remercie tous les participants de ce forum, qui, de part leurs retours éclairés, ont contribué à améliorer cette source.

Amicalement.

signaler à un administrateur
Commentaire de Eza le 16/02/2007 08:28:29

Salut,

Je n'ai pas pu répondre plus tôt je n'avais plus internet...
Merci infiniment pour cette correction :)
Je l'ai tester mais j'ai toujours le même bug :(

Merci d'avance,
Eza

signaler à un administrateur
Commentaire de opossum_farceur le 17/02/2007 22:05:33

EZA,
Désolé pour le temps de réponse, mais j'ai un gros soucis avec Internet...
Ton problème (dû à une portion représentant un pourcentage trop faible) montre qu'en plus de la modif du 15/02, il faut aussi en passer par le filtrage évoqué le 13/02, et que je voulais éviter.

Remplace donc la ligne suivante :
for ($j=$k=$v=0,$again=true;$j<$n;$j++) if ($arr[$j][0]) {
par celle-ci :
for ($j=$k=$v=0,$again=true;$j<$n;$j++) if ($arr[$j][0]/$sum>=0.002) {

où 0.002 (autrement dit 0.2%) est le seuil en dessous duquel une donnée ne sera pas traitée, une conséquence en sera que la somme des pourcentages restants ne sera pas strictement égale à 100% (dans le pire des cas on aura 99.81%), ce qui n'est pas d'une très grande rigueur, mais bon...

Amicalement.

signaler à un administrateur
Commentaire de Zebuel le 27/02/2007 10:43:45

Je poste ce commentaire juste pour dire merci.
J'avais un camembert qui fonctionnait mais qui était beaucoup plus basique.
Celui-ci est merveilleux.

signaler à un administrateur
Commentaire de Eza le 27/02/2007 13:21:04

Ca marche parfaitement...
merci opossum_farceur
le script est excellent...

signaler à un administrateur
Commentaire de Zebuel le 27/02/2007 16:31:35

Re Bonjour,

j'ai une petite requête.
J'ai essayé de trifouiller un peu dans le code mais pour l'instant je galère pour comprendre.
Comment faire pour afficher les valeurs que l'on a passé à côté ou à la place des pourcentages??

Merci

signaler à un administrateur
Commentaire de opossum_farceur le 28/02/2007 02:30:44

ZEBUEL,

Pour afficher tes valeurs à la place des pourcentages,tu remplaces la ligne :
$this->data[$k++]['value']=number_format(100*$arr[$j][0]/$sum,2,',','').'%';

par celle-ci :
$this->data[$k++]['value']=$arr[$j][0];

Tu peux aussi faire comme CHPITIT01, indiquer ta valeur après le pourcentage, à l'intérieur de parenthèses; dans ce cas tu remplaces la ligne (toujours la même!) :
$this->data[$k++]['value']=number_format(100*$arr[$j][0]/$sum,2,',','').'%';

par celle-ci :
$this->data[$k++]['value']=number_format(100*$arr[$j][0]/$sum,2,',','').'% ('.$arr[$j][0].')';

Amicalement.

signaler à un administrateur
Commentaire de Zebuel le 28/02/2007 09:06:30

Bonjour opossum_farceur,

je te dis un deuxième merci pour ta réponse,
c'est pile poil ce que je voulais.

Dés que j'aurai un peu de temps, je vais me plonger dans ton code pour le comprendre et ne pas faire un simple copier coller

Merci

signaler à un administrateur
Commentaire de supPsycho le 04/03/2007 23:09:48

Bonjour à tous,

Tout dabort, je tiens à dire qu'il y a du très jolie code la dessous et j'ai donc décidé de l'utiliser un poil mais j'ai une erreur qui me vient

Fatal error: Call to undefined function imagecreatetruecolor()on line 49  sachant que j'ai activé l'extension demandée

Est ce que quelqu'un serais d'ou provient ce problème ??

signaler à un administrateur
Commentaire de opossum_farceur le 05/03/2007 10:57:35

Peut-être faudrait-il redémarrer...
Aux amateurs, je signale une nouvelle mise à jour du 04/03 (voir l'historique).

signaler à un administrateur
Commentaire de supPsycho le 05/03/2007 11:26:44

Même après redémarrage, j'ai toujours le même problème

Je suis sous Windows et j'utilise WAMP5, est-ce que cela peut provoquer des problèmes ??

signaler à un administrateur
Commentaire de opossum_farceur le 06/03/2007 00:26:15

As-tu vérifié dans php.ini si la ligne concernant l'extension gd2 n'est plus en commentaires?

signaler à un administrateur
Commentaire de opossum_farceur le 26/03/2007 20:48:22

En réponse à VISTUO, voici une nouvelle version, qui permet de générer des camemberts "éclatés".
Le constructeur de la classe de base "phpmycamembert" admet désormais un paramètre supplémentaire, le booléen "$xploded"; il suffira que ce paramètre soit à "true" pour "éclater" le camembert.

signaler à un administrateur
Commentaire de vistuo le 02/04/2007 18:11:33

Merci opossum_farceur, ta source est superbe !

signaler à un administrateur
Commentaire de skalaska le 04/04/2007 10:30:12

D'abord bravo pour la source, vraiment très bien, très efficace.

Sinon deux petits soucis, il y a moyen d'y remédier ?

http://img257.imageshack.us/img257/5651/testjs4.jpg

signaler à un administrateur
Commentaire de opossum_farceur le 04/04/2007 20:17:37

VISTUO,
Comment, pas le moindre petit bug à signaler?
Plus sérieusement : merci de m'avoir donné l'envie de faire évoluer cette source!

SKALASKA,
1. La légende, qui est tronquée :
Une première solution consiste à modifier l'ordre des portions; on doit pouvoir trouver, il me semble, une combinaison permettant à toutes les légendes de s'afficher correctement.
Une deuxième solution, expérimentée par EZA, consiste à afficher les légendes en dehors de l'image.
Une troisième solution, que je viens d'expérimenter, consiste à utiliser une taille de police inférieure, en intervenant sur le code :

# tracés
if ($xploded) $this->aaxploded($thickness,$font,$size+6,$specialcase);
else $this->aaclassic($thickness,$font,$size+6);

à remplacer par :

# tracés
if ($xploded) $this->aaxploded($thickness,$font,$size+5,$specialcase);
else $this->aaclassic($thickness,$font,$size+5);

2. Le trait de légende incomplet :
Il a été partiellement occulté par la portion suivante; ce bug, que l'on constate également dans ma démo et que j'avais même pas remarqué, ne pouvait pas se produire avec les versions précédentes du script, mais j'ai voulu faire le malin et condenser le code. Me voilà donc condamné à revenir en arrière : prochaîne mise à jour ce week-end.

signaler à un administrateur
Commentaire de skalaska le 05/04/2007 14:09:09

Merci pour la réponse,

En changeant la taille de la police avec la solution 3 ça ne passe pas non plus ;-( donc je pose une question : ne serait-ce pas possible de mettre la légende sur deux lignes si elle est trop longue ?

Pour ce qui est du trai incomplet, j'ai refais l'expérience et il semblerait à priori que cela ne se produise pas en mode éclaté.

condensé : http://img292.imageshack.us/img292/1351/condenssa6.jpg
éclaté   : http://img329.imageshack.us/img329/4245/clatks1.jpg

signaler à un administrateur
Commentaire de skalaska le 05/04/2007 14:13:41

Une question de plus : Est-ce normal, que l'espacement paraisse plus gros entre de gros secteurs du graphe qu' entre de petits. Est-ce inévitable ?

MErci d'avance.

signaler à un administrateur
Commentaire de opossum_farceur le 05/04/2007 21:04:00

SKALASKA,

1. La taille de la police : Tu peux essayer une taille encore inférieure, en mettant en argument
$size+4
au lieu de
$size+5

2. La légende sur 2 lignes, tout se passe ici :
# préparation du texte
$this->data[$k]['legend']=$arr[$j][2];
$this->data[$k]['value']=number_format(100*$arr[$j][0]/$sum,2,',','').'%';
La ligne 'legend' s'occupe du texte, la ligne 'value' s'occupe du pourcentage : tu peux adapter le code à ta convenance. Tu remarqueras que je ne me propose pas de le faire : comprends-moi, mon objectif est de maintenir un code "générique", et ce qui est bon pour toi ne l'est pas forcément pour tout le monde.

3. As-tu exploré les solutions 1 et 2 évoquées plus haut?

4. Le trait incomplet : le camembert "éclaté" est dessiné dans une autre fonction et les différentes portions traitées dans un ordre particulier : d'abord la portion présente à "12h", pour terminer par celle présente à "18h". Pour le camembert "condensé", mise à jour ce WE.

5. L'espacement entre les portions : on doit pouvoir obtenir, au prix évidemment de calculs supplémentaires, un espacement constant (et arbitraire) tout en concervant des bords parallèles.
Je me suis bien évidemment posé la question, et puis j'ai choisi la facilité après avoir observé ce que l'on obtenait avec "excel" et "jpgraph". La technique est simple : toutes les portions, grosses et petites sont décalées de la même manière, et leurs "pointes", après translation, se retrouvent sur une petite ellipse égale, dans le script, à un sixième de l'ellipse de base.
Ce problème est intéressant et mérite que l'on s'y attarde (bien que le résultat ne soit pas garanti) : je vais voir...

Amicalement.

signaler à un administrateur
Commentaire de opossum_farceur le 08/04/2007 00:24:36

version 3.1 : correction bug signalé par SKALASKA, concernant les traits de légende des camemberts "condensés".

SKALASKA,

Je me suis penché sur le problème des espacements; j'ai trouvé une méthode qui marche, assez coûteuse en temps de calculs, qui permet de les avoir tous identiques. Le hic, c'est que dans certains cas particuliers le camembert devient tellement "éclaté" qu'il finit par ne plus ressembler à grand chose. D'autre part, mon instinct me dit que cette technique, qui fait appel à la fonction
"tangente" (qui n'est pas une fonction continue), va créer plus de problèmes qu'elle n'en résoud. Donc désolé, je laisse tomber.

Amicalement.

signaler à un administrateur
Commentaire de skalaska le 10/04/2007 08:19:36

Bon très bien, merci pour la correction, c'est impecable. Et pour ce qui est de l'écart c'est génant de toute façon. Merci pour cette superbe source.

signaler à un administrateur
Commentaire de skalaska le 10/04/2007 08:21:51

OUPS pardon, je voulais dire : "c'est PAS génant de toute façon."

signaler à un administrateur
Commentaire de Typhon91 le 02/06/2007 08:59:20

Bonjour,

Mon problème est tout bête mais je m'y perd dans 700 lignes de codes, tout ce que je souhaite faire c'est changer la couleur des lignes de légendes et l'écriture en blanc, comment m'y prendre ?

Merci

signaler à un administrateur
Commentaire de opossum_farceur le 02/06/2007 19:20:21

TYPHON91,

Pour écrire le texte en blanc, remplacer la ligne :
$this->textcolor=imagecolorallocate(
$this->img,0x00,0x00,0x00); # noir
par la ligne suivante :
$this->textcolor=imagecolorallocate(
$this->img,0xFF,0xFF,0xFF); # blanc

Pour tracer les traits en blanc, remplacer les lignes :
$this->linecolor[$max-$i]=imagecolorexactalpha(
$this->img,0,0,0,round(127*(1-$k/$total)));
et
$this->linecolor[$numdiv2-$i]=imagecolorexactalpha(
$this->img,0,0,0,round(127*(1-$k/$total)));
par les lignes suivantes :
$this->linecolor[$max-$i]=imagecolorexactalpha(
$this->img,0xFF,0xFF,0xFF,round(127*(1-$k/$total)));
et
$this->linecolor[$numdiv2-$i]=imagecolorexactalpha(
$this->img,0xFF,0xFF,0xFF,round(127*(1-$k/$total)));

Lors de la prochaîne mise à jour (à l'occasion du signalement du prochain bug!), je ferais en sorte que l'on
puisse déterminer la couleur du texte et des traits en un point unique du code.

Amicalement.

signaler à un administrateur
Commentaire de Typhon91 le 02/06/2007 21:33:03

Merci beaucoup sa m'a grandement aidé. Mille merci pour ce script qui est tout sumplement fabuleux franchement bravo !

Bonne chance et bonne continuation

signaler à un administrateur
Commentaire de ptitfuret57 le 23/08/2007 13:22:20

Bravo très beau développement... Cependant en poussant un peu j'ai pu m'apercevoir que certaine erreur résidaient encore...

En effet en taille 1 pour afficher les valeurs de 0,10 à 0,20% la couleur du petit pourcentage prend l'ensemble du font ...

De plus j'ai un Warning apache et qui me le fait planter d'ailleurs :
PHP Warning:  imagettftext(): Problem loading glyph in ...on line 477
imagettftext(): Could not set character size in  ... on line 479

Voilà je vais chercher mais si quelqu'un dispose d'informations ...

Voilà a + et encore un grand bravo à toi ///

signaler à un administrateur
Commentaire de opossum_farceur le 24/08/2007 20:31:56

@ptitfuret57,

1. "la couleur du petit pourcentage prend l'ensemble du font" :
Il s'agit-là apparemment du point faible du script, détaillé déjà à plusieurs reprises, et qui se
manifeste quand un pourcentage est trop faible.
Tu peux remplacer la ligne :
for ($j=$k=$v1=0;$j<$n;$j++) if ($arr[$j][0]) {
par la ligne suivante :
for ($j=$k=$v1=0;$j<$n;$j++) if ($arr[$j][0]/$sum>=0.002) {

2. "PHP Warning:  imagettftext(): " :
Le problème a également été évoqué, il y a de fortes chances que le support FreeType ne soit pas
installé sur ton serveur. La solution consiste là à se débrouiller avec le script présent en haut de cette page, dans la zone "Source"; ce script, plus simple que celui du zip, n'utilise pas le support FreeType.

signaler à un administrateur
Commentaire de cutmaster le 03/12/2007 12:49:24 10/10

Bonjour.
Ce code est vraiment très intéressant mais j'aurai 2 petites questions en fait :

1) serait-il envisageable de modifier la structure du tableau de données pour qu'il puisse recevoir l'information d'explosion de part ? Du coup on pourrait avoir un camembert avec une ou deux parts seulement explosées, les autres seraient collées ; et pas seulement tout le monde collé ou tout le monde éclaté.

2) (un peu hors sujet) : envisages tu de faire un camembert façon Xiti ?
http://pix.nofrag.com/c/a/f/931042e1fca806e4fe76f9722e300tt.jpg

En tout cas chapeau pour ton boulot...

signaler à un administrateur
Commentaire de opossum_farceur le 03/12/2007 20:47:40

@cutmaster,

1) serait-il envisageable de modifier la structure du tableau de données pour qu'il puisse recevoir l'information d'explosion de part ?
Oui, c'est possible évidemment, mais delà à dire que c'est facile à faire, c'est une autre histoire! En effet, les deux types de camemberts sont dessinés par deux fonctions différentes "aaxploded" et "aaclassic", dont les algorithmes sont sensiblement différents, en particulier
l'ordre dans lequel sont dessinées les portions; cette spécialisation permet en outre d'optimiser le code des camemberts "non-éclatés" en terme de temps d'exécution.
Ton idée vient en fait chambouler un peu toute cette organisation, il faut réécrire une partie du code (environ 1/3) et faire un "mix" des deux fonctions évoquées plus haut. Cà m'intéresse de le faire et je devrai pouvoir m'occuper de çà en début d'année prochaine.

2) envisages tu de faire un camembert façon Xiti ?
Non, pas vraiment; pour tout dire, ce qui m'intéresse dans les camemberts c'est l'aspect 3D, lequel n'apparait pas dans ton exemple.

A++

signaler à un administrateur
Commentaire de opossum_farceur le 02/02/2008 00:22:56

Salut,

- Voilà, avec cette version 4.0, la mise à jour intégrant l'information d'explosion de chaque part, comme suggéré par CUTMASTER.
- Le tableau des données admet donc un champ supplémentaire, le champ "xploded" : à 1, la part est "explosée", à 0 elle ne l'est pas.
- Le code php a "migré" vers php5, mais bon, çà n'est pas de la POO de haute volée, aussi il ne sera pas difficile s'il le faut de revenir à php4.
- Comme celà avait été évoqué avec TYPHON91, la couleur du texte et des traits de légende est configurable en un seul point du code :
$rgb=$this->hex2rgb(0x000000); # noir : couleur du texte et des lignes
A noter que cette couleur n'est pas passée en argument à la classe, la plupart des utilisateurs semblant se satisfaire de la couleur par défaut (noir).
- La classe admet cependant un nouvel argument : $ajax, qui permet d'adapter la sortie selon que la page appelante est en "ajax" ou en php.
- Pour bien illustrer le propos, j'ai fais 2 démos : une en "ajax" (index.html, testé avec FF2 et IE6), et une en php (index.php).
- La version "ajax" est en ligne à l'adresse :
http://michel.vanthodiep.free.fr/smooth3dcamembert/

A++

signaler à un administrateur
Commentaire de cutmaster le 02/02/2008 15:50:24

Enorme cette version 4...
Faut que je l'essaye dès lundi matin mais rien que la démo en Ajax me plait beaucoup.
Chapeau bas, c'est vraiment de l'excellent boulot.

signaler à un administrateur
Commentaire de opossum_farceur le 03/02/2008 18:04:42

Ravi que celà te plaise.
Il est vrai que cette démo ajax est plutôt rigolote, mais à l'origine elle n'était pour moi rien d'autre qu'un outil de contrôle pour anticiper les cas particuliers. L'ayant développée en local, je suis cependant un peu déçu par son comportement en ligne quand on n'a pas la chance d'avoir une liaison adsl au top.

A++

signaler à un administrateur
Commentaire de opossum_farceur le 12/03/2008 18:37:14

Hello!

Pour les amateurs de camemberts, une nouvelle source en SVG :
http://www.javascriptfr.com/codes/SVG3DCAMEMBERT_46033.aspx

A++

signaler à un administrateur
Commentaire de rlftova le 16/03/2008 02:53:12

Bonjour,
est-il possible de remplacer les couleurs 0xCC0000 par des variables de type $couleur dans les tableaux $arr ?
merci

signaler à un administrateur
Commentaire de opossum_farceur le 16/03/2008 19:55:48

@rlftova,

Que faut-il comprendre par "type $couleur"?

A++

signaler à un administrateur
Commentaire de rlftova le 16/03/2008 23:21:29

bonjour OPOSSUM_FARCEUR.
il faut entendre une variable php :
par exemple je stocke une couleur dans une base de données sous forme #xxxxxx. J'appelle par exemple ma variable $couleur.
j'ai essayé de définir une variable $couleurcamembert :
$couleurcamembert = "0x".substr($couleur, 1);
que j'insère dans le array, mais ça ne fonctionne pas.
merci de ta réponse.

signaler à un administrateur
Commentaire de opossum_farceur le 17/03/2008 16:35:38

@rlftova,

Ta couleur est stockée sous la forme de chaîne de caractère. Ton problème revient à convertir cette chaîne en une valeur numérique. Le PHP n'étant pas "typé", on a vite fait de faire la confusion entre des données de natures différentes (ici chaînes et nombres).

<?php
$couleur='#123456';
$couleurcamembert=hexdec(substr($couleur,1)); /* à insérer dans le tableau */

echo '<pre>';
echo 'chaîne de caractère : ',$couleur,'<br/>';
echo 'numérique, décimal  : ',$couleurcamembert,'<br/>';
echo 'numérique, hexa     : ',sprintf('0x%06X',$couleurcamembert);
echo '</pre>';
?>

A noter que pour afficher du numérique en hexa, on est obligé d'utiliser une fonction comme "sprintf()" qui ne trouve rien de mieux à faire que de reconvertir le nombre en chaîne...

A++

signaler à un administrateur
Commentaire de rlftova le 17/03/2008 17:51:41

Merci OPOSSUM_FARCEUR,
ta réponse force le respect.
je voyais bien en affichant mes couleurs qu'elle étaient tarnsformées en une succession de chiffres, mais je n'en voyais pas la cohérence. A présent, mes variables sont bien numériques et non 0x12345.

signaler à un administrateur
Commentaire de rlftova le 26/03/2008 00:45:37

Bonjour OPOSSUM_FARCEUR,
comment puis-je enlever les traits et les textes de légende sur le camembert ?
merci d'avance.

signaler à un administrateur
Commentaire de opossum_farceur le 26/03/2008 21:39:41

@rlftova,

Dans la méthode "aadraw()", il suffit de mettre en commentaires le code à partir du commentaire :
# traitement des légendes
et ce jusqu'à la fin.

A++

signaler à un administrateur
Commentaire de max35 le 19/04/2008 01:55:59 10/10

Salut,
Script très utile, j'utilisai une ancienne version sur un de mes site mais je viens de tester celle-ci et c'est parfait sauf...
Mon soucis c'est que les portions son toutes noir, je ne parvient pas à modifier les couleurs :S
Voici un site sur lequel je débat de mon soucis :
http://www.siteduzero.com/forum-83-265252-p1-soucis-avec-array.html

Merci.

signaler à un administrateur
Commentaire de opossum_farceur le 19/04/2008 16:02:19

@MAX35,

- Tout d'abord, quand tu postes du code, fais-le sous la forme "texte" plutôt que sous la forme d'un screenshot qui ne permet pas de faire des copier-coller et risque fort de décourager ton interlocuteur éventuel.
- Ton soucis est lié il me semble à ta manière d'exprimer les couleurs, je vois, par exemple :
$array_cam[]=array($nb_extension[0],'0x88ff49',etc...
Il existe 2 écritures possibles :
1) sous la forme de chaîne de caractères; ex : '#88ff49' ou "#88ff49" (certains systèmes peuvent aussi accepter '#8f4', en fait forme condensée de '#88ff44')
2) sous la forme numérique; en hexa : 0x88ff49, en décimal : 8978249 (c'est à dire : 136*65536+255*256+73)

et toi tu fais un "mix" des 2 : '0x88ff49' (ou "0x88ff49") n'a aucun sens et sera assimilé à un 0, qui est le code du "noir".
Ceci dit, le script du camembert (l'avant dernière version, il me semble), n'accepte que la 2ème écriture (pour des raisons de commodité, car la couleur doit ensuite être allouée avec la fonction de GD "imagecolorallocate" qui elle aussi n'accepte que du numérique).
Si tu es plus habitué à une manipulation sous forme de chaîne de caractère (ou alors si tes couleurs sont déjà stockées sous cette forme dans ta BD), qu'à celà ne tienne!, on peut très facilement convertir, et là je te renvoie à mon avant-dernier message du 17/03/2008.

A++

signaler à un administrateur
Commentaire de max35 le 25/04/2008 16:37:57

En effet j'avais bien vu ton message mais trop tard. Pour le moment j'ai laissé un peu "tombé" mais je regarderais plus tard. ;)

Merci de ta réponse rapide.

M@x.

signaler à un administrateur
Commentaire de PlayerMania le 26/05/2008 00:18:40 9/10

Félicitation opossum_farceur... du sacrés boulot...

Hélas je rencontre encore un dernier bug graphique, le voici en image :
http://img528.imageshack.us/img528/9594/camtestxs6.gif

La plupart du tps, ce bug n'apparait pas, cela dépend apparemment de les taille des parts et/ou de leur endroit, inclinaison, aa...

Peut on y faire qqch ?? Merci

signaler à un administrateur
Commentaire de opossum_farceur le 26/05/2008 01:49:08

@PlayerMania,

Je n'ai pas encore rencontré cette coquille!
Apparemment tu as pas mal modifié le code (les dimensions, l'inclinaison du camembert, etc...), c'est tout à ton honneur, car il n'est pas d'un accès très facile; est-tu sûr cependant que tes modifications ne sont pas en cause? As-tu essayé aussi avec le code d'origine? (désolé, mais pour moi c'est la seule référence), peux-tu me communiquer tes valeurs numériques? (j'ai fais un camembert avec les valeurs 4, 20 et 76 et j'ai pas réussi à reproduire le phénomène).

a++

signaler à un administrateur
Commentaire de PlayerMania le 26/05/2008 03:17:47

@opossum_farceur

Arf, éffectivement c'était encore cette inclinaison qui m'entourloupait...
$h=$w/1.3 est à proscrire pour éviter le bug que j'ai signaler (on croit que ça fonctionne, et en fait ça va bugger sous certaines découpes)
La modif de l'épaisseur y a peu être joué aussi dans mon cas avec le 1.3

Bref, au final j'ai juste repassé en 1.4, je verrai si je le recroise lol, j'ai tester mes valeurs dans ton camembert d'origine et ça ne bug pas.

Les valeur que j'avais : 127, 610, 2335
$w=114;
$h=$w/1.3;
$thickness=$w/5;

Merci encore pr ce merveilleux moteur de camembert !

signaler à un administrateur
Commentaire de opossum_farceur le 26/05/2008 19:32:33

@PlayerMania,

Attention, à modifier ainsi $h tu joues avec le feu, car on a un peu plus loin dans le code :
$this->b=$h/2;
$this->a et $this->b sont les 1/2 grand axe et 1/2 petit axe de l'ellipse du camembert et il est impératif que ces valeurs soient entières, afin que l'algorithme de Bresenham (exploité dans la méthode "aaellipse") ne fournisse pas de valeurs incorrectes pouvant se traduire par des "trous" dans l'ellipse (à la suite de quoi une couleur du camembert peut envahir toute l'image). C'est pour éviter ce genre de mésaventures que j'ai estimé plus prudent de proposer les formats précalculés "small", "medium" et "large". Je ne savais pas alors que certains utilisateurs essaieraient de créer un modèle "tiny"!
D'autre part, en modifiant ainsi $h, tu dérègles également le positionnement du texte, ce qui apparait nettement lorsqu'aucune des parts n'est "explosée" : aucune légende ne doit en principe être affichée sur le camembert.

a++

signaler à un administrateur
Commentaire de PlayerMania le 27/05/2008 03:03:21

@opossum_farceur,

Oui, ça me dit qqch cette histoire de chiffre entier à respecter (tu l'avais signalé dans le code d'une ancienne version me semble)
Béh en tout cas $this->a et b sont loin d'être entier chez moi, lol, et ça fonctionne, et depuis un bon moment, j'en ai vu défiler des camemberts, et le seul bug que j'ai rencontré est celui que je t'ai montré. (je ne l'ai plus depuis le rechangement de 1.3 en 1.4)

Bref, par précaution j'ai arrondi le résultat des divisions, pour être sur de n'avoir que des entiers dans $this->a et b, et vérifié qu'ils fassent bien la moitier de $w et $h en entier, ça à l'air de fonctionner à la normal.
Tu ne l'as pas fait parceque tes calculs donnaient que des entiers ?

(Le camembert avec $h=$w/1.4 me plait mieux qu'avec $h=$w/2)
++

signaler à un administrateur
Commentaire de opossum_farceur le 27/05/2008 20:06:13

@PlayerMania,

"Béh en tout cas $this->a et b sont loin d'être entier chez moi"

Cà n'est apparemment pas une raison suffisante pour que çà parte en vrille, mais si tu étudies un peu les algorithmes dont j'ai donné les liens, ils fonctionnent tous avec des valeurs entières (c'est d'ailleurs leur raison d'être!); cependant, PHP n'étant pas typé, on a vite fait de mettre des réels à la place, et souvent sans même s'en rendre compte.
Avec le script d'origine, et en n'agissant que sur le coefficient de division de $w (égal à 2 donc "normalement"), j'ai essayé tout un tas d'autres valeurs, eh bien, voilà le résultat des courses :
$h=$w/1.4458; # ok
$h=$w/1.4457; # ko
avec la 2ème valeur, une couleur envahit toute l'image (c'est un peu le talon d'Achille de Smooth3DCamembert, souvent d'ailleurs pour d'autres raisons), alors qu'avec la 1ère le résultat est correct. A préciser que les portions sont celles dont tu m'as donné les valeurs, la taille est "medium", de plus, il faut que la dernière portion soit explosée (si elle ne l'est pas, le résultat est correct!).
Il faut donc que tout un tas de conditions soient réunies pour que le phénomène se produise.
Sur l'image d'adresse :
http://michel.vanthodiep.free.fr/smooth3dcamembert/bugs/playermania.png
dont je n'ai affiché que les éléments pertinents, le cercle noir indique une discontinuité dans le tracé de l'ellipse, une discontinuité similaire existe par symétrie sur la partie gauche de l'ellipse (un petit coup de zoom!), eh bien, si tu balances un pot de peinture au milieu de la grosse portion, la couleur va envahir toute l'image, à cause du trou situé à gauche. La raison de ce trou? 2 points de l'ellipse occupent la même position, à cause donc d'un mauvais calcul de l'ellipse (avec des valeurs d'axes non entières), allié à une translation de la portion (en effet elle est "explosée"), le tout aboutissant à une erreur d'arrondi.
Tu pourrais me dire : oui mais, dans mon camembert, c'est pas exactement ce qui se passe! Exact, mais je n'ai voulu changer que le strict nécessaire pour aboutir à un bug! (d'autant que je ne suis pas sûr que tu n'ai pas fait d'autres modifs).

"Tu ne l'as pas fait parceque tes calculs donnaient que des entiers ?"

Ben oui, pensant que les utilisateurs se satisferaient des tailles prédéfinies...

++

signaler à un administrateur
Commentaire de lOeil le 06/07/2008 15:08:30 10/10

Merci pour cette source, vraiment du très très bon travail :)

Je voudrais un peu modifier le code afin de faire une sorte d'interaction entre l'utilisateur et le camembert, un peu à la façon svg3dcamembert

L'utilisateur pourrait cliquer sur les face du camembert afin d'excentrer certaine part du camembert (ce qui déclencherait également d'autres actions sur ma page: mise à jours de tableaux ...)

Pour cela, je pense utiliser des balises HTML <area> avec l'attribut shape="poly" afin préciser les coordonnées d'un triangle pour le dessus (je vais déjà voir ce que ça donne sur le dessus de la portion avant d'attaquer les faces "épaisseurs" qui seront plus difficiles à mettre en place) . Mon petit soucis vient du fait qu'il faut que je connaissent les coordonnées des différents triangles.
Voila une petite image pour mieux me faire comprendre:

http://img75.imageshack.us/img75/8717/trianglevp2.png

Pour l'instant tout est mis en place à part les coordonnées. Y aurait il une façon simple de les récupérer pour chaque part ?

signaler à un administrateur
Commentaire de opossum_farceur le 07/07/2008 01:31:53

@lOeil,

Ton idée est intéressante et réalisable; cependant, si tu comptes obtenir avec Smooth3dCamembert la même réactivité qu'avec SVG3dCamembert, tu risques fort d'être déçu! Avec SVG3dCamembert, tout se passe chez le client, çà répond donc au 1/4 de tour, avec Smooth3DCamembert, chaque opération requiert une communication avec le serveur pour qu'il redessine l'image et la renvoie, ce qui est une toute autre affaire!
Ayant développé Smooth3DCamembert en local, tout çà n'était pas très apparent, mais le jour où j'ai dû transférer l'application sur Free pour la démo, j'ai été plutôt refroidi (c'est peut-être à ce moment-là que m'est venue l'idée de faire un camembert avec SVG!).

Mais bon, concrètement, les coordonnées de chaque triangle apparaissent dans la méthode "aadraw()", un 1er point sera ($x1,$y1), un 2ème ($x2,$y2), le 3ème c'est le centre ($ox,$oy). Dans cette méthode, tu peux sauvegarder ces données dans un tableau qu'il reste à créer.

Le mode de transmission est forcément en Ajax, et là se pose le problème du format des données (xml, json, texte?), le "texte" a ma préférence pour sa simplicité, sa concision, et aussi qu'il faudra forcément retravailler les données côté client. Si chaque donnée est séparée par un "espace", çà peut donner :

echo $tempfile.'?'.mt_rand() t1x1 t1y1 t1x2 t1y2 t1ox t1oy t2x1 t2y1 t2x2 t2y2 t2ox t2oy etc...

Où "$tempfile" est le nom du fichier dans lequel tu as sauvegardé ton image.
Pourquoi ".'?'.mt_rand()" après le nom du fichier ? : pour éviter d'encombrer le serveur avec une foultitude de fichiers temporaires (qu'il faudrait de plus éliminer) l'idée est d'utiliser toujours le même fichier ("camembert.png" avec Smooth3DCamembert) et de ruser en lui greffant un argument fantôme pour éviter que le client aille rechercher l'image dans son cache.
Ensuite par "t1x1" il faut comprendre "coordonnée x1 du triangle t1", chaque triangle comportant donc 6 coordonnées.

Ensuite côté client, la récupération des données requiert un :
var arr=xhr.responseText.split(' ');
"xhr" étant ton objet XMLHttpRequest

Ensuite pour mettre à jour ton image, s'impose un :
document.getElementById('monimage').src=arr[0];
(en passant bien meilleur que le système de calques que j'ai utilisé dans ma démo et que je virerai à la première occasion) et pour terminer il faut recalculer chaque coordonnée (attention si ces nombres sont réels, la fonction "parseFloat()" peut s'avérer nécessaire) pour tenir compte de la position de ton image dans ta page.

a++

signaler à un administrateur
Commentaire de lOeil le 07/07/2008 23:20:00

Merci pour une réponse rapide et détaillée opossum_farceur :)

En fait avant de commencer à modifier le code j'avais déjà fait auparavant quelques tests.
Il s'avère que le résultat du camembert obtenu par la méthode ajax est donné avec un temps de réponse d'environ 250ms avec une connexion ADSL Orange et 150ms avec une connexion Free.
Ce temps de réponse est pour moi largement satisfaisant ;)

Par contre je ne te suis pas du tout pour ton histoire d'ajax, pour moi ça ne change rien:
Je vais seulement rajouter un paramètre GET afin de déterminer quelle part sera la plus excentrée et l'appel ajax se fera dans mon onclick.

je viens de récupérer les coordonnées des extrémités ça fonctionne super bien ... pour les triangles isocèles dont le sommet principal est aussi proche que 0° ...

En effet, pour une part de 50%, mon triangle se transforme en droite, du coup la surface est nulle ...

Pour les triangles dont la part est supérieure à 50% la surface du triangle ne correspond plus à la part ...

Du coup je remet en cause la façon de générer la surface cliquable :(

Si vous avez des idées je suis preneur :p

signaler à un administrateur
Commentaire de lOeil le 08/07/2008 00:37:15

Bon après avoir un peu réfléchi, je pense que ce n'est pas possible d'utiliser soit triangle soit carré soit cercle pour cerner tous les cas possibles afin de sélectionner la surface de chaque part.

La meilleure solution doit surement consister à utiliser shape = poly afin de spécifier des parties d'ellipses.
Pour cela il va donc falloir trouver l'équation de l'ellipse correspondante à chaque part du camembert.
Une fois cette équation, il va falloir ne garder qu'une partie des points.
On connait les coordonnées des extrema : points P1 et P2
Une fois qu'on connait la partie de l'ellipse que l'on veut garder, il fa falloir échantillonner.

N'y aurait-il pas une méthode plus simple ?

Sinon il y aurait peut être possibilité de récupérer directement les points de l'ellipse à partir du code déjà écrit ?
Il suffirait ainsi de faire l'échantillonnage et le tour serait joué ?

signaler à un administrateur
Commentaire de opossum_farceur le 08/07/2008 02:30:58

@lOeil,

"la méthode ajax est donné avec un temps de réponse d'environ 250ms"
Ah, tu sais mesurer le temps de réponse? (différent et forcément supérieur au temps d'exécution sur le serveur).

"Par contre je ne te suis pas du tout pour ton histoire d'ajax"
Il faut bien transmettre les coordonnées des triangles, non?
Mais je crois comprendre : ton camembert, c'est toujours le même, et t'as juste besoin de récupérer une fois pour toutes ces fameuses coordonnées...

"la surface du triangle ne correspond plus à la part"
Oups, j'avais oublié un détail : dans la méthode "aadraw()", les portions ne sont pas gérées dans le même ordre que dans le tableau fourni à la classe; en effet, pour des raisons faciles à comprendre, sont traitées d'abord les portions les plus éloignées (c'est-à-dire situées à 12h) pour terminer par les portions les plus proches (c'est-à-dire situées à 18h). Pour identifier correctement chaque triangle, en plus des 6 coordonnées déjà mentionnées, il faut donc ajouter un 7ème paramètre : le n° de la portion, donné dans le code de la méthode "aadraw()" par la variable "$j".

"je pense que ce n'est pas possible d'utiliser soit triangle"
Si c'est possible, c'est géré ainsi avec SVGCamembert, qui donne il me semble de bons résultats; exploites d'abord l'info du n° de la portion, là çà devrait marcher!

a++

signaler à un administrateur
Commentaire de lOeil le 08/07/2008 11:43:29

@opossum_farceur,

"Ah, tu sais mesurer le temps de réponse?"
J'utilise l'extension Firefox 'Firebug', l'onglet 'Console' te permet de visualiser le temps de réponse (d'ailleur cette extension est vraiment une des meilleure pour un développeur web :) )
Evidement 250ms est une moyenne. Je sais bien que ce résultat dépendra de la puissance du serveur, de sa bande passante etc ... mais ces tests ont été réalisés sur des serveurs gratuits Free, donc forcement moins puissant et plus chargés que le serveur réservé à ma future application.

"Si c'est possible, c'est géré ainsi avec SVGCamembert"
Voici un dessin explicitant ce que je voulais dire: http://img140.imageshack.us/img140/4699/bugtrianglerx1.png

signaler à un administrateur
Commentaire de opossum_farceur le 08/07/2008 16:38:02

@lOeil,

"pour une part de 50%, mon triangle se transforme en droite"
Oups, c'est vrai, j'avais pas capté, et il faut dire que là SVGCamembert n'a pas à se préoccuper de ce problème, qu'il gère en fait d'une toute autre manière (et j'ai donc dit une ânerie dans mon précédent message).

"La meilleure solution doit surement consister à utiliser shape = poly afin de spécifier des parties d'ellipses."
Cette solution est radicale, car tenant compte des cas les plus extrêmes (dont celui de la portion unique de 360°!), mais plutôt lourde à gérer.
Dans le bout de code suivant, tiré de la méthode "aadraw()" :

# dessine le dessus de la portion
for ($k=$index1,$backup0=array();$k<=$index2;$k++) {
   $xk=$ox+$this->ellipse[$k]['x'];
   $yk=$oy+$this->ellipse[$k]['y'];
   $backup0[]=imagecolorat($this->img,$xk,$yk);
   imagesetpixel($this->img,$xk,$yk,$color);
}

$xk et $yk représentent les coordonnées de chaque point du secteur elliptique de chaque portion. Tous ces points ne sont évidemment pas nécessaires, et là, se pose comme tu dis le problème de l'échantillonnage.

Si l'on est sûr que chaque portion n'éxcède pas 50% (avec donc un angle au sommet inférieur à 180°) une bonne approximation il me semble consisterait à ajouter aux 3 points du triangle un 4ème :
le point où le segment des légendes coupe l'ellipse.
Ce point (appelons-le "m") n'est pas utilisé dans la méthode "aadraw()" mais ses coordonnées sont faciles à reconstituer :
$mx=$gx+$px/5;
$my=$gy+$py/5;
A la suite de quoi notre triangle devient un quadrilatère.
L'image d'adresse :
http://michel.vanthodiep.free.fr/camembert/loeil1.png
montre ce que celà peut donner avec une grosse portion.

Pour les portions supérieures à 50%, on peut envisager de scinder le quadrilatère en 2 triangles :
http://michel.vanthodiep.free.fr/camembert/loeil2.png
On voit cependant que plus la portion est grosse, moins cette solution est valable.

"J'utilise l'extension Firefox 'Firebug'"
Merci pour l'info.

a++

signaler à un administrateur
Commentaire de lOeil le 12/07/2008 23:34:51

Voila j'ai mis en place l'échantillonnage, simple et efficace.
Les surfaces peuvent maintenant être cliquables et le nombre de points est largement raisonnable ou une précision correcte.

Par contre j'ai de gros soucis avec le trie des portions que tu effectues.
Pour montrer où j'en suis voila un zip: http://www.zshare.net/download/151953491ff0b707/
- Le trie me change à chaque fois la disposition des parts.
- Au bout de la 2eme requête ajax j'ai un problème avec le sort je pense, je n'arrive plus a récupérer les parts.

Ce code est évidemment une ébauche.
Y aurait il un moyen de ne pas utiliser de sort ?

signaler à un administrateur
Commentaire de galoane le 13/07/2008 08:11:07

Bonjour a tous

tout d'abord bravo super travail.
Par contre j'ai un tout petit probleme. L'image n'apparait pas et j'ai le message d'erreur suivant.
"Parse error: syntax error, unexpected T_CLASS in /data/members/free/multimania/fr/c/o/m/complert/htdocs/smooth3dcamembert/camembert.php on line 17".
que puis je faire pour resoudre ca???

signaler à un administrateur
Commentaire de opossum_farceur le 14/07/2008 03:13:56

@galoane,

Tu dois activer le php5 (par défaut sur Free on est avec php4). Pour çà, soit tu renommes ton fichier camembert.php5, soit tu crées à la racine de ton site (ou à l'endroit précis où se situe ton script php5) un fichier nommé ".htaccess" dans lequel tu indiques :
php 1

@lOeil,

Tu devrais davantage dissocier les rôles du serveur, qui est d'envoyer les données, de celui du client, qui est d'en assurer l'affichage. Dans ton code, l'affichage est géré côté serveur, ce qui rend malaisé le débogage.
Par exemple, des chose comme :
echo'\' onclick="ChargePage(\'camembert.php\',
n'ont vraiment rien à faire dans camembert.php, où le code devrait être du php pur à 100%.
Dans le même ordre d'idée, puisque ton idée requiert l'utilisation d'ajax, on pourrait envisager un fichier client avec l'extension (x)htm(l) et d'où le php serait totalement absent.

Ton image, toujours affichée dans le même calque grâce à la fonction "innerHTML", clignote; cet effet est fâcheux et rend discutable l'emploi même d'ajax. Une solution est d'utiliser alternativement 2 calques superposés en jouant avec leur attribut "z-index", c'est ce que j'ai fait dans ma version "ajax", cette solution est très délicate et trop dépendante du reste de la page, il faut lui préférer la solution avec l'image en "dur" côté client, et dont on se contente de changer la valeur de l'attribut "src". C'est de loin ce qu'il y a de plus fiable. Un exemple de cette gestion dans ma source d'adresse :
http://www.phpcs.com/code.aspx?ID=46344
que tu as l'air de connaître déjà, mais bon...
Schématiquement, côté serveur (comme je l'ai déjà signalé) :
echo $tempfile,'?',mt_rand();
où "$tempfile" est le nom du fichier temporaire contenant ton image
côté client :
document.getElementById('monimage').src=xhr.responseText;
où "xhr" est ton objet XMLHttpRequest, et "monimage" l'identifiant de ta balise "img"

Quant à ton utilisation du tableau $this->sort, elle m'a plongé dans un abîme de perplexité. L'indice véritable de la portion est donné, dans la méthode "aadraw()", par la variable $j (et là encore je me répète).
Le code :
$this->points[$j] = $arr_points;
à la place de :
$this->points[] = $arr_points;
est suffisant pour remettre les portions dans l'ordre.

Bon, j'arrête de tourner autour du pot : débugger ton code, c'est possible, mais à condition de tout reprendre depuis zéro!

a++

signaler à un administrateur
Commentaire de opossum_farceur le 29/09/2008 01:38:56

Nouvelle version 4.1 de la classe : what's new, doc?

- Amélioration/consolidation/optimisation du code existant

- Ajout de dégradés dans les parties verticales courbes du camembert (je les ai testés également dans les secteurs elliptiques horizontaux, pour finalement les abandonner, car ceux-ci étaient trop gourmands en temps d'exécution).

- L'exploitation "Ajax" de la classe a été améliorée, avec l'abandon de la gestion des calques avec "z-index" au profit d'une approche plus classique.

- Concernant l'idée développée par LOEIL, je propose ma version, avec les éléments que j'ai défendus au cours de la discussion (voir plus haut).

- Note : La partie "source" située en haut de cette page n'a pas été mise à jour (trop la flemme!), tout est donc dans le zip.

- adresses des démos en ligne :
http://michel.vanthodiep.free.fr/smooth3dcamembert/index.html
http://michel.vanthodiep.free.fr/smooth3dcamembert/index.php
http://michel.vanthodiep.free.fr/smooth3dcamembert/loeil/index.html

Merci pour les retours!

signaler à un administrateur
Commentaire de catsoap le 14/10/2008 22:43:24 10/10

magnifique !!

signaler à un administrateur
Commentaire de foxcon le 16/05/2009 15:06:24 10/10

Impressionant.... :-O

Mon soucis majeur se situe dans l'intégration des données à partir de ma base Mysql.

Les valeurs doivent etre récupérées a partir de la db, la légende reste fixe.
Si vous avez une piste, je suis preneur.

Merci

signaler à un administrateur
Commentaire de opossum_farceur le 17/05/2009 02:33:35

Salut,
En prenant exemple sur le fichier "index.php" fourni dans le zip, ton problème c'est de remplir dynamiquement la 1ère colonne du tableau "$arr"; tu prépares donc ce tableau à l'avance, avec tes champs "couleur", "légende" et "xploded" prédéfinis; pour ce qui est du champ "donnée" il suffit d'y mettre une valeur par défaut, par exemple 0.

/* si ta requête (mySQL j'imagine!) ressemble à :*/
$sql='select myvalue from mytable;';

/* tu en récupères les résultats...*/
$query=mysql_query($sql) or die('Erreur requête :<br/>'.$sql);

/* qui alimentent ensuite dynamiquement ton tableau $arr :*/
for ($j=0;$assoc=mysql_fetch_assoc($query);$j++) $arr[$j][0]=$assoc['myvalue'];

Il faut être sûr qu'il n'y a pas plus de résultats que le tableau a de lignes; en cas de doute, on peut remplacer la dernière ligne de code par :

for ($j=0,$n=count($arr);$assoc=mysql_fetch_assoc($query) && $j<$count;$j++) $arr[$j][0]=$assoc['myvalue'];

Ensuite, il faut s'inspirer du code de "index.php", choisir sa classe, les arguments qui vont avec, "linéariser" le tableau "$arr" avec la fonction "arr2str" et envoyer le tout par "get" au fichier "camembert.php".
Amicalement.

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

faire un graphique camembert 3D, a partir d'une base de données [ par otacon67 ] je suis un newbies en PHP, et je voudrais savoir comment creer un camembert en 3D, a partir d'une base de donn&#233;es merci pour votre soutien et vo Rafraichir une page [ par niko14 ] Hello everybody!!Voila le bin's!!En fait voila, j'ai une page ou on choisit un type de budget et on valide!Qd on a valid&#233; on arrive sur une page tableau de couleurs comme dans word [ par niko14 ] slt tout le monde!VOila mon probleme!J'ai un camembert donc je fais choisir les couleurs pour les differentes repartitions et en fait j'avais fait une statistiques : temps passé sur une page [ par Phil0 ] Bonjour, Je suis actuellement entrain de faire un script php de statistiques et je voudrais, si c'est possible, savoir comment connaitre le temps pass statistiques [ par gabs77 ] bonjour, je cherche a faire des statistiques numériques avec un formulaire de choix des informations a évaluerdonc les statistiques se feront sur la t Statistiques d'une newsletter [ par blaize21 ] Bonjour! Je viens de réaliser un script plutôt basique d'envoi de newsletter et je voudrais obtenir les statistiques de lecture de ma newsletter. J'a Statistiques [ par Sniperman113 ] Bonjour,Je voudrai créer un script de statistiques (notamment bénéfices des 30 derniers jours) sous forme graphique. Par exemple dans l'idéal, il faud générer des statistiques graphiques a partir d'un fichier xml [ par ammar_emi ] bonjour,je suis débutant en xml ,et je vx générer des statistiques graphiques d'un user d' une plateforme.J ai reussi à extraire les infos utiles pour générer des statistiques [ par charbouba ] svp comment utiliser gd pour tracé des graphiques a partir d'un fichier xmlsi qlq a un exemple ca serait mieux:) .merci.(c urgent) Librairie traceur fonction 3D [ par Jarod1980 ] Bonjour,Je souhaiterais si il existe une librairie en php permettant de tracer des fonctions mathématiques en 3D. J'ai fais une recherche sur net mais


Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Téléchargements

Logiciels à télécharger sur le même thème :

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,406 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.