Javascript Dice

License

Copyright
2013 ETH Zurich, www.socio.ethz.ch, c/o Marc Hoeglinger <hoeglinger@soz.gess.ethz.ch>
License
GPL V2, http://www.gnu.org/licenses/gpl-2.0.txt
Author
Philip Tschiemer <tschiemer@filou.se>
Link
https://github.com/tschiemer/qualtrics-gambling

Setup

To load the dice Javascript library please insert the following line once in your html site:

    <!-- dice javascript -->

    <!-- include this line anywhere in document -->
    <script type="text/javascript" src="http://www.your.url.com/your/path/dice.js"></script>

    <!-- / dice javascript -->
            

The dice then can be initialized in two ways:

  1. Using pure Javascript Objects, resp one call.
  2. Setting up HTML elements and call Javascript on these.

Pure Javascript approach

For this approach simply the following must be inserted into the HTML document

    <script type="text/javascript">
    var my_options = {
        // options are explained below
    };
    dice_create_here('My Throw Button Label',my_options);
    </script>
                

Thereby a dice is created exactly in the position where the code is inserted. Along with the dice a throw button having the label My Throw Button Label is created.

HTML/Javascript approach

In case you want to apply custom styling to your dice (eg. define specific positioning) then you can set the second appreach where you set the dive anchor and buttons as desired, eg as follows:

    <div id="my_dice_id"></div>

    <br/> <!-- Only needed to make a new line, such that it's prettier. -->
    
    <button id="my_throw_button_id">My Throw Button Label</button>
                

.. and initialize the dice (add the code AFTER the HTML!) as follows:

    <script type="text/javascript">

    var my_options = {
    // ... options explaiend below
    };

    new Dice('my_dice_id','my_throw_button_id',my_options);

    </script>
                

Options

The dice options are set through as fields of an object, following you see an example with all possibel options (remember, this is inside the script-tag):

    var my_options = {

        // Number of possible throws before the dice (and buttons) are deactived.
        // Optionl, default = 0.
        // 0        infinite throws / dice will never be deactivated
        //          or if a result_set is given, will be thrown exactly the remaining
        //          number of throws considering the first_throw_nr
        // N > 0    exactly N throws
        //          ATTENTION: if a result set is given aswell as a first_throw_nr and the 
        //          total throw count can grow highger than the result_set count, the drawn 
        //          results will be drawn according to the fallback_strategy.
        //          
        possible_throws: 0, 

        // Fallback strategy to use, if for a given result set and an expected
        // number of results, there are too few results given.
        // Optional, default: wrap-around. Possible values:
        //      'wrap-around'   Drawing will begin from the first given result again
        //      'random'        A random result according to the given probabilities will be drawn.
        fallback_strategy: 'wrap-around',

        // List of all possible values and their probablities.
        // Required.
        // The probabilities will be normalized, ie actual probability = given probability / sum of all probabilities
        // The key property is used both to identify the result and to load the correct result image resource.
        value_set : [
            {key: "1", probability: 1},
            {key: "2", probability: 1},
            {key: "3", probability: 1},
            {key: "4", probability: 1},
            {key: "5", probability: 1},
            {key: "6", probability: 1}
        ],

        // List of predefined result keys
        // Optional
        // If given the dice can automatically only be thrown as many times as there are given keys.
        // Can take two forms, the values must be strings as used for keys in the value set, otherwise an error occurs:
        // Form 1 : array of keys
        result_set: ['1','2','1','2'],

        //Form 2: Comma separated (string) list
        result_set: '1,2,3,4,5,6',

        // Index (starting at 0) of result_set keys to use for this sequence.
        // Optional (default = 0), natural number incl. zero.
        // Static example, in this case '3' would be the first result
        first_throw_nr: 2, 
        // Dynamic example using session cookies to remember the current throw count (to avoid repetitions)
        first_throw_nr:getCookie('throw_nr',0),

        // Roll animation duration in seconds
        // Optional, default = 1.
        // MUST NOT be 0 (zero)

        // Can be a number as follows:
        // roll_duration: 1, 
        // .. or can be a function to vary duration, as follows:
        roll_duration: function(){ return 1 + 3*(1 - Math.random()); }, // example duration drawn randomly from [1, 4]

        // Generic image settings
        // Required
        images : {

            // Base URL of the base folder where your images reside.
            // Required.
            // MUST have a trailing slash
            base_url : 'http://www.your-domain.com/your/image/path/',

            // Image extension used for result images
            // Required.
            // Result images are loaded from images.base_url + result.key + images.ext
            // eg. for result 6: http://www.your-domain.com/your/image/path/6.png
            ext  : '.png',

            // Image to show initially.
            // Optional.
            init : 'init.png'
        },

        // Options related to animation
        // Optional (ie can be ommitted)
        animation: {

            // Rotate image if possible? (default: true, ie if omitted, will rotate)
            rotate: true,

            // Swap Images? (default: true, ie if omitted will swap images randomly during throw animation)
            swap_images: true,

            // Animation images to use instead of result images.
            // If omitted or array of zero elements, will use result images.
            images: ['smiley.png','smiley-green.png','smiley-rosa.png']
        },

        // Callback function to handle results
        // Optional
        // Will be called at each throw.
        // Passed arguments is the throw number (inclusive this throw, it will be the n-th one)
        // and  the result key as defined in value_set.
        result_callback: function(throw_nr, result_key){
            // your handling here

            //If using a defined result set, and you want to avoid reusing
            // the same sequence again, you might consider setting a cookie to remember which throw
            // exactly it is.
            // Attention: please make sure to delete the cookie at some point, best before the
            // cookie is instantiated
            setCookie('throw_nr',throw_nr + this.first_throw_nr);
        },

        // Callback function to be called upon permanent deactivation of dice
        // Optional
        finished_callback: function(){
            // your function here
        }
    };
                

