Gerando gráficos com PHP e highcharts.com

Alô Comunidade PHP! Neste artigo eu pretendo mostrar como preencher uma lacuna no desenvolvimento de aplicativos gerenciais que dependem de 2 gráficos importantes: Pizza e Linhas. Soluções como o PHPLot funcionam, mas não dão o resultado esperado. Vamos lá?

[ Hits: 17.532 ]

Por: Evaldo Barbosa em 13/06/2011


Introdução



Sempre que posso eu pesquiso alguma forma nova de fazer o meu trabalho, uma forma nova de aumentar minha produtividade. Ultimamente tenho estudado SCRUM, técnica pomodoro e outras formas de realizar autogerenciamento sem que isso se torne um parto. Tive uma última demanda por gráficos para os meus projetos, um aplicativo de controle dos meus contratos e também um de finanças pessoais (que posso comentar em outros artigos) e os implementei num primeiro momento com o PHPLot que é fácil, leve e dá um bom resultado, porém não era ainda o que eu queria. Eu queria mesmo era uma coisa parecida com os gráficos do Google Analytics, ou seja, algo em javascript, de preferência Jquery. Procurando encontrei o highcharts.

Como eu sempre evito parar pra escrever código javascript, automatizo a criação do resultado com PHP. Crio uma classe em PHP que faça a parte chata do trabalho, ou seja, gerar o código javascript, chamar o arquivo do plugin etc. Resultado: produtividade lá em cima.

A situação do gráfico de linhas

Pensa naquele gráfico bonito mostrando o andamento de uma situação, seja ela o saldo atual de suas contas, o desenvolvimento de um trabalho, a cotação do dólar etc. Essas são situações exemplo para a utilização desse tipo de gráfico e que são facilmente resolvíveis com o highcharts e com PHP.

Os dados a serem passados são poucos, o resultado é ótimo. Vamos exemplificar aqui uma série de quinze dias de resultados de saldos de uma determinada conta, pode ser uma poupança, uma conta banco movimento ou qualquer que você queira usar como exemplo para reproduzir. Os resultados serão, aqui, do dia primeiro ao décimo quinto dia de um dados mês onde os dados serão apresentados em forma de um array, onde o índice do array que contém os dados é o legenda para essa série e nos arrays aninhados o valor do índice zero é o dia e do índice hum valor é o saldo. Entendido?

Vamos aos dados então:

$dados = array('Saldo'=>array(
   array(1, 900 ),
   array(2, 1205 ),
   array(3, 1351 ),
   array(4, 1300 ),
   array(5, 1285 ),
   array(6, 1555 ),
   array(7, 2001.5 ),
   array(8, 1916.15 ),
   array(9, 1894 ),
   array(10, 2201 ),
   array(11, 1863.81 ),
   array(12, 3332.21 ),
   array(13, 3332.21 ),
   array(14, 3110.21 ),
   array(15, 2900.21 )
));

A classe LineChart

Para solucionar o problema vamos criar a class LineChart (no meu caso eu a estendo de outra class, a TSWObject, mas isso aqui não vem ao caso, o resultado não depende diretamente disso). A implementação é a seguinte:

<?php
/**
* LineChart
* Classe que implementa a abstração de gráficos highcharts.com para
* gráfico de linhas.
*
* @author Evaldo Barbosa <[email protected]>
*/
class LineChart /*extends TSWObject*/
{
   private $container;
   private $title;
   private $subtitle;
   private $yAxis;
   private $series;

     /**
    * Construtor da classe.
    * @param array $conf Array com as configurações para que o gráfico funcione.
    * As chaves desse array deve ser iguais aos nomes dos atributos internos dessa classe.
    * Perceba que o índice title pode ter mais de um índice, equivalentes a título e subtítulo respectivamente.
    * @return void
    */
   function __construct($conf) {
      $this->title      = $conf['title'][0];
      $this->subtitle   = $conf['title'][1];
      $this->container   = $conf['container'];
      $this->series      = $conf['series'];
      $this->yAxis      = $conf['y'];
   }

