Coin flip using js | XM Community
Skip to main content
Solved

Coin flip using js


Forum|alt.badge.img+6
  • Level 2 ●●
  • 19 replies

I want respondents to observe the outcome of a virtual coin flip. For example, I have two images pic_head and pic_tail, and I want the images to flip over a couple of times before it lands on the outcome. The coin flip starts automatically when the page loads and should stop after 2 or 3 secs.

Does anyone have a related js code for this that I could refer to? 

 

Thanks!

Best answer by Tom_1842

I found a codepen by user Siva that I was able to put into Qualtrics.

To give it a try, first create the Embedded Data fields of "headsCount" and "tailsCount" and put them at the top of the Survey Flow.

Then create a Text/Graphic question and use the Rich Content Editor's HTML/Source view "<>" to update the question text with the below:

<div class="container">
<h2>Flip this coin!</h2>

<div id="coin">
<div id="heads" class="heads">&nbsp;</div>

<div id="tails" class="tails">&nbsp;</div>
</div>
<button id="flip">Flip Coin</button>

<p>Heads: <span id="headsCount">0</span> Tails: <span id="tailsCount">0</span></p>

<p><span id="status">&nbsp;</span></p>
</div>

Next, add the below to the question's JavaScript in the OnReady section:

const coin = document.querySelector('#coin');
const button = document.querySelector('#flip');
const status = document.querySelector('#status');
const heads = document.querySelector('#headsCount');
const tails = document.querySelector('#tailsCount');

let headsCount = 0;
let tailsCount = 0;


function deferFn(callback, ms) {
  setTimeout(callback, ms); 
}

function processResult(result) {
   if (result === 'heads') {
      headsCount++;
      heads.innerText = headsCount;
	Qualtrics.SurveyEngine.setEmbeddedData("headsCount",headsCount);
    } else {
      tailsCount++;
      tails.innerText = tailsCount;
	Qualtrics.SurveyEngine.setEmbeddedData("tailsCount",tailsCount);
    }
    status.innerText = result.toUpperCase();
}

function flipCoin() {
  coin.setAttribute('class', '');
  const random = Math.random();
  const result = random < 0.5 ? 'heads' : 'tails';
 deferFn(function() {
   coin.setAttribute('class', 'animate-' + result);
   deferFn(processResult.bind(null, result), 2900);
 }, 100);
}

button.addEventListener('click', flipCoin);

Finally, add the below CSS to the Style section of the Look & Feel, updating the heads/tails image URLs with your own:

h2 {
  margin: .25rem;
}

div.container {
  margin: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
}

#flip {
  padding: 1rem;
  background-color: skyblue;
}

#coin {
  position: relative;
  width: 15rem;
  height: 15rem;
  margin: 2rem 0rem;
  transform-style: preserve-3d;

}

#coin div {
  width: 100%;
  height: 100%;
  border: 2px solid black;
  border-radius: 50%;
  backface-visibility: hidden;
  background-size: contain;
  position: absolute;
}

.heads {
    background-image: url("https://en.numista.com/catalogue/photos/inde/2311-original.jpg");
}

.animate-heads {
  animation: flipHeads 3s;
  animation-fill-mode: forwards;
}

@keyframes flipHeads {
  from {
    transform: rotateY(0deg);
  }
  to {
    transform: rotateY(1800deg);
  }
}

.tails {
    background-image: url("https://en.numista.com/catalogue/photos/inde/3165-original.jpg");
  transform: rotateY(-180deg);
}

.animate-tails {
  animation: flipTails 3s;
  animation-fill-mode: forwards;
}

@keyframes flipTails {
  from {
    transform: rotateY(0deg);
  }
  to {
    transform: rotateY(1620deg);
  }
}

 

View original

3 replies

Forum|alt.badge.img+32
  • Level 6 ●●●●●●
  • 241 replies
  • July 19, 2023

