Home > database >  How do I fade in text in a div, while simultaneously descrambling the text in JavaScript
How do I fade in text in a div, while simultaneously descrambling the text in JavaScript

Time:10-21

How do I perform an animated transformation on text while performing a fade in effect during the animated transformation?

        // ——————————————————————————————————————————————————
        // TextScramble
        // ——————————————————————————————————————————————————

        class TextScramble {
            constructor(elm, numWords) {
                this.el = el
                this.numWords = numWords;
                this.chars = '!<>-_\\/[]{}—= *^?#1234567890________'
                this.update = this.update.bind(this)
            }
            setText(newText) {
                const oldText = this.el.innerText
                const length = Math.max(oldText.length, newText.length)
                const promise = new Promise((resolve) => this.resolve = resolve)
                this.queue = []
                for (let i = 0; i < length; i  ) {
                    const from = oldText[i] || ''
                    const to = newText[i] || ''
                    const start = Math.floor(Math.random() * 40)
                    const end = start   Math.floor(Math.random() * 40)
                    this.queue.push({ from, to, start, end })
                }
                cancelAnimationFrame(this.frameRequest)
                this.frame = 0
                this.update()
                return promise
            }
            update() {
                let output = ''
                let complete = 0
                for (let i = 0, n = this.queue.length; i < n; i  ) {
                    let { from, to, start, end, char } = this.queue[i]
                    if (this.frame >= end) {
                        complete  
                        output  = to
                    } else if (this.frame >= start) {
                        if (!char || Math.random() < 0.28) {
                            char = this.randomChar()
                            this.queue[i].char = char
                        }
                        output  = `<span >${char}</span>`
                    } else {
                        output  = from
                    }
                }
                this.el.innerHTML = output
                if (complete === this.queue.length) {
                    this.resolve()
                } 
                else {
                    this.frameRequest = requestAnimationFrame(this.update)
                    this.frame  
                }
            }
            randomChar() {
                return this.chars[Math.floor(Math.random() * this.chars.length)]
            }
        }

        // ——————————————————————————————————————————————————
        // Example
        // ——————————————————————————————————————————————————

        const phrases = {
            'Coding' : 'none',
            'With' : 'none',
            'Muhammad': 'none',
            'Coding With Muhammad' : 'fade'
        }
        let phraseValues = Object.keys(phrases);
        const el = document.querySelector('.text')
        const fx = new TextScramble(el, phraseValues.length)

        let counter = 0
        let animation = phraseValues[0];

        let animate = () => {
            return function(callback) {
            document.querySelector(".text").animate([
                // keyframes
                { opacity: '0' },
                { opacity: '1' }
                    ], {
                    // timing options
                    duration: 3500,
                    iterations: 1
                });
                callback();
            }
        }   

        const next = () => {
        fx.setText(phraseValues[counter]).then(() => {
                if (counter <= phraseValues.length)
                    setTimeout(next, 800)
                else {
                    animation = phrases[phraseValues[counter]]
                    setTimeout(animate(next), 800)
                }
            })
            counter = (counter   1) % phraseValues.length
        }
        next()
html, body {
            font-family: 'Roboto Mono', monospace;
            background: #212121;
            height: 100%;
        }
        .container {
            height: 100%;
            width: 100%;
            justify-content: center;
            align-items: center;
            display: flex;
        }
        .text {
            font-weight: 100;
            font-size: 28px;
            color: #FAFAFA;
        }
        .dud {
            color: #757575;
        }
        .fadeIn {
            animation: fade 10s;
        }
 <div class="container">
        <div class="text"></div>
    </div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

I was very close:

I moved the callback invocation statement above the closure return statement below it. I left the animation keyframes as is.

Finally I modified the setTimeout in the phrase to be animated, to be as follows:

I placed a next and animate as callbacks in the setTimeout together to be called back in cascade sequence.

I used a anonymous function definition using arrow notation.

On animate (the function I wrote) I passed in the fx.update function definition as the callback, and invoked the closure function returned animate as the Higher Order Function, like so.

See Results!

// ——————————————————————————————————————————————————
            // TextScramble
            // ——————————————————————————————————————————————————
    
            class TextScramble {
                constructor(elm, numWords) {
                    this.el = el
                    this.numWords = numWords;
                    this.chars = '!<>-_\\/[]{}—= *^?#1234567890________'
                    this.update = this.update.bind(this)
                }
                setText(newText) {
                    const oldText = this.el.innerText
                    const length = Math.max(oldText.length, newText.length)
                    const promise = new Promise((resolve) => this.resolve = resolve)
                    this.queue = []
                    for (let i = 0; i < length; i  ) {
                        const from = oldText[i] || ''
                        const to = newText[i] || ''
                        const start = Math.floor(Math.random() * 40)
                        const end = start   Math.floor(Math.random() * 40)
                        this.queue.push({ from, to, start, end })
                    }
                    cancelAnimationFrame(this.frameRequest)
                    this.frame = 0
                    this.update()
                    return promise
                }
                update = () => {
                    let output = ''
                    let complete = 0
                    for (let i = 0, n = this.queue.length; i < n; i  ) {
                        let { from, to, start, end, char } = this.queue[i]
                        if (this.frame >= end) {
                            complete  
                            output  = to
                        } else if (this.frame >= start) {
                            if (!char || Math.random() < 0.28) {
                                char = this.randomChar()
                                this.queue[i].char = char
                            }
                            output  = `<span >${char}</span>`
                        } else {
                            output  = from
                        }
                    }
                    this.el.innerHTML = output
                    if (complete === this.queue.length) {
                        this.resolve()
                    } 
                    else {
                        this.frameRequest = requestAnimationFrame(this.update)
                        this.frame  
                    }
                }
                randomChar() {
                    return this.chars[Math.floor(Math.random() * this.chars.length)]
                }
            }
    
            // ——————————————————————————————————————————————————
            // Example
            // ——————————————————————————————————————————————————
    
            const phrases = {
                'Coding' : 'none',
                'With' : 'none',
                'Muhammad': 'none',
                'Coding With Muhammad' : 'fade'
            }
            let phraseValues = Object.keys(phrases);
            const el = document.querySelector('.text')
            const fx = new TextScramble(el, phraseValues.length)
    
            let counter = 0
            let animation = phraseValues[0];
    
            let animate = (callback) => {
                callback();
                return function() {
                    document.querySelector(".text").animate([
                       // keyframes
                       { opacity: '0' },
                       { opacity: '1' }
                    ], {
                        // timing options
                        duration: 3500
                    });
                }
            }   
    
            const next = () => {
            fx.setText(phraseValues[counter]).then(() => {
                    if (counter < phraseValues.length-1)
                        setTimeout(next, 800)
                    else {
                        setTimeout(() => {next, animate(next, fx.update)()}, 800)
                    }
                })
                counter = (counter   1) % phraseValues.length
            }
            next()
html, body {
            font-family: 'Roboto Mono', monospace;
            background: #212121;
            height: 100%;
        }
        .container {
            height: 100%;
            width: 100%;
            justify-content: center;
            align-items: center;
            display: flex;
        }
        .text {
            font-weight: 100;
            font-size: 28px;
            color: #FAFAFA;
        }
        .dud {
            color: #757575;
        }
<div class="container">
        <div class="text"></div>
 </div>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related