-2

I have a this spinning wheel, what I am trying to do is when the wheel starts spinning the block which is currently in the center should have opacity 100% and the rest is lets say 50% so it will give that highlight effect.

Codepen link:

Code in link

Thanks in advance

Block in the center should be highlighted when spinning

aaaaSton2
  • 7
  • 1
  • 3
  • If we do this in javascript it's gonna affect performance heavily since you're gonna check the position of every block relative to the line in the middle every second. if you want an alternative to this, you could probably have 2 semi-transparent elements or pseudo-elements on both sides of your selector and have a gap the size of 1 block between them. not the effect you want, but close – KyloDev Apr 16 '23 at 18:12
  • could You show me example in code how would it look like ? – aaaaSton2 Apr 16 '23 at 18:20
  • do you want to show the element under the selector like in the focus? – Faust Life Apr 16 '23 at 18:24
  • I don’t see any css or js in your code pen that attempts to set opacity. – James Apr 16 '23 at 18:34
  • yes because I didnt know how to do it thats why I asked... – aaaaSton2 Apr 16 '23 at 21:47

4 Answers4

0

Have all the .card elements have opacity: 0.5. We shall apply the opacity: 1 on the active .card as needed. To try to keep it as performant as possible, we only listen for active positional change when the spinner is spinning. We use requestAnimationFrame() to time our checks to the display frame.

const {
  start,
  stop,
  tick
} = (() => {
  // Whether we should be actively listening for changes in the active item.
  let highlightListen = false;
  // The currently highlighted item.
  let active;

  // Do a check of which element should be highlighted.
  const tick = () => {
    // Get the x-coordinate of the middle of the screen.
    const middle = window.innerWidth / 2;
    const middleCard = document
      // Get all elements at the point in the document of x: middle, y: 50px.
      .elementsFromPoint(middle, 50)
      // Filter this list to `.card` elements.
      .filter((element) => element.matches('.card'))
      // Get the first item from this array.
      ?.[0];

    // If this middle card is different from the last-known active item.
    if (active !== middleCard) {
      // Remove the highlight opacity style that was on the previously
      // active item.
      if (active) {
        active.style.opacity = '';
      }
      // Add the highlight opacity style to the new middle card. Check
      // that it exists since we might have hit an instance where the
      // the middle of the screen is not on a card.
      if (middleCard) {
        middleCard.style.opacity = '1';
      }
      // Store the new middle card.
      active = middleCard;
    }

    // If we should be listening to positional changes, run this check
    // again on the next drawing frame.
    if (highlightListen) {
      requestAnimationFrame(tick);
    }
  };

  return {
    // Start listening for active changes.
    start() {
      highlightListen = true;
      tick();
    },
    // Stop listening for active changes.
    stop() {
      highlightListen = false;
    },
    // Do a single check.
    tick,
  };
})();

$(document).ready(function() {
  //setup multiple rows of colours, can also add and remove while spinning but overall this is easier.
  initWheel();
  // Once all the elements are set up, do a single check to mark the initial state.
  tick();

  $('button').on('click', function() {
    var outcome = parseInt($('input').val());
    spinWheel(outcome);
  });
});

function initWheel() {
  var $wheel = $('.roulette-wrapper .wheel'),
    row = "";

  row += "<div class='row'>";
  row += "  <div class='card red'>1<\/div>";
  row += "  <div class='card black'>14<\/div>";
  row += "  <div class='card red'>2<\/div>";
  row += "  <div class='card black'>13<\/div>";
  row += "  <div class='card red'>3<\/div>";
  row += "  <div class='card black'>12<\/div>";
  row += "  <div class='card red'>4<\/div>";
  row += "  <div class='card green'>0<\/div>";
  row += "  <div class='card black'>11<\/div>";
  row += "  <div class='card red'>5<\/div>";
  row += "  <div class='card black'>10<\/div>";
  row += "  <div class='card red'>6<\/div>";
  row += "  <div class='card black'>9<\/div>";
  row += "  <div class='card red'>7<\/div>";
  row += "  <div class='card black'>8<\/div>";
  row += "<\/div>";

  for (var x = 0; x < 29; x++) {
    $wheel.append(row);
  }
}

