import jQuery from "jquery"; // Helpers /** * "Types" out a DOM element, emulating the way a human might. */ class Typer { private element: JQuery; private text: string; private cursor: boolean; private typed: number; private min: number; private max: number; private blink_tick: number; private blink_timeout: number; private end?: number; /** * Create the typer. * @param {HTMLElement} element - The element to type. * @param {number} blink - The time between cursor blinks. * @param {number} blink_timeout - How long the cursor should keep * blinking for after the text * finishes typing. */ constructor(element: JQuery, blink: number, blink_timeout: number) { // Retrieve the current content and wipe it. We also make the // element visible if it was hidden. this.element = element; this.text = this.element.html(); this.element.html(""); this.element.css("visibility", "visible"); this.cursor = false; this.typed = 0; this.min = 20; this.max = 70; this.blink_tick = blink; this.blink_timeout = blink_timeout; this.end = null; } /** * Start typing. */ type() { this._type(); this._blink(); } /** * Draw the current text line, i.e., anything that has been typed * so far, and a cursor if it is currently supposed to be on. * @private */ _draw() { let text = this.text.slice(0, this.typed); if (this.cursor) { text += "\u2588"; } window.requestAnimationFrame(() => this.element.html(text)); } /** * Type the next character, and prepare to draw the next one. If * no new characters are to be drawn, set the end timestamp. * @private */ _type() { this.typed += 1; this._draw(); if (this.typed != this.text.length) setTimeout(this._type.bind(this), this._type_tick()); else { this.end = Date.now(); } } /** * Make the cursor change blink status, and prepare for the next * blink. * @private */ _blink() { this.cursor = !this.cursor; this._draw(); // As long as we are typing, keep blinking if (this.typed != this.text.length) setTimeout(this._blink.bind(this), this.blink_tick); // Once typing ends, keep going for a little bit else if (Date.now() - this.end < this.blink_timeout) setTimeout(this._blink.bind(this), this.blink_tick); // Make sure we get rid of the cursor in the end else { this.cursor = true; setTimeout(this._blink.bind(this), this.blink_tick); } } /** * Calculate a "human" time for the next character to type. * @private */ _type_tick() { return Math.round(Math.random() * this.max) + this.min; } } jQuery(($) => { const typer = new Typer($(".head-line .typed").first(), 500, 3000); typer.type(); });