This is a unique idea, unfortunately I can’t assist with the css code to do this though.  An alternative might be is if you can create an animated image or video & insert that into the survey instead, have two versions and then randomise which is shown.  This would need you to have an animation of a coin flip, rather than a static image.  You might be able to find something like this online though.


Tom_1842
Level 8 ●●●●●●●●
Forum|alt.badge.img+28
  • Level 8 ●●●●●●●●
  • 876 replies
  • Answer
  • July 19, 2023

I found a codepen by user Siva that I was able to put into Qualtrics.

To give it a try, first create the Embedded Data fields of "headsCount" and "tailsCount" and put them at the top of the Survey Flow.

Then create a Text/Graphic question and use the Rich Content Editor's HTML/Source view "<>" to update the question text with the below:

<div class="container">
<h2>Flip this coin!</h2>

<div id="coin">
<div id="heads" class="heads">&nbsp;</div>

<div id="tails" class="tails">&nbsp;</div>
</div>
<button id="flip">Flip Coin</button>

<p>Heads: <span id="headsCount">0</span> Tails: <span id="tailsCount">0</span></p>

<p><span id="status">&nbsp;</span></p>
</div>

Next, add the below to the question's JavaScript in the OnReady section:

const coin = document.querySelector('#coin');
const button = document.querySelector('#flip');
const status = document.querySelector('#status');
const heads = document.querySelector('#headsCount');
const tails = document.querySelector('#tailsCount');

let headsCount = 0;
let tailsCount = 0;


function deferFn(callback, ms) {
  setTimeout(callback, ms); 
}

function processResult(result) {
   if (result === 'heads') {
      headsCount++;
      heads.innerText = headsCount;
	Qualtrics.SurveyEngine.setEmbeddedData("headsCount",headsCount);
    } else {
      tailsCount++;
      tails.innerText = tailsCount;
	Qualtrics.SurveyEngine.setEmbeddedData("tailsCount",tailsCount);
    }
    status.innerText = result.toUpperCase();
}

function flipCoin() {
  coin.setAttribute('class', '');
  const random = Math.random();
  const result = random < 0.5 ? 'heads' : 'tails';
 deferFn(function() {
   coin.setAttribute('class', 'animate-' + result);
   deferFn(processResult.bind(null, result), 2900);
 }, 100);
}

button.addEventListener('click', flipCoin);

Finally, add the below CSS to the Style section of the Look & Feel, updating the heads/tails image URLs with your own:

h2 {
  margin: .25rem;
}

div.container {
  margin: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
}

#flip {
  padding: 1rem;
  background-color: skyblue;
}

#coin {
  position: relative;
  width: 15rem;
  height: 15rem;
  margin: 2rem 0rem;
  transform-style: preserve-3d;

}

#coin div {
  width: 100%;
  height: 100%;
  border: 2px solid black;
  border-radius: 50%;
  backface-visibility: hidden;
  background-size: contain;
  position: absolute;
}

.heads {
    background-image: url("https://en.numista.com/catalogue/photos/inde/2311-original.jpg");
}

.animate-heads {
  animation: flipHeads 3s;
  animation-fill-mode: forwards;
}

@keyframes flipHeads {
  from {
    transform: rotateY(0deg);
  }
  to {
    transform: rotateY(1800deg);
  }
}

.tails {
    background-image: url("https://en.numista.com/catalogue/photos/inde/3165-original.jpg");
  transform: rotateY(-180deg);
}

.animate-tails {
  animation: flipTails 3s;
  animation-fill-mode: forwards;
}

@keyframes flipTails {
  from {
    transform: rotateY(0deg);
  }
  to {
    transform: rotateY(1620deg);
  }
}

 


Forum|alt.badge.img+6
  • Author
  • Level 2 ●●
  • 19 replies
  • July 19, 2023

Thanks @ScottG and @Tom_1842 for the super helpful suggestions! 

I tried @Tom_1842’s code and it works perfectly! Thanks for the detailed code. 

 

Thanks again!