Here\'s my function.
function duplicate_step_through_highlighted (element_jq, target_jq, char_cb) {
console.log( element_jq);
var conten
Here is my solution, it is a more efficient, cleaner and faster way of doing it:
var start = 0; //Makes sure you start from the very beggining of the paragraph.
var text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras viverra sem dolor, nec tempor purus luctus vitae. Nulla massa metus, iaculis et orci euismod, faucibus fringilla metus. Sed pellentesque in libero nec.'; //Your text
var speed = 14; //Of course you can choose your own speed, 0 = instant, the more you add the slower it gets.
function typeWriter() {
if (start < text.length) {
document.querySelector('.demo').innerHTML += text.charAt(start);
start++;
}
setTimeout(typeWriter, speed);
}
<body onload="typeWriter();">
<p class="demo"></p>
</body>
I made a simple script to use on my website, it might help those who are looking to achieve this effect.
Here is a link for the repo at Github, here is the explanation:
class Typer {
constructor(typingSpeed, content, output) {
this.typingSpeed = typingSpeed;
// Parses a NodeList to a series of chained promises
this.parseHtml(Array.from(content), output);
};
makePromise(node, output) {
if (node.nodeType == 1) // element
{
// When a new html tag is detected, append it to the document
return new Promise((resolve) => {
var tag = $(node.outerHTML.replace(node.innerHTML, ""));
tag.appendTo(output);
resolve(tag);
});
} else if (node.nodeType == 3) // text
{
// When text is detected, create a promise that appends a character
// and sleeps for a while before adding the next one, and so on...
return this.type(node, output, 0);
} else {
console.warn("Unknown node type");
}
}
parseHtml(nodes, output) {
return nodes.reduce((previous, current) => previous
.then(() => this.makePromise(current, output)
.then((output) => this.parseHtml(Array.from(current.childNodes), output))), Promise.resolve());
}
type(node, output, textPosition) {
var textIncrement = textPosition + 1;
var substring = node.data.substring(textPosition, textIncrement);
if (substring !== "") {
return new Promise(resolve => setTimeout(resolve, this.typingSpeed))
.then(() => output.append(substring))
.then(() => this.type(node, output, textIncrement));
}
return Promise.resolve(output);
}
}
You might want to have a look at my recent answer or this older one (Demo), on how to implement such an effect.
Tip: Don't clone the elements into new ones, just hide them and make them appear part-for-part.
Also, it might be easier not to deal with jQuery instances at all but native DOM elements. So yes, a rewrite might do :-) And I think it does need a stack as well.
function animate(elements, callback) {
/* get: array with hidden elements to be displayes, callback function */
var i = 0;
(function iterate() {
if (i < elements.length) {
elements[i].style.display = "block"; // show
animateNode(elements[i], iterate);
i++;
} else if (callback)
callback();
})();
function animateNode(element, callback) {
var pieces = [];
if (element.nodeType==1) {
while (element.hasChildNodes())
pieces.push(element.removeChild(element.firstChild));
setTimeout(function childStep() {
if (pieces.length) {
animateNode(pieces[0], childStep);
element.appendChild(pieces.shift());
} else
callback();
}, 1000/60);
} else if (element.nodeType==3) {
pieces = element.data.match(/.{0,2}/g); // 2: Number of chars per frame
element.data = "";
(function addText(){
element.data += pieces.shift();
setTimeout(pieces.length
? addText
: callback,
1000/60);
})();
}
}
}
animate($("#foo").children());
Demo at jsfiddle.net
How it works:
addText
function adds some character to the current text node, and sets a timeout for itself - animation! In case everything is done, it invokes the callback
function.childStep
runs the animation on a childnode, and passes itself as the callback until no children are left - then nvokes the callback
function.animateNode
recursively runs over the node tree and animates the textnodes in thier order.iterate
function calls animateNode
(after unhinding them) on all input elements, by passing itself as the callback. After all input elements are finished, it invokes the outer callback
which is given as the second argument to animate
.