Today Christmas, I wish you all a happy holiday. Since it is Christmas, then we will learn something interesting, with dozens of lines of code to achieve a high-performance lottery game. Also based on this, to consolidate our javascript foundation, as well as the front-end application of some basic algorithms.

Results show

You will reap

  • Application of anti – shaking function
  • Use CSS to achieve nine grid layout
  • Algorithm for generating n – dimensional ring coordinates
  • How to achieve the circular random orbital motion function
  • Achieve acceleration animation
  • Performance analysis and optimization

Design ideas

The specific implementation

Since there are many schemes to achieve the nine grid drawing animation, such as using dynamic active border animation, using random algorithms and timers to set where to stop, and so on. In order to further improve performance, this paper introduces the method, will use the coordinate method, and cut the cost of operating the dom, entirely by js, realize the calculation of the path of the sliding block, block elements using absolute positioning, let it from the document flow, avoid other elements re-paint, and so on, finally click the button we will use image stabilization function to avoid frequently executed the function, cause unnecessary performance loss.

1. Nine-grid layout implementation

To make you more familiar with the DOM structure, I’m not going to do dynamic generation in JS. The following HTML structure:

<div class="wrap">
    <div class="title">Christmas whiff</div>
    <div class="box">
        <div class="item">I love you</div>
        <div class="item">Do you love me</div>
        <div class="item">I do not love you</div>
        <div class="item">Do you love me</div>
        <div class="item start">start</div>
        <div class="item">Do you love me</div>
        <div class="item">goodbye</div>
        <div class="item">Thank you for your help</div>
        <div class="item">Do you love me</div>
        <div class="spin"></div>
    </div>
</div>
Copy the code

We use Flex to achieve the layout, the core code is as follows:

.box {
    display: flex;
    flex-wrap: wrap;
    width: 300px;
    height: 300px;
    position: relative;
    .item {
        box-sizing: border-box;
        width: 100px;
    }
    / / the slider
    .spin {
        box-sizing: border-box;
        position: absolute;
        left: 0;
        top: 0;
        display: inline-block;
        width: 100px;
        height: 100px;
        background-color: rgba(0.0.0.2); }}Copy the code

To wrap the flex child elements, set flex-wrap: wrap; At this point, the nine-grid layout is implemented. The slider is absolutely positioned. For details on how to move along the circular track, see the following section.

2. Algorithm to generate n-dimensional ring coordinates

