Making a DHTML Script

Understanding the library

As mentioned before the reason we want to use a library is to take care of the most basic browser differences and concentrate on making the real code. The library has a lot of methods built in that we can reuse at any time. So when we need to make a script, effect or a menu that’s special for one site we just include the library (with the functions you need) and start coding.

In this tutorial we’ll make a simple but cute dragable menu script where we can drag the “head” of the menu and the rest slides after it. It’s important that you understand the basics about how the library works to be able to follow this tutorial, so if you haven’t please read the DHTML Lib tutorial.

Then let’s start coding!

Starting with HTML and styles

We’ll start by thinking a little about how to add our DIV tags. We need two mayor divs, one for the head part and one parent div for all the items. Then we’ll have one div for each item inside the parent div (in this example we’ll make 4 items). At this point we should also think a little about how the menu should behave on events that occur on the divs. Here’s a little overview:

So we’ll start with the HTML code to add inside the body tag:

<div id="divHead"> Menu</div>
<div id="divMenu">
  <div id="divItem0" class="clItem">Test item1</div>
  <div id="divItem1" class="clItem">Test item2</div>
  <div id="divItem2" class="clItem">Test item3</div>
  <div id="divItem3" class="clItem">Test item4</div>
</div>

Then we need to give the divs some styles:

<style>
#divMenu{
  position:absolute;
  font-family:arial,helvetica;
  font-size:12px;
  width:150;
  height:200;
  clip:rect(0,150,200,0);
  layer-background-color:silver;
  padding:4px
}
#divHead{
  position:absolute;
  font-family:arial,helvetica;
  font-size:12px;
  layer-background-color:#333333;
  background-color:#333333;
  clip:rect(0,150,20,0);
  height:20;
  cursor:move;
  z-index:10;
  width:150;
  padding:2px;
  font-size:13px;
  color:white;
  font-weight:bold
}
DIV.clItem{
  position:absolute;
  font-family:arial,helvetica;
  font-size:12px;
  height:30;
  top:0;
  padding:4px;
  width:150;
  clip:rect(0,150,30,0);
  cursor:hand
}</style>

We place that style tag in the head of our page. I wont talk much about these styles settings now, if you know a little CSS it should be pretty simple to follow. The height,widths and clipping are taken from FIG 1 that where made before I started making the menu. As you can see I have added cursor definitions (NOTE: Setting the cursor only works in Explorer 4+ and Netscape 6) and set the background colors. I set clip values to the same as height and width and layer-background-color to make NS4 cover the entire div with the background color. Did you know many Viagra Potenzmittel Shops using DHTML? They don´t buy Cialis or natürliche Potenzmittel on a dnymic shop, but viagra.

Then we are ready to start with the fun part, the scripting.

Making the script

We start with the easy part, adding a reference to out lib.js file in the head part of our page. (if you haven’t downloaded it yet, see the lib page) Like this:

<script language="JavaScript1.2" src="lib.js" type="text/javascript"></script>

Now we have the libary ready and can start with the code for the menu. First I want to make some global variables for the script. That can be easily changed:
numItems - The number of menu items we want to have.
itemOnColor - The background color to change the item to onmouseover
itemOffColor - The background color to change the item to onmouseout
So we set them like this:

numItems=4
itemOnColor="red"
itemOffColor="silver"

We also need to be able to control where each item goes when clicked so I add an array with links:

itemLinks=new Array()
itemLinks[0]="" 'Note that arrays always start at 0
itemLinks[1]="http://www.bratta.com"
itemLinks[2]="http://www.yahoo.com"
itemLinks[3]="http://www.altavista.com"

The next part of the script is be a init function where all the library objects are made, the placement of the layers are fixed and the script will start:

function init(){
  oHead=new lib_obj('divHead')
  oMenu=new lib_obj('divMenu')
  oMenu.bg(menuBgColor)
  oHead.dragdrop()

  oItems=new Array()
  var h=0
  for(i=0;i<numItems;i++){
    oItems[i]=new lib_obj('divItem'+i,'divMenu')
    oItems[i].moveIt(0,h)
    h+=oItems[i].h
    oItems[i].bg(itemOffColor)
    oItems[i].evnt.onmouseover=new Function("mover("+i+")")
    oItems[i].evnt.onmouseout=new Function("mout("+i+")")
    if(bw.ns4){
      oItems[i].ref.captureEvents(Event.MOUSEDOWN)
      oItems[i].ref.onmousedown = new Function("location.href='+itemLinks[i]+''")
    }else oItems[i].evnt.onclick=new Function("location.href='+itemLinks[i]+''")
  }
  oMenu.clipTo(0,oMenu.w,h,0,1)
  moveM2(10)
}

This function should be called to “start” the menu script, so either onload or just after the HTML divs are loaded. Let’s go line by line:

oHead=new lib_obj('divHead') - Here we make a new lib object called oHead which references the div called divHead.

oMenu=new lib_obj('divMenu') - Here we make a new lib object called oMenu which references the div called divHead.

oHead.dragdrop() - Set drag and drop support for the oHead object.

Then we make a new array which will contain all the items for the menu oItems=new Array() The we loop the array once for each item. Remember that we set the numItems variable above to 4, so this line for(i=0;i<numItems;i++) means that we want to loop from 0 to 4. The reason we use a loop here is because it makes smaller code and that it should be easy to add more elements (just add another HTML div and change numItem to 5). Inside each loop we start of by making each oItem[i] object (i is the counter for the loop):
oItems[i]=new lib_obj('divItem'+i,'divMenu'), then we move the object to left 0 and top h. As you see above h=0, on the line below h+=oItems[i].h we add the height of each element to the h variable so the item will be moved to the height of the previous item. That way the items will be below one another. After that we set the default background color oItems[i].bg(itemOffColor).

Now comes a little interesting part of the code; each lib object has a property called evnt that we use to set events for the object. We remember from FIG 1 that we wanted a onmouseover and a onmouseout event for the item divs that should change the background colors, we will make those functions in a little bit. An event handler set like this doesn’t support any arguments to a function, that’s why we attach the event to a new Function, the argument we want to pass is the number of the current item, so we go like this: oItems[i].evnt.onmouseover=new Function("mover("+i+")").

After that we set the onclick event which will make the page go to the the link for that item when clicked. Netscape 4 doesn’t support onclick events on layers, so we have to use onmousedown, but first we have to capture the event for that div (ref points to the document of that div) oItems[i].ref.captureEvents(Event.MOUSEDOWN), then add the event: oItems[i].ref.onmousedown = new Function("location.href=\'+itemLinks[i]+'\'"). For all other browsers we just set the onclick event like this: oItems[i].evnt.onclick=new Function("location.href=\'+itemLinks[i]+'\'")

We then end by clipping the main menu object to the same height and width as all the items: oMenu.clipTo(0,oMenu.w,h,0,1)
The last line in this function starts another function that will always check if the menu is moved. I will explain that function in a little bit.

Now we’ll make the mover and mout functions that will be called onmouseover and onmouseout of each item. They are pretty straight forward and look like this:

function mover(i){
  oItems[i].bg(itemOnColor)
}
function mout(i){
  oItems[i].bg(itemOffColor)
}

The argument is the number of the item that calls the functions. Then we just set the background color to the itemOnColor or the itemOffColor variables that we defined earlier.

The last but most important function moveM2 (called from last line in init above) looks like this:

function moveM2(inc){
  endx=oHead.x;
  endy=oHead.y+oHead.h
  x=oMenu.x;
  y=oMenu.y
  distx = endx - x;
  disty = endy - y
  num = Math.sqrt(Math.pow(distx,2)+Math.pow(disty,2))/inc
  dx = distx/num;
  dy = disty/num
  if((Math.floor(Math.abs(dx))<Math.floor(Math.abs(endx-x))
  ||Math.floor(Math.abs(dy))<Math.floor(Math.abs(endy-y)))){
    oMenu.moveBy(dx,dy)
  }else oMenu.moveIt(endx,endy)
  setTimeout("moveM2("+inc+")",20)
}

This function will loop itself and run all all the time while the user is on the page. Is basically just checks if there is a difference between the oHead object position and the oMenu object position, and if there is it will slide the oMenu object to the correct position. So when you drag the oHead object this function will notice that there is a difference between the positions and “fix” it. It has one argument; inc which helps us control how fast the oMenu object will slide.

Some of this examples you can see on Wordpress Blogs example Crazylifeblog

Again we’ll go line by line: The first four lines just set some varibles so it will be easier to follow below: endx=oHead.x - The x (left) position that the slide will end at.
endx=oHead.y+oHead.h - The y (top) position that the slide will end at.
x=oMenu.x - The current x (left) position of the oMenu object.
y=oMenu.y - The current y (top) position of the oMenu object.
Then we have two lines that figures out the distance we need to slide for x and y:
distx = endx - x, disty = endy - y.
The next line is pure good old fashion math, to get the slide to move correctly (we want the left and the top “sliding” to end at the same time) we find the number that we will divide the distance with to get the x and y to move the correctly number of pixel each time. We take the square root of the the distance powered by 2 and divided by inc: num = Math.sqrt(Math.pow(distx,2)+Math.pow(disty,2))/inc

