Add charting on mobile browsers

Use PHP, XML, jQuery, jQuery mobile, and jQuery charting to create a slick interactive mobile polling application

Develop online applications that are both thumb and user friendly for the mobile environment with PHP, XML, jQuery, jQuery mobile, and jQuery charting. In this article, build the back end and front end of a polling application that uses charting to show the results of each poll.

03 Oct 2011 - In Frequently used acronyms, for term HTTP, replaced the incorrect definition of "Hypertext Markup Language" with the correct definition of "Hypertext Transfer Protocol".

Share:

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

Photo of Jack HerringtonJack Herrington is an engineer, author, and presenter who lives and works in the Bay Area. You can keep up with his work and his writing at http://jackherrington.com.



03 October 2011 (First published 13 September 2011)

Also available in Chinese Russian Japanese Spanish

Charting on mobile platforms

Mobile technologies generate a lot of interest, and it's easy to see why. The power of modern cell phones rivals that of desktops from just a few years back. The one I have in my pocket is dual core! In fact, the "phone" aspect of phones is now almost secondary. Web browsing and applications are where it's at, and with tools like jQuery Mobile you can easily put a mobile-friendly face on your application.

Frequently used acronyms

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

In this article, I use a combination of PHP and XML on the back end and jQuery, jQuery Mobile, and jqPlot on the front end to build a highly interactive polling application. In the completed example application, the administrator of the site can create new poll questions with associated answers. On the front end, users can navigate through a list of polls, vote on which answer they like best, and see a graph of the results. You will be amazed at the power of mobile devices today and easily you can write applications for them with off-the-shelf tools.

You'll first write the back end, then work forward to build the front end of the application.


Creating the polls

To build out the back end, start with defining the data model for the MySQL database. Listing 1 shows the code to create the two tables that drive the application.

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

The first table, polls, holds the different polls, each one containing a question. The second table, answers, holds the answers to each poll question, using the poll field to manage the relation and a count value with the current number of votes for that answer.

This is not really a production-worthy polling application schema. A production-worthy model should include a vote table used to track votes to users so that people vote only once. Because the accuracy of polling isn't the primary concern of this article, I leave it to you to make those modifications if you really want to build a polling application.

To build the database, first use mysqladmin to create it and then use the mysql command to run the db.sql script as shown here:

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

With the database created, it's time to build the PHP page so you can add new polls to the database. Listing 2 shows the code for the create.php page.

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

At the top of the script is the PHP code that adds the question and its answers into the database if the form was posted. The first thing the PHP code does is connect to the database. It then checks to see if a question was posted. If so, it first inserts a new record into the polls table and gets back its unique ID. After that, it adds each answer using the add_answer function defined at the very top of the script. This add_answer function simply adds a new record into the answer table with the answer and the unique ID of its related poll.

At the bottom of the PHP file is the HTML code for the form. The form tag submits the values in the form back to the script when a user selects the submit button.

Figure 1 shows what this looks like in the browser.

Figure 1. Adding a poll question
Screen capture of web form with fields for a quesiton and six answers plus an Add question button

Figure 1 shows a very simple web form that has six input fields. The first is the question, followed by five answer inputs. At the bottom is an Add Question button to add the question to the database.

When you click Add Question, the program adds the record to the database and returns the form again to you with the values blanked out so that you can add another question. To actually see the available polls, you need a new script. The polls.php script, in Listing 3, returns an XML block that lists the currently available polls.

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

The script first connects to the database and runs a simple SELECT query against the polls table. The script then creates a new XML DOM document, adds a "polls" tag at the root, then adds individual "poll" tags to it for each poll. Each poll tag has the unique ID of the poll and the text of the question.

To test the page, simply navigate to it in the browser and select View Source to see what is returned. Another option is to use curl to get the XML return as noted here:

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

The front end accesses this script using an Ajax request.

The next three scripts deal with the answers part of the polls. To make it easier on yourself, first create a helper function called build_answers that, when given a database handle and a poll ID, outputs the XML for all the answers to that poll (see Listing 4).

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

