BT

Gráficos Incríveis em Rails

Postado por Srividya Sharma , traduzido por Flávia Castro de Oliveira em 06 Fev 2009 |

As Aplicações Web frequentemente analisam dados no banco de dados gerando relatórios. Os gráficos fornecem uma representação visual dos relatórios, que pode ser usada para facilitar o entendimento e geralmente facilitar a síntese de dados. Ruby On Rails é uma das tecnologias que pode ser usada para criar essas aplicações web com relatórios e gráficos. Neste artigo, nós discutiremos sobre como criar gráficos em Ruby on Rails.

Para gerar gráficos a partir de relatórios ou dados no banco de dados, precisamos de um bom produto de gráficos. Gruff, JFreeChart, XML/SWF charts, FusionCharts são alguns dos produtos disponíveis para Ruby on Rails. A tabela a seguir apresenta uma comparação grosseira destes produtos. Repare que nem todos os produtos foram experimentados e testados. A maior parte da análise a seguir é baseada em informações coletadas a partir da documentação dos produtos.

  Gruff JFreeChart XML/SWF FusionCharts Free FusionCharts v3 (Paid)
Tipo Ruby classes Java Class files Flash charting component Flash Charting component Flash Charting component
Sistema de Operação O/S Independente O/S Independente O/S Independente O/S Independente O/S Independente
Adobe Flash Plug-in exigido Não Não Sim Sim Sim
Adequado para Análises de Dados Avançadas Não Sim Sim Não Sim
Qualquer plug-ins ou software podem ser instalados Sim- RMagick, ImageMagick e Gruff Sim, JDK versão 1.3 ou posterior Não Não Não
Os gráficos podem ser animados? Não Sim Sim Sim Sim
Capacidade para salval o gráfico como imagem Sim Sim Sim Não Sim
Suporte UTF8 Não Documentado Sim Sim Sim Sim
Facilidade de Uso em RoR Sim, mas muita codificação envolvida. Não muito fácil de usar. Não serve para o usuário final. Complexo, também muitas tags xml para configurar o gráfico. Muito fácil de usar. Os desenvolvedores e os usuários final podem usá-lo. Muito fácil de usar. Os desenvolvedores e os usuários final podem usá-lo.
Bar Charts 2D, 3D Sim Sim Sim Sim Sim
Gráficos de linha Sim Sim Sim Sim Sim
Gráficos Scatter Sim Sim Sim Sim Sim
Gráficos de Área Sim Sim Sim Sim Sim
Pie 2D, 3D Sim Sim Sim Sim Sim
Doughnut 2D, 3D Não Yes, Ring Chart Sim Sim Sim
Gráficos Gantt Não Sim Não Sim Sim ( as part of FusionWidgets v3)
Gráficos de Combinação Não Sim Sim Sim Sim
Gráficos Gauge Não Sim ( como parte de XML/SWF Gauge) Sim Não Sim ( como parte do FusionWidgets v3)
Gráficos em tempo real Não Não Não Não Sim ( como parte do FusionWidgets v3)
Dados-dirigidos a Mapas Não Não Não Não Sim ( como parte do FusionWidgets v3)

Neste artigo, nós exploraremos os gráficos em Rails utilizando FusionCharts e a base de dados do MySQL. FusionCharts é um componente de gráficos baseado em flash que pode gerar gráficos interativos e animados. FusionCharts pode ser usado com qualquer linguagem de script da web, para entregar gráficos poderosos com a mínima codificação. O FusionCharts vem com módulos para ser usado com RoR. Facilidade para usar, variedades de tipos de gráficos, boa documentação e um bom suporte é a motivação por trás da utilização do FusionCharts para este artigo.

Este artigo descreve o mecanismo de geração de gráficos usando FusionCharts em Ruby on Rails através de uma aplicação de exemplo. Para executar a aplicação de exemplo discutida neste artigo, é necessário o seguinte:

•  FusionCharts Free/ v3:

FusionCharts Free pode ser baixado em www.fusioncharts.com/free , ou a versão comercial com mais opções pode ser baixada em www.fusioncharts.com . Neste artigo, usamos a versão gratuita para criar os gráficos.

A instalação do FusionCharts implica apenas em copiar e colar o SWF e os arquivos .rb do pacote de download para a pasta apropriada na aplicação. Os arquivos .rb estão presentes na pasta: Pacote de Download > Code > RoR > Libraries.

•  Ruby 1.8.6 ou superior:

Disponível em http://www.rubyonrails.org/down

•  Rails gem 2.0.2 ou superior:

Com o RubyGems carregado, você pode instalar o Rails e suas dependências pela linha de comando:

   gem install rails

O Rails também pode ser baixado como pacote stand-alone aqui .

• MySQL 4.0 ou superior:

Pode ser baixado aqui .

