Before we start, lets scope the reason why you might want to use any timer in Captivate, let alone a Javascript timer.

If you’ve ever made Captivate Quiz slides, you know that you can easily set up a scenario where the user only has a finite amount of time to answer a question, and that you can create a customised message to let them know when their time is up.

But you have to be using a Quiz slide to do this, and displaying the elapsed time is not possible out of the box.

This tutorial shows how you can accurately control the configuration and display of a countdown timer and use the process to display it where and whenever you like. The output will be displayed as HTML5 in a browser with Javascript enabled (default).

You’ll need a text editor to edit the code.

How to use a Javascript timer in Captivate splash screen

If you’ve done any of my previous Captivate Javascript tutorials, you’ll know that I use Sublime Text as my code editor – but you can use any text or code editor.

The basic steps are:

  1. Write the Javascript Code
  2. Use an action to include it in your Captivate Output
  3. Publish and browse your project.

Setting up the development environment.

There’s a small production expediency we’re going to use. Because we’ll probably want to tweak code and just refresh the browser rather than have to re-publish in Captivate, we’re going to use a local server environment

(No, don’t panic – there’s a post on my blog on how to do this here).

Click on the logos below for download info. If you don’t have a local server set up, then this tutorial is going to be difficult if not impossible unless you publish directly to a server on the web. In that case just exchange localhost with your domain name.

Launch your Web Server (WAMP or MAMP or XAMPP or similar). Make sure it’s running properly by browsing to http://localhost/projectfolder.

MAMP Pro
WAMP
XAMPP

Creating and saving your Javascript code file.

Return to your text editor and get ready to cut some code. Start by opening your text/code editor and creating a new file.

Save it in your project folder as timer.js. I usually create a js folder as well for clarity’s sake. So the path to your file will be: http://localhost/projectfolder/js/timer.js.

You might like to add some code comments to describe what the file’s purpose is, version and date. This is a typical professional developer approach.

You can download the code file at the end of this tutorial. Just to be sure that we’re clear here, you’re going to:

  1. Write your code
  2. Link the code file to your Captivate file
  3. Publish your project.
Javascript Folder
Execute Javascript
Enter frame Javascript

Connecting your code to Captivate

While we’re in development mode, we’ll access our code file at the top level of our project folder (where you made it in the previous step).

Once we’ve tested it, we’ll change the address that Captivate expects to find it and move it to http://localhost/publish/assets/js/.

But more of that in good time. So here’s how we hook our Javascript file to Captivate. Remember we’re currently storing the Javascript file at http://localhost/projectfolder/js/timer.js.

Creating a Javascript Alert

The best way to figure out if the Javascript file hooked up properly is to create a browser alert (later you’ll be using the console for this purpose). So write this code in your Javascript file and save it:

alert("Javascript file connected!");

Now lets hook up the file to Captivate.

Check the screenshot above for clarity.

  1. Select the first slide and click the actions tab.
  2. Choose ‘Execute Javascript’.
  3. Type the following into the script window:
$("body").append("");

Save your file and publish it to the publish location : http://localhost/projectfolder/publish

Testing Javascript connection

Now lets test the Javascript connection. If you browse to your publish location via localhost, something like this: http://localhost/projectfolder/publish.

You should see your Captivate project ready to play.

Click the play button and hopefully you’ll see something like this:

Javascript alert message
Captivate Project Variables
Add a new Captivate Project Variable

Setting up Captivate Variables

Because the timer script is going to need a variable, open the Project menu and choose Variables.

By the way, this could easily be hard-coded into the Javascript file, but setting the value up in Captivate is far more re-usable and gives me an opportunity to add extra value to this tutorial.

Add a new variable called ‘secondsLeft’ and assign it a value of 60.

Yes, we’re counting down 60 seconds!

Add some comments that may help you identify this variable later on as required.

Displaying a user variable

Create a new slide and then draw a Smart shape – I’ve used a simple circle.

Double click into the Smart Shape to add some text.

In the Properties panel, look for the button under the text alignment buttons that looks like this: [X].

This symbol allows you to present a variable in text. You could type it if you prefer.

Click the button and in the drop-down menu, choose user rather than System variables.

You should see the variable that you created. Select it and now you should see it appear in the text surrounded by $$ signs.

This indicates that a variable is being used. Style it as required. I’ve made mine large.

Insert Captivate Variable
Display Captivate User variable
Captivate Multistate Object Label
Captivate Multistate Object

Creating the Timer multistate Object

Because we’re going to be controlling the Smart Shape using Javascript, we need to assign it a name that we’ll address from the Javascript file.

So select the shape and assign it a name. I used ‘countdown’. Now we’ll add a state to the Smart Shape that will be presented when the time runs out.

Select the Smart Shape and enter the object states timeline by clicking the State View button.

Create a new state by duplicating the ‘Normal’ state and label it ‘timesup’.

Change the colours and text to represent completed time.

Enabling a frame script

Now we’re going to make a link to a function in our Javascript file. Confused?

We haven’t done anything to the Javascript file, but in a moment we’re going to create a function there called ‘countdownTimerStart’.