     /**
    * Método que gera os dados e os retorna para implementação na página.
    * @return string
    */
   function render() {
      //A linha abaixo foi comentada porque a mesma chama uma outra classe
      //que uso para facilitar a geração das minhas tags internas do header
      //da página como tags de chamadas de arquivos CSS <link>
      //de chamadas de arquivos JS ou códigos JS personalizados sob demanda
      //que nela chamo de LiveScripts. Idéia para outro artigo!
      //Header::addJSFile("linechart","/js/highcharts/highcharts.js");

             $series = array();
      $data = array();
      $axis = array();
      foreach ( $this->series as $key=>$row ) {
         $data[$key] = array();
         foreach( $row as $_row ) {
            $axis[] = $_row[0];
            $data[$key][] = $_row[1];
         }
      }
      $axis = "'" . implode("','",$axis) . "'";

             foreach( $data as $key=>$row ) {
         $i = implode(",",$row);
         $series[] = "{name:'{$key}',data:[{$i}]}";
      }
      $series = implode(",",$series);

             $str = "chart = new Highcharts.Chart({
               chart: {
                  renderTo: '{$this->container}',
                  defaultSeriesType: 'line',
                  marginRight: 130,
                  marginBottom: 25
               },
               title: {
                  text: '{$this->title}',
                  x: -20 //center
               },
               subtitle: {
                  text: '{$this->subtitle}',
                  x: -20
               },
               xAxis: {
                  categories: [{$axis}]
               },
               yAxis: {
                  title: {
                     text: '{$this->yAxis['title']}'
                  },
                  plotLines: [{
                     value: 0,
                     width: 1,
                     color: '#808080'
                  }]
               },
               tooltip: {
                  formatter: function() {
                            return '<b>'+ this.series.name +'</b><br/>'+
                        this.x +': '+ this.y;
                  }
               },
               legend: {
                  layout: 'vertical',
                  align: 'right',
                  verticalAlign: 'top',
                  x: -10,
                  y: 100,
                  borderWidth: 0
               },
               series: [{$series}]
            });
      ";
      //Lembra que falei do LiveScript?
      //Header::addLiveScript( $str );
      return $str
   }
}
?>

A implementação original foi modificada para que não houvesse dependência em relação a nenhum outro arquivo ou classe do meu framework, salve o código acima num arquivo chamado linechart.php, iremos usá-lo em breve. Vamos agora ao HTML que receberia esse o resultado desse código. Chamemos o arquivo de linechart_exemplo.php que conterá o código PHP que usará a classe anterior e também o HTML que será a interface com o gráfico. Vamos ao código!

<html>
<head>
<title>Exemplo de LineCharts com PHP e Highcharts</title>
<!-- LEMBRE-SE DE BAIXAR OS ARQUIVOS DO JQUERY E HIGHCHARTS.COM /-->
<script src=”js/jquery.js”></script>
<script src=”js/highcharts.js”></script>
<script>
<?
require(“linechart.php”);
$dados = array('Saldo'=>array(
array(1, 900 ),
array(2, 1205 ),
array(3, 1351 ),
array(4, 1300 ),
array(5, 1285 ),
array(6, 1555 ),
array(7, 2001.5 ),
array(8, 1916.15 ),
array(9, 1894 ),
array(10, 2201 ),
array(11, 1863.81 ),
array(12, 3332.21 ),
array(13, 3332.21 ),
array(14, 3110.21 ),
array(15, 2900.21 )
));
$charts = new LineChart(array(
   "title"      => array("Seu desempenho nos últimos 15 dias","Acompanhamento diário"),
   "container"   => "container",
   "y" => array(
      "title"=>"Em R$"
   ),
   "series"   => $dados
));
?>
$(document).ready(function() {
   <? echo $charts->render(); ?>
});
</script>
</head>

<body>
   <div id=”container”><!-- AQUI FICARÁ O GRÁFICO /--></div>
</body>

</html>

De posso do HTML e do código que gera o gráfico, mãos à obra!

Teste no seu browser. Visto o resultado, vamos ao próximo gráfico.

A situação do gráfico pizza

Essa é uma situação bem corriqueira e simples de pensar e resolver. A circunferência completa equivale a 100% e cada categoria dada tem a sua porcentagem. Um exemplo é a distribuição de gastos entre categorias como alimentação, lazer, transporte etc.

Para esse gráfico a abordagem é bem parecida à abordagem anterior, ou seja, os dados serão passados como um array. Vamos a ele:

$dados = array( array("FREE LANCE",8.87), array("SALARIOS",84.01), array("Poupança",7.12)) ;

A classe PieChart

Como no exemplo anterior vamos criar uma classe, dessa vez a PieChart, que desempenhará o mesmo papel de abstrair o javascript facilitando a geração do gráfico sem ter que meter a mão direto no Jquery. O código segue abaixo:

<?php
/**
* PieChart
* Classe que implementa a abstração de gráficos highcharts.com para
* gráfico tipo pizza.
*
* @author Evaldo Barbosa <[email protected]>
*/
class PieChart extends TSWObject {
   private $container;
   private $title;
   private $subtitle;

      /**
    * Construtor da classe.
    * @param array $conf Array com as configurações para que o gráfico funcione.
    * As chaves desse array deve ser iguais aos nomes dos atributos internos dessa classe.
    * Perceba que o índice title pode ter mais de um índice, equivalentes a título e subtítulo respectivamente.
    * @return void
    */
   function __construct($conf) {
      $this->title      = $conf['title'][0];
      $this->subtitle   = $conf['title'][1];
      $this->container   = $conf['container'];
      $this->series      = $conf['series'];
   }

