Skip to content

Instantly share code, notes, and snippets.

@peterb0yd
Created October 21, 2018 14:23
Show Gist options
  • Save peterb0yd/4585b523c7168c451fb0a8ab58dbdfa3 to your computer and use it in GitHub Desktop.
Save peterb0yd/4585b523c7168c451fb0a8ab58dbdfa3 to your computer and use it in GitHub Desktop.
A file for creating dynamically typed text using plain HTML and vanilla Javascript
/**
* This module is used to simulate text typing in the DOM
*
*/
export default class Typer {
/**
* @func constructor
* @param el: dom element
* @param words: words to iterate
* @param typespeed: speed the each char will be 'typed'
* @description: initializes the Typer object
*/
constructor(el, words, typespeed = 100) {
this.el = el
this.words = words
this.typespeed = typespeed
this.interval = null
this.timeouts = []
this.isAnimationRunning = false
onFocusHandler(this)
}
/**
* @func startAnimation
* @description: starts an infinite loop animating through each word
*/
startAnimation() {
this.isAnimationRunning = true
const delayTime = this.words.length * 2000
const typingTime = this.words.map(w => w.split('').length * 2).reduce(getSum)
const totalTime = typingTime * this.typespeed + delayTime
this.interval = setInterval(this.runAnimation.bind(this), totalTime)
this.runAnimation()
}
/**
* @func runAnimation
* @description: runs the full typing animation once. adds and removes
* the text to and from the dom element's HTML
*/
runAnimation() {
let wordTime = 0
this.words.map(word => {
this.timeouts.push(setTimeout(async () => {
await this.typeText(word)
await delay(this, 1000)
await this.clearText()
await delay(this, 1000)
}, wordTime))
wordTime += word.split('').length * this.typespeed * 2 + 2000
})
}
/**
* @func stopAnimation
* @description: starts an infinite loop animating through each word
*/
async stopAnimation() {
clearInterval(this.interval)
this.timeouts.map(t => clearTimeout(t))
this.el.innerText = ''
await delay(this, 1000)
}
/**
* @func typeText
* @param word: String word to type
* @description: adds one char at a time within the dom's elements HTL
*/
async typeText(word) {
return new Promise(resolve => {
const chars = word.split('')
let charTime = 0
chars.map((char, i) => {
charTime += this.typespeed
this.timeouts.push(setTimeout(() => {
this.el.innerText += char
if (i === chars.length - 1) resolve()
}, charTime))
})
})
}
/**
* @func clearText
* @description: removes one char at a time within the dom element's HTML
*/
async clearText() {
return new Promise((resolve, reject) => {
const innerText = this.el.innerText
const chars = innerText.split('')
let charTime = 0
chars.map((char, i) => {
charTime += this.typespeed
this.timeouts.push(setTimeout(() => {
this.el.innerText = innerText.substring(0, this.el.innerText.length - 1)
if (i === chars.length - 1) resolve()
}, charTime))
})
})
}
}
/**
* @func delay
* @param self: the Typer instance
* @param t: the delay time length in milliseconds
* @description: delays a function
*/
const delay = async (self, t) => {
return new Promise((resolve, reject) => {
self.timeouts.push(setTimeout(() => resolve(), t))
})
}
/**
* @func getSum
* @param t: the total sum
* @param n: additional number to add to sum
* @description: gets a sum from an array of numbers
*/
const getSum = (t, n) => t + n
/**
* @func onFocusHandler
* @param self: the Typer instance
* @description: handles the user clicking out of the webpage or switching tabs
*/
const onFocusHandler = self => {
window.tabIndex = 0
window.onfocus = async () => {
await self.stopAnimation()
if (self.isAnimationRunning)
self.startAnimation()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment