There and Back Again

Website Usage Visuationzation and AJAX Tricks

I’ve been working on a small website stats project, mainly because webalizer et al don’t meet my needs. The actual implementation is mod_log_sql + a bunch of php/sql script to transform that to a star schema and then some php scripts for visualization.

Things are finally getting to the point of being useful, I have enough of the dw built out that I can answer basic questions about my site with a little sql fun, plus I have one good report. Now this report is where the AJAX tricks come into play, its a trick because were loading in data asyncronously, but its a trick because its done by changing the src of imges instead of using XMLHttpRequest. There is also a lot of neat JavaScript fun happen which I use to put up a loading screen while the images are being generated.

A look at the Report

Anyhow lets get a look actual report so you can see whats going on (normally I would post a link but 500 hits on this report would kill my server the main query takes 5-10 second, which can be optomized but i haven’t bothered). The image below is the starting page of the report, it has a list of my top blog articles this month with the date they were actually posted (well showed up in my logs) and there total hits. There are also 4 blank graphs with a default placeholder graphic.
Report Screenshot at start

Now if you click on one of the links in the table the 4 graphs will be updated with drilldown information about that page. The Images are generated with a query and then some processing with Image_Graph so they take anywhere from half a second to 2 to update, they also update at different times. To make things more user friendly I added a loading div that covers each image while its loading. This is shown in the screenshot below.
Report Screenshot during Load

After a second or two, the graphs finish loading and the loading screens disapear. This leaves you with a nicely updated report. Another nice effect (at least in firefox) is that the graphs stay cached as you click around between the different drilldown screens, but will update after a reload of the page. This makes for a snappy experience if you want to go back to something you’ve already seen.
Report Screenshot load finished

Making it Work

I’m not going to go into the details of the actual sql and Image_Graph code (contact me if you want to talk about it) but I will cover the JavaScript code that does the loading.

The way it works is:
You have a hidden javascript div that is a template for the 4 loading divs, it can contain anything you want (I’m lazy so mine just says loading).


On page load a setup function finds all the graph images (there are all in a div with the id of graphHolder) loops over the images and creates a loading div by cloneing the template. The new clones are then added to the same container as the images and absolutely positioned so they cover them. Since the template has display:none you don’t see the loading divs yet.

function setup() {
        var imgs = document.getElementById('graphHolder').getElementsByTagName('img');
        for( var i = 0; i < imgs.length; i++) {
                imgs[i].loading = document.getElementById('graphLoading').cloneNode('true');
                document.getElementById('graphHolder').appendChild(imgs[i].loading);
                imgs[i].loading.style.left = imgs[i].offsetLeft + 'px';
                imgs[i].loading.style.top = imgs[i].offsetTop + 'px';
        }
}

When we click on a link where actually using a javascript: url to call the updateGraph function, this function sets all the loading divs to a display of block so they cover the images and then it sets there new src.

function updateGraph(url) {
        var imgs = document.getElementById('graphHolder').getElementsByTagName('img');
        for( var i = 0; i < imgs.length; i++) {
                imgs[i].loading.style.display = 'block';
        }

        document.getElementById('hitsGraph').src = "urlHitsBreakDown.php?url="+escape(url);
        document.getElementById('searchGraph').src = "urlHitsBreakDown.php?type=search&url="+escape(url);
        document.getElementById('refGraph').src = "urlHitsBreakDown.php?type=referrer&url="+escape(url);
        document.getElementById('topRefGraph').src = "topGraph.php?type=referrer&url="+escape(url);

}

And finally the Images have onload handlers hard coded on them that call loadingDone passing in this. Loading done then sets display back to none.

function loadingDone(el) {
        if (el.loading) {
                el.loading.style.display = 'none';
        }
}

Something to play around with

So below is a real quick example so you can see if for yourself.

Code of Example:



Image Loading Example











Code of php script for making the color blocks with a nice delay.

require_once 'Image/Color.php';

sleep(2);

$im = imagecreatetruecolor(300,300);
$color = Image_Color::namedColor2RGB($_GET['color']);

$bg = imagecolorallocate($im,$color[0],$color[1],$color[2]);
imagefill($im,0,0,$bg);

header('Content-type: image/png');
imagepng($im);

Wrapping it up

The great thing about AJAX is its more AJ then anything. If you have JavaScript there is no shortage of ways to load new data. Oh and on an unrelated note I'm writing an AJAX book, it should be some time in Jan, and I should have been writing a chapter of that instead of messing around with this :-). I'll blog with some more details about that some time this weekend.

5 thoughts on “Website Usage Visuationzation and AJAX Tricks

  1. Luke K

    Looks slick. I did something like this a while back using GD and some JS, but no XHR (rudimentary image.src =”” replacement). If you need any help with the SQL stuff let me know, I’d love to lend a hand.

  2. visakavel

    very fine, easy to understand. i would like to know the disadvantage of ajax can u say.

  3. Joshua Eichorn Post author

    Paul:
    That depends on how you use AJAX, but its a pretty simple rule. If the only way to get to content is through JavaScript then the search engines won’t index it.

    So you need think about how your going to use AJAX and make sure you don’t lock out content you want the search engines to find.