Palavra:   

Revista PHP / PHP

Flávia Jobstraibizer

Analista de sistemas, DBA Mysql, PostgreSQL, Oracle, SQLServer e Firebird. Desenvolvedora de sistemas, e administradora de servidores FreeBSD. Conheça o site www.flaviajobs.com.br

Construindo um gráfico pizza com GD

Que o GD tem mil e uma utilidade, isso você já sabe. Que ele é chatinho de trabalhar, isso provavelmente você também já descobriu. Mas apesar de tudo isso, é uma das formas mais rápidas de se criar imagens 100% baseadas em script.
É o caso do gerador de relatórios de gráficos que vamos ver a seguir.

Utilizando PHP e GD, vamos criar um relatório de vendas, baseado na quantidade de vendas de cada vendedor. De posse desses valores, vamos gerar um gráfico em formato pizza, com as porcentagens de vendas.

O exemplo deste código, está aqui: http://www.flaviajobs.com.br/sistemas/revistaphp/graficopizza1.php
Inclui o exemplo de preenchimento. Preencha e gere o gráfico para ver como funciona. J

Primeiramente, criei o formulário que você viu aí em cima. Ele apenas informa ao script php, o que tem que ser feito.

No arquivo: graficopizza1.php, temos o form:

<form id="form1" name="form1" method="post" action="graficopizza.php">
<span class="style1">Relat&oacute;rio de vendas</span><br />
<br />
<span class="style1">Nome do relat&oacute;rio:</span>
<label>
<input name="titulo" type="text" id="titulo" size="40" />
</label>
<br />
<span class="style1">Cor do fundo do relat&oacute;rio:</span>
<label>
<input name="fundo" type="text" id="fundo" />
</label>
<span class="style3">(no formato rgb, separado por tra&ccedil;os: 255-255-255-255 )</span><br />
<br />
<span class="style1">Vendedores:</span><br />
<label>
<textarea name="usuarios" cols="30" rows="4" id="usuarios"></textarea>
<span class="style1">(nomes separados por virgulas) </span></label>
<p><span class="style1">Quantidades de vendas de cada vendedor acima (na ordem dada acima):</span><br />
<label>
<input name="valores" type="text" id="valores" size="40" />
</label>
<span class="style3">(separar por virgula)</span> <br />
</p>
<label>
<input name="Submit" type="submit" class="style1" value="Gerar gr&aacute;fico" />
</label>
</form>

Informei na action deste form, o método POST de envio , e o arquivo graficopizza.php, e é dele que vamos falar agora.

graficopizza.php
Primeiro vamos pegar os dados principais do form, que são: os nomes dos vendedores, e a quantidade de vendas de cada um deles.
No meu caso, tanto os nomes dos vendedores quanto as quantidades de vendas, são passadas separadas por vírgula. Fiz isso pra facilitar minha vida, mas você pode implementar como achar melhor.

<?php
// verificando os nomes dos usuários e os valores passados pelo form
if (isset($_REQUEST["usuarios"])) $dp = explode(",",$_REQUEST["usuarios"]);
if (!isset($_REQUEST["valores"]));

// separando os valores das vendas de cada usuário, com virgula
$valores = explode(",",$_REQUEST["valores"]);

// contando os valores. neste script, setei para que o limite fosse 100 valores
// ou seja, 100 usuários, com seus respsctivos 100 valores.

$n_valores = count($valores);
if ($n_valores > 100) $n_valores = 100;
$total = 0;
for ($z=0; $z<$n_valores; $z++) {
if ($parte[$z]<0);
$w=$z+1;
$parte[$w] = $valores[$z];
$total += $valores[$z];
}

Feito isso, começo a pré-montar o gráfico, com base nas informações conseguidas acima

// calculando o diametro da pizza, no caso, 200 pixels
$d = Array();
$diametro = 200;
$radius = $diametro/2;

// convertendo os valores, para graus, afinal, o negócio é redondo..rs
for ($y=1; $y<=$n_valores; $y++) $d[$y] = ($parte[$y]/$total) * 360;
$im = ImageCreate(450, 300);