In the following you find a minimized and commentless version of the required options:

    var my_options = {
        value_set : [
            {key: "1", probability: 1},
            {key: "2", probability: 1},
            {key: "3", probability: 1},
            {key: "4", probability: 1},
            {key: "5", probability: 1},
            {key: "6", probability: 1}
        ],
        images : {
            base_url : 'http://www.your-domain.com/your/image/path/',
            ext  : '.png'
        }
    };
                

Qualtrics Integration

In the following you will find three full examples of integrating the dice into Qualtrics, simpler variants can be used by apropriate reduction.

As a general note, any linked resources as javacsript or image files should reside on a secure server accessible through HTTPS, otherwise browsers might block the content or give warnings.

Qualtrics Example: 1 dice, simple integration

The goal is to have a simple dice that does nothing else than just being there and being throwable (and stores the result of each throw in a Qualtrics embedded field).

Question Text inserted as HTML
    <!-- include dice source.-->
    <script src="http://www.your-domain.com/some-path/dice/dice.js" type="text/javascript"></script>

    <!-- an alternative approach to encorporating the javascript source is to embed it directly, uncomment as necessary -->
    <script type="text/javascript">
    .. include complete dice.js file here    
    </script>

                    
    <!-- Actual dice html here -->
    <div id="dice"></div>
    <br>
    <button id="throw">Throw dice!</button>

    <!-- Instantiate dice here. As results are not stored, it need not be added to a javascript block. -->
    <script type="text/javascript">
    new Dice('dice','throw',{
        value_set: [
            {key: '1',probability: 1},
            {key: '2',probability: 1},
            {key: '3',probability: 1},
            {key: '4',probability: 1},
            {key: '5',probability: 1},
            {key: '6',probability: 1}
        ],
        images : {
            base_url: 'http://www.your-domain.com/some-path/dice/img/',
            ext: '.png',
            init: 'qmark1.png'
        },
        result_callback: function(throw_nr,result_key){

            // Save result to embedded data field (need
            //not be set through survey flow settings)
            Qualtrics.SurveyEngine.setEmbeddedData('result_matrix_embedded'+throw_nr, result_key);

        }
    });
    </script>

            

Qualtrics Example: 3 pages whereof 2 with 1 dice, (common) predefined result set without repetition

The goal is to have a simple dice that use predefined results (ex. a reliable randomized sequence) without repetition (inclusive page reload) and storing the results in given data fields (page 1: indexed with 1-3, page 2: indexed with 4-5).

Page 1: Question Text inserted as HTML
    <!-- include cookie source. -->
    <script src="http://www.your-domain.com/some-path/dice/cookiehelper.js" type="text/javascript"></script>

    <!-- reset session cookie counter 
    This is not per se necessary, but recommended if you want to use a predefined sequence, this might be an approach
    But essentially, it depends on your strategy.  -->
    deleteCookie('cookie_throw_nr');
            
