Tracking Clicks, Building a Clickmap with PHP and jQuery

Avatar of Chris Coyier
Chris Coyier on (Updated on )

📣 Freelancers, Developers, and Part-Time Agency Owners: Kickstart Your Own Digital Agency with UACADEMY Launch by UGURUS 📣

This demo and article was originally created by Jay Salvat and can be seen here in French. Thanks Jay!

The Plan

  • Record the X and Y coordinates of the mouse cursor when it is clicked on a web page.
  • Save those coordinates to a database
  • When called, display a “clickmap” on top of the web page visually displaying the locations of those clicks.

Why?

Because it’s a cool proof of concept. Should you use this in production and base major design decisions off it? Maybe not, but I could see it being used as a tool in examining user behavior in some situations.

View DemoDownload Files

The Technologies

The website will be built using PHP. We need PHP for a couple of reasons. Most importantly we need a server side language to deal with saving and retrieving from the database. Also, we’ll be abstracting that database interaction into a separate file to keep our code clean. PHP enables us to post variables back and forth between these files.

We’ll be using JavaScript of the jQuery variety to track the mouse clicks and post that click data to the PHP file doing the database saving. jQuery will also help us display the overlay and place the little graphics we’ll use to display the click locations.

Build the Database

Our code won’t be automatically creating the tables necessary for you, you’ll have to create a database and the structure on your own. Here is the SQL:

CREATE TABLE  `clickmap` ( 
  `id` int(10) unsigned NOT NULL auto_increment, 
  `x` smallint(4) unsigned NOT NULL, 
  `y` smallint(4) unsigned NOT NULL, 
  `location` varchar(255) NOT NULL, 
  PRIMARY KEY  (`id`), 
  KEY `location` (`location`) 
)

We are keeping things as simple as we can for the demo. If you wanted to extend the idea, you may also want to add extra info to this table like IP address and date/time so you have more detailed info for each click.

The Markup (page being tracked)

Just some structure for us to work with here. We’ll link to a CSS file, load up jQuery, link to a JavaScript file of our own devising as well as set up a place to write JavaScript right here, and put some content in the page.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Click Map Demo</title>
    <link rel="stylesheet" type="text/css" href="style.css" />
    <script src="//www.google.com/jsapi" type="text/javascript"></script>
    <script type="text/javascript" src="js/jquery.js">
    <script type="text/javascript" src="js/clickmap.js"></script>
    <script type="text/javascript">
        $(function() {
            // do stuff
        });
    </script>
</head>
<body>
    <img src="images/baywatch.jpg" alt="baywatch" />
    <p class="button displayClicks"><a href="#demo">Display Click Map</a></p>
</body>
</html>

Not much content there, just a picture of the Baywatch crew and a simple button.

The jQuery JavaScript

The JavaScript is going to do two major things for us: saving clicks and displaying clicks.

Saving Clicks

For efficiencies sake, we’ll abstract into a couple of different functions that we can call anytime. One to start saving clicks and one to stop saving clicks.

(function($) { 

$.fn.saveClicks = function() { 
    $(this).bind('mousedown.clickmap', function(evt) { 
        $.post('/examples/ClickMap/clickmap.php', {  
            x:evt.pageX,  
            y:evt.pageY,  
            l:escape(document.location.pathname) 
        }); 
    }); 
}; 
 
$.fn.stopSaveClicks = function() { 
     $(this).unbind('mousedown.clickmap'); 
};

})(jQuery); 

We are binding the mousedown event to the element it gets called on (it will be the whole document) and then using jQuery’s post function to send some data (the coordinates) to a special file (clickmap.php). Pretty neat really, the people will never know it, but each of those clicks is sending data back to the server.

Displaying Clicks

Again, two functions. One is in charge of creating the overlay and displaying the click graphics (the PHP sends all the data but the jQuery does the appending). The other removes everything. We make use of the jQuery get function.

$.displayClicks = function(settings) { 
    $('<div id="clickmap-overlay"></div>').appendTo('body'); 
    $('<div id="clickmap-loading"></div>').appendTo('body'); 
    $.get('/examples/ClickMap/clickmap.php', { l:escape( document.location.pathname) },  
        function(htmlContentFromServer) { 
            $(htmlContentFromServer).appendTo('body');     
            $('#clickmap-loading').remove(); 
        } 
    ); 
}; 
 
$.removeClicks = function() { 
    $('#clickmap-overlay').remove(); 
    $('#clickmap-container').remove(); 
}; 

Firing it all off

We’ll include some JavaScript right on the page to fire everything off.

<script type="text/javascript">
    $(function() {
        $(document).saveClicks(); 
    
        $('.displayClicks').click(function() {
            $.displayClicks();
            $('#clickmap-overlay').click(function() {
                 $.removeClicks();
                 $(document).saveClicks();
            });
            $(document).stopSaveClicks();
            return false;
        });
    });
</script>

The PHP

So now we’ve seen code that boths POSTS and GETS from a PHP file that we haven’t seen yet. That magic happens in a file we’ll call clickmap.php. In either case, we need to connect to the database and then close that connection. The rest of it is defendant on if we are POSTing or GETting.

<?php 
    $DB = mysql_connect("localhost", "db_user", "db_password"); 
    mysql_select_db("db_name", $DB);     
    
    if (isset($_POST['l'])) { 
        $query = sprintf("  INSERT INTO clickmap  
                            SET x = '%s', y = '%s', location = '%s'",  
                            $_POST['x'], $_POST['y'], $_POST['l']);        
        $result = mysql_query($query);
    };
        
    if (isset($_GET['l'])) { 
        $query = sprintf("  SELECT x, y FROM clickmap  
                            WHERE location = '%s' 
                            ORDER BY id DESC
                            limit 200",  
                            $_GET['l']); 
        $results = mysql_query($query); 
             
        $html = '<div id="clickmap-container">'; 
        while ($row = mysql_fetch_array($results)) { 
        $html .= sprintf('<div style="left:%spx;top:%spx"></div>', $row['x'] - 10, $row['y'] - 10); 
    } 
        $html .= '</div>'; 
         
        echo $html; 
    };  
   
    mysql_close($DB); 
?>

Fairly straightforward… when POSTing, save the data to the database. When GETting, retrieve it. In this demo we only grab the last 200 clicks, but you can alter or remove that restriction as needed. Here you can see how the each of the click graphics positions itself when the overlay comes up. The exact coordinate data that was saved when the click was produced is used to set CSS “top” and “left” values.

The CSS

The actual clickmap stuff doesn’t need a heck of a lot in terms of styling. Just the overlay itself, a loading area (in case it takes a while to get all the click data), and the little graphics for the clicks themselves.

#clickmap-overlay { 
    position:fixed; 
    top:0; left:0; 
    width:100%; height:100%;  
    background-color:#000; 
    filter:alpha(opacity=70); opacity: 0.7; 
} 

#clickmap-loading { 
    position:fixed; 
    top:0; left:0; 
    width:100%; height:100%;  
    background:transparent url(images/loading.gif) no-repeat center center; 
} 

#clickmap-container div { 
    position:absolute; 
    width:20px; height:20px; 
    background:transparent url(images/click.png) no-repeat center center; 
} 

All Together

I know sometimes reading through all the code samples can be kind of mind bending and confusing. As always, you are welcome to download the code and see it all in context so it makes more sense. Special thanks again to Jay Salvat for the original creation of this idea. Jay is a 35 year old web developer living in the French Rivera and the lead developer at Kuantic. He is the creator of the very cool markItUp! rich text editor for jQuery and the new project Sunday Morning (coming soon).

View DemoDownload Files