// cores que serão utilizadas nas fatias do gráfico
$preto = ImageColorAllocate($im, 0, 0, 0);
$branco = ImageColorAllocate($im, 255, 255, 255);
$verde = ImageColorAllocate($im, 0, 255, 0);
$rosa = ImageColorAllocate($im, 255, 128, 128);
$amarelo = ImageColorAllocate($im, 255, 255, 128);
$vermelho = ImageColorAllocate($im, 255, 0, 0);
$lilas = ImageColorAllocate($im, 128, 128, 192);
$marrom = ImageColorAllocate($im, 128, 64, 64);
$laranja = ImageColorAllocate($im, 255, 128, 64);
$vinho = ImageColorAllocate($im, 64, 0, 64);
$gelo = ImageColorAllocate($im, 210, 210, 210);
$azul = ImageColorAllocate($im, 0, 0, 255);
$cinza = ImageColorAllocate($im, 102, 102, 102);
$amarelo2 = ImageColorAllocate($im, 255, 255, 0);
$vermelho2 = ImageColorAllocate($im, 126, 14, 1);


Pegando mais dados informados no form, no caso, o fundo, pra continuar montando o relatório.

// verificando se foi passada a variável fundo, através do form
// no formato rgb, separados por traço: 255-255-255-255
// se foi, mostra a cor, senão, deixa em branco.

$e=0;
if (isset($_REQUEST["fundo"])) {
$r = explode("-",$_REQUEST["fundo"]);
for ($z=0; $z<3; $z++) {
if (is_numeric($r[$z])) {
if ($r[$z] >= 0) {
if ($r[$z] <= 255) $e++;
}
}
}
}

Você deve estar se perguntando porque o script pega alguns dados do form, muito depois de ter começado a montar o relatório. Isso se deve mais ao fato organizacional do que qualquer outra coisa. Eu prefiro solicitar os dados que já foram passados, somente no momento em que vou utiliza-los, evitando carregar todos eles no inicio do arquivo.

Bem, vamos continuar montando o gráfico, agora montando a parte mais ‘bonitinha’.

$cor[] = $branco;
$cor[] = $verde;
$cor[] = $rosa;
$cor[] = $amarelo;
$cor[] = $vermelho;
$cor[] = $lilas;
$cor[] = $marrom;
$cor[] = $gelo;
$cor[] = $azul;
$cor[] = $cinza;
$cor[] = $laranja;
$cor[] = $vinho;
$cor[] = $amarelo2;
$cor[] = $vermelho2;
$cor[] = $preto;

// preenchendo o fundo da imagem, com a cor informada no form, ou deixando em branco
ImageFill($im, 0, 0, $fundo);

// desenhando a linha de base
ImageArc($im, 153, 153, $diametro, $diametro, 315, 135, $preto);

$u_angulo = 0;
for ($z=1; $z<=$n_valores; $z++) {
// calculando o arco do gráfico
ImageArc($im, 150, 150, $diametro, $diametro, $u_angulo,($u_angulo+$d[$z]), $preto);
$u_angulo = $u_angulo + $d[$z];
$end_x = round(150 + ($radius * cos($u_angulo*pi()/180)));
$end_y = round(150 + ($radius * sin($u_angulo*pi()/180)));
ImageLine($im, 150, 150, $end_x, $end_y, $preto);
}

$a_angulo = 0;

for ($z=1; $z<=$n_valores; $z++) {
$ponteiro = $a_angulo + $d[$z];
$e_angulo = ($a_angulo + $ponteiro) / 2;
$a_angulo = $ponteiro;
$end_x = round(150 + ($radius * cos($e_angulo*pi()/180)));
$end_y = round(150 + ($radius * sin($e_angulo*pi()/180)));
$mid_x = round((150+($end_x))/2);
$mid_y = round((150+($end_y))/2);
ImageFillToBorder($im,$mid_x,$mid_y,$preto,$cor[$z]);
}

 

Agora vamos formatar a legenda lateral. Nela está contidos os nomes dos vendedores, e a porcentagem de vendas de cada um, com base nos valores previamente informados no formulário.


if ($e == 3)    
$fundo = ImageColorAllocate($im, $r[0], $r[1], $r[2]);
else
// sequencia de cores, que serão utilizadas nas fatias do gráfico
$fundo = $branco;
$sombra = $cinza;
// parâmetros da legenda lateral
// distancia horizontal

$r_x=300;
// distancia vertical
$r_y=3;
$e = 280/($n_valores+1);

