Añadir gráficos en navegadores móviles

Use PHP, XML, jQuery, jQuery mobile y jQuery charting para crear una hábil aplicación de sondeos móviles interactivos

Comments

Gráficos en plataformas móviles

Las tecnologías móviles generan mucho interés y es fácil ver por qué. El poder de los teléfonos celulares modernos rivaliza con el de los desktops desde hace apenas unos cuantos años. ¡El que tengo en mi bolsillo es dual core! De hecho, el aspecto de "teléfono" de los teléfonos es ahora casi secundario. La navegación web y las aplicaciones están donde se encuentre, y con herramientas como jQuery Mobile puede fácilmente ponerle una apariencia de tipo móvil a su aplicación.

En este artículo, uso una combinación de PHP y XML en el fondo y jQuery, jQuery Mobile y jqPlot en la parte frontal para construir una aplicación de sondeo altamente interactiva. En la aplicación de ejemplo completada, el administrador del sitio puede crear nuevas preguntas de sondeo con respuestas asociadas. En la parte frontal, los usuarios pueden navegar a través de una lista de sondeos, votar sobre qué respuesta les gusta más y ver un gráfico de los resultados. Se sorprenderá con el poder de los dispositivos móviles de hoy y puede escribir fácilmente aplicaciones para ellos con herramientas comerciales.

Primero escribirá el fondo de la aplicación y después avanzará para construir la parte frontal.

Creando los sondeos

Para construir el fondo, inicie por definir el modelo de datos para la base de datos de MySQL. El Listado 1 muestra el código para crear las dos tablas que impulsan la aplicación.

Listado 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 ) );

La primera tabla, polls, aloja los distintos sondeos, cada uno conteniendo una pregunta. La segunda tabla, answers, aloja las respuestas para cada pregunta de sondeo, usando el campo de sondeo para gestionar la relación y un valor de conteo con el número actual de votos para esa respuesta.

Este no es realmente un esquema de aplicación de sondeo que sirva para la producción. Un modelo que sirva para la producción debe incluir una tabla de votos usada para realizar el seguimiento de los votos de los usuarios, de forma que esas personas voten sólo una vez. Ya que la precisión del sondeo no es la principal preocupación de este artículo, dejaré que usted haga esas modificaciones si realmente desea construir una aplicación de sondeo.

Para construir la base de datos, primero use mysqladmin para crearla y después use el comando mysql para ejecutar el script db.sql como se muestra aquí:

% mysqladmin --user=root --password=foo create polls
% mysql --user=root --password=foo polls < db.sql

Con la base de datos creada, es momento de construir la página de PHP, de forma que pueda añadir nuevos sondeos a la base de datos. El Listado 2 muestra el código para la página create.php.

Listado 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>

En la parte superior del script se encuentra el código PHP que añade la pregunta y sus respuestas en la base de datos si el formulario fue publicado. Lo primero que hace el código PHP es conectarse a la base de datos. Entonces verifica si una pregunta fue publicada. Si es así, primero inserta un nuevo registro en la tabla de sondeos y recupera su ID único. Después de eso, añade cada respuesta usando la función add_answer definida en la parte superior del script. Esta función add_answer simplemente añade un nuevo registro en la tabla de respuesta con la respuesta y el ID exclusivo de su sondeo relacionado.

En el fondo del archivo PHP está el código HTML para el formulario. El código del formulario envía los valores en el formulario de regreso al script cuando un usuario selecciona el botón submit.

La Figura 1 muestra cómo se ve esto en el navegador.

Figura 1. Añadiendo una pregunta de sondeo
Añadiendo una pregunta de sondeo
Añadiendo una pregunta de sondeo

La Figura 1 muestra un formulario web muy simple que tiene seis campos de entrada. El primero es la pregunta, seguida por cinco entradas de respuesta. Al fondo está un botón Add Question para añadir la pregunta a la base de datos.

Cuando hace clic en Add Question, el programa añade el registro a la base de datos y retorna el formulario nuevamente a usted con los valores en blanco, de forma que pueda añadir otra pregunta. Para realmente ver los sondeos disponibles, necesita un nuevo script. El script polls.php, en el Listado 3, retorna un bloque de XML que lista los sondeos disponibles actualmente.

Listado 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();
?>

El script primero se conecta a la base de datos y ejecuta una simple consulta SELECT en la tabla de sondeos. Después el script crea un nuevo documento DOM de XML, añade una etiqueta "polls" en la raíz, después añade etiquetas "poll" individuales en ella para cada sondeo. Cada etiqueta de sondeo tiene el ID exclusivo del sondeo y el texto de la pregunta.

Para probar la página, simplemente navegue hacia ella en el navegador y seleccione View Source para ver lo que es retornado. Otra opción es usar curl para obtener el retorno de XML como se muestra a continuación:

$ curl "http://localhost/poll/polls.php"
<?xml version="1.0"?>
<polls><poll id="1" question="Is jQuery great?"/></polls>
$

La parte frontal accede a este script usando una solicitud de Ajax.

Los siguientes tres scripts manejan la parte de las respuestas de los sondeos. Para facilitarse las cosas usted mismo, primero cree una función de ayudante llamada build_answers que, cuando se da un descriptor de contexto de base de datos y un ID de sondeo, da como salida el XML para todas las respuestas para ese sondeo (vea el Listado 4).

Listado 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();
}
?>

La función build_answers primero usa la conexión de base de datos para consulta SQL para obtener las respuestas para el sondeo especificado. Después de eso, usa código DOM de XML para crear una nueva salida de XML con una etiqueta "answers" en la raíz y etiquetas "answer" para cada una de las respuestas de ese sondeo. Cada respuesta tiene su ID exclusivo, el texto de respuesta y el conteo de votos para esa respuesta.

