Ways to showcase the outcome of a spin after each rotation

I am currently working on a spinning code snippet that allows users to spin and potentially win different amounts. The code includes functionality to prevent more than 3 spins, set random rotation values, and animate the spinning effect.

However, I now want to enhance the user experience by adding an indicator that displays the result of each spin once it stops. For example, if a user lands on $10, I want to visibly show them their winnings below the spinning wheel.

This concept is best illustrated in the image linked below: https://i.sstatic.net/4it0s.png

Answer №1

Here is the solution for you :).

To determine the position of the spinner, I implemented a while loop that continuously subtracted 360 from the degrees value until it fell within the range of 0 to 360. By considering the 8 sections of the spinner and their respective angles (45 degrees each), along with the starting point at $40, I used conditional statements in JavaScript to pinpoint where the spinner landed.

In addition, I included a div element

<div id="line"></div>
to create an arrow indicator indicating the final result. You can view the code snippet here:

[JavaScript code snippet]  
[CSS styling rules]
[HTML structure]

Answer №2

By utilizing the getBoundingClientRect() method, we can ascertain the position of the top paddle. The paddles are divided in half based on their width values, with the group containing the top paddle having the smallest width. Within this group, the paddle with the lowest y coordinate is identified as the topmost paddle.

All paddle elements are selected using the querySelectorAll function, converted into an array using Array.from(), and iterated over using forEach().

A multi-dimensional array is populated with the paddle's text content, width, and y coordinate. This array is sorted first by width, then by y coordinate, placing the topmost paddle at the beginning of the array. The amount associated with the winning paddle can be accessed at paddles[0][0].

function getSpin() {
  let paddles = [];
  Array.from(document.querySelectorAll('span[class^="span"]')).forEach(function(paddle) {
    let gbcr = paddle.getBoundingClientRect();
    paddles.push([paddle.textContent, Math.round(gbcr.width), Math.round(gbcr.y)]);
  });
  return paddles.sort(function(a, b) {
    if (a[1] > b[1]) {
      return 1;
    } else if (a[1] < b[1]) {
      return -1;
    }
    if (a[2] < b[2]) {
      return -1;
    } else if (a[2] > b[2]) {
      return 1;
    }
  })[0][0];
}

A message div is included beneath the button:

<button class="spin" onclick="myfunction()">SPIN</button>

<div id="spinresult">Click "SPIN" to play.</div>

The winning message is calculated and displayed within it during the setTimeout function nested in the myFunction function.

setTimeout(function() {
  element.classList.add('animate');
  document.querySelector('#spinresult').textContent = `Congratulations, you've won ${getSpin()}!`;
}, 5000); //5000 = 5 seconds

An arrow down indicator is rendered using a div placed before the spin box and styled using CSS.

<div class="arrow-down"></div>
<div id="box" class="box">

// JavaScript code here truncated for brevity
// CSS code here truncated for brevity
// HTML code here truncated for brevity

Answer №3

After finding inspiration from @john 's response...

A new technique utilizing a random degree value and the JavaScript remainder operator % has been implemented to determine the range in which the spin wheel's degree value falls:

1-45, 46-90, 91-135, 136-180, 181-225, 226-270, 271-315, 316-360
.

To account for the starting offset of 22 degrees on the wheel, ensuring that the top paddle is centered, the calculated degree range value is adjusted by subtracting 21 degrees.

By adjusting the range value appropriately, the specific portion of the wheel—corresponding to a paddle—can be identified by dividing it by 45 degrees and rounding down. Typically, this provides a value between 0 - 7, aligning with the array of win values. However, if the degree range is below 22, a -1 is returned and adjusted to index 7.

let spinCount = 0;
let [xx, yy] = [1024, 9999]; // [min, max]
let win = ["$60", "$10", "$80", "$30", "$50", "$20", "$70", "$40"];

document.querySelector('.spin').addEventListener('click', spin);

function spin() {
  if (spinCount > 3) {
    alert("No more spins.");
    return false;
  }
  let deg = Math.floor(Math.random() * (xx - yy)) + yy;
  let deg_off = (deg % 360) - 21;
  let widx = Math.floor((deg_off / 45));
  widx = (0 <= widx) ? widx : 7;

  document.getElementById('box').style.transform = `rotate(${deg}deg)`;
  let mainbox = document.getElementById('mainbox');
  mainbox.classList.remove('animate');

  setTimeout(function() {
    mainbox.classList.add('animate');
    document.getElementById("winnings").textContent 
      = `Congratulations, you've won ${win[widx]}`;
  }, 5000); //5000 = 5 second

  spinCount++;
}
* {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
  outline: none;
}

