preface

I haven’t moved for a long time. Recently, I just wrote a “slot machine” and sent it to discuss with everyone what implementation schemes there are and the pros and disadvantages of some implementation schemes. This paper mainly uses backgroundImage repeat, backgroundPositionY and other attributes for technical implementation. The development environment is under VUE, but fortunately, the basic function is transformed, does not involve too much DOM structure, and the cost of transforming components function is not very big;

Other options

Js-vue-nine Grid Lucky draw >>>

Js-vue-big Wheel Lottery >>>

UI

  • Let’s take a look at the static UI, just to get a sense of what an image is

Project analysis

  • One: parameter configuration, flexible adjustment later

    Input parameters, including moving belly, winding number, reference value, etcCopy the code
  • Two: initialize the starting position of UI and dynamically set the background

    1. Dynamically set the background to facilitate component maintenance and avoid CSS rewriting. 2Copy the code
  • Three. Configure grouping, each line needs to define the end position, operation bus, etc

    Three single lines, configuration classes for each single line, and the entry operations that run are also hereCopy the code
  • 4. Track line calculation

    Trajectory calculation, in recursive mode, an array of distances for each run, that is, trajectory linesCopy the code
  • Five. Track operation

    RequestAnimationFrame Frame animation is enabledCopy the code

Initial reference value reference diagram

  • Note, in order to better fit and calculate, fixed unit PX is used as measurement, involving all types of models, dynamic calculation is carried out with reference value, and most of the operations of “/2” in the following are treated as 2 times PSD;
  • And the following running award line drawings, all referred to as line drawings;

Solution Analysis – Parameter Configuration

I’m not going to pass it in, I’m going to go into default mode;

