Apple Menu

This is my favourite stuff. I think I have made it third time and I think I can make it any time. Its so much fun everytime.

Okay whats with the Apple. I saw a similar menu on Apple'e website during my 2nd semester in SICSR and was so amazed with it that decided to make it on my own. And it came out so well that I can't explain the amount of satisfaction that it brought along. But due to some reason it got lost. My old pc problem.

The second time I made it during the Patni Javascript training session. It didn't came out that well. So, now I decided to make it the way I made it earlier and here in Chennai, and Eureka. I have done it again.

So, here is a short tutorial for it.

The HTML

First of all, the HTML markup. Nothing great. A wrapper container for the whole thing, a fixed header, and the main wrapper container for menu items and then the menu item blocks.

Here is all of it.

<div id="main_container">
    <div id="header"><span class="headerText">Apple Menu</span></div>
    <div id="menu_items">
        <div id="menu_item1" class="menu_item" style="position:relative;">
            <div class="content">
                <img src="image1.png" alt="App Store" />
                <span>Application Store</span>
            </div>
            <div class="label" onmouseover="animateMenus(1,true)"><br/>Simplest way to find and download apps</div>
        </div>
        <div id="menu_item2" class="menu_item">
            <div class="content">
                <img src="image2.png" alt="Game Center" />
                <span>Game Center</span>
            </div>
            <div class="label" onmouseover="animateMenus(2,true)"><br/>Play games on your Mac</div>
        </div>
        <div id="menu_item3" class="menu_item">
            <div class="content">
                <img src="image3.png" alt="Preview" />
                <span>Preview</span>
            </div>
            <div class="label" onmouseover="animateMenus(3,true)"><br/>View and edit images and PDFs</div>
        </div>
        <div id="menu_item4" class="menu_item">
            <div class="content">
                <img src="image4.png" alt="Launchpad" />
                <span>Launchpad</span>
            </div>
            <div class="label" onmouseover="animateMenus(4,true)"><br/>Fast way to find and open your apps</div>
        </div>
        <div id="menu_item5" class="menu_item">
            <div class="content">
                <img src="image5.png" alt="iTunes" />
                <span>iTunes</span>
            </div>
            <div class="label" onmouseover="animateMenus(5,true)"><br/>A world of entertainment</div>
        </div>
    </div>
</div>

The CSS

If you view the page now, you won't even a slightest of ideas how the menu is going to look. So, we need to arrange the menu items to allow for smooth animations.

Here is the css for the entire menu.

#main_container
{
    overflow:auto;
    width:225px;
    border:0px solid black;
    font:12px 'Verdana';
}

#main_container #header
{
    width:98%;
    border:1px solid #CCCCCC;
    text-align:center;
    overflow:hidden;
}

#main_container #header .headerText
{
    padding:5px 10px;
    font-size:18px;
    display:inline-block;
}

#main_container #menu_items
{
    position:relative;
    width:98%;
    overflow:hidden;
    border-left:1px solid #CCCCCC;
    border-right:1px solid #CCCCCC;
    height:500px;
}

#main_container #menu_items .menu_item
{
    width:100%;
    border-bottom:1px solid #CCCCCC;
    height:200px;
    position:absolute;
    background:white;
}

#main_container #menu_items .menu_item .content
{
    width:100%;
    text-align:center;
}

#main_container #menu_items .menu_item .label
{
    width:100%;
    background:#F9F9F9;
    text-align:center;
}

Include this CSS file in your html file.

<link href="menu.css" rel="stylesheet" type="text/css" />
<!--[if IE 8]>
    <style type="text/css">
        #main_container #menu_items .menu_item .label{-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#FFFFFF, endColorstr=#F0F0F0, GradientType=1)";}
    </style>
<![endif]-->
<!--[if lte IE 7]>
    <style type="text/css">
        #main_container #menu_items .menu_item .label{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#FFFFFF, endColorstr=#F0F0F0);}
    </style>