The build_answers function first uses the database connection to SQL query to get the answers for the specified poll. After that, it uses XML DOM code to create a new XML output with an "answers" tag at the root and "answer" tags for each of the answers for that poll. Each answer has its unique ID, the answer text and the count of votes for that answer.

To hook that up to a page, you need an answers.php script as in Listing 5.

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

This simple script connects to the database and sends the ID from the quest into the build_answers function.

Shown below is an example from a request to this 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>
$

The final step on building out the service is to create an Ajax page to allow for voting. Listing 6 shows this script.

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

The difference between this script and the answers.php page is that you first find the count of the specified answer, then increment it and update the answer record in the database. In addition, when the script finds the answer it stores the unique ID of the related poll in the $poll variable. That poll ID is then sent to build_answers to output the current set of answers.

The importance of exporting the current state of the answers is that it allows voting and getting the current results of the poll all in one step. Because the alternative is first doing the vote, then doing the answers request to get the current vote count, doing it all in one step by having the vote script return a list of the current answer counts is definitely optimal.

With the back-end scripts completed, it's time to get into scripting the front end.


Building the front end

Mobile interfaces are very different from traditional web pages. The number of options is reduced, and the available options and buttons are made larger so that it's easy to navigate with your thumb. Now you could spend a lot of time building all that stuff for yourself, but why do that when there is jQuery Mobile? jQuery Mobile is a user interface toolkit built on top of the extremely popular jQuery JavaScript library.

The interface is built in three "pages" within the one web page. The first page has the list of questions. When the user selects a question, the page slides to the left to show the second page, which displays a list of answers for the selected question. When the user then selects an answer, that page slides to the left and the third page appears. The third page displays a chart that shows the results for the selected poll. To build the chart, use the very cool jqPlot library, which is also built on jQuery.

Listing 7 shows the code for all of this.

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

This is a lot of code but if you think about it as three different pages all in one page, it's a little easier to follow. It starts with the home page, which is defined at the beginning of the body tag. The ul list tag in the home page is populated by the Ajax request, which is run when the document is ready. That Ajax request calls the polls.php script that returns some XML, which is then parsed and turned into li tags, which are added to the ul tag.

When the user clicks a poll list item in the home page, the answers page displays. Then the openPoll function is called, which populates the li tag on the answers page using the same technique done on the home page.

When an answer is selected, the vote.php script is invoked in the vote method. When the Ajax method returns, the plotData function is called, which uses the jqPlot library to build the "donut chart" with the results.

Take a look at how this appears in production. Figure 2 shows the home page.

Figure 2. The home screen
Screen capture of home screen with a question

Figure 2 shows a mobile-friendly page with a list button for each of the available polls. In this case, however, there is just a single poll so there is only a single button. When you click the button you see the answers page as shown in Figure 3.

Figure 3. The answers page
Screen capture of home screen with four answers for the poll

Figure 3 shows the list of answers for this poll. The page also includes a back button so the user return to the home page. jQuery Mobile takes care of all that for you so you can concentrate on the application.

Click an answer to register a vote and view a results graph, as in Figure 4.

Figure 4. The first results
Screen capture of donut-shaped graph of results based on one vote

Figure 4 shows a graph that looks remarkably like a donut. With only a single vote, you see just the one element in the data series. To add a few more votes, click the back button and vote several more times. You can then see the result in Figure 5.

Figure 5. After more votes have been added
Screen capture of donut-shaped graph of results based on multiple votes

That looks a lot better! Each question takes up a proportion of the graph relative to its total of votes.

Conclusion

Are mobile devices the future? If not, they are certainly a big part of it. iPhones, iPads, and Android phones and tablets are selling wildly. People want a convenient device that gives them access to the online applications that are both thumb and user friendly. From the development standpoint, the problem is in making the effort to develop multiple versions of the user interface for these devices. Libraries like jQuery and jQuery Mobile make it extremely easy to build out user interfaces that work in the mobile environment.

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into XML on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML, Open source, Web development, Mobile development
ArticleID=756118
ArticleTitle=Add charting on mobile browsers
publish-date=10032011