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

Desarrolle aplicaciones online que sean de pulgar y fáciles de usar para el entorno móvil con PHP, XML, jQuery, jQuery mobile y jQuery charting. En este artículo, construya el fondo y la parte frontal de una aplicación de sondeo que use gráficos para mostrar los resultados de cada sondeo.

03 de octubre de 2011 - En Acrónimos de uso frecuente, para el término HTTP, se sustituyó la definición incorrecta de "Hypertext Markup Language" con la definición correcta de "Hypertext Transfer Protocol".

Jack D. Herrington, Senior Software Engineer, Leverage Software Inc.

Photo of Jack HerringtonJack Herrington es un ingeniero, autor y presentador que vive y trabaja en el Área de la Bahía. Puede mantenerse al tanto de su trabajo y sus escritos en http://jackherrington.com.



26-03-2012

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.

Acrónimos de uso frecuente

  • Ajax: Asynchronous JavaScript + XML
  • DOM: Document Object Model
  • HTTP: Hypertext Transfer Protocol
  • SQL: Structured Query Language
  • XML: Extensible Markup Language

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

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

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

¡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

Aprender

  • La biblioteca jQuery: Visite este excelente website que documenta todos los dispositivos y las extensiones disponibles para jQuery.
  • jqPlot: Vea gráficos de dona—simplemente el inicio de una gama increíble de opciones de visualización disponible.
  • jQuery Mobile: Descubra lo fácil que puede construir aplicaciones web móviles hermosas y funcionales.
  • El sitio de PHP : Explore la mejor referencia para PHP que hay disponible.
  • El sitio de W3C: Visite un gran sitio para estándares, en particular el estándar de XML es relevante para este artículo.
  • Más contenido de jQuery Mobile en developerWorks: Aprenda más sobre la tecnología de jQuery Mobile.
  • Más artículos de este autor (Jack Herrington, developerWorks, marzo de 2005 a la fecha): Lea artículos sobre Ajax, JSON, PHP, XML y otras tecnologías.
  • ¿Nuevo en XML? Obtenga los recursos que necesita para aprender XML.
  • Área XML en developerWorks: Encuentre los recursos que necesita para avanzar en sus habilidades en el área de XML, incluyendo DTDs, esquemas y XSLT. Vea la Biblioteca técnica XML para obtener una amplia gama de artículos técnicos y consejos, tutoriales, estándares e IBM Redbooks.
  • Certificación IBM XML: Conozca cómo puede usted convertirse en un Desarrollador Certificado IBM en XML y en tecnologías relacionadas.
  • Eventos técnicos y webcasts de developerWorks: Manténgase actualizado(a) con la tecnología en estas sesiones.
  • developerWorks en Twitter: Únase hoya para seguir los tweets developerWorks.
  • developerWorks podcasts: Escuche interesantes entrevistas y discusiones para desarrolladores de software.
  • Demostraciones on demand de developerWorks: Observe demostraciones que van desde la instalación de productos y demostraciones de configuración para principiantes, hasta funcionalidades avanzadas para desarrolladores experimentados.

Obtener los productos y tecnologías

Comentar

Comentarios

developerWorks: Ingrese

Los campos obligatorios están marcados con un asterisco (*).


¿Necesita un IBM ID?
¿Olvidó su IBM ID?


¿Olvidó su Password?
Cambie su Password

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. La información en su propio perfil (nombre, país/región y nombre de la empresa) se muestra al público y acompañará a cualquier contenido que publique, a menos que opte por la opción de ocultar el nombre de su empresa. Puede actualizar su cuenta de IBM en cualquier momento.

Toda la información enviada es segura.

Elija su nombre para mostrar



La primera vez que inicia sesión en developerWorks se crea un perfil para usted, teniendo que elegir un nombre para mostrar en el mismo. Este nombre acompañará el contenido que usted publique en developerWorks.

Por favor elija un nombre de 3 - 31 caracteres. Su nombre de usuario debe ser único en la comunidad developerWorks y debe ser distinto a su dirección de email por motivos de privacidad.

Los campos obligatorios están marcados con un asterisco (*).

(Por favor elija un nombre de 3 - 31 caracteres.)

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


Toda la información enviada es segura.


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