A aplicação de exemplo desenvolvida para este artigo é uma aplicação time tracker básica. Esta é uma aplicação simples onde um funcionário preenche o tempo para uma semana e vê o gráfico baseado nas horas inputadas. Este artigo discutirá a aplicação de exemplo em duas partes. A primeira parte trata com o desenvolvimento da aplicação básica que inclui listar, editar, mostrar e destruir para employees e timesheets. Se você já tem uma aplicação em que você tem que integrar gráficos, então você pode pular esta parte e ir para a próxima parte, que explica a integração de gráficos com a aplicação. O artigo espera que o leitor tenha um conhecimento básico de Ruby on Rails.

Criando a Aplicação time tracker básica

Usando scaffold, a funcionalidade básica de listar, mostrar, editar e deletar para employees e timesheets pode ser gerado. Os comandos básicos para gerar os controllers employee e timesheet são os seguintes: (executar os dois últimos comandos dentro da pasta TimeTrackerApplication criada com o primeiro comando)

rails –d mysql TimeTrackerApplication
ruby script/generate scaffold Employee name:text
ruby script/generate scaffold Timesheet log_date:datetime hours_spent:integer employee_id:integer

Em seguida, você deve modificar o database.yml presente na pasta de configuração para apontar para “timetrackerdb” e as entradas do username e password corresponde à seu database. Então, você deve executar os seguintes comandos rake para criar o database,

rake db:create
rake db:migrate

Afim de estabelecar o relacionamento (foreign key) entre tabelas employees e timesheets, você deve executar a seguinte query em sua instância do mysql:

alter table timesheets add constraint fk_employee_id foreign key fk_employee_id(employee_id) references employees(id) on delete cascade 

Evidentemente, que há outras maneiras de criar foreign keys; uma discussão do que está além do escopo deste artigo. Para representar o relacionamento (foreign key) acima em Ruby on Rails, você terá que criar uma associação entre os modelos.

No modelo Employee, depois da declaração da classe, escreva o seguinte:

has_many :timesheets 

E no modelo Timesheet você precisa escrever:

belongs_to :employee 

Para inserir os valores do exemplo em seu database, você precisa executar o script sql db/sampledata.sql. A aplicação básica está pronta. Você pode adicionar, visualizar, editar ou deletar employees.

Integrar Gráficos na Aplicação

Com a aplicação time tracker básica no lugar, aqui está o que é necessário para gerar os gráficos de time tracker para um employee:

•  Copiar a pasta FusionCharts disponível no download do FusionCharts Free/Pro
   (Download Package > Code > FusionCharts), para a pasta public do TimeTrackerApplication.

•  Copiar o arquivo FusionCharts.js presente na pasta Download Package > Code > FusionCharts
    para a pasta public/javascripts.

•  Copiar o fusioncharts_helper.rb da pasta Download Package > Code > RoR > Libraries
    para a pasta lib do TimeTrackerApplication.

Isso completa a configuração do FusionCharts.

A partir da página de listagem de employees, um link para o Gráfico Time Tracker precisar ser criado. Assim, para cada employee, haverá um link paragem visualizar seu tempo como um gráfico. O link para o gráfico time tracker é criado no arquivo app/views/employees/index.html.erb. A listagem 1 mostra os detalhes do link adicionado. Adicione este link e depois outros links na página.

Listagem 1

 <%= link_to 'Time Chart', {:action=>'view_timesheet_chart',:id=>employee.id} %>

A figura 1 ilustra a página de listagem de employees da aplicação. As características vistas na Figura 1 foram obtidas facilmente através de configuração de database e ruby scaffold como já visto no artigo. Esta página pode ser visualizada acessando o endereço "http://yourserver:port/employees". A parte pertinente desta tela é mostrada na Figura 1.

Figura 1

A action invocada clicando sobre este link "Time Chart" é a ação view_timesheet_chart do controller employees. A Listagem 2 mostra o código para esta ação. Está ação renderiza o gráfico para o employee selecionado. A ação contata o modelo Employee para achar os timesheets para este employee dentro do período de "2008-12-01" à "2008-12-07" e em seguida renderiza o "view_timelog_chart.html.erb". Para manter as coisas simples, o date range foi fixado no controller. Na aplicação do mundo real, o date range para gerar o relatório / gráfico deverá ser selacionado pelo usuário.

Listagem 2

EmployeesController

  def view_timesheet_chart
    start_date= "2008-12-01"
    end_date="2008-12-07"
    @employee_id = params[:id]
    employee_details_with_timesheets =  Employee.find_with_timesheets_in_date_range(@employee_id,start_date,end_date)
    if(!employee_details_with_timesheets.nil?)
        @employee_details_with_timesheets =employee_details_with_timesheets[0]
    else
      @employee_details_with_timesheets =nil;
    end
    headers["content-type"]="text/html"