This function will activate the timer and the text in the ‘countdown’ Smart Shape will change every second until time runs out, and then show the ‘timesup’ frame that you just created.

Select the frame and add an action when the EnterFrame event occurs. Choose Execute Javascript as the action and type the following into the script window:

countdownTimerStart();
Execute Javascript

Writing the Countdown Code

Republish your file: http://localhost/projectfolder/publish.

Test from localhost and make sure you see the alert message. Now switch to your code editor and let’s start cutting code!

All you’ll need to do from here on in is to refresh your browser with the published page. Remember you’ll be able to download the completed Javascript code and Captivate file from my website when you’re done.

Start off by removing the alert message you made earlier.

Creating getter/setter functions

You are going to add the two getter/setter functions that will allow you to easily interact with any variable that you have defined in Captivate.

Type your code as below. Note that the console.log() lines are just so you can keep track of what’s going on in your browser’s console without having to rely on those pesky browser alert boxes for feedback.

You’ll be using these functions in a moment to get the value of the ‘secondsLeft’ variable you created in Captivate earlier.

/* ----------------------------------------- */
// Captivate Variable Getter/Setter
/* ----------------------------------------- */
function setCpVariable(p_var,p_val){
	console.log("setCpVariable: "+p_var+" : "+p_val);
	window.cpAPIInterface.setVariableValue(p_var,p_val);
}

function getCpVariable(p_var){
	var cpVar = window.cpAPIInterface.getVariableValue(p_var);
	console.log("getCpVariable: "+p_var+" : "+cpVar);
	return cpVar;	
}

Declaring global variables

We’re going to create two global variables: 

secondsLeft : this keeps track of how much time is left.

countdownInterval : controls the interval object which will trigger a function every second.

Add the following lines to the top of your code. Add the comments if you wish.

/* ----------------------------------------- */
// Variable Declarations 
/* ----------------------------------------- */
// for ease of use, this global Javascript variable name 
// matches the Captivate variable name.
// it's not essential to use this naming convention, 
// but it makes things easier to work with.
// it keeps track of how much time is left
var secondsLeft; 

// this variable controls the interval object which 
// will trigger a function every second.
var countdownInterval; 

Creating a function

We’re going to create an initialisation function, the purpose of which is to set the value in our Javascript variable by getting it from Captivate.

Then we’re going to call the function to activate it.

Add the following lines to the top of your code after your variable declarations. Add the comments if you wish.

/* ----------------------------------------- */
// Initialisation 
/* ----------------------------------------- */
function initialise(){
	console.log(":: initialise ::");
	// get the number of seconds you want to use in the timer 
	// from your Captivate User Variable
	// note that I'm using a simple pair of setter/getter functions 
	// at the bottom of this code to simplify the process
	// and make getting/setting Captivate variables easier. 
	// It's totally re-usable
	secondsLeft = getCpVariable("secondsLeft");
}

Calling a function

Now call the function that you just created by adding the following line to the bottom of your code.

initialise();

Save your file, refresh your browser and play the file. If you right-mouse click on your browser window and choose ‘inspect’, then click on the Console tab, you should see the output showing the variable you set, and the value you set it to.

Creating the countdown function

Here’s the function that will be called every second. Essentially it decrements the ‘secondsLeft’ variable by one every second.

It then checks to see if there is any time left, and if it has run out, change the state of the multistate object from ‘Normal’ to ‘timesup’.

Later on, we’ll create another function that initialises this one. Type the code below after your ‘initialise’ function:

/* ----------------------------------------- */
/* function called on interval by countdownTimerStart */
/* ----------------------------------------- */
function countdown() {
    setCpVariable("secondsLeft",secondsLeft);
    secondsLeft=(--secondsLeft);
    if (secondsLeft<=0) {
      clearInterval(countdownInterval);
      // change the state of the timer countdown multistate object;
      cp.changeState("countdown","timesup");
    }
    console.log("<-- interval running -->")
  }

Starting the timer

Now all we have to do is start the timer. Remember you added an ‘Execute Javascript ’ action on your Captivate frame script earlier?

Well this is the function that it‘s calling. It will first of all make sure that the multistate object is showing the correct frame and also make sure that any previous instances of the interval are removed before starting a new one.

Type the code below after your ‘initialise’ function:

/* ----------------------------------------- */
/* Start timer - called from Captivate frame script */
/* ----------------------------------------- */
function countdownTimerStart() {
	cp.changeState("countdown","Normal");
	clearInterval(countdownInterval);
  	countdownInterval = setInterval(countdown,1000);
}

Refining the code with a reset

If you test your file now by refreshing the browser, you should see that it functions perfectly.

But if you want to finesse it you should consider creating a ‘resetTimer’ function that you can either call when the timer is finished, or perhaps by adding an ‘Execute Javascript’ action onto a Captivate button.

Here’s the function and also the spot in the ‘countdown’ function where you’d enable it (line 11 here):

