Skip to content

Instantly share code, notes, and snippets.

@dievardump
Last active September 29, 2020 12:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dievardump/9df871ab80b60476890a977a66a7234c to your computer and use it in GitHub Desktop.
Save dievardump/9df871ab80b60476890a977a66a7234c to your computer and use it in GitHub Desktop.
Simple Text animation using gsap
/* for gsap transform */
.split-text__line,
.split-text__letter,
.split-text__word {
display: inline-block;
}
/* don't break "words" wrapper */
.split-text__word {
white-space: nowrap;
}
/* hide spaces at the beginning of a line first word, or at the end of the last word of a line */
.split-text__word.split-text__first-of-line .split-text__space:first-child,
.split-text__word.split-text__last-of-line .split-text__space:last-child {
display: none;
}
function debounce(func, wait = 100) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(this, args);
}, wait);
};
}
const splits = [];
const redrawSplits = debounce(() => {
splits.forEach((split) => split.asLines(true));
}, 10);
// export default class SpliText {
class SplitText {
constructor($element, asElement = 'span') {
if (!$element) {
return null;
}
this.$element = $element;
this.asElement = asElement;
this.text = this.$element.innerText;
this.$elements = [];
this.letters = [];
this.words = [];
this.lines = [];
this.wrap();
splits.push(this);
if (splits.length === 1) {
window.addEventListener('resize', redrawSplits);
}
}
wrap() {
const $fragment = document.createDocumentFragment();
let word = 0;
this.words[word] = document.createElement(this.asElement);
this.words[word].classList.add('split-text__word');
for (let i = 0; i < this.text.length; i++) {
const letter = this.text[i];
const $element = document.createElement(this.asElement);
$element.innerHTML = letter.replace(' ', '&nbsp;');
$element.setAttribute('data-original', letter);
$element.classList.add('split-text__letter');
this.words[word].appendChild($element);
// if space don't add to $elements
if (letter !== ' ') {
this.letters.push($element);
} else {
$element.classList.add('split-text__space');
word++;
this.words[word] = document.createElement(this.asElement);
this.words[word].classList.add('split-text__word');
}
this.$elements.push($element);
}
this.words.forEach(($word) => $fragment.appendChild($word));
this.$element.innerText = '';
this.$element.appendChild($fragment);
this.asLines();
}
asLines(force = false) {
if (!force && this.lines.length) {
return this.lines;
}
// type can be any
let lines = [];
let line = -1;
let top = -Infinity;
this.words.forEach(($element) => {
const rect = $element.getBoundingClientRect();
$element.classList.remove('split-text__first-of-line');
$element.classList.remove('split-text__last-of-line');
if (rect.y != top) {
if (lines[line]) {
const length = lines[line].length;
if (length) {
lines[line][0].classList.add('split-text__first-of-line');
lines[line][length - 1].classList.add('split-text__last-of-line');
}
}
line++;
lines[line] = [];
top = rect.y;
}
lines[line].push($element);
});
lines = lines.map((words) => {
const $line = document.createElement(this.asElement);
this.$element.appendChild($line);
words.forEach(($word) => {
$line.appendChild($word);
});
$line.classList.add('split-text__line');
return $line;
});
this.lines.forEach(($line) => {
$line.parentNode.removeChild($line);
});
this.lines = lines;
return lines;
}
asWords() {
return this.words;
}
asLetters() {
return this.letters;
}
destroy() {
this.$element.innerText = this.text;
// remove all references to domElements
this.$elements = [];
this.letters = [];
this.words = [];
this.lines = [];
splits.splice(splits.indexOf(this), 1);
if (splits.length === 0) {
window.removeEventListener('resize', redrawSplits);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment