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 <tryadesoftware@gmail.com>
*/
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 <tryadesoftware@gmail.com>
*/
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.