/** * jQuery.smoothDivScroll - Smooth div scrolling using jQuery. * This plugin is for turning a set of HTML elements's into a smooth scrolling area. * * Copyright (c) 2009 Thomas Kahn - thomas.kahn(at)karnhuset(dot)net * * This plugin is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This plugin is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. . * * Date: 2009-04-20 * @author Thomas Kahn * @version 0.8 * * Changelog * --------------------------------------------- * 0.8 - Major update. New parameter setup. Lots of new autoscrolling capabilities and * new parameters for controlling the scrolling speed. Made it possible to start * the scroller at a specific element. * * 0.7 - Added support for autoscrolling after the page has loaded. * Added support for making the hot spots visible at start for X number of seconds * or visible all the time. * * 0.6 - First version. */ (function($) { jQuery.fn.smoothDivScroll = function(options){ var defaults = { scrollingHotSpotLeft: "div.scrollingHotSpotLeft", // The hot spot that triggers scrolling left scrollingHotSpotRight: "div.scrollingHotSpotRight", // The hot spot that triggers scrolling right scrollWrapper: "div.scrollWrapper", // The wrapper element that surrounds the scrollable area scrollableArea: "div.scrollableArea", // The actual element that is scrolled left or right hiddenOnStart: false, // True or false. Determines whether the element should be visible or hidden on start ajaxContentURL: "", // Optional. If supplied, content is fetched through AJAX using the supplied URL countOnlyClass: "", // Optional. If supplied, the function that calculates the width of the scrollable area will only count elements of this class scrollingSpeed: 25, // A way of controlling the scrolling speed. 1=slowest and 100= fastest. mouseDownSpeedBooster: 3, // 1 is normal speed (no speed boost), 2 is twice as fast, 3 is three times as fast, and so on autoScroll: "", // Optional. Leave it blank if you don't want any autoscroll. // Otherwise use the values "onstart" or "always". // onstart - the scrolling will start automatically after // the page has loaded and scroll according to the method you've selected // using the autoScrollDirection parameter. When the user moves the mouse // over the left or right hot spot the autoscroll will stop. After that // the scrolling will only be triggered by the host spots. // always - the hot spots are disabled alltogether and the scrollable area // will only scroll automatically. autoScrollDirection: "right", // This parameter controls the direction and behavior of the autoscrolling. // Optional. The values are: // right - autoscrolls right and stops when it reaches the end // left - autoscrolls left and stops when it reaches the end // (only relevant if you have set the parameter startAtElementId). // backandforth - starts autoscrolling right and when it reaches // the end, switches to autoscrolling left and so on. Ping-pong style. // endlessloop - continuous scrolling right. An endless loop of elements. autoScrollSpeed: 1, // 1-2 = slow, 3-4 = medium, 5-13 = fast -- anything higher = superfast pauseAutoScroll: "", // Optional. Values mousedown and mouseover. Leave blank for no pausing abilities. visibleHotSpots: "", // Optional. Leave it blank for invisible hot spots. // Otherwise use the values "onstart" or "always". // onstart - makes the hot spots visible for X-number of seconds // after tha page has loaded and then they become invisible. // always - hot spots are visible all the time. hotSpotsVisibleTime: 5, // If you have selected "onstart" as the value for visibleHotSpots, // you set the number of seconds that you want the hot spots to be // visible after the page has loaded. After this time they will fade // away and become invisible again. startAtElementId: "" // Optional. Use this parameter if you want the offset of the // scrollable area to be positioned at a specific element directly // after the page has loaded. First give your element an ID in the // HTML code and then provide this ID as a parameter. }; options = $.extend(defaults, options); /* Identify global variables so JSLint won't raise errors when verifying the code */ /*global autoScrollInterval, autoScroll, clearInterval, doScrollLeft, doScrollRight, hideHotSpotBackgrounds, hideHotSpotBackgroundsInterval, hideLeftHotSpot, hideRightHotSpot, jQuery, makeHotSpotBackgroundsVisible, setHotSpotHeightForIE, setInterval, showHideHotSpots, window, windowIsResized */ // Iterate and make each matched element a SmoothDivScroll return this.each(function() { // Create a variable for the current "mother element" var $mom = $(this); // Load the content of the scrollable area using the optional URL. // If no ajaxContentURL is supplied, we assume that the content of // the scrolling area is already in place. if(options.ajaxContentURL.length !== 0){ $mom.scrollableAreaWidth = 0; $mom.find(options.scrollableArea).load((options.ajaxContentURL), function(){ $mom.find(options.scrollableArea).children((options.countOnlyClass)).each(function() { $mom.scrollableAreaWidth = $mom.scrollableAreaWidth + $(this).outerWidth(true); }); // Set the width of the scrollable area $mom.find(options.scrollableArea).css("width", ($mom.scrollableAreaWidth + "px")); // Hide the mother element if it shouldn't be visible on start if(options.hiddenOnStart) { $mom.hide(); } windowIsResized(); setHotSpotHeightForIE(); }); } // Some variables used for working with the scrolling var scrollXpos; var booster; // The left offset of the container on which you place // the scrolling behavior. // This offset is used when calculating the mouse x-position // in relation to scroll hot spots var motherElementOffset = $mom.offset().left; // A variable used for storing the current hot spot width. // It is used when calculating the scroll speed var hotSpotWidth = 0; // Set the booster value to normal (doesn't change until the user // holds down the mouse button over one of the hot spots) booster = 1; var hasExtended = false; // Stuff to do once on load $(window).one("load",function(){ // If the content of the scrolling area is not loaded through ajax, // we assume it's already there and can run the code to calculate // the width of the scrolling area, resize it to that width if(options.ajaxContentURL.length === 0) { $mom.scrollableAreaWidth = 0; $mom.tempStartingPosition = 0; $mom.find(options.scrollableArea).children((options.countOnlyClass)).each(function() { // Check to see if the current element in the loop is the one where the scrolling should start if( (options.startAtElementId.length !== 0) && (($(this).attr("id")) == options.startAtElementId) ) { $mom.tempStartingPosition = $mom.scrollableAreaWidth; } // Add the width of the current element in the loop to the total width $mom.scrollableAreaWidth = $mom.scrollableAreaWidth + $(this).outerWidth(true); }); // Set the width of the scrollableArea to the accumulated width $mom.find(options.scrollableArea).css("width", $mom.scrollableAreaWidth + "px"); // Check to see if the whole thing should be hidden at start if(options.hiddenOnStart) { $mom.hide(); } } // Set the starting position of the scrollable area. If no startAtElementId is set, the starting position // will be the default value (zero) $mom.find(options.scrollWrapper).scrollLeft($mom.tempStartingPosition); // If the user has set the option autoScroll, the scollable area will // start scrolling automatically if(options.autoScroll !== "") { autoScrollInterval = setInterval(autoScroll, 6); } // If autoScroll is set to always, the hot spots should be disabled if(options.autoScroll == "always") { hideLeftHotSpot(); hideRightHotSpot(); } // If the user wants to have visible hot spots, here is where it's taken care of switch(options.visibleHotSpots) { case "always": makeHotSpotBackgroundsVisible(); break; case "onstart": makeHotSpotBackgroundsVisible(); hideHotSpotBackgroundsInterval = setInterval(hideHotSpotBackgrounds, (options.hotSpotsVisibleTime * 1000)); break; default: break; } }); // If autoScroll is running, here's where it's stopped when the user positions the mouse over one of the hot spots $mom.find(options.scrollingHotSpotRight, options.scrollingHotSpotLeft).one('mouseover',function(){ if(options.autoScroll == "onstart") { clearInterval(autoScrollInterval); } }); // EVENT - window resize $(window).bind("resize",function(){ windowIsResized(); }); // A function for doing the stuff that needs to be // done when the browser window is resized function windowIsResized() { // If the scrollable area is not hidden on start, reset and recalculate the // width of the scrollable area if(!(options.hiddenOnStart)) { $mom.scrollableAreaWidth = 0; $mom.find(options.scrollableArea).children((options.countOnlyClass)).each(function() { $mom.scrollableAreaWidth = $mom.scrollableAreaWidth + $(this).outerWidth(true); }); $mom.find(options.scrollableArea).css("width", $mom.scrollableAreaWidth + 'px'); } // Reset the left offset of the scroll wrapper $mom.find(options.scrollWrapper).scrollLeft("0"); // Get the width of the page (body) var bodyWidth = $("body").innerWidth(); // If the scrollable area is shorter than the current // window width, both scroll hot spots should be hidden. // Otherwise, check which hot spots should be shown. if(options.autoScroll !== "always") { if($mom.scrollableAreaWidth < bodyWidth) { hideLeftHotSpot(); hideRightHotSpot(); } else { showHideHotSpots(); } } } // HELPER FUNCTIONS FOR SHOWING AND HIDING HOT SPOTS function hideLeftHotSpot(){ $mom.find(options.scrollingHotSpotLeft).hide(); } function hideRightHotSpot(){ $mom.find(options.scrollingHotSpotRight).hide(); } function showLeftHotSpot(){ $mom.find(options.scrollingHotSpotLeft).show(); // Recalculate the hot spot width. Do it here because you can // be sure that the hot spot is visible and has a width if(hotSpotWidth <= 0) { hotSpotWidth = $mom.find(options.scrollingHotSpotLeft).width(); } } function showRightHotSpot(){ $mom.find(options.scrollingHotSpotRight).show(); // Recalculate the hot spot width. Do it here because you can // be sure that the hot spot is visible and has a width if(hotSpotWidth <= 0) { hotSpotWidth = $mom.find(options.scrollingHotSpotRight).width(); } } function setHotSpotHeightForIE() { // Some bugfixing for IE 6 jQuery.each(jQuery.browser, function(i, val) { if(i=="msie" && jQuery.browser.version.substr(0,1)=="6") { $mom.find(options.scrollingHotSpotLeft).css("height", ($mom.find(options.scrollableArea).innerHeight())); $mom.find(options.scrollingHotSpotRight).css("height", ($mom.find(options.scrollableArea).innerHeight())); } }); } // ************************************************** // EVENTS - scroll right // ************************************************** // Check the mouse X position and calculate the relative X position inside the right hot spot $mom.find(options.scrollingHotSpotRight).bind('mousemove',function(e){ var x = e.pageX - (this.offsetLeft + motherElementOffset); scrollXpos = Math.round((x/hotSpotWidth) * options.scrollingSpeed); if(scrollXpos === Infinity) { scrollXpos = 0; } }); // mouseover right hot spot $mom.find(options.scrollingHotSpotRight).bind('mouseover',function(){ if(options.autoScroll == "onstart") { clearInterval(autoScrollInterval); } rightScrollInterval = setInterval(doScrollRight, 6); }); // mouseout right hot spot $mom.find(options.scrollingHotSpotRight).bind('mouseout',function(){ clearInterval(rightScrollInterval); scrollXpos = 0; }); // scrolling speed booster right $mom.find(options.scrollingHotSpotRight).bind('mousedown',function(){ booster = options.mouseDownSpeedBooster; }); // stop boosting the scrolling speed $("*").bind('mouseup',function(){ booster = 1; }); // The function that does the actual scrolling right var doScrollRight = function() { if(scrollXpos > 0) { $mom.find(options.scrollWrapper).scrollLeft($mom.find(options.scrollWrapper).scrollLeft() + (scrollXpos*booster)); } showHideHotSpots(); }; // ************************************************** // Autoscrolling // ************************************************** if(options.pauseAutoScroll == "mousedown" && options.autoScroll == "always") { $mom.find(options.scrollWrapper).bind('mousedown',function(){ clearInterval(autoScrollInterval); }); $mom.find(options.scrollWrapper).bind('mouseup',function(){ autoScrollInterval = setInterval(autoScroll, 6); }); } else if(options.pauseAutoScroll == "mouseover" && options.autoScroll == "always") { $mom.find(options.scrollWrapper).bind('mouseover',function(){ clearInterval(autoScrollInterval); }); $mom.find(options.scrollWrapper).bind('mouseout',function(){ autoScrollInterval = setInterval(autoScroll, 6); }); } var previousScrollLeft = 0; var pingPongDirection = "right"; var hasChanged = false; var swapAt; // The autoScroll function var autoScroll = function() { if (options.autoScroll == "onstart") { showHideHotSpots(); } switch(options.autoScrollDirection) { case "right": $mom.find(options.scrollWrapper).scrollLeft($mom.find(options.scrollWrapper).scrollLeft() + options.autoScrollSpeed); break; case "left": $mom.find(options.scrollWrapper).scrollLeft($mom.find(options.scrollWrapper).scrollLeft() - options.autoScrollSpeed); break; case "backandforth": // Calculate an indicator variable to see if the scrolling has reached the end previousScrollLeft = $mom.find(options.scrollWrapper).scrollLeft(); if(pingPongDirection == "right") { $mom.find(options.scrollWrapper).scrollLeft($mom.find(options.scrollWrapper).scrollLeft() + options.autoScrollSpeed); } else { $mom.find(options.scrollWrapper).scrollLeft($mom.find(options.scrollWrapper).scrollLeft() - options.autoScrollSpeed); } if(previousScrollLeft === $mom.find(options.scrollWrapper).scrollLeft()) { if(pingPongDirection == "right") { pingPongDirection = "left"; } else { pingPongDirection = "right"; } } break; case "endlessloop": // Calculate an indicator variable to see if the scrolling has reached the end previousScrollLeft = $mom.find(options.scrollWrapper).scrollLeft(); if(!(hasChanged)) { if(options.startAtElementId !== "") { swapAt = $mom.find(options.scrollWrapper).scrollLeft() + $("#" + options.startAtElementId).outerWidth(); } else { swapAt = $mom.find(options.scrollWrapper).scrollLeft() + $mom.find(options.scrollableArea).children(":first-child").outerWidth(); } hasChanged = true; } // Do the autoscrolling $mom.find(options.scrollWrapper).scrollLeft($mom.find(options.scrollWrapper).scrollLeft() + options.autoScrollSpeed); // Check to see if the first element in the scrollableArea needs to be moved to become the last or if the scrolling has reached the end if((swapAt <= $mom.find(options.scrollWrapper).scrollLeft()) || ((options.startAtElementId !== "") && (previousScrollLeft === $mom.find(options.scrollWrapper).scrollLeft()))) { // Clone the first element and append it last in the scrollableArea $mom.find(options.scrollableArea).append($mom.find(options.scrollableArea).children(":first-child").clone()); // Compensate for the removal of the first element by $mom.find(options.scrollWrapper).scrollLeft(($mom.find(options.scrollWrapper).scrollLeft() - $mom.find(options.scrollableArea).children(":first-child").outerWidth())); // Remove it from its original position as the first element $mom.find(options.scrollableArea).children(":first-child").remove(); hasChanged = false; } break; default: break; } }; // ************************************************** // EVENTS - scroll left // ************************************************** // Check the mouse X position and calculate the relative X position inside the left hot spot $mom.find(options.scrollingHotSpotLeft).bind('mousemove',function(e){ var x = $mom.find(options.scrollingHotSpotLeft).innerWidth() - (e.pageX - motherElementOffset); scrollXpos = Math.round((x/hotSpotWidth) * options.scrollingSpeed); if(scrollXpos === Infinity) { scrollXpos = 0; } }); // mouseover left hot spot $mom.find(options.scrollingHotSpotLeft).bind('mouseover',function(){ if(options.autoScroll == "onstart") { clearInterval(autoScrollInterval); } leftScrollInterval = setInterval(doScrollLeft, 6); }); // mouseout left hot spot $mom.find(options.scrollingHotSpotLeft).bind('mouseout',function(){ clearInterval(leftScrollInterval); scrollXpos = 0; }); // scrolling speed booster left $mom.find(options.scrollingHotSpotLeft).bind('mousedown',function(){ booster = options.mouseDownSpeedBooster; }); // The function that does the actual scrolling left var doScrollLeft = function() { if(scrollXpos > 0) { $mom.find(options.scrollWrapper).scrollLeft($mom.find(options.scrollWrapper).scrollLeft() - (scrollXpos*booster)); } showHideHotSpots(); }; // ************************************************** // Hot spot functions // ************************************************** // Function for showing and hiding hot spots depending on the // offset of the scrolling function showHideHotSpots() { // When you can't scroll further left // the left scroll hot spot should be hidden // and the right hot spot visible if($mom.find(options.scrollWrapper).scrollLeft() === 0) { hideLeftHotSpot(); showRightHotSpot(); } // When you can't scroll further right // the right scroll hot spot should be hidden // and the left hot spot visible else if(($mom.scrollableAreaWidth) <= ($mom.find(options.scrollWrapper).innerWidth() + $mom.find(options.scrollWrapper).scrollLeft())) { hideRightHotSpot(); showLeftHotSpot(); } // If you are somewhere in the middle of your // scrolling, both hot spots should be visible else { showRightHotSpot(); showLeftHotSpot(); } } // Function for making the hot spot background visible function makeHotSpotBackgroundsVisible() { // Alter the CSS (SmoothDivScroll.css) if you want to customize // the look'n'feel of the visible hot spots // The left hot spot $mom.find(options.scrollingHotSpotLeft).addClass("scrollingHotSpotLeftVisible"); // The right hot spot $mom.find(options.scrollingHotSpotRight).addClass("scrollingHotSpotRightVisible"); } // Hide the hot spot backgrounds. function hideHotSpotBackgrounds() { clearInterval(hideHotSpotBackgroundsInterval); // Fade out the left hot spot $mom.find(options.scrollingHotSpotLeft).fadeTo("slow", 0.0, function(){ $mom.find(options.scrollingHotSpotLeft).removeClass("scrollingHotSpotLeftVisible"); }); // Fade out the right hot spot $mom.find(options.scrollingHotSpotRight).fadeTo("slow", 0.0, function(){ $mom.find(options.scrollingHotSpotRight).removeClass("scrollingHotSpotRightVisible"); }); } }); }; })(jQuery);