/* ----------------------------------------- */
/* function called on interval by countdownTimerStart */
/* ----------------------------------------- */
function countdown() {
    setCpVariable("secondsLeft",secondsLeft);
    secondsLeft=(--secondsLeft);
    if (secondsLeft<=0) {
      clearInterval(countdownInterval);
      // change the state of the timer countdown multistate object;
      cp.changeState("countdown","timesup");
      resetTimer();
    }
    console.log("<-- interval running -->")
  }

/* ----------------------------------------- */
//Timer: Resets Timer - called by countdown() when time is up
/* ----------------------------------------- */
function resetTimer() {
  clearInterval(countdownInterval);
  secondsLeft=60;
  setCpVariable("secondsLeft",secondsLeft);
}

Conclusion

Hopefully this tutorial has made you think about how powerful Javascript can be in your Captivate projects. I know that cutting code can sometimes be a little daunting, but persevere – you may even learn to love it.

Stay tuned for the next episode and don’t forget to download the source files for the project from my website.

If you’re needing some help developing eLearning projects, or need a website, please feel free to contact me.

Resources

Here’s the Javascript code that you can copy and paste. There are also a couple of download links where you can get the Captivate Source files (2019) and the Javascript code.

/* 
This file is stored in a js folder, on the same level as the published folder.
This script hooked in first slide of captivate project with:
$("body").append("");

When published, the js file should be copied to 'publishedfolderlocation/assets/js'

*/

/* ----------------------------------------- */
// Countdown Timer
/* Activated by frame script */
/* ----------------------------------------- */
/* 
In Captivate, create a variable called 'secondsLeft' (or whatever you want to call it, so long as it matches the variable called by setCpVariable in the countdown function below.)
Go to the slide you want to trigger the timer function on
Create a text caption or smartshape and insert the variable : $$secondsLeft$$
Add a javascript action to the frame and call the function that starts the timer : countdownTimerStart();
More info at https://jrdesign.ccom.au/blog
*/

/* ----------------------------------------- */
// Variable Declarations 
/* ----------------------------------------- */
// for ease of use, this global Javascript variable name 
// matches the Captivate variable name.
// it's not essential to use this naming convention, 
// but it makes things easier to work with.
// it keeps track of how much time is left
var secondsLeft; 

// this variable controls the interval object which 
// will trigger a function every second.
var countdownInterval; 

/* ----------------------------------------- */
// Initialisation 
/* ----------------------------------------- */
function initialise(){
	console.log(":: initialise ::");
	// get the number of seconds you want to use in the timer 
	// from your Captivate User Variable
	// note that I'm using a simple pair of setter/getter functions 
	// at the bottom of this code to simplify the process
	// and make getting/setting Captivate variables easier. 
	// It's totally re-usable
	secondsLeft = getCpVariable("secondsLeft");
}



/* ----------------------------------------- */
/* Start timer - called from Captivate frame script */
/* ----------------------------------------- */
function countdownTimerStart() {
	cp.changeState("countdown","Normal");
	clearInterval(countdownInterval);
  	countdownInterval = setInterval(countdown,1000);
}

/* ----------------------------------------- */
/* function called on interval by countdownTimerStart */
/* ----------------------------------------- */
function countdown() {
    setCpVariable("secondsLeft",secondsLeft);
    secondsLeft=(--secondsLeft);
    if (secondsLeft<=0) {
      clearInterval(countdownInterval);
      // change the state of the timer countdown multistate object;
      cp.changeState("countdown","timesup");
      resetTimer();
    }
    console.log("<-- interval running -->")
  }
/* ----------------------------------------- */
//Timer: Resets Timer - called by countdown() when time is up
/* ----------------------------------------- */
function resetTimer() {
  clearInterval(countdownInterval);
  secondsLeft=60;
  setCpVariable("secondsLeft",secondsLeft);
}
/* ----------------------------------------- */
// GETTERS AND SETTERS
/* ----------------------------------------- */

/* ----------------------------------------- */
// Get current slide number
/* ----------------------------------------- */
function getCurrentSlide(){
	return getCpVariable("cpInfoCurrentSlide");
}
/* ----------------------------------------- */
// Captivate Variable Getter/Setter
/* ----------------------------------------- */
function setCpVariable(p_var,p_val){
	console.log("setCpVariable: "+p_var+" : "+p_val);
	window.cpAPIInterface.setVariableValue(p_var,p_val);
}

function getCpVariable(p_var){
	var cpVar = window.cpAPIInterface.getVariableValue(p_var);
	console.log("getCpVariable: "+p_var+" : "+cpVar);
	return cpVar;	
}

/* ----------------------------------------- */
// RUN NOW
/* ----------------------------------------- */
initialise();






Access Tutorial Assets

If you’re a JRD Customer or JRD Registered Student, you can access special information and download the tutorial assets here.

What’s in there?

A zip file containing the Captivate 2019 source file and the source Javascript file.

Useful Links

Thank you!

Thanks to James Fitzroy Photography for the loan of his image. James is an incredible photographer who manages to capture the real essence of the Australian Outback. If you like this image, you should check out his website and his facebook page.