@param {number} @param {number} @param {number} @param {number} @param {number
function generateCirclePath(n, cell) {
  let arr = []
  for(let i=0; i< n; i++) {
      arr.push([i*cell, 0])}for(let i=0; i< n- 1; i++) {
      arr.push([(n- 1)*cell, (i+1)*cell])
  }
  for(let i=0; i< n- 1; i++) {
      arr.push([(n-i2 -)*cell, (n- 1)*cell])
  }
  for(let i=0; i< n2 -; i++) {
      arr.push([0, (n-i2 -)*cell])
  }
  return arr
}
Copy the code

If it’s a unit coordinate, then the cell is 1. The purpose of the cell design is in place. In order to integrate with the actual elements, we can manually set the width of the cell to achieve different sizes of n-dimensional circular coordinate sets.

3. Realization of circular random orbit motion function

From the analysis of the lucky draw animation, we can see that the trajectory of our slider is actually a set of circular coordinates, so we just need to let the vertex of the slider (the default upper left corner) change along the set of circular coordinates step by step.

function run(el, path, n = 1, i = 0, len = path.length) {
    setTimeout((a)= > {
        if(n > 0) {
          if(len <= i) {
              i = n === 1 ? len : 0
              n--
          }
          el.css('transform'.`translate(${path[i][0]}px, ${path[i][1]}px)`)
          run(el, path, n, ++i, len)
        }
    }, 300)}Copy the code

This will be able to achieve our slider in accordance with the nine frame motion animation, of course, the above function is only the basic animation, has not achieved at random position to stop, and the acceleration of the slider movement, this requires certain skills and JS basic knowledge such as closure.

3.1 Acceleration motion

The acceleration motion can be as simple as changing the delay time of setTimeout for each turn. The code is as follows:

function run(el, path, n = 1, speed = 60, i = 0, len = path.length) {
    setTimeout((a)= > {
        if(n > 0) {
          if(len <= i) {
              i = n === 1 ? len : 0
              n--
              speed += (300 - speed) / n
          }
          el.css('transform'.`translate(${path[i][0]}px, ${path[i][1]}px)`)
          run(el, path, n, speed, ++i, len)
        }
    }, speed)   
}
Copy the code
3.2 Random stop implementation

The random stop section mainly uses the MATH.random API. In the last circle, we decide when to stop according to the random value returned. Here we implement the random value inside the function.

/** * @param {element} el @param {array} path @param {array} path @param {number} speed @param {number} speed * @param @param {number} len = @param {number} len = @param {number} random
function run(el, path, n = 1, speed = 60, i = 0, len = path.length, random = Math.floor(Math.random() * len)) {
    setTimeout((a)= > {
        if(n > 0) {
          // If n is 1, set the winning value
          if(n === 1) {
            len = random
          }
          if(len <= i) {
              i = n === 1 ? len : 0
              n--
              speed += (300 - speed) / n
          }
          el.css('transform'.`translate(${path[i][0]}px, ${path[i][1]}px)`)
          run(el, path, n, speed, ++i, len, random)
        }
    }, speed)   
}
Copy the code

4. Realize the anti-shaking function and application of click start

Anti – shaking function:

// Anti-shake function, avoid frequent click to execute multiple functions
function debounce(fn, interval = 300) {
  let timeout = null
  return function () {
      clearTimeout(timeout)
      timeout = setTimeout((a)= > {
          fn.apply(this.arguments)
      }, interval)
  }
}
Copy the code

So when we click, the code should look like this:

// Click the Start button to start the drawing
$('.start').on('click',debounce((a)= > { run($('.spin'), generateCirclePath(3.100), 3)}))Copy the code

extension

After the article was published, some warm-hearted friends put forward several suggestions, which are summarized as follows:

  • Provide a callback after the draw animation ends to notify the page to process the other logic
  • When processing multiple clicks, although the stabilization is added, the user clicks the start button before the end of the animation, and the animation will be executed again, resulting in faster and faster animation, resulting in chaos.

Based on the above problems, I have made further expansion to solve the above mentioned problems.

  1. Add a callback when the animation ends:
/** * Ring random orbit motion function * @param {element} el motion dom element * @param {array} path motion ring coordinate set * @param {func} cb animation end callback * @param @param {number} I @param {number} len @param {number} len @param {number} random
function run(el, path, n = 1, cb, speed = 60, i = 0, len = path.length, random = Math.floor(Math.random() * len)) {
    setTimeout((a)= > {
        if(n > 0) {
          // If n is 1, set the winning value
          if(n === 1) {
            len = random
          }
          if(len <= i) {
              i = n === 1 ? len : 0
              n--
              speed += (300 - speed) / n
          }
          el.css('transform'.`translate(${path[i][0]}px, ${path[i][1]}px)`)
          run(el, path, n, cb, speed, ++i, len, random)
        }else {
          cb && cb()
        }
    }, speed)
}
Copy the code
  1. When processing multiple clicks, although the stabilization is added, the user clicks the start button before the end of the animation, and the animation will be executed again, resulting in faster and faster animation, resulting in chaos.
// 1. Click the "Start" button to start the drawing
$('.start').on('click',debounce((a)= > {
    // Disable clicking after clicking Start
    $('.start').css('pointer-events'.'none')
    run($('.spin'), generateCirclePath(3.100), 3, () = > {// After the animation is over, click the open button
      $('.start').css('pointer-events'.'auto')
      alert('Draw over')})}))Copy the code

Thank you for your serious suggestions. Continue to optimize.

conclusion

The advantage of this implementation is that it supports the lottery of n-dimensional ring coordinates. There are many applications based on the coordinate method, especially in games and graphics. It is important to consider the performance and scalability in the implementation process, so that we can use the same methodology in different scenarios. I will put the complete source code of this article on Github, welcome to exchange learning ~

The last

If you want to learn more about H5 games, Webpack, node, gulp, CSS3, javascript, nodeJS, Canvas data visualization and other front-end knowledge and practical, welcome to join us in the public account “Interesting Talk front-end” to learn and discuss, and jointly explore the boundary of the front-end.

More recommended

  • 2 years of vUE project practical experience summary
  • Javascript Design Patterns front-end Engineers Need to Know in 15 minutes (with detailed mind maps and source code)
  • “Front-end combat summary” the use of pure CSS website skin and focus diagram switch animation
  • “Front-end combat summary” using CSS3 to achieve cool 3D rotation perspective
  • Add a loading progress bar to your site using pace. Js
  • The Application of design Pattern of “Summary of Front End Actual Combat” — Memorandum Pattern
  • “Front End Combat Summary” using postMessage to achieve pluggable cross-domain chatbot
  • “Front-end combat summary” of the variable promotion, function declaration promotion and variable scope detailed explanation
  • “Front-end combat summary” how to change the URL without refreshing the page
  • A picture shows you how to play vue-Cli3 quickly
  • Vue Advanced Advanced series – Play with Vue and vuex in typescript
  • Implementing a CMS full stack project from 0 to 1 based on nodeJS (Part 1)
  • Implementing a CMS full stack project from 0 to 1 based on nodeJS (middle)
  • Implement a CMS full stack project from 0 to 1 based on nodeJS (Part 2)
  • Write a mock data server using nodeJS in 5 minutes
  • With CSS3 to achieve stunning interviewers background that background animation (advanced source)
  • Teach you to use 200 lines of code to write a love bean spell H5 small game (with source code)
  • Cartesian product is implemented and applied in javascript