Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scroll page so that element is visible

I've just tried prototype's scrollTo function and as the documentation states, it

Scrolls the window so that element appears at the top of the viewport

I'd like a function that

  1. only scrolls if the element is not entirely visible within the viewport
  2. scrolls so that the element appears at the center of the viewport

does anyone know of such a function in prototype, scriptaculous or stand-alone?

like image 463
pstanton Avatar asked Jan 11 '11 11:01

pstanton


2 Answers

I guess you need something like this (demo):

window.height

function getWindowHeight() {
  var body  = document.body;
  var docEl = document.documentElement;
  return window.innerHeight || 
         (docEl && docEl.clientHeight) ||
         (body  && body.clientHeight)  || 
         0;
}

Scroll

function scrollElemToCenter(id, duration) {
  var el = document.getElementById(id);
  var winHeight = getWindowHeight();
  var offsetTop = el.offsetTop;
  if (offsetTop > winHeight) { 
    var y = offsetTop - (winHeight-el.offsetHeight)/2;
    // wo animation: scrollTo(0, y);
    scrollToAnim(y, duration);
  }
}

Animation (optional, you can use script.aculo.us, etc.)

function interpolate(source,target,pos) { return (source+(target-source)*pos); }
function easing(pos) { return (-Math.cos(pos*Math.PI)/2) + 0.5; }

function scrollToAnim(targetTop, duration) {
  duration || (duration = 1000);
  var start    = +new Date,
      finish   = start + duration,
      startTop = getScrollRoot().scrollTop,
      interval = setInterval(function(){
        var now = +new Date, 
            pos = (now>finish) ? 1 : (now-start)/duration;
        var y = interpolate(startTop, targetTop, easing(pos)) >> 0;
        window.scrollTo(0, y);
        if(now > finish) { 
          clearInterval(interval);
        }
      }, 10);
}  

get scroll root

var getScrollRoot = (function() {
  var SCROLL_ROOT;
  return function() {
    if (!SCROLL_ROOT) {
      var bodyScrollTop  = document.body.scrollTop;
      var docElScrollTop = document.documentElement.scrollTop;
      window.scrollBy(0, 1);
      if (document.body.scrollTop != bodyScrollTop)
        (SCROLL_ROOT = document.body);
      else 
        (SCROLL_ROOT = document.documentElement);
      window.scrollBy(0, -1);
    }
    return SCROLL_ROOT;
  };
})();
like image 157
25 revs, 4 users 83% Avatar answered Oct 09 '22 09:10

25 revs, 4 users 83%


Here is an alternative approach, that uses some of Prototype's built in functionality for working with the viewport and scroll dimensions...

function scrollToCenterOfElement(id){
  // Cache element and property lookups...

  var element = $(id);
  var height = element.measure('height');
  var top = element.cumulativeOffset().top;
  var scroll = document.viewport.getScrollOffsets();
  var dimensions = document.viewport.getDimensions();

  // Checks to see if the top offset plus the height of the element is greater
  // than the sum of the viewport height and vertical scroll offset, which means
  // that the element has yet to be fully scrolled in to view, or if the 
  // top offset is smaller than the vertical scroll offset, which means the element
  // has already been (at least partly) scrolled out of view..

  if ((top + height > dimensions.height + scroll.top) || (top < dimensions.height + scroll.top)) {

    // Scroll window to sum of top offset plus half the height of the element
    // minus half of the viewport height, thus centering the element vertically.
    window.scrollTo(0, top + (height / 2) - (dimensions.height / 2));

  }

}

scrollToCenterOfElement('my-element');
like image 21
Rumble Avatar answered Oct 09 '22 08:10

Rumble