<![endif]-->
<style type="text/css">
    #menu_items .content img
    {
        padding-top:10px;
    }

    #menu_items .label
    {
        font:bold 14px 'Verdana';
    }

    #menu_items .content span
    {
        display:block;
        margin:10px 3px;
        font-size:10px;
    }
</style>

I have included some more page level css just so to make things tidier. And also, some IE specifics.

Word of Wisdom: Don't panic if you have come across with the weird conditional css tags for the first time. Yes, you heard it right. They are conditional css tags to allow inclusion of browser specific css values for the elements. simply means that you want to include the subsequent following css style code if the Internet Explorer(IE) version is less than or equal to 7.0. would simple include the subsequent css style if the browser if IE.

The Javascript

Time to get it working. Here is the code for the javascript


/******************************************************************************
Initalizing the control variables.
******************************************************************************/
var menuItemCount       = 5;     // Total menu items
var offSet              = 50;    // Vertical Offset of each menu item
var menuItemHeight      = 200;   // Total Height of each menu item
var animationTimeDelay  = 20;    // Time delay of animation. Smaller value --> Faster animation
var animationController = null;  // Object that controls the animation of the menu items
var slideDistance       = 10;    // Distance the menu items slide after each time delay.
                                 // Make sure this value is a multiple of (menuItemHeight-offSet)

// id values for the menu items. Dont change unless you know what you are doing.
var menuItemIdName      = "menu_item";


/******************************************************************************
Function    : initialize()
Description : Initializes the Menu Items.
******************************************************************************/
function initialize()
{
    alignMenuItems();   // Align the menu items initially.
}


/******************************************************************************
Function    : alignMenuItems()
Description : Called initially to align the menu items.
******************************************************************************/
function alignMenuItems()
{
    var menuItem;

    var yOffSet = 0;

    // Iterate all the menu items and set them to one over another
    for(var i=1; i<=menuItemCount; i++)
    {
        menuItem = document.getElementById(menuItemIdName+i); // Get the current menu item
  var imgDiv = menuItem.getElementsByTagName("div")[0]; // Get the Image Div
  var descDiv = menuItem.getElementsByTagName("div")[1];// Get the Description Div

  // Set the heights for imgDiv and descDiv
  imgDiv.style.height = (menuItemHeight-offSet) + "px";
  descDiv.style.height = offSet + "px";

        menuItem.style.top = yOffSet + "px";                  // Set the vertical offset
        menuItem.style.zIndex = (menuItemCount - i + 1);      // Layer the menu item in the menu stack

        yOffSet += offSet;                                   // Calculate the vertical offset of the next menu item
    }

    // Set the total height of the parent <div> as much as occupied by all the menu item
    menuItem.parentNode.style.height = (yOffSet + menuItemHeight - offSet + 1) + "px";
}


/******************************************************************************
Function    : animateMenus()
Description : Animate the menus items.
Parameter   : menuItemNumber  -  Menu item on which triggers the animation.
                                 The items above this menu item are slided upwards.
                                 The items below this menu item are slided downwards.
              reanimate       -  While animation of the menu items, if the user triggers the
                                 animation of another menu item, then it is used to clear the
                                 earlier animation controller and set the controller to do the
                                 animation for the new menu item.
******************************************************************************/
function animateMenus(menuItemNumber,reanimate)
{
    // We have to SlideUp all the menuItems < menuItemNumber (1,2,3 < 4)
    // And we have to SlideDown the menuItems >= menuIteNumber

    // Check if the controller has been asked to do another animation or previous animation
    if(!(reanimate))
    {
        // Lets check if our menu items got positioned correctly or not.
        if(slideUp(menuItemNumber) || slideDown(menuItemNumber))
        {
            // Menu Items not positioned properly. Let position them and engage the animation controller
            animationController = window.setTimeout("animateMenus("+menuItemNumber+",false)",animationTimeDelay);
        }
        else
        {
            // Menu Items are positioned properly. No animation to be done. Free the animation controller
            window.clearTimeout(animationController);
            animationController = null;
        }
    }
    else
    {
        // New menu item triggered this function before completion of other.
        // Terminate the older number and start for the new menu item
        window.clearTimeout(animationController);
        animationController = null;
        animateMenus(menuItemNumber,false);
    }
}