The next step is to get the actual pixels to move for x and y; dx = distx/num; , dy = disty/num; We are now ready to start and check whether we should move the menu, I’ll take part one of this line first: Math.floor(Math.abs(dx))<Math.floor(Math.abs(endx-x)) Math.floor just rounds the numbers and makes them integers (rounds down to nearest hole number). Math.abs makes the number positiv no matter if it’s a negative number or not, we need this because we want the menu to move both ways, left and right (or up and down). So this line basically says: if the number of pixels to move x position is lower then the position to end at minus the current position - go on. The second part of that line does the same thing for the y position. If that line evaluates to true we will move the menu by dx and dy pixels: oMenu.moveBy(dx,dy). If it doesn’t evaluate to true we just move the menu straight to the endx and endy.
Ok, one line left, this is an easy one; setTimeout("moveM2("+inc+")",20) - it’s a timeout that calls this function every 20 milliseconds.
Why do we do that you might ask, well there are lots of different ways we could have done it for instance called the function only when the oHead is dragged or similar, but believe me; to make it as stable as possible this is the best way to go. Netscape 4 doesn’t support clearTimeout very well and if we did it another way there’s a pretty big chance we would have gotten some problems with multiple timeouts trying to do the same thing. Though timeouts are pretty heavy on the system it’s ok as long as you don’t have a lot of them going at the same time. Anyway, after that little side track I have good news; We are done!

Now we just need to paste it all together into one page and we have ourselves a brand new DHTML script.

 

The code

<html>
<head>
	<title>Drag menu from DHTMLCentral.com</title>
<style>
#divMenu{
  position:absolute;
  font-family:arial,helvetica;
  font-size:12px;
  width:150;
  height:200;
  clip:rect(0,150,200,0);
  layer-background-color:silver;
  padding:4px
}
#divHead{
  position:absolute;
  font-family:arial,helvetica;
  font-size:12px;
  layer-background-color:#333333;
  background-color:#333333;
  clip:rect(0,150,20,0);
  height:20;
  cursor:move;
  z-index:10;
  width:150;
  padding:2px;
  font-size:13px;
  color:white;
  font-weight:bold
}
DIV.clItem{
  position:absolute;
  font-family:arial,helvetica;
  font-size:12px;
  height:30;
  top:0;
  padding:4px;
  width:150;
  clip:rect(0,150,30,0);
  cursor:hand
}
</style>
<script language="JavaScript1.2" src="lib.js" type="text/javascript"></script>
<script>
/****************************************************************************
Drag menu from DHTMLCentral.com
*   Copyright (C) 2001 Thomas Brattli
*   This script was released at DHTMLCentral.com
*   Visit for more great scripts!
*   This may be used and changed freely as long as this msg is intact!
*   We will also appreciate any links you could give us.
*
*   Tutorial availble at dhtmlcentral.com
*   Made by Thomas Brattli 2001
***************************************************************************/
numItems=4 //How many items?
itemOnColor="red" //Item background color onmouseover
itemOffColor="silver" //Item background color onmouseout

itemLinks=new Array() //Link array - one link for each item
itemLinks[0]=""
itemLinks[1]="http://www.bratta.com"
itemLinks[2]="http://www.yahoo.com"
itemLinks[3]="http://www.altavista.com"

function init(){
  oHead=new lib_obj('divHead')
  oMenu=new lib_obj('divMenu')
  oHead.dragdrop()
  oItems=new Array()
  h=0
  for(i=0;i<numItems;i++){
    oItems[i]=new lib_obj('divItem'+i,'divMenu')
    oItems[i].moveIt(0,h)
    oItems[i].bg(itemOffColor)
    oItems[i].evnt.onmouseover=new Function("mover("+i+")")
    oItems[i].evnt.onmouseout=new Function("mout("+i+")")
    if(bw.ns4){
      oItems[i].ref.captureEvents(Event.MOUSEDOWN)
      oItems[i].ref.onmousedown = new Function("location.href='"+itemLinks[i]+"'")
    }else oItems[i].evnt.onclick=new Function("location.href='"+itemLinks[i]+"'")
    h+=oItems[i].h
  }
  oMenu.clipTo(0,oMenu.w,h,0,1)
  moveM2(10)
}
function mover(i){
  oItems[i].bg(itemOnColor)
}
function mout(i){
  oItems[i].bg(itemOffColor)
}
function moveM2(inc){
  endx=oHead.x; endy=oHead.y+oHead.h
  x=oMenu.x;
  y=oMenu.y
  distx = endx - x;
  disty = endy - y
  num = Math.sqrt(Math.pow(distx,2)+Math.pow(disty,2))/inc
  dx = distx/num;
  dy = disty/num
  if((Math.floor(Math.abs(dx))<Math.floor(Math.abs(endx-x))||
  Math.floor(Math.abs(dy))<Math.floor(Math.abs(endy-y)))){
  oMenu.moveBy(dx,dy)
  }else oMenu.moveIt(endx,endy)
  setTimeout("moveM2("+inc+")",20)
}
onload=init;
</script>
</head>

<body>
<div id="divHead"> Menu</div>
<div id="divMenu">
  <div id="divItem0" class="clItem">Test item1</div>
  <div id="divItem1" class="clItem">Test item2</div>
  <div id="divItem2" class="clItem">Test item3</div>
  <div id="divItem3" class="clItem">Test item4</div>
</div>
Regular content goes here
</body>
</html>

Note that you need the lib.js file that can be found in the DHTML library in the same directory of your file for this to work.

Good luck!

Leave a Reply