Forgive me for being clickbait this time, but this is actually a digital flipper animation, except that we can completely use JS to achieve this without using anything else.

Take a look at the results first:

(PS :1. In response to the title, the red and black basketball score board was specially made; 2. GIF is looping ~~)

For this effect, I started with

    and

  • with four columns. Rotation of the list, the most intuitive is this. The most troublesome method is to make two or three layers of packages, and then set overflow, especially when there are disgusting scrollbars. The scrollbars are not only ugly, but also make errors in the width of each element calculated. In fact, it is not a very good method.

But that was a thing of the past. I didn’t have a choice before, but now I want to be the good guy using background-position.

Σ (っ ° Д °) っ what? !background-positionCan you write that?

Yes, you can write. If you can’t think of how to write friends can go to recall the Sprite figure this knowledge point.

Ohhh, д OMEGA, Sprite? This?

No, we’re referring to Image sprites, also known as CSS textures and sprites, which are used in many web apps that use lots of small ICONS. It can be used with a portion of an image, making it possible to use a single image file instead of multiple small files. A single image requires fewer HTTP requests and is more memory – and bandwidth-friendly than a single image file with a small icon. For details, see the introduction of MDN

The Sprite image here can be realized because CSS has the background-position property. Different backgrounds can be obtained by taking different positions on an image as the background.

O (~ ▽ ~)d OK, I understand this, then what relation does it have with the dynamic effect that we are going to talk about today?

What would happen if background-position moved?

⊙(· ◇ ·)? Up, down, left, right… What’s so special about that…

Yeah, up and down and left and right. But wouldn’t it be possible to achieve the dynamic effect we have today?

If the design lion were given a picture like this:

Combine that with the background-position we just talked about, and you know what to do?

(゜-゜) Moving up and down…

Yes, we can change the value of background-position so that it looks like a number wheel by moving up or down a frame!

