JavaScript Scroll
This page contains code that you can use to create a JavaScript scroll. This is a JavaScript marquee that displays scrolling text. The text scrolls in any direction you need; horizontally (from right to left, left to right), or vertically (down to up, or up to down). The JavaScript scroll was originally created by Netscape and is distributed using the Mozilla Public License. It should work on most browsers.
This JavaScript scrolling script comes in two parts: The first part is an external .js file, which contains the scrolling text code. The second part is the customizable part, where you enter your own parameters.
Here are some samples, just to get you started.
Instructions
First of all, download xbMarquee.js.
If you prefer not to download the file, you can copy/paste the contents into a file (see bottom of this article).
Once you've done that, you can use any of the following codes to display your JavaScript scroller. These codes simply provide the parameters for the xbMarquee.js file. These parameters determine things such as the scroll direction, the text to scroll, the speed of the marquee etc. You only need to reference xbMarquee.js once on any page that uses the code (regardless of how many marquees are on that page).
Right to Left
This marquee scrolls from right to left.
Example:
Left to Right
This text scrolls from left to right.
Example:
Faster
This text scrolls from right to left, but much faster than the previous examples.
Example:
Scrolling Up
This text scrolls upwards. The height of the marquee has changed too - from 29px to 200px.
Example:
Scrolling Down
This text scrolls downwards.
Example:
Contents of xbMarquee.js
Below are the full contents of xbMarquee.js. You will need this for the above marquee examples to work.
/*
* $Id: xbMarquee.js,v 1.21 2003/09/14 21:22:26 bc Exp $
*
*/
/* ***** BEGIN LICENSE BLOCK *****
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Netscape code.
*
* The Initial Developer of the Original Code is
* Netscape Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Doron Rosenberg <[email protected]>
* Bob Clary <[email protected]>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
***** END LICENSE BLOCK ***** */
function xbMarquee(id, height, width, scrollAmount, scrollDelay, direction, behavior, html)
{
this.id = id;
this.scrollAmount = scrollAmount ? scrollAmount : 6;
this.scrollDelay = scrollDelay ? scrollDelay : 85;
this.direction = direction ? direction.toLowerCase() : 'left';
this.behavior = behavior ? behavior.toLowerCase() : 'scroll';
this.name = 'xbMarquee_' + (++xbMarquee._name);
this.runId = null;
this.html = html;
this.isHorizontal = ('up,down'.indexOf(this.direction) == -1);
if (typeof(height) == 'number')
{
this.height = height;
this.heightUnit = 'px';
}
else if (typeof(height) == 'string')
{
this.height = parseInt('0' + height, 10);
this.heightUnit = height.toLowerCase().replace(/^[0-9]+/, '');
}
else
{
this.height = 100;
this.heightUnit = 'px';
}
if (typeof(width) == 'number')
{
this.width = width;
this.widthUnit = 'px';
}
else if (typeof(width) == 'string')
{
this.width = parseInt('0' + width, 10);
this.widthUnit = width.toLowerCase().replace(/^[0-9]+/, '');
}
else
{
this.width = 100;
this.widthUnit = 'px';
}
// xbMarquee UI events
this.onmouseover = null;
this.onmouseout = null;
this.onclick = null;
// xbMarquee state events
this.onstart = null;
this.onbounce = null;
var markup = '';
if (document.layers)
{
markup = '<ilayer id="' + this.id + 'container" name="' + this.id + 'container" ' +
'height="' + height + '" ' +
'width="' + width + '" ' +
'clip="' + width + ', ' + height + '" ' +
'>' +
'<\/ilayer>';
}
else if (document.body && typeof(document.body.innerHTML) != 'string')
{
markup = '<div id="' + this.id + 'container" name="' + this.id + 'container" ' +
'style="position: relative; overflow: scroll; ' +
'height: ' + this.height + this.heightUnit + '; ' +
'width: ' + this.width + this.widthUnit + '; ' +
'clip: rect(0px, ' + this.width + this.widthUnit + ', ' + this.height + this.heightUnit + ', 0px); ' +
'">' +
'<div id="' + this.id + '" style="position:relative;' +
(this.isHorizontal ? 'width:0px;' : '') + // if we scroll horizontally, make the text container as small as possible
'">' +
(this.isHorizontal ? '<nobr>' : '') +
this.html +
(this.isHorizontal ? '<\/nobr>' : '') +
'<\/div>' +
'<\/div>';
}
else
{
markup = '<div id="' + this.id + 'container" name="' +
this.id + 'container" ' +
'style="position: relative; overflow: hidden; ' +
'height: ' + this.height + this.heightUnit + '; ' +
'width: ' + this.width + this.widthUnit + '; ' +
'clip: rect(0px, ' + this.width + this.widthUnit + ', ' + this.height + this.heightUnit + ', 0px); ' +
'">' +
'<\/div>';
}
document.write(markup);
window[this.name] = this;
}
// Class Properties/Methods
xbMarquee._name = -1;
xbMarquee._getInnerSize = function(elm, propName)
{
var val = 0;
if (document.layers)
{
// navigator 4
val = elm.document[propName];
}
else if (elm.style && typeof(elm.style[propName]) == 'number')
{
// opera
// bug in Opera 6 width/offsetWidth. Use clientWidth
if (propName == 'width' && typeof(elm.clientWidth) == 'number')
val = elm.clientWidth;
else
val = elm.style[propName];
}
else
{
//mozilla and IE
switch (propName)
{
case 'height':
if (typeof(elm.offsetHeight) == 'number')
val = elm.offsetHeight;
break;
case 'width':
if (typeof(elm.offsetWidth) == 'number')
val = elm.offsetWidth;
break;
}
}
return val;
};
xbMarquee.getElm = function(id)
{
var elm = null;
if (document.getElementById)
{
elm = document.getElementById(id);
}
else
{
elm = document.all[id];
}
return elm;
}
xbMarquee.dispatchUIEvent = function (event, marqueeName, eventName)
{
var marquee = window[marqueeName];
var eventAttr = 'on' + eventName;
if (!marquee)
{
return false;
}
if (!event && window.event)
{
event = window.event;
}
switch (eventName)
{
case 'mouseover':
case 'mouseout':
case 'click':
if (marquee[eventAttr])
return marquee['on' + eventName](event);
}
return false;
};
xbMarquee.createDispatchEventAttr = function (marqueeName, eventName)
{
return 'on' + eventName + '="xbMarquee.dispatchUIEvent(event, \'' + marqueeName + '\', \'' + eventName + '\')" ';
};
// Instance properties/methods
xbMarquee.prototype.start = function ()
{
var markup = '';
this.stop();
if (!this.dirsign)
{
if (!document.layers)
{
this.containerDiv = xbMarquee.getElm(this.id + 'container');
if (typeof(this.containerDiv.innerHTML) != 'string')
{
return;
}
// adjust the container size before inner div is filled in
// so IE will not hork the size of percentage units
var parentNode = null;
if (this.containerDiv.parentNode)
parentNode = this.containerDiv.parentNode;
else if (this.containerDiv.parentElement)
parentNode = this.containerDiv.parentElement;
if (parentNode &&
typeof(parentNode.offsetHeight) == 'number' &&
typeof(parentNode.offsetWidth) == 'number')
{
if (this.heightUnit == '%')
{
this.containerDiv.style.height =
parentNode.offsetHeight * (this.height/100) + 'px';
}
if (this.widthUnit == '%')
{
this.containerDiv.style.width =
parentNode.offsetWidth * (this.width/100) + 'px';
}
}
markup += '<div id="' + this.id + '" name="' + this.id + '" ' +
'style="position:relative; visibility: hidden;' +
(this.isHorizontal ? 'width:0px;' : '') + // if we scroll horizontally, make the text container as small as possible
'" ' +
xbMarquee.createDispatchEventAttr(this.name, 'mouseover') +
xbMarquee.createDispatchEventAttr(this.name, 'mouseout') +
xbMarquee.createDispatchEventAttr(this.name, 'click') +
'>' +
(this.isHorizontal ? '<nobr>' : '') +
this.html +
(this.isHorizontal ? '<\/nobr>' : '') +
'<\/div>';
this.containerDiv.innerHTML = markup;
this.div = xbMarquee.getElm(this.id);
this.styleObj = this.div.style;
}
else /* if (document.layers) */
{
this.containerDiv = document.layers[this.id + 'container'];
markup =
'<layer id="' + this.id + '" name="' + this.id + '" top="0" left="0" ' +
xbMarquee.createDispatchEventAttr(this.name, 'mouseover') +
xbMarquee.createDispatchEventAttr(this.name, 'mouseout') +
xbMarquee.createDispatchEventAttr(this.name, 'click') +
'>' +
(this.isHorizontal ? '<nobr>' : '') +
this.html +
(this.isHorizontal ? '<\/nobr>' : '') +
'<\/layer>';
this.containerDiv.document.write(markup);
this.containerDiv.document.close();
this.div = this.containerDiv.document.layers[this.id];
this.styleObj = this.div;
}
// Start must not run until the page load event has fired
// due to Internet Explorer not setting the height and width of
// the dynamically written content until then
switch (this.direction)
{
case 'down':
this.dirsign = 1;
this.startAt = -xbMarquee._getInnerSize(this.div, 'height');
this._setTop(this.startAt);
if (this.heightUnit == '%')
this.stopAt = this.height * xbMarquee._getInnerSize(this.containerDiv, 'height') / 100;
else
this.stopAt = this.height;
break;
case 'up':
this.dirsign = -1;
if (this.heightUnit == '%')
this.startAt = this.height * xbMarquee._getInnerSize(this.containerDiv, 'height') / 100;
else
this.startAt = this.height;
this._setTop(this.startAt);
this.stopAt = -xbMarquee._getInnerSize(this.div, 'height');
break;
case 'right':
this.dirsign = 1;
this.startAt = -xbMarquee._getInnerSize(this.div, 'width');
this._setLeft(this.startAt);
if (this.widthUnit == '%')
this.stopAt = this.width * xbMarquee._getInnerSize(this.containerDiv, 'width') / 100;
else
this.stopAt = this.width;
break;
case 'left':
default:
this.dirsign = -1;
if (this.widthUnit == '%')
this.startAt = this.width * xbMarquee._getInnerSize(this.containerDiv, 'width') / 100;
else
this.startAt = this.width
this._setLeft(this.startAt);
this.stopAt = -xbMarquee._getInnerSize(this.div,'width');
break;
}
this.newPosition = this.startAt;
this.styleObj.visibility = 'visible';
}
this.newPosition += this.dirsign * this.scrollAmount;
if ( (this.dirsign == 1 && this.newPosition > this.stopAt) ||
(this.dirsign == -1 && this.newPosition < this.stopAt) )
{
if (this.behavior == 'alternate')
{
if (this.onbounce)
{
// fire bounce when alternate changes directions
this.onbounce();
}
this.dirsign = -this.dirsign;
var temp = this.stopAt;
this.stopAt = this.startAt;
this.startAt = temp;
}
else
{
// fire start when position is a start
if (this.onstart)
{
this.onstart();
}
this.newPosition = this.startAt;
}
}
switch(this.direction)
{
case 'up':
case 'down':
this._setTop(this.newPosition);
break;
case 'left':
case 'right':
default:
this._setLeft(this.newPosition);
break;
}
this.runId = setTimeout(this.name + '.start()', this.scrollDelay);
};
xbMarquee.prototype.stop = function ()
{
if (this.runId)
clearTimeout(this.runId);
this.runId = null;
};
xbMarquee.prototype.setInnerHTML = function (html)
{
if (typeof(this.div.innerHTML) != 'string')
{
return;
}
var running = false;
if (this.runId)
{
running = true;
this.stop();
}
this.html = html;
this.dirsign = null;
if (running)
{
this.start();
}
};
// fixes standards mode in gecko
// since units are required
if (document.layers)
{
xbMarquee.prototype._setLeft = function (left)
{
this.styleObj.left = left;
};
xbMarquee.prototype._setTop = function (top)
{
this.styleObj.top = top;
};
}
else
{
xbMarquee.prototype._setLeft = function (left)
{
this.styleObj.left = left + 'px';
};
xbMarquee.prototype._setTop = function (top)
{
this.styleObj.top = top + 'px';
};
}