body {
  font-family: Open Sans;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  overflow: hidden;
  background: rgb(60, 60, 242);
  background: linear-gradient(90deg, rgba(60, 60, 242, 1) 0%, rgba(98, 245, 230, 1) 52%, rgba(60, 60, 242, 1) 100%);
  background-size: cover;
}

.mainbox {
  position: relative;
  width: 500px;
  height: 500px;
  text-align: center;
}

.mainbox:after {
  position: absolute;
  content: '';
  width: 32px;
  height: 32px;
  background: url('../img/arrow-wheel.png') no-repeat;
  background-size: 32px;
  right: -30px;
  top: 50%;
  transform: translateY(-50%);
}

.box {
  width: 100%;
  height: 100%;
  position: relative;
  border-radius: 50%;
  border: 10px solid #fff;
  overflow: hidden;
  transition: all ease 5s;
}

span {
  width: 50%;
  height: 50%;
  display: inline-block;
  position: absolute;
}

.span1 {
  clip-path: polygon(0 92%, 100% 50%, 0 8%);
  background-color: #fffb00;
  top: 120px;
  left: 0;
}

.span2 {
  clip-path: polygon(100% 92%, 0 50%, 100% 8%);
  background-color: #ff4fa1;
  top: 120px;
  right: 0;
}

.span3 {
  clip-path: polygon(50% 0%, 8% 100%, 92% 100%);
  background-color: #ffaa00;
  bottom: 0;
  left: 120px;
}

.span4 {
  clip-path: polygon(50% 100%, 92% 0, 8% 0);
  background-color: #22ff00;
  top: 0;
  left: 120px;
}

.box1 .span3 b {
  transform: translate(-50%, -50%) rotate(-270deg);
}

.box1 .span1 b,
.box2 .span1 b {
  transform: translate(-50%, -50%) rotate(185deg);
}

.box2 .span3 b {
  transform: translate(-50%, -50%) rotate(90deg);
}

.box1 .span4 b,
.box2 .span4 b {
  transform: translate(-50%, -50%) rotate(-85deg);
}

.box2 {
  width: 100%;
  height: 100%;
  transform: rotate(-135deg);
}

span b {
  font-size: 24px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.spin {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 75px;
  height: 75px;
  border-radius: 50%;
  border: 4px solid #fff;
  background-color: #001aff;
  color: #fff;
  box-shadow: 0 5px 20px #000;
  font-weight: bold;
  font-size: 22px;
  cursor: pointer;
}

.spin:active {
  width: 70px;
  height: 70px;
  font-size: 20px;
}

.mainbox.animate:after {
  animation: animateArrow 0.7s ease infinite;
}

@keyframes animateArrow {
  50% {
    right: -40px;
  }
}

#winnings {
  padding: 1em;
  font-family: sans-serif;
  color: white;
}

.arrow-down {
  position: absolute;
  right: 50%;
  z-index: 9;
}

.arrow-down::before {
  position: absolute;
  left: -1.35em;
  content: "";
  border-top: 1em solid red;
  border-left: 1em solid transparent;
  border-right: 1em solid transparent;
}
<div id="mainbox" class="mainbox">
  <div class="arrow-down"></div>
  <div id="box" class="box">
    <div class="box1">
      <span class="span1"><b>$10</b></span>
      <span class="span2"><b>$20</b></span>
      <span class="span3"><b>$30</b></span>
      <span class="span4"><b>$40</b></span>
    </div>
    <div class="box2">
      <span class="span1"><b>$50</b></span>
      <span class="span2"><b>$60</b></span>
      <span class="span3"><b>$70</b></span>
      <span class="span4"><b>$80</b></span>
    </div>
  </div>

  <button class="spin">SPIN</button>
  <div id="winnings">Click "SPIN" to initiate.</div>

</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

jQuery - class remains unchanged on second click event

Operations: Upon clicking on an element with the class thumb_like or thumb_unlike, a like will be added or removed for the image using a POST request. The element with the class thumb_count will increase or decrease based on user actions. For example, lik ...

Incorporating Bootstrap JS into Next.js

Currently, I am in the process of learning next.js and experimenting with incorporating Bootstrap into my projects. To begin, I initiated a new project using npx create-next-app@latest my-app, utilizing the newly created "app" directory structure. Follow ...

Initializing start scripts in the package.json file

When launching my react app locally, I need to execute three commands: cd react-web npm run postinstall export REACT_APP_CUSTOMER_ENVIRONMENT=xxx npm start After running these commands, the application server starts on localhost:3000. For the start script ...