(‘ ⌒´ sweet!

Huh? What’s the matter?

(‘ ⌒´ sweet) and the implementation of pure JS? So you need pictures to do it? You can’t do anything if the design lion doesn’t give you a big picture!

You really say this to the point, want to map every do a dynamic effect have to draw, this is not very troublesome?

Don’t worry, we are front-end ER, as long as the graph is not complicated, we can draw it by ourselves ~~

Next, let’s take out the canvas and draw pictures ~~:

const canvas = document.createElement('CANVAS'); // Let's create a canvas first
    canvas.height = (30 + 5) * 10; // Then set the width and length of the canvas, depending on the font we want to set
    canvas.width = 40; // Let's say we need to make a 30px word with a 5px distance
    const ctx = canvas.getContext('2d');
    ctx.font = '30px Impact'; // Set the font size and font style
    ctx.fillStyle = 'red'; // Set the font style
    for (let i = 0; i < 10; i++) { // Start looping numbers
        ctx.fillText(i, 5.30 + (i * 35));
    }
Copy the code

This little piece of code will give us a simple number diagram for animation:

Here we set the size of the number to be 30px and the spacing between the top and bottom to be 5px, so the total height of the corresponding canvas is :(30 + 5) * 10; So the height of each number I is going to be I * 35 (this is an important number, as we’ll see);

If I put a little bit of emphasis here, you’ll notice that in our code we start writing on the canvas at coordinate (5, 30), so you might ask: Why not at coordinate (5,0)? Didn’t you start at (5,30) with a 30px gap at the top? There really is no gap. Because the coordinate of canvas text is different from that of general text. Generally, elements of Canvas or DOM are aligned with the point in the upper left corner as the standard point, but the text of Canvas is not aligned with the point in the lower left corner as the standard point. More specifically, the standard point is the leftmost end of the text baseline. Don’t believe it? If we draw a dot and a line at (5, 30), we can see:

So you have to be a little bit careful here.

We don’t need to add it to the DOM at all. We can export it directly from the canvas:

const bgimg = canvas.toDataURL();
Copy the code

So we have a graph that we can use

(o゚▽゚)

Then we can move on — set the background image to the DOM and animate it using rAF and Tween as mentioned earlier:

The first is the rAF module. This time, the callback function is used to make rAF independent from the function, so as to achieve the decoupling effect of rAF and other animation modules.

/** * rAFPart * @param Duration animation execution time * @param callback function, used to change the DOM style, takes progress the current time process and duration animation execution as arguments to call TWEEN */
function rAFPart(duration, callback) {
        let startTime = 0;
        function rolllingStep(timestamp) {
            if(! startTime) { startTime = timestamp; }const progress = timestamp - startTime;
            callback(progress,duration);
            if (progress <= duration) {
                requestAnimationFrame(rolllingStep);
            }
        }
        requestAnimationFrame(rolllingStep);
    }
Copy the code

The second is the TWEEN function, which is used to calculate interval interpolation :(quadEaseOut eases the argument so that it is not commented again)

 function Tween(t, b, c, d) {
        if ((t /= d / 2) < 1) return c / 2 * t * t + b;
        return -c / 2 * ((--t) * (t - 2) - 1) + b;
    }
Copy the code

Then we can write the effect:

let cacheRed1 = 0; // Set four global variables to cache background-positions of the current four numbers. This is the red units digit
let cacheRed2 = 0;  // Red tens
let cacheBlack1= 0; // Black bits
let cacheBlack2 = 0; // Black tens
function rolling() {
        const cr1 = cacheRed1++;
        const br1 = cacheBlack1++; // Cache background-position data before scrolling
        rAFPart(1000, (progress, duration) => { // Perform a single-digit flip scroll
            const red1BgPos = Math.ceil(Tween(progress, cr1 * 35.35, duration).toFixed(2));
            const blk1BgPos = Math.ceil(Tween(progress, br1 * 35.35, duration).toFixed(2));
            BlackNumber[1].style.backgroundPosition = '0 -' + blk1BgPos + 'px';
            RedNumber[1].style.backgroundPosition = '0 -' + red1BgPos + 'px';
        });
        if (cacheBlack1 >= (cacheBlack2 + 1) * 10) { // Check whether the number in the black tens place needs to be flipped
            const br2 = cacheBlack2++; // The cache is then incremented
            rAFPart(1000, (progress, duration) => { // Perform a flip
                const pos = Math.ceil(Tween(progress, br2 * 35.35, duration).toFixed(2));
                BlackNumber[0].style.backgroundPosition = '0 -' + pos + 'px';

            });
        }
        if (cacheRed1 >= (cacheRed2 + 1) * 10) { // Check whether the number in the black tens place needs to be flipped
            const cr2 = cacheRed2++;
            rAFPart(1000, (progress, duration) => {
                const pos = Math.ceil(Tween(progress, cr2 * 35.35, duration).toFixed(2));
                RedNumber[0].style.backgroundPosition = '0 -' + pos + 'px';

            });
        }
        setTimeout((a)= > { // Repeat the execution
            rolling();
        }, 1500)}Copy the code

There are two points to explain here. First, we did not remember the specific background-position in detail, but used numbers from 0 to 9 to represent it, because we already knew the height of a number when we drew the figure above, so we knew clearly where each number was. And if we want to jump to the specified number later, it’s obviously better to use 0-9. Then, we should pay attention to the cache. RAF module is not executed at one time. When it returns to call back the callback function, it uses the background-position before the last increment to add it to TWEEN calculation.

Okay, that’s it, that’s it! Let’s see how it looks again:

Final filling: During browser debugging, it is found that if the background-position exceeds the size of the image, the browser will automatically repeat it, that is, the digital image with length 350 above. If the height of background-position is set to 350px, The browser will display the 0px position of the repeat image as the background, so if you want to do multiple rotation animations, you know what to do? (Squint)

Last but not least: this effect is fine for dynamic effects because it does not require interaction. However, in the case of interaction, this effect may not be applicable

Homer Simpson 2019.04.21

reference

A paid effect for jQuery House

No, I didn’t buy the source code for this effect, I just clicked F12 and did some analysis

Implement image merging in CSS

This article is original and shall not be reproduced without permission ~~

There are mistakes, please correct ~~

Attached is the github blog address (there is a working demo) : github.com/homerious/a…

Those who are interested can go up and have a look

END