function spinWheel(roll) {
  var $wheel = $('.roulette-wrapper .wheel'),
    order = [0, 11, 5, 10, 6, 9, 7, 8, 1, 14, 2, 13, 3, 12, 4],
    position = order.indexOf(roll);

  //determine position where to land
  var rows = 12,
    card = 75 + 3 * 2,
    landingPosition = (rows * 15 * card) + (position * card);

  var randomize = Math.floor(Math.random() * 75) - (75 / 2);

  landingPosition = landingPosition + randomize;

  var object = {
    x: Math.floor(Math.random() * 50) / 100,
    y: Math.floor(Math.random() * 20) / 100
  };

  $wheel.css({
    'transition-timing-function': 'cubic-bezier(0,' + object.x + ',' + object.y + ',1)',
    'transition-duration': '6s',
    'transform': 'translate3d(-' + landingPosition + 'px, 0px, 0px)'
  });

  // Start active positional checking.
  start();

  setTimeout(function() {
    $wheel.css({
      'transition-timing-function': '',
      'transition-duration': '',
    });

    var resetTo = -(position * card + randomize);
    $wheel.css('transform', 'translate3d(' + resetTo + 'px, 0px, 0px)');

    // Stop active positional checking.
    stop();
  }, 6 * 1000);
}
body {
  font-family: 'Titillium Web', sans-serif;
  background: #191B28;
}

.roulette-wrapper {
  position: relative;
  display: flex;
  justify-content: center;
  width: 100%;
  margin: 0 auto;
  overflow: hidden;
}

.roulette-wrapper .selector {
  width: 3px;
  background: grey;
  left: 50%;
  height: 100%;
  transform: translate(-50%, 0%);
  position: absolute;
  z-index: 2;
}

.roulette-wrapper .wheel {
  display: flex;
}

.roulette-wrapper .wheel .row {
  display: flex;
}

.roulette-wrapper .wheel .row .card {
  height: 75px;
  width: 75px;
  margin: 3px;
  border-radius: 8px;
  border-bottom: 3px solid rgba(0, 0, 0, 0.2);
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 1.5em;
  opacity: 0.5;
}

.card.red {
  background: #F95146;
}

.card.black {
  background: #2D3035;
}

.card.green {
  background: #00C74D;
}

* {
  box-sizing: border-box;
}
<link href="https://fonts.googleapis.com/css?family=Titillium+Web" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

<div class='roulette-wrapper'>
  <div class='selector'></div>
  <div class='wheel'></div>
</div>

<div>
  <input placeholder='outcome'>
  <button>
    Spin Wheel
  </button>
</div>
Wongjn
  • 8,544
  • 2
  • 8
  • 24
0

$(document).ready(function() {
  //setup multiple rows of colours, can also add and remove while spinning but overall this is easier.
  initWheel();

  $('button').on('click', function() {
    var outcome = parseInt($('input').val());
    spinWheel(outcome);
  });
});

function initWheel() {
  var $wheel = $('.roulette-wrapper .wheel'),
    row = "";

  row += "<div class='row'>";
  row += "  <div class='card red'>1<\/div>";
  row += "  <div class='card black'>14<\/div>";
  row += "  <div class='card red'>2<\/div>";
  row += "  <div class='card black'>13<\/div>";
  row += "  <div class='card red'>3<\/div>";
  row += "  <div class='card black'>12<\/div>";
  row += "  <div class='card red'>4<\/div>";
  row += "  <div class='card green'>0<\/div>";
  row += "  <div class='card black'>11<\/div>";
  row += "  <div class='card red'>5<\/div>";
  row += "  <div class='card black'>10<\/div>";
  row += "  <div class='card red'>6<\/div>";
  row += "  <div class='card black'>9<\/div>";
  row += "  <div class='card red'>7<\/div>";
  row += "  <div class='card black'>8<\/div>";
  row += "<\/div>";

  for (var x = 0; x < 29; x++) {
    $wheel.append(row);
  }
}