Exploring the power of asynchronous Mongoose queries using the async await

I have a system where authenticated users can create new user accounts and assign them to specific groups. The middleware flow for this process is outlined in the following route: router.post('/account/add-users', userController.validateRegist ...

Angular has the ability to round numbers to the nearest integer using a pipe

How do we round a number to the nearest dollar or integer? For example, rounding 2729999.61 would result in 2730000. Is there a method in Angular template that can achieve this using the number pipe? Such as using | number or | number : '1.2-2' ...

Is the component experiencing issues with its style functionality?

I am attempting to add CSS styles to app.component.ts using the :host property, but I am not seeing the desired results. The CSS is being applied, but not correctly. .ts export class AppComponent { title = "Default Title" data = 'This is defaul ...

Pre-requisites verification in TypeScript

I have a typescript class with various methods for checking variable types. How can I determine which method to use at the beginning of the doProcess() for processing the input? class MyClass { public static arr : any[] = []; // main method public stati ...

What is the best way to convert a string in JavaScript to be case-insensitive?

Can anyone assist me? Challenge: Develop a function called indexOfIgnoreCase which takes in two strings and identifies the first instance of the second string within the first string. This function should be insensitive to letter case. For example, indexO ...

The MUI component with hideBackDrop={true} is preventing me from clicking outside of the Drawer component to close it

I implemented a Drawer component which opens when an icon on the Map is clicked. The drawer menu appears along with a backshadow that drops over the map. Interestingly, clicking on the map while the backshadow is displayed closes the drawer without any i ...

Assemblage of Marionettes: Adding multiple elements to the DOM

I am working on a Marionette application and have come across an issue with inserting new tab items. I have a collection of tabs, but when adding a new item, I need to insert DOM elements in two different areas. The problem is that Marionette.CollectionV ...

Ways to transform date into a different structure using JavaScript

Fetching a date from an API gives me this format: 2017-04-20T07:00:00Z How can I convert it to the following format? 20.04.2017 I am using React to render the date: <div>{props.data.day}</div> I attempted to use toISOString().slice(0, 1 ...

Implementing a callback function following the completion of file reading in Phonegap

I have been facing this issue for quite some time now and I need assistance in finding a solution: When it comes to developing an android app, I rely on the phonegap framework. There is an async function called readFromFile() that reads a json file store ...

Retrieving extra data from JSON

Instead of just returning a success status in the JSON response from the controller, I would like to also include the person's name. Currently, the JSON response indicates whether the operation was successful and uses JsonRequestBehavior.AllowGet. T ...

"Error encountered when attempting to call the requestFocus() method on a Java applet from JavaScript

I'm encountering an issue with calling the requestFocus() method in JavaScript. Uncaught TypeError: Object #<HTMLAppletElement> has no method 'requestFocus' Below is my JavaScript code within the <head> tags: function onLoad() ...

What is the best way to split text copied from a textarea into <p> paragraphs with an equal number of characters in each?

Check out this JSFiddle version I've found a JSFiddle example that seems perfect for my current project needs. However, I'm wondering how to modify the code to ensure that each paragraph is evenly divided with the same number of characters and a ...

How can you position two elements at the bottom of a ul element with a lengthy height?

Looking for a way to position the last two li elements at the bottom of a large-height ul element while keeping the rest at the top. The implementation can be viewed here. Here is an example of the code: .my-ul { height: 90vh; width: 40%; backgr ...

Move the element that can be dragged with the identifier X to the designated drop area with the identifier

I am attempting to create a function that will allow me to drag a draggable element and drop it into a designated container using their IDs. However, I am unsure of how to get started. dropToContainer("myDraggable", "div3"); function dropToContainer(co ...

Could HTML code be inserted into the <Head> section of a NextJS page?

I need to add meta tags retrieved from the backend for a certain page to the Head section of my page component. In React, I know that I can incorporate HTML using <div dangerouslySetInnerHTML={{__html: response.someHtml}} />. Can this same method b ...

Using SimplyJS and XML: extracting the value of a specific key

Hey there, I wanted to update you on my progress with the Pebble Watch project. I've switched over to using an official external API to make HTTP requests for values, and now I'm receiving results in XML format instead of JSON. Here's a ...

Exploring the mechanics of JavaScript and jQuery Ajax: What's the secret to its function

It's common knowledge that browsers are single-threaded, meaning they can only either render the UI or execute Javascript snippets. While web workers offer a way to achieve multi-threading, let's focus on the default behavior. I'm curious a ...