end

Usando o employee id como parâmetro, esta action contata o modelo Employee para achar os timesheets para este employee dentro do período especificado. A função a ser adicionada na classe Employee é mostrada na Listagem 3 abaixo:

Listagem 3

Employee.rb

def self.find_with_timesheets_in_date_range(id, start_date, end_date)
    conditions="employees.id =? and log_date between ? and ?"
    employee_details_with_timesheets=self.find(:all, :include=>'timesheets', :conditions=> [conditions,id,start_date,end_date], :order=>'log_date asc')
    return employee_details_with_timesheets
end

A action finalmente renderiza "view_time_chart.html.erb". A template "view_timelog_chart.html.erb" usa o layout "employees.html.erb" que é comum a todas as views do controller de employees. Assim, o código na view é curto e doce como visto na Listagem 4.

Listagem 4

view_timesheet_chart.html.erb (in app/views/employees folder)

<%= javascript_include_tag "FusionCharts"%>

<%
# O xml é obtido como uma string do builder template.
str_xml = render "employees/timesheet_data"
#Criar o Gráfico - Coluna 3D Chart com dados do strXML
render_chart '/FusionCharts/Column3D.swf' , '' , str_xml , 'TimeChart' ,  650 ,  400 ,  false ,  false do -%>
<%  end -%> 

A partir do código acima, entendemos o seguinte como sendo os passos envolvidos para renderizar um gráfico na página view:

  1. Incluir o arquivo FusionCharts.js.
  2. Obter os dados xml do builder. ( O builder usa os dados da action do controller para a contrução do xml)
  3. Renderizar o gráfico chamando a função render_chart com os parâmetros apropriados

Normalmente, o tempo é representado em um gráfico Gantt e este gráfico também está diponível no FusionCharts. Aqui, para sermos mais simples, o gráfico de Coluna foi usado.

O segundo passo envolve a criação do xml. FusionCharts uses XML (eXtensible Markup Language) para criar e manipular gráficos. O gráfico todo do FusionCharts é controlado por parâmetros XML. Você usa XML para definir a aparência e as propriedades funcionais para o gráfico. Há muitas propriedades que você pode definir para cada tipo de gráfico. FusionCharts tem uma estrutura XML específica para cada gráfico. O gráfico em discussão é um gráfico de uma única série (com apenas um conjunto de dados), representando o dia da semana e o número de horas gastadas pelo empregado nesse dia. Um xml de exemplo para este gráfico é mostrado na Listagem 5.

Listagem 5

Sample Single-Series Chart XML












Para gerar um xml semelhante ao mostrado na Listagem 5 mas com o dado presente no database, o arquivo builder é usado.

Como é que o builder contrói o gráfico xml? O builder constrói o xml para o gráfico usando a variável @employee_details_with_timesheets armazenada na action. A Listagem 6 mostra o conteúdo do arquivo builder.

Listagem 6

timesheet_data.builder (na pasta app/views/employees)

xml = Builder::XmlMarkup.new(:indent=>0)
options = {
 :caption=>'Time Tracker Chart',
 :subcaption=>'For Employee '+ @employee_details_with_timesheets.name   ,
 :yAxisName=>'Hours Spent',
 :xAxisName=>'Day',
 :showValues=>'1',
 :formatNumberScale=>'0',
 :numberSuffix=>' hrs.'
}
xml.graph(options) do
  for timesheet in @employee_details_with_timesheets.timesheets do
     log_day = timesheet.log_date.strftime('%a')
     xml.set(:name=>log_day,:value=>timesheet.hours_spent,:color=>''+get_FC_color)
  end
end

No builder, você deve primeiro criar um novo objeto XMLMarkup com o valor para "indent" igual a zero e usar este objeto para a contrução do xml.

Todas as opções requeridas para a configuração do gráfico está presente em um hash chamado options, que é passado para a alta tag acima (graph). Para obter detalhes das opções que podem ser passadas para o gráfico, por favor consulte a documentação completa do FusionCharts. O elemento xml raiz é "graph". Dentro deste, existe um elemento "set" correspondente a cada timesheet do employee selecionado. Cada elemento “set” tem nome e valor como atributos. O nome deve conter o dia da semana e o valor conterá as horas gastas pelo employee neste dia. O builder usa a variável @employee_details_with_timesheets da action do controller, para obter estes valores.

Finalmente, na página view, o gráfico é renderizado usando o método render_chart que recebe o nome do arquivo swf do gráfico, a url, o xml, largura (width), altura (height), debugMode e registerWithJS como parâmetros. Esta função está diponível no módulo fusioncharts_helper presente na pasta lib. Isto pode ser acessado de todas as views incluindo o application_helper.rb como mostrado na Listagem 7.

Listagem 7

application_helper.rb