function spinWheel(roll) {
  var $wheel = $('.roulette-wrapper .wheel'),
    order = [0, 11, 5, 10, 6, 9, 7, 8, 1, 14, 2, 13, 3, 12, 4],
    position = order.indexOf(roll);

  //determine position where to land
  var rows = 12,
    card = 75 + 3 * 2,
    landingPosition = (rows * 15 * card) + (position * card);

  var randomize = Math.floor(Math.random() * 75) - (75 / 2);

  landingPosition = landingPosition + randomize;

  var object = {
    x: Math.floor(Math.random() * 50) / 100,
    y: Math.floor(Math.random() * 20) / 100
  };

  $wheel.css({
    'transition-timing-function': 'cubic-bezier(0,' + object.x + ',' + object.y + ',1)',
    'transition-duration': '6s',
    'transform': 'translate3d(-' + landingPosition + 'px, 0px, 0px)'
  });

  setTimeout(function() {
    $wheel.css({
      'transition-timing-function': '',
      'transition-duration': '',
    });

    var resetTo = -(position * card + randomize);
    $wheel.css('transform', 'translate3d(' + resetTo + 'px, 0px, 0px)');
  }, 6 * 1000);
}
body {
  font-family: 'Titillium Web', sans-serif;
  background: #191B28;
}

.roulette-wrapper {
  position: relative;
  display: flex;
  justify-content: center;
  width: 100%;
  margin: 0 auto;
  overflow: hidden;
}

.roulette-wrapper .selector {
  width: 3px;
  background: grey;
  left: 50%;
  height: 100%;
  transform: translate(-50%, 0%);
  position: absolute;
  z-index: 2;
}

/* What I added */
.roulette-wrapper .selector:before,
.roulette-wrapper .selector:after {
  content: '';
  position: absolute;
  height: 100%;
  width: calc(50vw - (75px / 2));
  background: #191B28;
  opacity: 50%
}

.roulette-wrapper .selector:before {
  right: 37px;
}

.roulette-wrapper .selector:after {
  left: 37px;
}
/****************/

.roulette-wrapper .wheel {
  display: flex;
}

.roulette-wrapper .wheel .row {
  display: flex;
}

.roulette-wrapper .wheel .row .card {
  height: 75px;
  width: 75px;
  margin: 3px;
  border-radius: 8px;
  border-bottom: 3px solid rgba(0, 0, 0, 0.2);
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 1.5em;
}

.card.red {
  background: #F95146;
}

.card.black {
  background: #2D3035;
}

.card.green {
  background: #00C74D;
}

* {
  box-sizing: border-box;
}
<link href="https://fonts.googleapis.com/css?family=Titillium+Web" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

<div class='roulette-wrapper'>
  <div class='selector'></div>
  <div class='wheel'></div>
</div>

<div>
  <input placeholder='outcome'>
  <button>
    Spin Wheel
  </button>
</div>

It's not exactly what you wanted but it's close and less heavy on the computing side

KyloDev
  • 256
  • 1
  • 10
0

How to check overlapping you can find here jQuery/JavaScript collision detection But I'm not sure that your solution is correct...

Faust Life
  • 61
  • 5
  • in your code, it could be something like this one in `initWheel` fix row initialization `row += "
    "; row += "
    1<\/div>";...` in `spinWheel` method add this one: `var list = $('.list');` in the `setTimeout` method add this one: `[...list].find((element) => { if (isOverlapping($selector,element)) { element.style = 'opacity: 100%'; } else { element.style = 'opacity: 50%'; } });`
    – Faust Life Apr 16 '23 at 19:05
0

A different approach would be to overlay the cards with a semi transparent grayish color, with the middle bit transparent. That way no extra calculations have to happen.

Here's a simple snippet - overlaying with a black, transparent, black linear-gradient. Obviously you can alter that to get the effect you want.

