lassemt
lassemt

Reputation: 156

jQuery animated typing based on scroll position

I'm working on a project where I need text to write it self(like a typewriting effect) while the user scrolls the page.

I want 0% of the characters of a paragraph to show when the page is 0% scrolled, and the full paragraph to show when the page is 50% scrolled. It should also work in reverse. So the characters should disappear one by one if the user scrolls back up.

I already have a function that creates the effect I want to achieve based on interval and not scroll..

(function($) {
$.fn.writeText = function(content) {
    var contentArray = content.split(""),
        current = 0,
        elem = this;
    setInterval(function() {
        if(current < contentArray.length) {
            elem.text(elem.text() + contentArray[current++]);
        }
    }, 100);
};

})(jQuery);

http://jsfiddle.net/tQnG8/413/

I'm hoping that someone want to share their thoughts on how to solve this without using plugins.

Upvotes: 0

Views: 305

Answers (1)

Anly
Anly

Reputation: 309

I don't think you can reuse the code above for the effect you want. Although I'm sure you don't need me to tell you this, I'll summarize it anyway:

We have to:

  1. listen for a scroll event,
  2. calculate the percentage the page is scrolled,
  3. then calculate the index to where the text should be visible,
  4. and lastly, display it.

The most difficult part (imo) would be the second step to calculate the percentage the page is scrolled. Here is how I calculate it:

 var percent = (document.documentElement.scrollTop + window.innerHeight) / (document.body.clientHeight); // calculate the % the page is scrolled
 percent *= 2; //since we want 50% scroll to equate to 100% text

We get the scroll offset (in pixels) using document.documentElement.scrollTop and then add window.innerHeight so that we get the lower edge of the scroller. Then we simply divide by the total scrollable height, which is document.body.clientHeight. In the end, we should multiply the calculated percentage by 2 because you want 50% page scroll to equate to 100% visible text.


One problematic thing is that "scroll height" is dependent on the content. So if we then tie "the content" to the "scroll" we get a nasty loop.

An appropriate solution would be to always have the content text "added" / "layed out", and play with the "visibility". Compare the effect of display: none; to visibility: hidden;.

Here is what I ended up with:

 //this.children().detach();
 var $visible = $("<span style='visibility:visible;'></span>");
 var $hidden = $("<span style='visibility:hidden;'></span>"); //style='opacity:0.5;'   instead to visualise what is happening

 $visible.text(text); //or add it to $hidden instead, but I prefer this so that things degrade gracefully if the rest of the script fails
 this.prepend($visible).append($hidden);


And here is the whole code:

(function($) {
    $.fn.writeText = function(text) {
        //this.children().detach();
        var $visible = $("<span style='visibility:visible;'></span>");
        var $hidden = $("<span style='visibility:hidden;'></span>");
        //var $hidden = $("<span style='opacity:0.5;'></span>"); //to visualise what is happening

        $visible.text(text);
        this.prepend($visible).append($hidden);

        var scrollHandler = function() {
            var percent = (document.documentElement.scrollTop + window.innerHeight) / (document.body.clientHeight); // calculate the % the page is scrolled
            percent *= 2; //since we want 50% scroll to equate to 100% text

            var offset = Math.round(percent * text.length); //calculate the index to where the text should be visible

            //do the actual "writing"
            $visible.text(text.slice(0,offset));
            $hidden.text(text.slice(offset));
        };

        scrollHandler(); //initial call
        $(window).scroll(scrollHandler);

        return this; //return the jquery object for chaining
    }
})(jQuery);

You can see it here with demo content: http://jsfiddle.net/sy45zs3v/

Upvotes: 2

Related Questions