/******************************************************************************
Function    : slideUp()
Description : Moves all the menu items < menuItemNumber parameter passed
Parameter   : menuItemNumber  -  All the menu items with number < menuItemNumber will be
                                 slided upwards.
Returns     : true  - if this function need to be called again to align the menu items
              false - if this function need not be called to align the menu items
******************************************************************************/
function slideUp(menuItemNumber)
{
    var menuItem;              // Holds the current menu item object

    var moreToSlide = false;   // Determines whether more menu items need to be slided or not

    // Iterate all the menu items < menuItemNumber and slide them upwards
    for(var i=1; i<menuItemNumber; i++)
    {
        // Get the current menu item
        menuItem = document.getElementById(menuItemIdName+i);

        // Get the current vertical offset.
        var y = parseInt(menuItem.style.top);

        //alert("Slide Up\ncounter -->"+i+"\ny ---> "+y+"\nCondition -->"+(-(menuItemHeight - offSet + ((i-1) * offSet))));

        // Check if we have to slide up other menu items or not.
        if(y != (((i-1)*offSet) -  (menuItemHeight-offSet)))
        {
            // Set the sliding counter to true
            moreToSlide = true;

            // Slide the current menu item upwards
            menuItem.style.top = (y - slideDistance) + "px";
        }

    }

    // Return whether we need to call this function again or not
    return moreToSlide;
}


/******************************************************************************
Function    : slideDown()
Description : Moves all the menu items >= menuItemNumber parameter passed
Parameter   : menuItemNumber  -  All the menu items with number >= menuItemNumber will be
                                 slided downwards.
Returns     : true  - if this function need to be called again to align the menu items
              false - if this function need not be called to align the menu items
******************************************************************************/
function slideDown(menuItemNumber)
{
    var menuItem;              // Holds the current menu item object

    var moreToSlide = false;   // Determines whether more menu items need to be slided or not

    // Iterate all the menu items < menuItemNumber and slide them upwards
    for(var i=menuItemNumber; i<=menuItemCount; i++)
    {
        // Get the current menu item
        menuItem = document.getElementById(menuItemIdName+i);

        // Get the current vertical offset.
        var y = parseInt(menuItem.style.top);

        //alert("Slide Down -- "+i+"---> Height -"+y);

        // Check if we have to slide down this menu items or not.
        if(y!=((i-1) * offSet))
        {
            // Set the sliding counter to true
            moreToSlide = true;

            // Slide the current menu item upwards
            menuItem.style.top = (y + slideDistance) + "px";
        }
    }

    // Return whether we need to call this function again or not
    return moreToSlide;
}

Here is a list of configuration variables used. Make appropriate modifications as per your requirements.
  • menuItemCount - Total menu items in your menu. Set this integer value.
  • offSet - Offset of the menu item from the menu item just above it to show the lower section of the current menu item.
  • menuItemHeight - Total height of a single menu item
  • animationTimeDelay - Determines the speed of the animation. Lower the value, faster the animation.
  • slideDistance - In each animation frame, how much each menu item should move. The lesser the value, the smoother the animation.
  • menuItemIdName - This is the id value for all the menu items+a numeric suffix.

Making it work

Okay. Once you are done doing the setup in the menu.js, its time to set the stage. We need to call a function as soon as the page loads.

<body onload="initialize();">

If you doing anything else when the page loads, you can do something like this:


<body onload="yourcode(); initialize();">

Done. Now you should view the page to get the menu setup for the animation.

Slide on the menu items to see what you have just assembled.

Here is the complete version. Download

Tested on IE6 and IE7. Not sure about other browsers. With my experience, it should work fine on Firefox 2+.

Comments

Popular posts from this blog

Personal Contact Manager

An apt quote

Alone