<link href="https://fonts.googleapis.com/css?family=Titillium+Web" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<style>
  body {
    font-family: 'Titillium Web', sans-serif;
    background: #191B28;
  }
  
  .roulette-wrapper {
    position: relative;
    display: flex;
    justify-content: center;
    width: 100%;
    margin: 0 auto;
    overflow: hidden;
  }
  
  .roulette-wrapper::after {
    content: '';
    width: 100%;
    height: 100%;
    background-image: linear-gradient(to right, black, transparent calc(50% - (75px / 2)) calc(50% + (75px / 2)), black);
    top: 0;
    left: 0;
    position: absolute;
  }
  
  .roulette-wrapper .selector {
    width: 3px;
    background: grey;
    left: 50%;
    height: 100%;
    transform: translate(-50%, 0%);
    position: absolute;
    z-index: 2;
  }
  
  .roulette-wrapper .wheel {
    display: flex;
  }
  
  .roulette-wrapper .wheel .row {
    display: flex;
  }
  
  .roulette-wrapper .wheel .row .card {
    height: 75px;
    width: 75px;
    margin: 3px;
    border-radius: 8px;
    border-bottom: 3px solid rgba(0, 0, 0, 0.2);
    display: flex;
    align-items: center;
    justify-content: center;
    color: white;
    font-size: 1.5em;
  }
  
  .card.red {
    background: #F95146;
  }
  
  .card.black {
    background: #2D3035;
  }
  
  .card.green {
    background: #00C74D;
  }
  
  * {
    box-sizing: border-box;
  }
</style>
<div class='roulette-wrapper'>
  <div class='selector'></div>
  <div class='wheel'></div>
</div>

<div>
  <input placeholder='outcome'>
  <button>
    Spin Wheel
  </button>
</div>
<script>
  $(document).ready(function() {
    //setup multiple rows of colours, can also add and remove while spinning but overall this is easier.
    initWheel();

    $('button').on('click', function() {
      var outcome = parseInt($('input').val());
      spinWheel(outcome);
    });
  });

  function initWheel() {
    var $wheel = $('.roulette-wrapper .wheel'),
      row = "";

    row += "<div class='row'>";
    row += "  <div class='card red'>1<\/div>";
    row += "  <div class='card black'>14<\/div>";
    row += "  <div class='card red'>2<\/div>";
    row += "  <div class='card black'>13<\/div>";
    row += "  <div class='card red'>3<\/div>";
    row += "  <div class='card black'>12<\/div>";
    row += "  <div class='card red'>4<\/div>";
    row += "  <div class='card green'>0<\/div>";
    row += "  <div class='card black'>11<\/div>";
    row += "  <div class='card red'>5<\/div>";
    row += "  <div class='card black'>10<\/div>";
    row += "  <div class='card red'>6<\/div>";
    row += "  <div class='card black'>9<\/div>";
    row += "  <div class='card red'>7<\/div>";
    row += "  <div class='card black'>8<\/div>";
    row += "<\/div>";

    for (var x = 0; x < 29; x++) {
      $wheel.append(row);
    }
  }

  function spinWheel(roll) {
    var $wheel = $('.roulette-wrapper .wheel'),
      order = [0, 11, 5, 10, 6, 9, 7, 8, 1, 14, 2, 13, 3, 12, 4],
      position = order.indexOf(roll);

    //determine position where to land
    var rows = 12,
      card = 75 + 3 * 2,
      landingPosition = (rows * 15 * card) + (position * card);

    var randomize = Math.floor(Math.random() * 75) - (75 / 2);

    landingPosition = landingPosition + randomize;

    var object = {
      x: Math.floor(Math.random() * 50) / 100,
      y: Math.floor(Math.random() * 20) / 100
    };

    $wheel.css({
      'transition-timing-function': 'cubic-bezier(0,' + object.x + ',' + object.y + ',1)',
      'transition-duration': '6s',
      'transform': 'translate3d(-' + landingPosition + 'px, 0px, 0px)'
    });

    setTimeout(function() {
      $wheel.css({
        'transition-timing-function': '',
        'transition-duration': '',
      });

      var resetTo = -(position * card + randomize);
      $wheel.css('transform', 'translate3d(' + resetTo + 'px, 0px, 0px)');
    }, 6 * 1000);
  }
</script>

Note: the GPU usage on my laptop was 15% when this was running.

A Haworth
  • 30,908
  • 4
  • 11
  • 14