// desenhando os quadradinhos
for ($z=1; $z<=$n_valores; $z++) {
$w_x = $r_x;
$w_y = $r_y + ($z * $e);
$parte[$z] = round($parte[$z]/$total * 100,1);
imagefilledrectangle($im, $w_x,$w_y,$w_x+15,$w_y+15,$sombra);
imagerectangle($im,$w_x-3,$w_y-3,$w_x+12,$w_y+12,$preto);
imagefilltoborder($im,$w_x-1,$w_y+11,$preto,$cor[$z]);
$w = $z - 1;
if (isset($dp[$w])) $w = "% " . substr($dp[$w],0,12);

else $w = "%";
imagestring($im,3,$w_x+20,$w_y,$parte[$z].$w,$preto);
}

Agora sim, podemos finalizar o relatório, pegando o título informado no form, e desenhando o circulo por fora da pizza, que agora está completa.

// criando a sombra do circulo da pizza 
ImageFillToBorder($im, 150 + 72, 150 + 72, $preto, $sombra);
ImageArc($im, 153, 153, $diametro, $diametro,315,135,$sombra);

// verifica se foi passado um titulo através do form
// se foi, mostra

if (isset($_REQUEST["titulo"])) {
$x = strlen($_REQUEST["titulo"]);
if ($x > 100) $w = substr($_REQUEST["titulo"],0,100);
else {
$w = "";
for ($z=1; $z<((30-$x)/2); $z++) $w.=" ";
$w.=$_REQUEST["titulo"];
}
// cor do titulo
ImageString($im, 5, 20, 10, $w, $preto);
}


Feito isso, acabou-se o trabalho, vamos apenas imprimir TUDO isso que fizemos, na tela, em formato de imagem, que no meu caso, usei PNG. (quem viu meu outro tutorial de GD, deve ter visto que também usei PNG lá. Eu prefiro png, por ser muito mais leve, e por costume mesmo... :). E já que sempre que preciso fazer transparências, acabo apanhando do gif, optei por fazer tudo em PNG! J )

// impressão de tudo o que foi feito acima, em png
Header("Content-Type: image/png");
ImagePNG($im); ?>

Bem, acredito que mesmo os trechos de código, estão muito bem explicadinhos, mas se você não entendeu alguma parte, pode me escrever no fjferr@gmail.com ou então, comente aqui.

Opções de Interação

Comentários

Ajuda
Por: Andre, 06/03/2009   15:32:27
Parabéns flávia por seu artigo. Nossa. funcionou show de bola. Olha que sou iniciante em php e consegui fazê-lo rodar sem problemas. Apenas tive que descomentar a linha da dll do gd( hehe coisa de principiante). Preciso da seguinte ajuda: Esse código não permite que junto com o gráfico eu mescle tag´s htmls???? tipo, quero colocar um cabeçalho, uma formatação para impressão, pode me ajudar???. Pelo artigo...Nota 10000
Muito bom
Por: Carlos, 29/04/2007   23:43:05
Flávia, muito bom esse artigo, se tiver mais sobre criação de gráficos, será bem vindo. :)
Resposta
Por: Flávia, 14/01/2007   09:43:19
Francis, o artigo está em perfeito funcionamento, por isso sempre deixo o exemplo para que vejam. Não tenho como saber que tipo de erro é, se vc nem mesmo o colocou. Abraço.
Warning: Division by zero in /home/francis/public
Por: Francis, 14/01/2007   06:53:24
Olá Flávia, li o artigo que vc escreveu, nota 10. Quando fui colocar em prática tá dando um erro na linha 54 que não consegui resolver, uma divisão por 0.
Desde já grato pela atenção
Francis
Resposta
Por: Flávia, 04/01/2007   10:04:52
Marcos, eu mexeo MUITO com GD. Aqui nos meus artigos, você vai ver bastante coisa sobre usos do GD. Abraço.
Brilhante!
Por: Marcos, 04/01/2007   09:30:40
A Flávia como sempre brilhante em suas explicações. O assunto é meio chato de compreender, mas tudo muito bem esmiuçado. Só uma sugestão: você poderia publicar um link com mais informações sobre a biblioteca GD para aqueles que quiserem se aprofundar mais no assunto.