props: { img: { type: String, default: '' }, rlc: { type: Object, default: () => { return { eh: 158/2, // Each area starts from a blank area - ends at the end of a single module ew: 119/2, // Reference width ih: 63/2, // Initial move height 63 = (312/2-93) 312 = container height, calculate the intermediate distance 93 = the position between the first blank area and the middle of the first card ah: 2368/2, // full map height RFH: (158-63) / 2, // starting base value the first element runs to the middle base position sp: 50, // speed ln: 7, // laps dt: 750 // The default number of markets after the execution of the next track}}}},Copy the code

Solution analysis – Initializes the starting location of the UI

  • Mounted: Specifies whether to automatically read a line graph when the total height is passed in

    Var vm = this if (this.rlc. Ah) {this.c_ah = this.rlc. Ah this.initpx ()} else {var img = new Image() img.src = this.img img.onload = function (e) { vm.c_ah = img.height / 2 vm.initPx() } } },Copy the code
  • initPx

    InitPx () {window.addeventListener ('DOMContentLoaded', e => { const ps = document.getElementById('tiger-wrap').getElementsByTagName('p') var width = null var newheight = null Width = ps[0]. ClientWidth newheight = parseInt(width/(this.rlc.ew/this.c_ah)) // Scale to calculate px adaptors This.initstart = parseInt((this.rlc.ih/this.c_ah) * newheight) // Calculate the true height according to the reference sinking height this.ph = newheight // The total height of the wizard map ps.forEach(ele => { ele.style.backgroundImage = `url(${this.img})` ele.style.backgroundSize = `100% ${newheight}px` ele.style.backgroundPositionY = `${this.initStart}px` }) }) }Copy the code

Solution Analysis – Configure groups

  • Get the operating parameters of each line graph, and this function as the external entry;

  • In the calculation of scale, the operation of -2 is to define the first winning unit as 1, that is, the moving distance is minus, and the moving distance is -y.

    start (drawArr, Var prevConfig = this.drawConfig this. DrawConfig = var prevConfig = this.drawConfig  [] const reference = this.rlc.rfh const img1 = this.$refs.img1 const img2 = this.$refs.img2 const img3 = this.$refs.img3 const domArr = [img1, img2, img3] drawArr.forEach((val, Index) => {const scale = reference + this.rlc.eh * (val-2) // Use the first drop as a reference for this.rlc.eh * (val-2 const pp = prevConfig[index] ? Math.abs(prevConfig[index].endPoint) : 0 this.drawConfig.push({ endPoint: -parseint ((scale/this.c_ah) * this.ph), // startPoint: (prevConfig [index] && prevConfig [index] endPoint) | | 0, / / position height index, index, / / the current draw position the dom: DomArr [index], // The current dom turn: true, // Whether the current group raffle switch stotal: -this.ph * this.rlc.ln -parseint ((scale/this.c_ah) * this.ph), // -this.ph * this.rlc.ln - parseInt((scale/this.c_ah) * this.ph) + pp // Compatible last stay position calculation bus})}) // Start running according to the set interval this.drawConfig.forEach((val, index) => { setTimeout(() => { this.Rundom(val) }, index * this.rlc.dt) }) this.endBack = endBack },Copy the code

Scheme analysis – Track line calculation

  • That is to get the running data set, simple understanding, maintain a reasonable array of lines to reduce large numerical acceleration, reduce numerical deceleration;

  • The end data string should be pixel 1, so as to stop at the specified position without any offset. In this paper, it is set as 10.

    Runline (domPage) {// track each line corresponds to a set of track movements const {total, startPoint, Stotal} = domPage const lineArr = [] const num = this.rlc.sp // Each trajectory distance/speed let numwrap = 0 let slow = 0 let newnumwrap If (this.initStart > startPoint && startPoint === 0) {if (this.initStart > startPoint && startPoint === 0) { lineArr.push([this.initStart, 0, 3]) } for (let i = 0; i < forlength; I ++) {slow = I * 0.5 + 3 linearr. push([-i * num + startPoint, num * -i - num + startPoint, slow]) } numwrap = lineArr[lineArr.length - 1][1] * 1 for (let j = 0; j < forlength; j++) { lineArr.push([ -j * num + numwrap, num * -j - num + numwrap, LineArr [lineArr. Leng-1][1])} lineArr[lineArr. Leng-1][1] if (newnumwrap > total && total === stotal) { if (Math.abs(total) - Math.abs(newnumwrap) > 10) { const next2 = newnumwrap - (Math.abs(total) - Math.abs(newnumwrap) - 10) lineArr.push([newnumwrap, next2, 3]) } lineArr.push([newnumwrap, total, If (total > stotal) {if (math.abs (stotal) - math.abs (total) > 10) {const next2  = newnumwrap - (Math.abs(stotal) - Math.abs(newnumwrap) - 10) lineArr.push([newnumwrap, next2, 3]) } lineArr.push([newnumwrap, stotal, 1]) } return lineArr },Copy the code

Solution analysis – Trajectory running

  • With the above, processed configuration, to run data, that is, loop data groups, — data values

    Rundom (domPage) {var num = domPage. / / orbit the startPoint | | this. InitStart / / the default starting from 0 var lineConfig = This.RunBody(() => {lineConfig. ForEach (ele => {if) (num > ele[1] && num <= ele[0]) { num = num - ele[2] } }) if (num <= lineConfig[lineConfig.length - 1][1]) { this.drawConfig[domPage.index].turn = false if (! this.drawConfig[2].turn) { this.endBack && this.endBack() } } domPage.dom.style.backgroundPositionY = `${num}px` if (! this.drawConfig[domPage.index].turn) { domPage.dom.style.backgroundPositionY = `${ this.drawConfig[domPage.index].endPoint }px` } }, domPage) },Copy the code
  • The frame of animation

    RunBody (into, DomPage) {/ / sports requestAnimationFrame webkitRequestAnimationFrame / / animation to treatment Recursive implementation / / not compatible mode Using setTimeout if (! this.drawConfig[domPage.index].turn) return const RunBody = () => { into() this.RunBody(into, domPage) } if (window.requestAnimationFrame) { window.requestAnimationFrame(RunBody) } else if (window.webkitRequestAnimationFrame) { window.webkitRequestAnimationFrame(RunBody) } else { window.setTimeout(RunBody, 10)}},Copy the code

Components use

  • The introduction of
import tigerDraw from './components/tiger/tiger'
<tigerDraw ref="tigerDraw" :img="img"></tigerDraw>
Copy the code
  • call
this.$refs.tigerDraw.start([1, 2, 3], () => {})
Copy the code

Effect of lucky draw

conclusion

This is the general implementation of the idea, some places are a little rough; In addition, from the overall description, some compatible reference values or a bit around, or need to combine the source code to run, otherwise there may not be too direct sense of substitution; To the end is also hope to be able to cast a brick to attract jade, explore a variety of implementation schemes, comparative analysis of some advantages and disadvantages.

Attached to this article – source address, welcome to discuss ha ~