Para enganchar eso en una página, necesita un script answers.php como en el Listado 5.

Listado 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']  );
?>

Este sencillo script se conecta a la base de datos y envía el ID de la búsqueda a la función build_answers .

A continuación se muestra un ejemplo de una solicitud de este 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>
$

La etapa final para construir el servicio es crear una página de Ajax para permitir la votación. El Listado 6 muestra este script.

Listado 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 );
?>

La diferencia entre este script y la página answers.php es que usted primero encuentra el conteo de la respuesta especificada, después lo incrementa y actualiza el registro de respuestas en la base de datos. Además, cuando el script encuentra la respuesta almacena el ID exclusivo del sondeo relacionado en la variable $poll . Ese ID de sondeo es después enviado a build_answers para dar la salida del conjunto actual de respuestas.

La importancia de exportar el estado actual de las respuestas es que permite la votación y obtener los resultados actuales del sondeo, todo en una etapa. Ya que la alternativa es primero hacer el voto y después hacer la solicitud de respuestas para obtener el conteo de votos actual, hacerlo todo en una etapa al hacer que el script de voto retorne una lista de los conteos de respuestas actuales es definitivamente lo óptimo.

Con los scripts de backend completados, es momento de hacer scripts en la parte frontal.

Construyendo la parte frontal

Las interfaces móviles son muy distintas de las páginas web tradicionales. El número de opciones es reducido y las opciones y botones disponibles se hacen más grandes, de forma que es fácil navegar con su pulgar. Ahora podría pasar mucho tiempo construyendo todas las cosas usted mismo, ¿pero por qué hacerlo cuando existe jQuery Mobile? jQuery Mobile es un kit de herramientas de interfaz de usuario construido sobre la extremadamente popular biblioteca de jQuery JavaScript.

La interfaz está construida en tres "páginas" dentro de una página web. La primera página tiene la lista de preguntas. Cuando el usuario selecciona una pregunta, la página se desliza hacia la izquierda para mostrar la segunda página, que muestra una lista de respuestas para la pregunta seleccionada. Después, cuando el usuario selecciona una respuesta, esa página se desliza hacia la izquierda y la tercera página aparece. La tercera página muestra un gráfico que tiene los resultados del sondeo seleccionado. Para construir el gráfico, use la sensacional biblioteca jqPlot, que también está basada en jQuery.

El Listado 7 muestra el código para todo esto.

Listado 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>

Este es mucho código, pero si piensa en él como las tres páginas distintas, todo en una sola página, es un poco más fácil de seguir. Comienza con la página de inicio, que es definida al principio de la etiqueta del cuerpo. La etiqueta de lista ul en la página de inicio es llenada por la solicitud de Ajax, que es ejecutada cuando el documento está listo. La solicitud de Ajax llama al script polls.php que retorna algo de XML, que es después analizado y convertido en etiquetas li , que son añadidas a la etiqueta ul .

Cuando el usuario hace clic en un elemento de lista de sondeos en la página de inicio, la página de respuestas se muestra. Después la función openPoll es llamada, que llena la etiqueta li en la página de respuestas usando la misma técnica realizada en la página de inicio.

Cuando una respuesta es seleccionada, el script vote.php es invocado en el método vote . Cuando el método de Ajax regresa, la función plotData es llamada, la cual usa la biblioteca jqPlot para construir el "gráfico de dona" con los resultados.

Observe cómo aparece esto en producción. La Figura 2 muestra la página de inicio.

Figura 2. La pantalla de inicio
La pantalla de inicio
La pantalla de inicio

La Figura 2 muestra una página de tipo móvil con un botón de lista para cada uno de los sondeos disponibles. En este caso, sin embargo, sólo hay un sondeo, así que sólo hay un botón. Cuando hace clic en el botón ve la página de respuestas como se muestra en la Figura 3.

Figura 3. La página de respuestas
La página de respuestas
La página de respuestas

La Figura 3 muestra la lista de respuestas para este sondeo. La página también incluye un botón de retroceso para que el usuario regrese a la página de inicio. jQuery Mobile se encarga de todo eso por usted, de forma que pueda concentrarse en la aplicación.

Haga clic en una respuesta para registrar un voto y ver el gráfico de resultados, como en la Figura 4.

Figura 4. Los primeros resultados
Los primeros resultados
Los primeros resultados

La Figura 4 muestra un gráfico que se parece bastante a una dona. Con sólo un voto, usted ve el único elemento en la serie de datos. Para añadir algunos votos más, haga clic en el botón de retroceso y vote varias veces más. Después puede ver el resultado en la Figura 5.

Figura 5. Después de que se han añadido más votos
Después de que se han añadido más votos
Después de que se han añadido más votos

¡Eso se ve mucho mejor! Cada pregunta toma una proporción del gráfico relativa a su total de votos.

Conclusión

¿Los dispositivos móviles son el futuro? Si no, ciertamente son una gran parte de él. Los iPhones, iPads y los teléfonos y tablets de Android se están vendiendo ampliamente. Las personas quieren un dispositivo conveniente que les de acceso a las aplicaciones online que sean de pulgar y fáciles de usar. Desde el punto de vista del desarrollo, el problema es hacer el esfuerzo para desarrollar múltiples versiones de la interfaz de usuario para estos dispositivos. Bibliotecas como jQuery y jQuery Mobile hacen extremadamente fácil construir interfaces de usuario que funcionen en el entorno móvil.


Recursos para Descargar


Temas relacionados


Comentarios

Inicie Sesión o Regístrese para agregar comentarios.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=Linux
ArticleID=806598
ArticleTitle=Añadir gráficos en navegadores móviles
publish-date=03262012