Gráfico nas Plataformas de Dispositivo Móvel
As tecnologias de dispositivo móvel geram um grande interesse e é muito fácil ver por quê. A capacidade dos telefones celulares modernos compete com os desktops de alguns poucos anos atrás. O que tenho no bolso é um dual core! Aliás, o quesito “chamada de voz” dos telefones está praticamente em segundo plano nos dias de hoje. O navegador e aplicativos da Web é o que está em voga, e com as ferramentas como jQuery Mobile, é possível agregar facilmente um aspecto adequado para dispositivo móvel ao seu aplicativo.
Neste artigo, eu uso uma combinação de PHP e XML no backend; e jQuery, jQuery Mobile e jqPlot no front-end; para criar um aplicativo de pesquisa altamente interativo. No aplicativo de exemplo concluído, o administrador do site pode criar novas questões de pesquisa com respostas associadas. No front-end, os usuários podem navegar por uma lista de pesquisas, votar na que resposta considerarem melhor e ver um gráfico de resultados. Você ficará impressionado com a capacidade dos dispositivos móveis de hoje em dia e é possível escrever facilmente aplicativos para eles usando ferramentas de prateleira.
Primeiro, você escreverá o backend, em seguida, trabalhará no front-end do aplicativo.
Para desenvolver o backend, inicie com a definição do modelo de dados do banco de dados MySQL. A Listagem 1 mostra o código para criar as duas tabelas que comandam o aplicativo.
Listagem 1. db.sql
DROP TABLE IF EXISTS polls; CREATE TABLE polls( id INT NOT NULL AUTO_INCREMENT, question TEXT NOT NULL, primary key ( id ) ); DROP TABLE IF EXISTS answers; CREATE TABLE answers( id INT NOT NULL AUTO_INCREMENT, poll INT NOT NULL, answer TEXT NOT NULL, count INT, primary key ( id ) ); |
A primeira tabela, polls, mantém as diferentes pesquisas, cada uma contendo uma questão. A segunda tabela, answers,
mantém as respostas para cada questão da pesquisa, usando o campo poll para gerenciar a relação e o valor de contagem com o número atual de votos para essa resposta.
Esse não é realmente um esquema de aplicativo de pesquisa digno de produção. Um modelo digno de produção deve incluir uma tabela de votação usada para rastrear os votos aos usuários de modo que cada pessoa vote apenas uma vez. Como a exatidão da pesquisa não é a preocupação primária deste artigo, eu deixo a seu encargo fazer essas modificações se realmente desejar criar um aplicativo de pesquisa.
Para criar o banco de dados, primeiro use mysqladmin para criá-lo e, em seguida, use o comando mysql para executar o script db.sql como mostrado aqui:
% mysqladmin --user=root --password=foo create polls % mysql --user=root --password=foo polls < db.sql |
Com o banco de dados criado, é hora de criar a página PHP de modo que seja possível incluir novas pesquisas no banco de dados. A Listagem 2 mostra o código para a página create.php.
Listagem 2. create.php
<?php
function add_answer( $db, $qid, $answer ) {
$sql = 'INSERT INTO answers VALUES ( 0, ?, ?, 0 )';
$sth = $db->prepare($sql);
$sth->execute( array( $qid, $answer ) );
}
$dd = new PDO('mysql:host=localhost;dbname=polls', 'root', '');
if ( isset( $_POST['question'] ) ) {
$sql = 'INSERT INTO polls VALUES ( 0, ? )';
$sth = $dd->prepare($sql);
$sth->execute( array( $_POST['question'] ) );
$qid = $dd->lastInsertId();
if ( isset( $_POST['a1'] ) && strlen( $_POST['a1'] ) > 0 )
add_answer( $dd, $qid, $_POST['a1'] );
if ( isset( $_POST['a2'] ) && strlen( $_POST['a2'] ) > 0 )
add_answer( $dd, $qid, $_POST['a2'] );
if ( isset( $_POST['a3'] ) && strlen( $_POST['a3'] ) > 0 )
add_answer( $dd, $qid, $_POST['a3'] );
if ( isset( $_POST['a4'] ) && strlen( $_POST['a4'] ) > 0 )
add_answer( $dd, $qid, $_POST['a4'] );
if ( isset( $_POST['a5'] ) && strlen( $_POST['a5'] ) > 0 )
add_answer( $dd, $qid, $_POST['a5'] );
}
?>
<html>
<body>
<form method="post">
<table>
<tr><th>Question</td><th><input type="text" name="question" /></td></tr>
<tr><th>Answer 1</th><td><input type="text" name="a1" /></td></tr>
<tr><th>Answer 2</th><td><input type="text" name="a2" /></td></tr>
<tr><th>Answer 3</th><td><input type="text" name="a3" /></td></tr>
<tr><th>Answer 4</th><td><input type="text" name="a4" /></td></tr>
<tr><th>Answer 5</th><td><input type="text" name="a5" /></td></tr>
</table>
<input type="submit" value="Add Question" />
</form>
</body>
</html>
|
No alto do script, está o código PHP que incluirá a questão em sua resposta no banco
de dados, se o formulário for postado. A primeira coisa que o código PHP faz é
conectar-se ao banco de dados. Em seguida, ele faz uma verificação para confirmar se uma questão foi postada. Em caso afirmativo, ele primeiro insere um novo registro na
tabela polls e obtém de volta seu ID exclusivo. Depois disso, ele inclui cada
resposta usando a função add_answer definida bem no início
do script. Essa função add_answer simplesmente inclui um
novo registro na tabela de respostas com a resposta e o ID exclusivo de sua pesquisa
relacionada.
Na parte inferior do arquivo PHP, está o código HTML do formulário. A tag do formulário envia os valores no formulário de volta ao script quando um usuário seleciona o botão submit.
A Figura 1 mostra como isso se parece no navegador.
Figura 1. Adicionando uma Questão de Pesquisa
A Figura 1 mostra um formulário da Web muito simples que tem seis campos de entrada. O primeiro é a questão, seguido por cinco entradas de resposta. Na parte inferior, está o botão Add Question para incluir a questão no banco de dados.
Quando você clica em Add Question, o programa inclui o registro no banco de dados e retorna o formulário novamente para você com os valores em branco de modo que seja possível incluir outra questão. Para ver realmente as pesquisas disponíveis, é necessário um novo script. O script polls.php, na Listagem 3, retorna um bloco XML que lista as pesquisas disponíveis no momento.
Listagem 3. polls.php
<?php
header( 'Content-Type:text/xml' );
$dbh = new PDO('mysql:host=localhost;dbname=polls', 'root', '');
$sql = 'SELECT * FROM polls';
$q = $dbh->prepare( $sql );
$q->execute( array() );
$doc = new DOMDocument();
$r = $doc->createElement( "polls" );
$doc->appendChild( $r );
foreach ( $q->fetchAll() as $row) {
$e = $doc->createElement( "poll" );
$e->setAttribute( 'id', $row['id'] );
$e->setAttribute( 'question', $row['question'] );
$r->appendChild( $e );
}
print $doc->saveXML();
?>
|
Primeiro, o script se conecta ao banco de dados e executa uma consulta SELECT na tabela polls. O script, então, cria um novo documento XML DOM, inclui uma tag "polls" na raiz e inclui tags "poll" individuais nele para cada pesquisa. Cada tag poll tem o ID exclusivo da pesquisa e o texto da questão.
Para testar a página, simplesmente navegue até ela no navegador e selecione View
Source para ver o que é retornado. Outra opção é usar curl para obter o retorno XML como anotado aqui:
$ curl "http://localhost/poll/polls.php" <?xml version="1.0"?> <polls><poll id="1" question="Is jQuery great?"/></polls> $ |
O front-end acessa esse script usando uma solicitação Ajax.
Os próximos três scripts tratam as respostas como parte das pesquisas. Para tornar
isso mais fácil, crie uma função auxiliar denominada build_answers que,
dada uma manipulação de banco de dados e um ID de pesquisa, resulte no XML para
todas as respostas para essa pesquisa (consulte Listagem 4).
Listagem 4. build_answers.php
<?php
function build_answers( $dbh, $poll ) {
$sql = 'SELECT * FROM answers WHERE poll=?';
$q = $dbh->prepare( $sql );
$q->execute( array( $poll) );
$doc = new DOMDocument();
$r = $doc->createElement( "answers" );
$doc->appendChild( $r );
foreach ( $q->fetchAll() as $row) {
$e = $doc->createElement( "answer" );
$e->setAttribute( 'id', $row['id'] );
$e->setAttribute( 'answer', $row['answer'] );
$e->setAttribute( 'count', $row['count'] );
$r->appendChild( $e );
}
print $doc->saveXML();
}
?>
|
A função build_answers primeiro usa a conexão de banco de dados para consulta SQL, a fim de obter respostas para a pesquisa especificada. Depois disso, ela usa o código XML DOM para criar umas novas saídas XML com uma tag "answer" para cada uma das respostas da pesquisa. Cada resposta tem seu IDexclusivo, o texto da resposta e a contagem dos votos para essa resposta.
Para ligar isso a uma página, você precisa de um script answers.php como na Listagem 5.
Listagem 5. answers.php
<?php
require_once( 'build_answers.php' );
header( 'Content-Type:text/xml' );
$dbh = new PDO('mysql:host=localhost;dbname=polls', 'root', '');
build_answers( $dbh, $_REQUEST['id'] );
?>
|
Esse script simples conecta-se ao banco de dados e envia o ID do desafio na função build_answers.
Abaixo está um exemplo de uma solicitação para esse script:
$ curl "http://localhost/poll/answers.php?id=1"
<?xml version="1.0"?>
<answers>
<answer id="1" answer="Yep, awesome!" count="7"/>
<answer id="2" answer="It's pretty good." count="2"/>
<answer id="3" answer="It's ok." count="1"/>
<answer id="4" answer="Nah, it's not so hot." count="1"/>
</answers>
$
|
A etapa final na criação do serviço é criar uma página Ajax que leve em consideração a votação. a Listagem 6 mostra esse script.
Listagem 6. vote.php
<?php
require_once( 'build_answers.php' );
header( 'Content-Type:text/xml' );
$poll = 0;
$dd = new PDO('mysql:host=localhost;dbname=polls', 'root', '');
if ( isset( $_REQUEST['id'] ) ) {
$sth = $dd->prepare("SELECT count, poll FROM answers WHERE id=?");
$sth->execute( array( $_REQUEST['id'] ) );
$count = 0;
foreach ( $sth->fetchAll() as $row) {
$count = $row['count'];
$poll = $row['poll'];
}
$count++;
$sql = 'UPDATE answers SET count=? WHERE id=?';
$sth = $dd->prepare($sql);
$sth->execute( array( $count, $_REQUEST['id'] ) );
}
build_answers( $dd, $poll );
?>
|
A diferença entre esse script e a página answers.php é que você primeiro localiza a
contagem da resposta especificada, em seguida, a incrementa e atualiza o registro da
resposta no banco de dados. Além disso, quando o script localiza a resposta, ela
armazena o ID exclusivo da pesquisa relacionada na variável
$poll. Esse ID de pesquisa é enviado a build_answers para gerar o conjunto atual de respostas.
A importância da exportação do estado atual das respostas é que ele permite votar e obter os resultados atuais da pesquisa, tudo em uma única etapa. Como a alternativa é fazer primeiro o voto e, em seguida, a solicitação de respostas para obter a contagem de voto atual, e tudo isso em uma única etapa, fazer o script de voto para retornar uma lista das contagens de resposta atuais é definitivamente excelente.
Com os scripts do backend concluídos, é o momento de começar os scripts do front-end.
As interfaces de dispositivo móvel são muito diferentes das páginas da Web tradicionais. O número de opções é reduzido e as opções disponíveis e botões são maiores de modo que seja fácil navegar usando o polegar. Agora, você pode gastar muito tempo criando todas essas coisas sozinho, mas por que fazer isso quando existe o jQuery Mobile? O jQuery Mobile é um kit de ferramentas de interface com o usuário desenvolvido sobre a biblioteca jQuery JavaScript extremamente popular.
A interface é criada em três "páginas" dentro de uma página da Web. A primeira página tem a lista de questões. Quando o usuário seleciona uma questão, a página desliza para esquerda para mostrar a segunda página, que exibe uma lista de respostas para a questão selecionada. Quando os usuários selecionam uma resposta, a página desliza para a esquerda e a terceira página aparece. A terceira página exibe um gráfico que mostra os resultados para a pesquisa selecionada. Para desenvolver um gráfico, use a excelente biblioteca jqPlot, que também é criada em jQuery.
A Listagem 7 mostra o código para tudo isso.
Listagem 7. index.html
<html><head>
<link rel="stylesheet" href="css/jquery.mobile-1.0a4.1.css" />
<link rel="stylesheet" type="text/css" href="css/jquery.jqplot.css" />
<script src="js/jquery-1.6.1.min.js"></script>
<script src="js/jquery.mobile-1.0a4.1.js"></script>
<script language="javascript" type="text/javascript"
src="js/jquery.jqplot.js"></script>
<script language="javascript" type="text/javascript"
src="js/plugins/jqplot.donutRenderer.js"></script>
<script type="text/javascript">
function plotData( data ) {
ds = [];
$(data).find('answer').each( function() {
ds.push( [ $(this).attr('answer'), parseInt( $(this).attr('count') ) ] );
} );
$.jqplot('chart1', [ds], {
seriesDefaults:{
renderer:$.jqplot.DonutRenderer
},
legend: {show:true}
});
}
function vote( poll, answer ) {
$.ajax( { url: 'vote.php',
data:{id:answer},
success:function( data ) {
plotData( data );
}
});
}
function openPoll( poll ) {
$.ajax( { url: 'answers.php',
data:{id:poll},
success:function( data ) {
$(data).find('answer').each( function() {
var name = $(this).attr('answer');
var id = $(this).attr('id');
$('#answer-list').append(
'<li><a href="#results" poll="'+poll+'" answer="'+id+'"
class="answer">'+name+'</a></li>'
);
} );
$('.answer').click(function(e) {
vote( $(this).attr('poll'),
$(this).attr('answer') );
})
$('ul').listview('refresh');
}
});
}
$(document).ready(function(){
$.jqplot.config.enablePlugins = true;
$.ajax( { url: 'polls.php',
success:function( data ) {
$(data).find('poll').each( function() {
var name = $(this).attr('question');
var id = $(this).attr('id');
$('#poll-list').append(
'<li><a href="#answers" pollid="'+id+'" class="poll">'+name+'</a></li>'
);
});
$('.poll').click(function(e) {
openPoll( $(this).attr('pollid') );
})
$('ul').listview('refresh');
}
});
});
</script>
</head><body>
<div data-role="page" id="home">
<div data-role="header"><h1>Poll Central</h1></div>
<div data-role="content">
<ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b"
id="poll-list">
</ul>
<div id="chart0" class="plot" style="width:400px;height:280px;"></div>
</div>
</div>
<div data-role="page" id="answers">
<div data-role="header">
<h1 id="poll-question">Question</h1>
</div>
<div data-role="content">
<ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b"
id="answer-list">
</ul>
</div>
</div>
<div data-role="page" id="results">
<div data-role="header">
<h1>Results</h1>
</div>
<div data-role="content">
<div data-role="collapsible">
<h3>Results Graph</h3>
<p>
<div class="jqPlot" id="chart1" style="height:320px; width:480px;"></div>
</p>
</div>
<a href="#home" data-role="button">Start Again</a>
</div>
</div>
</body></html>
|
Isso é um monte de código, mas se você pensar que são três páginas diferentes em uma única página, é um pouco mais fácil de acompanhar. Começa com a página inicial, que é definida no início da tag body. A tag de lista ul na página inicial é preenchida pela solicitação Ajax, que é executada quando o documento está pronto. Essa solicitação Ajax chama o script polls.php que retorna algum XML, que é então analisado e transformado nas tags li, que são incluídas na tag ul.
Quando o usuário clica em um item da lista de pesquisa na página inicial, a página de resposta é exibida.
Em seguida, a função openPoll é chamada, o que preenche a tag li na página de respostas usando a mesma técnica feita na página inicial.
Quando uma resposta é selecionada, o script vote.php é chamado no método vote . Quando o método Ajax retorna, a função plotData é chamada, que usa a biblioteca jqPlot para desenvolver o "gráfico de rosca" com os resultados.
Veja como isso aparece na produção. A Figura 2 mostra a página inicial.
Figura 2. A tela inicial
A Figura 2 mostra uma página adequada para dispositivo móvel com um botão de lista para cada uma das pesquisas disponíveis. Nesse caso, contudo, há apenas uma única pesquisa, de modo que haja apenas um único botão. Quando você clica no botão, você vê a página de respostas como mostrado na Figura 3.
Figura 3. A Página de Respostas
A Figura 3 mostra a lista de respostas para essa pesquisa. A página também inclui um botão back, para que o usuário retorne à página inicial. O jQuery Mobile toma conta de tudo isso para você, para que você possa se concentrar no aplicativo.
Clique em uma resposta para registrar um voto e visualizar um gráfico de resultados, como na Figura 4.
Figura 4. Os Primeiros Resultados
A Figura 4 mostra um gráfico que se parece notavelmente como uma rosca. Com apenas um único voto, você vê apenas o único elemento na série de dados. Para incluir alguns votos a mais, clique no botão back e vote várias vezes. Você pode ver o resultado na Figura 5.
Figura 5. Depois que Mais Votos Foram Incluídos
Isso se parece muito melhor! Cada questão ocupa uma proporção do gráfico relativo a seu total de votos.
Os dispositivos móveis são o futuro? Se não forem, certamente, eles fazem uma grande parte dele. iPhones, iPads, telefones Android e tablets são vendidos amplamente. As pessoas desejam um dispositivo conveniente que lhes proporcione acesso a aplicativos on-line que sejam operáveis com o polegar e fáceis de usar. Do ponto de vista de desenvolvimento, o problema é fazer o esforço de desenvolver várias versões da interface com o usuário desses dispositivos. Bibliotecas como jQuery e jQuery Mobile tornam extremamente fácil criar interfaces com o usuário que funcionem no ambiente de dispositivo móvel.
Aprender
- The jQuery library: Visite este Web site excelente que documenta todos os recursos e extensões disponíveis para jQuery.
- jqPlot: Confira os gráficos de rosca—apenas o início de um intervalo surpreendente de opções de visualização disponíveis.
- jQuery Mobile: Descubra quão fácil é criar aplicativos da Web bonitos e funcionais para dispositivo móvel.
- O PHP : explore a melhor referência para PHP que está disponível.
- O W3C: Visite um ótimo site sobre padrões, em particular o padrão XML é relevante para este artigo.
- Mais conteúdo do jQuery Mobile no developerWorks: Saiba mais sobre a tecnologia jQuery Mobile.
- Mais artigos desse autor (Jack Herrington, developerWorks, março de 2005-hoje): Leia artigos sobre Ajax, JSON, PHP, XML e outras tecnologias.
- Iniciante em XML? Obtenha os recursos necessários para aprender XML.
- Área de XML do developerWorks: localize os recursos necessários para avançar em conhecimentos na arena XML, incluindo
DTDs, esquemas e XSLT. Consulte a Biblioteca técnica de XML para obter um intervalo amplo de artigos técnicos e dicas, tutoriais, padrões e IBM Redbooks.
- Certificação XML da IBM: Descubra como se tornar um Desenvolvedor Certificado pela IBM em XML e tecnologias relacionadas.
- eventos técnicos e webcasts do developerWorks: Mantenha-se atualizado em relação à tecnologia nessas sessões.
- developerWorks no Twitter: Inscreva-se hoje para seguir os tweets do developerWorks.
- Podcasts do developerWorks: Ouça entrevistas e discussões interessantes para desenvolvedores de software.
- Demos on demand do developerWorks: Acompanhe demos que abrangem desde a instalação de produto e configuração para iniciantes até funcionalidade avançada para desenvolvedores experientes.
Obter produtos e tecnologias
- Versões de avaliação de produtos IBM: Faça o download ou explore as versões de teste on-line no IBM SOA Sandbox e entre em contato com as ferramentas de desenvolvimento de aplicativos e produtos de middleware do DB2®, Lotus®, Rational®, Tivoli®e WebSphere®.
Discutir
- Fóruns de discussão da zona de XML: Participe de qualquer uma das várias discussões relacionadas a XML.
- A comunidade do developerWorks: Entre em contato com outros usuários do developerWorks e explore os blogs, fóruns, grupos e wikis voltados para desenvolvedores.
