How to create an image based dynamic countdown timer with Imagecache

This tutorial is sponsored by the Save Joseph campaign, a grassroots effort to find a good friend and stellar artist a satisfying, creative job in the next 10 days. I know someone in the Drupal community could use this kind of talent. Learn more about the effort at savejoseph.org.

I have 10 days to find my friend a job, and as part of this effort, I wanted to create an image people could use on their web sites that would dynamically change each day. My first thought was that imagecache would be great for this, but there are two issues that make dynamic text in imagecache tricky:

  1. Imagecahce images are... well... cached. Once they're made, they don't get re-made until you flush the cache.
  2. Browsers cache images too, so even if the image was refreshed on the server, the client-side image wouldn't change from one day to the next.

I was able to work around these using a couple of interesting techniques. The end result is something that looks like this:

Before you start, you'll need to download the Imagecache Actions module to add the ability to overlay text on an image.

The first step was to create the background image. I created the image in Photoshop with an empty space where the countdown was supposed to go:

Next, I created a new imagecache preset to overlay text. It's down there at the bottom:

I changed the following settings:

  • Font size: 9
  • X-offset: center
  • Y-offset: top+40
  • HEX: #FFFFFF

And for the text, I checked the Evaluate text as PHP code box, and used the following code:

$interval = strtotime('August 5, 2010') - time();
$interval = ucwords(format_interval($interval, 2) . ' left');
return $interval;

August 5th is my deadline, and what this code does is use the awesome format_interval function to create a string based on a time difference in seconds. I've set the granularity to 2 so that right now it will say 1 Week, 2 Days but in a few days it will say 6 days, 4 hours.

Next, I uploaded the background picture to the theme directory of my site. Then, I used the imagecache theme function to load up the image with the overlay:

theme('imagecache', 'save_joseph_box', path_to_theme() . '/images/save-joseph.png');

Then, I put this in a page preprocessing function in template.php and assigned it to a variable that I could use in my theme. This is really temporary code so that I can copy the output, so it could have gone anywhere.

function jc_preprocess_page(&$vars, $node) {
  $vars['save_joseph'] = theme('imagecache', 'save_joseph_box', path_to_theme() . '/images/save-joseph.png';
}

Then, I just added a print statement in my page.tpl.php page so I could see the image. Embedding this in the page template temporarily allowed me to play with the imagecache settings until I got the font size and positioning right while seeing a preview:

  <?php print $save_joseph; ?>

Okay, now we have a functioning text overlay that at least is current as of this moment. But, tomorrow, the image will be out of date. So, we need to flush this imagechange to get a re-rendering of the image whenever the text changes. Here's the strategy I used:

  1. Set up a hook_cron function
  2. In the function, use the same code above to create a textual output of the date.
  3. Load a variable that has the last textual output saved (the first time, this will be blank)
  4. Check if the new time and the previous time are different
  5. If so, clear the iimagecache
  6. Save the new text string to the variable we used before

And here's the code to do it:

function common_misc_cron() {
  $interval = strtotime('August 5, 2010') - time();
  $interval = ucwords(format_interval($interval, 2) . ' left');
  $last_time = variable_get('jc_save_time', 0);
  if ($interval != $last_time) {
    imagecache_preset_flush(array('presetid' => 'save_joseph_box'));
    variable_set('jc_save_time', $interval);
  }
}

Now we'll have an up-to-date image all the time. Except that browsers will cache images for a while, so we need a way to make the browser think it's a unique image every time to pull it fresh from the server. The way we do this is by adding a dynamic query string to the end of the image URL that will change randomly on every page load.

My goal was to make it really easy to put this image on a web page, so I needed a way to bundle this dynamic-ness with the image. So, using PHP to generate this string was out of the question. The way do to it was to use JavaScript to add the query string to the src of the image tag:

<script type="text/javascript">document.getElementById("save_joseph").src = 
document.getElementById("save_joseph").src + "?unique=" + new Date().valueOf();</script>

For folks that can't use JavaScript (in Facebook and MySpace, for example), I also provided an image that just had the end date on it, so it could be static. Not as cool, but at least functional:

Finally, I added the script with the HTML image output, copied it, and put in in a blog entry so that people could copy and paste the code to use on their sites.

SAVE JOSEPH! Week Days Left Bea'hero. Save an artist. LEARN MORE Be her Be ITT BLOC SAVE JOSEPH! &quot;BelThero.T Save an arlisi. LEARN MORE VII Be her Be mckj nenaer iext cackii'ich ihl hoo static or aynamiL toaea; text lO an imgge using imageapi sext i_u-iiKe eueLis. Add Resize Resize an image to an exact set of dimensions, ignoring aspect ratio. Add Rotate Rotate an image. Add Rounded CORNERS This is tru cropping, not overlays, so the result can be transparent. Add Scale Resize an imac&quot;' maintaining the original aspect-ratio (only one value necessary). Add Scale And Cro' .esize an image while maintaining aspect ratio, MEN crop it to the specified dimensions. moo anarpen iharpen an image using unsharp masking. Add Text Add static or dynamic (coded) text to an image. AJJ .'jackoround) Choose the file image you wish to use as an background, and position the processed image on it. an an an can an one Cror an AN to an as an to on imlmqq '■■JfllfJl1.- rati' ■atio, [jii IMF ALL 1 Haul LOWE WI 1.1 Ij' iif -it .IT III' ,SLt= .it, os-.-iuswIuli is Jl MSll Ml Add SAVE JOSEPH! by August 5th! &quot;&quot;jBelThero. Save an artist. LEARN MORE an Sai/ean Be here [ill Be


Comments

You could get around the JS URL query thing by setting up some expire rules in .htaccess.

So, would you add the expiration in the site that hosts the image? And that would be respected by various browsers? If so, that would be perfect.