require 'fusioncharts_helper'
include FusionChartsHelper 

Os arquivos swf necessários para mostrar os gráficos estão presentes na pasta public/FusionCharts. Aqui o Column3D.swf foi utilizado mas qualquer outro tipo de gráfico de série única poderia ser gerado apenas mudando o nome do arquivo swf. Os dados foram fornecidos usando o método dataXML mas os dados tembém podem ser fornecidos através de um dataURL. Exemplos disto estão presentes na documentação do FusionCharts.

Agora, clicando no link "Time Chart" para um employee na página de listagem de employees, os registros de tempo para a semana 01/12/2008 à 07/12/2008 são apresentados na forma de um gráfico. O gráfico de timesheet será semelhante ao da Figura 2 mostrada abaixo.

Figura 2

Sumário das etapas para gerar um gráfico:

Após a configuração do FusionCharts na aplicação e inclusão do FusionChartsHelper no application_helper.rb, os passos são os seguitens:

  1. Na action do controller, busque os dados necessários para o gráfico no database.
  2. Escreva um builder para construir o xml do gráfico a partir destes dados.
  3. Na view referente à action do controller do passo 1, obter o xml a partir do builder, passando os dados para ele ou deixando o builder usar os dados a partir da action do controller.
  4. Em seguida, chamar a função render_chart com parâmetros apropriados (incluindo o xml obtido no passo 3)

Neste artigo, você aprendeu como criar um gráfico simples usando FusionCharts em Ruby on Rails através da aplicação time tracker. Com algumas modificações para a aplicação de exemplo, você pode criar um gráfico com um overview de tempo para todas os employees. Provavelmente, a partir deste gráfico você pode entrar nos datelhes de um determinado employee para obter os detalhes de tempo para ele. Você pode usar Ajax para mostrar o gráfico. As possibilidades são inúmeras. O download do FusionCharts contém vários exemplos que podem ser explorados. A aplicação de exemplo deste artigo está disponível para download aqui.

Sobre o Autor:

O autor é um consultor com mais de 6 anos de experiência na indústria de TI e tem interesse em uma variedade de tecnologias web, envolvendo J2EE, Ruby On Rails & PHP.

Olá visitante

Você precisa cadastrar-se no InfoQ Brasil ou para enviar comentários. Há muitas vantagens em se cadastrar.

Obtenha o máximo da experiência do InfoQ Brasil.

Dê sua opinião

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber mensagens dessa discussão

Flex? by Rodrigo Pereira Fraga

Esqueceram de colocar o Flex como solução para gráficos.
Poderia utilizar comunicando via Http, WebServices, RemoteObject...

Essa é da versão 2.0, mas dá para ver o que é possível fazer com os gráficos:
demo.quietlyscheming.com/ChartSampler/app.html

Erros by Eduardo Vasconcelos

Esse tutorial possui alguns erros. Vc deve corrigi-los. Coloquei um exemplo abaixo com as modificações. Relação entre Cliente e Pedido.
* No Controller *
def view_pedido_chart
start_date= "2009-01-01"
end_date="2009-10-27"
@cliente_id = params[:id]
cliente_details_with_pedidos = Cliente.find_with_pedidos_in_date_range(@cliente_id,start_date,end_date)
if(!cliente_details_with_pedidos.nil?)
@cliente_details_with_pedidos = cliente_details_with_pedidos[0]
else
@cliente_details_with_pedidos = nil;
end
headers["content-type"]="text/html"
end

*Cliente*

def self.find_with_pedidos_in_date_range(id, start_date, end_date)
conditions="pedidos.cliente_id =? and pedidos.data_pedido between ? and ?"
cliente_details_with_pedidos = self.find(:all, :include => 'pedidos',:conditions=> [conditions,id,start_date,end_date], :order=>'data_pedido asc')
return cliente_details_with_pedidos
end

*Builder do XML*

xml = Builder::XmlMarkup.new(:indent=>0)
options = {
:caption=>'Gasto do Cliente',
:subcaption=>'Cliente '+ @cliente_details_with_pedidos.nome,
:yAxisName=>'Valor Gasto',
:xAxisName=>'Dia',
:showValues=>'1',
:formatNumberScale=>'0',
:numberSuffix=>' reais'
}
xml.graph(options) do
for pedido in @cliente_details_with_pedidos.pedidos do
data_pedido = pedido.data_pedido.strftime('%a')
xml.set(:name=>data_pedido,:value=>pedido.valor_total,:color=>'blue')
end
end

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber mensagens dessa discussão

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber mensagens dessa discussão

2 Dê sua opinião

Conteúdo educacional

Feedback geral
Bugs
Publicidade
Editorial
InfoQ Brasil e todo o seu conteúdo: todos os direitos reservados. © 2006-2014 C4Media Inc.
Política de privacidade
BT