Page 2: Question Text inserted as HTML
    <!-- include dice source.-->
    <script src="http://www.your-domain.com/some-path/dice/dice.js" type="text/javascript"></script>
    <!-- include cookie source. -->
    <script src="http://www.your-domain.com/some-path/dice/cookiehelper.js" type="text/javascript"></script>

                    
    <!-- Actual dice html here -->
    <div id="dice"></div>
    <br>
    <button id="throw">Throw dice!</button>

    <!-- Instantiate dice here. As results are not stored, it need not be added to a javascript block. -->
    <script type="text/javascript">
    new Dice('dice','throw',{
        value_set: [
            {key: '1',probability: 1},
            {key: '2',probability: 1},
            {key: '3',probability: 1},
            {key: '4',probability: 1},
            {key: '5',probability: 1},
            {key: '6',probability: 1}
        ],
        possible_throws: 6,
        //So the results will be going from 1 to 6 with five 6s in a row.
        // For Qualtrics you might consider using a specific sequence which is bound to a user
        result_set: '1,2,3,4,5,6,6,6,6,6', 
        first_throw_nr: getCookie('cookie_throw_nr',${e://Field/qualtrics_throw_nr}+0), Using two approaches to get the first throw index
        fallback_strategy: 'random', // If more throws are necessary just use Javascript's Math.random()
        images : {
            base_url: 'http://www.your-domain.com/some-path/dice/img/',
            ext: '.png',
            init: 'qmark1.png'
        },
        result_callback: function(throw_nr,result_key){

            // Save result to embedded data field (need
            //not be set through survey flow settings)
            Qualtrics.SurveyEngine.setEmbeddedData('result_matrix_embedded'+throw_nr, result_key);

            // You could use this approach
            Qualtrics.SurveyEngine.setEmbeddedData('qualtrics_throw_nr', throw_nr + this.first_throw_nr);

            // .. or this one using cookies (might be more reliable)
            setCookie('result_throw_nr',throw_nr + this.first_throw_nr);
        }
    });
    </script>

            
Page 3: Question Text inserted as HTML
    <!-- include dice source.-->
    <script src="http://www.your-domain.com/some-path/dice/dice.js" type="text/javascript"></script>
    <!-- include cookie source. -->
    <script src="http://www.your-domain.com/some-path/dice/cookiehelper.js" type="text/javascript"></script>

                    
    <!-- Actual dice html here -->
    <div id="dice"></div>
    <br>
    <button id="throw">Throw dice!</button>

    <!-- Instantiate dice here. As results are not stored, it need not be added to a javascript block. -->
    <script type="text/javascript">
    new Dice('dice','throw',{
        value_set: [
            {key: '1',probability: 1},
            {key: '2',probability: 1},
            {key: '3',probability: 1},
            {key: '4',probability: 1},
            {key: '5',probability: 1},
            {key: '6',probability: 1}
        ],
        possible_throws: 4,
        result_set: '1,2,3,4,5,6,6,6,6,6', //So the results will be going from 1 to 6 with five 6s in a row
        first_throw_nr: getCookie('cookie_throw_nr',${e://Field/qualtrics_throw_nr}+0), Using two approaches to get the first throw index
        fallback_strategy: 'wrap-around', // If more throws are necessary wrap around going through the same sequence again. (default value)
        images : {
            base_url: 'http://www.your-domain.com/some-path/dice/img/',
            ext: '.png',
            init: 'qmark1.png'
        },
        result_callback: function(throw_nr,result_key){

            // Save result to embedded data field (need
            //not be set through survey flow settings)
            //NOTE: to use the correct index there is an offset being added to the throw_nr
            Qualtrics.SurveyEngine.setEmbeddedData('result_matrix_embedded'+(throw_nr+3), result_key);

            // You could use this approach
            Qualtrics.SurveyEngine.setEmbeddedData('qualtrics_throw_nr', throw_nr + this.first_throw_nr);

            // .. or this one using cookies (might be more reliable)
            setCookie('result_throw_nr',throw_nr + this.first_throw_nr);
        }
    });
    </script>

            

In case a user goes through the form without reloading any page, she would end up with the following sequence: Page 1: 1,2,3,4,5,6 Page 2: 6,6,6,6

In case a user goes through the form but reloads the second page after doing the throws but before submitting the form, the following sequence would result: Page 1: 1,2,3,4,5,6 Page 2: 1,2,3,4

Qualtrics Example: Integrated, hidden multiple results

Goal is to have three seperate dices, each can be thrown once and stores its result into a hidden data matrix. Users have a second data matrix question to fill in their answers.

The question is of type Matrix Table with settings:

In this example the dice results are stored twofold:

  1. Just like any other questionnaire data and can be retrieved within the questionnaire like any other data fields (the results must not but can be defined as embedded data to be accessible), eg:
    ${q://QID21/ChoiceNumericEntryValue/1}
  2. The throw results will be written to an embedded data field which can be read as follows:
    ${e://Field/result_matrix_embedded1}
Assume the the question to be Question 21, Q21 respectively (as defined by the Qualtrics system).

Question Text inserted as HTML
    <!-- include dice source.-->
    <script src="http://www.your-domain.com/some-path/dice/dice.js" type="text/javascript"></script>

    <!-- an alternative approach to encorporating the javascript source is to embed it directly, uncomment as necessary -->
    <script type="text/javascript">
    .. include complete dice.js file here    
    </script>

    <!--
    incorporate this hidden decoy button to stop random clicks on the question area
    to trigger the first button from being fired unnecessarily
    -->
    <button onclick="return false;" style="display:none"></button>

    <!-- the table is only needed to present the dices in a row, it does not have any functional meaning -->
    <table>
        <tbody>
            <tr>
                <td>
                    
                    <!-- Actual dice html here -->
                    <div id="dice1"></div>
                    <br>
                    <button id="throw1">Throw dice 1</button>

                </td>
                <td>
                    
                    <div id="dice2"></div>
                    <br>
                    <button id="throw2">Throw dice 2</button>

                </td>
                <td>
                    
                    <div id="dice3"></div>
                    <br>
                    <button id="throw3">Throw dice 3</button>

                </td>
            </tr>
        </tbody>
    </table>

    <!-- to hide the actual data entry matrix
        ATTENTION if you make this question mandatory make sure that users without
        javascript (that cannot use the dice) do not face this question, otherwise
        they will face a required question they cannot answer
    -->
    <style type="text/css">
    #QID21 div.QuestionBody {display:none}    
    </style>
                
Javascript added to question.

    Qualtrics.SurveyEngine.addOnload(function()
    {
      // Required for the callback functions to work.
      var self = this;

      // For our comfort, the common settings are predefined.
      var value_set = [
          {key:"1",probability:1},
          {key:"2",probability:1},
          {key:"3",probability:1},
          {key:"4",probability:1},
          {key:"5",probability:1},
          {key:"6",probability:1}
        ];

      var images = {
        base_url:'http://www.your-domain.com/some-path/dice/img/',
        ext:'.png',
        init: 'qmark1.png'
      };

      // Instantiate dice 1
       new Dice("dice1","throw1",{
        possible_throws: 1,
        value_set: value_set,
        images: images,
        result_callback: function(throw_nr,result_key){
          
            // Save result to embedded data field (need
            //not be set through survey flow settings)
            Qualtrics.SurveyEngine.setEmbeddedData('result_matrix_embedded'+throw_nr, result_key);

            // Set choice by result key, choice index respectively
            // Attention: choices must be in correct order (ie choice 1 must have value 1, etc)
            self.setChoiceValue('1', result_key, true);

            // should you use only 1 dice that can be thrown multiple times
            // you can use <throw_nr> instead of the predefined '1'
            // self.setChoiceValue(throw_nr,result_key,true);

            // Optionally change the label of the throw button.
            document.getElementById('throw1').innerHTML = 'Thank you!';
            // .. or hide it altogether.
            document.getElementById('throw1').style.visibility = 'hidden';
          
        }
       });

       // Instantiate dice 2
       new Dice("dice2","throw2",{
        possible_throws: 1,
        value_set: value_set,
        images: images,
        result_callback: function(throw_nr,result_key){
          self.setChoiceValue('2', result_key, true);
        }
       });


       // Instantiate dice 3
       new Dice("dice3","throw3",{
        possible_throws: 1,
        value_set: value_set,
        images: images,
        result_callback: function(throw_nr,result_key){
          self.setChoiceValue('3', result_key, true);
        }
       });

    });​

                

Examples

Example HTML predefined.



Example HTML predefined, with predefined result sequence.



Example HTML predefined, unfair dice (6 with probability 0.66).



Example HTML predefined, result predefined.



Example HTML predefined, custom animation images.



Example Pure Javascript, two throws


Example HTML predefined with custom styling, and three throws.