You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
75 lines
2.6 KiB
JavaScript
75 lines
2.6 KiB
JavaScript
/*
|
|
Copyright (c) 2021 by Justin Windle (https://codepen.io/soulwire/pen/mErPAK)
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
and associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
export class TextScramble {
|
|
constructor(el) {
|
|
this.el = el
|
|
this.chars = '!<>-_\\/[]{}—=+*^?#________'
|
|
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 class="dud">${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)]
|
|
}
|
|
}
|