Letter Scramble

by Louis Walch

HTML

<div class="intro">Scramble text on hover desired times, and ending back on original value. <br />Also reset action on hover out.</div>

<hr />
<p>Scramble words:</p>
<br />

<span class="scramble">Scramble</span><span class="scramble">Foxtrot</span><span class="scramble">Foo Bar</span><a href="#" class="scramble">Linkable Item</a><span class="scramble">L◘®em↔p♫um d☺lor</span>

<br /><br />
<span class="scramble">(2023) Longer item that could wrap multiple lines</span>
<span class="scramble">(2023) Longer item that could wrap multiple lines</span><span class="scramble">Longer item that could wrap multiple lines but this time text only</span>

<br /><br />
<div class="scramble small">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.</div>

<br />
<hr />
<p>Scramble letters:</p>
<br />

<span class="scramble" data-mode="letters">Scramble</span><span class="scramble" data-mode="letters">Foxtrot</span><span class="scramble" data-mode="letters">Foo Bar</span><a href="#" class="scramble" data-mode="letters">Linkable Item</a><span class="scramble" data-mode="letters">L◘®em↔p♫um d☺lor</span>

<br /><br />
<span class="scramble" data-mode="letters">(2023) Longer item that could wrap multiple lines</span>
<span class="scramble" data-mode="letters">(2023) Longer item that could wrap multiple lines</span><span class="scramble" data-mode="letters">Longer item that could wrap multiple lines but this time text only</span>

<br /><br />
<div class="scramble small" data-mode="letters">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque...

SCSS

BODY {
    font-family: Arial;
    margin: 20px;
    max-width: 1000px;
}
A {
    color: inherit;
    text-decoration: none;
    &:hover {
        text-decoration: underline;
    }
}
.intro {
    padding: 20px 20px 40px 20px;
    font-style: italic;
    color: #999;
}
.scramble {
    font-size: 30px;
    line-height: 50px;
    background-color: pink;
    margin: 20px 20px 20px 0;
    &.small {
        max-width: 600px;
        font-size: 15px;
        line-height: 19px;
    }
}

JavaScript

var scrambleText = function(text){
	let scrambled = '';
    text = text.split('');
    while (text.length > 0) {
		let letter = text.splice(text.length * Math.random() << 0, 1);
		scrambled += letter;
    }
   	return scrambled.replace(' ', '&nbsp;');
}


var scrambleWords = function(text){
    let words = text.split(' ');
    let words_scrambled = [];
    for (i = 0; i < words.length; i++) {
		let scrambled = scrambleText(words[i]);
        words_scrambled.push(scrambled);
	}    
    return words_scrambled.join(' ');
}


var scrambler = {
	timer : false,
	setup : function() {
    	$(this).data('original', $(this).text());
    },
	action : function() {
    	let $this = $(this);
    	let original = $this.data('original');
		let loop = 0;
		let loops = 5;
        let delay = 110;
        let mode = $this.data('mode') || 'words';
        let engine = (mode == 'letters') ? scrambleText : scrambleWords;
        
        $this.html(engine(original));
        
        scrambler.timer = setInterval(function() {
            if (++loop === loops) {
                clearInterval(scrambler.timer);
                // $this.html(original);
            } else {
            	$this.html(engine(original));
            }   
        }, delay);

    },
	reset : function() {
/*         clearInterval(scrambler.timer);
                let $this = $(this);
        $this.html($this.data('original'));    
         */    },
};


$('.scramble')
	.each(scrambler.setup)
    .hover(scrambler.action, scrambler.reset);