      /**
    * Método que gera os dados e os retorna para implementação na página.
    * @return string
    */
   function render() {
      $series = array();
      foreach ( $this->series as $row ) {
         $row[1] = sprintf("%01.2f",$row[1]);
         $series[] = "['{$row[0]}',{$row[1]}]";
      }
      $series = implode(",",$series);

             //Header::addJSFile("piechart","/js/highcharts/highcharts.js");
      $str = "chart = new Highcharts.Chart({
               chart: {
                  renderTo: '{$this->container}',
                  plotBackgroundColor: null,
                  plotBorderWidth: null,
                  plotShadow: false
               },
               title: {
                  text: '{$this->title}'
               },
               tooltip: {
                  formatter: function() {
                     return '<b>'+ this.point.name +'</b>: '+ this.y +' %';
                  }
               },
               plotOptions: {
                  pie: {
                     allowPointSelect: true,
                     cursor: 'pointer',
                     dataLabels: {
                        enabled: false
                     },
                     showInLegend: true
                  }
               },
                series: [{
                  type: 'pie',
                  name: '{$this->subtitle}',
                  data: [{$series}]
               }]
            });";
      //Lembra que falei do LiveScript?
      //Header::addLiveScript( $str );
      return $str;
   }
}
?>

O código HTML para este exemplo é muito semelhante ao outro, a diferença fica a cargo somente no array de dados e na chamada para a classe PieChart. Mas para que não fique muito vago, apresentarei o bloco onde haverá a mudança. Veja o código que será modificado no header:

<script>
<?
require('piechart.php');
$dados = array( array("FREE LANCE",8.87), array("SALARIOS",84.01), array("Poupança",7.12)) ;
$charts = new PieChart(array(
   "title"   => array("Visão geral das suas receitas","Distribuição por categoria"),
   "container"   => "container",
   "series"   => $dados
));
?>
$(document).ready(function() {
   <? echo $charts->render(); ?>
});
</script>

Salve esse código como piecharts_exemplo.php e rode no seu browser.

Conclusão

Todos sabemos que gráficos deixam a informação mais elegante e mais fáceis de ler. Gráficos com informações consistentes fazem com que o gestor possa tomar decisões mais rapidamente sem analisar uma massa de dados, pois a função que eles desempenham é justamente a de sintetizar uma visão tirada de uma amostra de dados.

Fazer com que o PHP automatize a tarefa chata de incluir o Javascript dentro de uma página HTML ao estilo macarrão, ou mesmo dentro de um template Smarty ou outra suite de templates cria, além da sensação de poder fazer mais rápido, uma melhor estrutura para manutenção do código.

A todos aqueles que tiverem dúvidas ou sugestões a fazer para as classes podem entrar em contato comigo através de e-mail ou então podem me encontrar no twitter em @evaldobarbosa para trocarmos ideias.

Aguardem outros artigos.
   

Páginas do artigo
   1. Introdução
Outros artigos deste autor

Utilizando PHP e Apache para desligar um Ubuntu

Construindo componentes em PHP e jQuery

Abordagem exemplificada de orientação à objeto com PHP 5

Macromedia Studio 8 no Wine em detalhes

Abordagem exemplificada à Orientação a Objetos com PHP

Leitura recomendada

PHP Orientado a Objetos

Gráficos em PHP Highcharts

Debian com Apache, PHP4, PHP5 e MySQL

Ninguém planeja fracassar, mas muitos fracassam por não planejar

Requisições assíncronas em PHP usando AJAX - Parte I

  
Comentários
[1] Comentário enviado por rogerio_gentil em 13/06/2011 - 16:19h

Não foquei a leitura no código, mas gostei bastante da dica. Acho que faltou colocar algumas imagens exemplificar o uso deste componente.

[2] Comentário enviado por evaldobarbosa em 13/06/2011 - 17:06h

Obrigado pelo comentário, Rogério. Se quiser dar uma olhada em uma outra versão do mesmo artigo ele encontra-se em http://bit.ly/l5jVvi.

[3] Comentário enviado por italoror em 16/06/2011 - 10:51h

Hum nesse caso muito interessante o que é php?

R:PHP é o acrônimo de Hipertext Preprocesor. É uma linguagem de programação do lado do servidor gratuito e independente de plataforma, rápido, com uma grande livraria de funções e muita documentação.
Uma linguagem do lado do servidor é aquela que se executa no servidor web, justo antes da página ser enviada através da Internet ao cliente. As páginas que se executam no servidor podem realizar acessos a bases de dados, conexões em rede, e outras tarefas para criar a página final que será vista pelo cliente. O cliente somente recebe uma página com o código HTML resultante da execução da PHP. Como a página resultante contém unicamente código HTML, é compatível com todos os navegadores. Podemos saber algo mais sobre a programação do servidor e do cliente no artigo

[4] Comentário enviado por evaldobarbosa em 26/12/2012 - 11:16h

italoror, o foco do artigo não é o PHP em si, mas uma forma de usar a biblioteca highcharts com php.
Existem muitos outros artigos aqui que são mais básico e colocar mais um falando mais do mesmo eu não achei justo com outros autores.


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner
Linux banner
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts