circlecube

RSS comments
LinkedIn Twitter delicious fb last.fm

Posts Tagged ‘abstract’

My earlier simple mega menu implementation post displayed some simple css and jquery to explode a standard navigation menu into a mega-menu… I’ve made it even better. My biggest issue with that implementation was that it did not keep the order like you’d expect. It read left to right in columns rather than down each column. In the example you can see the first column of three would read from the top: a, d, g, j… this could potentially be confusing. So I wanted to update it to keep the order better and just stack the columns of elements rather than the elements themselves.

I used some different jquery to execute this. First we walk through the menu elements and calculate which column they should be in. We basically map that element’s (li)index to the column it should be, some big math. Luckily I had some experience from actionscript in my arsenal doing just that, so porting the function to javascript I was ready to go. If your number X falls between A and B, and you would like to convert it to Y which falls between C and D follow this formula: Y = (X-A)/(B-A) * (D-C) + C. Plugging this function in and cancelling out the zeros and adding some rounding to get integers I got: Math.floor((liindex / $total * $cols)+1). Using this I added a class to each ‘li’ designating which column it should be in, and then used wrapAll to wrap them into column divs. Very simple and a much better implementation overall anyways. Better code, better user experience… what more can you ask… so here’s the example and jquery code. I’m thinking I should make this into a jquery plugin or something, any thoughts?

better-mega-menu-screenshot

See the mega menu in action

Javascript code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
jQuery(document).ready(function() {
    //clean up the row of the mega menu. add css class to each element on bottom row.
    //only if more than 7 elements. if more than 16, mm-3
    jQuery('#nav li ul').each(function(ulindex, ulele){
        $total = jQuery(this).children('li').size();
        if ($total <= 7) {
            jQuery(this).addClass('mm-1');
        }
        else {
            $cols = Math.floor(($total) / 8) + 1;
            $remainder = $total % $cols;
            $rows = Math.ceil($total / $cols);
            jQuery(this).addClass('mm-' + $cols + ' total-' + $total + ' rem-'+$remainder );
           
            jQuery(this).children().each(function(liindex, liele){
                //alert("total: "+$total+", remainder: "+ $mod+", ulindex: "+ulindex+", liindex: "+liindex);
                //If your number X falls between A and B, and you would like to convert it to Y which falls between C and D follow this formula: Y = (X-A)/(B-A) * (D-C) + C.
                jQuery(this).addClass('col-' + Math.floor((liindex / $total * $cols)+1) );
                if( (liindex+1) % $rows == 0) {
                    jQuery(this).addClass('last');
                }
            });
       
            for (var colcount = 1; colcount<= $cols; colcount++){
                jQuery(this).children('.col-'+colcount).wrapAll('<div class="col" />');
            }
        }
    });
});

css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
ul { list-style:none; }

/********** < Navigation */
.nav-container { float:left; background: #398301; margin: 10em 0; width: 960px; }
#nav { border: 0px none; padding:3px 0 2px 44px; margin:0; font-size:13px; }

/* All Levels */
#nav li { text-align:left; position:relative; }
#nav li.over { z-index:999; }
#nav li.parent {}
#nav li a { display:block; text-decoration:none; }
#nav li a:hover { text-decoration:none; }
#nav li a span { display:block; white-space:nowrap; cursor:pointer; }
#nav li ul a span { white-space:normal; }

/* 1st Level */
#nav li { float:left; }
#nav li a { float:left; padding:5px 10px; font-weight:normal; color: #fff; text-shadow: 1px 1px #1b3f00; }
#nav li a:hover { color: #fff; text-shadow: 1px 1px 3px #ccc; }
#nav li.over a,
#nav li.active a { color:#fff; }

/* 2nd Level */
#nav ul { position:absolute; width:15em; top:26px; left:-10000px; border:1px solid #1b3f00; border-width: 0 1px 2px 1px; background:#398301; padding: 6px 0 6px; }
#nav ul div.col { float:left; width: 15em; }
#nav ul li { float:left; padding: 0; width: 15em; }
#nav ul li a { float:none; padding:6px 9px; font-weight:normal; color:#FFF !important; text-shadow: 1px 1px #1b3f00; border-bottom:1px solid #1b3f00; background:#398301; }
#nav ul li a:hover { color:#fff !important; text-shadow: 1px 1px 3px #ccc; background: #2b6301; }
#nav ul li.last > a { border-bottom:0; }
#nav ul li.last.parent > a { border-bottom:0; }

#nav ul li.over > a  { font-weight:normal; color:#fff !important; background: #1b3f00; }
#nav ul.mm-1 { width: 15em; }
#nav ul.mm-2 { width: 30em; }
#nav ul.mm-3 { width: 45em; }
#nav ul.mm-4 { width: 60em; }
/* 3rd+ leven */
#nav ul ul { top:-6px; background: #1b3f00; }

/* Show Menu - uses built-in magento menu hovering */
#nav li.over > ul { left:0; }
#nav li.over > ul li.over > ul { left:14em; }
#nav li.over ul ul { left:-10000px; }

/* Show Menu - uses css only, not fully across all browsers but, for the purpose of the demo is fine by me */
#nav li:hover > ul { left:0; z-index: 100; }
#nav li:hover > ul li:hover > ul { left:14em; z-index: 200; }
#nav li:hover ul ul { left:-10000px; }

Download

Visit this demo page and view source or save as…

  • del.icio.us
  • Digg
  • email
  • Facebook
  • Google Bookmarks
  • LinkedIn
  • Mixx
  • Print
  • PDF
  • StumbleUpon
  • Technorati
  • Twitter
  • RSS
14 Jul 2010

Better jquery mega-menu tutorial

Author: Evan Mullins | Filed under: tutorial

I’ve been skinning quite a few ecommerce sites with the magento platform and wanted a simple way to explode the navigation menus. Some sites end up getting a long list of categories and sub-categories, so I wanted to do a mega-menu style navigation. One way to do it was to rewrite the html code for the navigation and pop each column into another nested unordered list. I’m not a fan of doing this because one – I didn’t want to manipulate the html. I like the simplicity of ul navigation with a clear flat list of li elements. Of course for nested sub-navigation any li can contain another ul. I wanted to just use some css and maybe javascript to visually accomplish the same thing. I also wanted it to be portable, so I could take it and use it on a wordpress install or even a plain html site. I went to my favorite: jquery. I knew there was a likely plugin out there already that would do something similar, but nothing after my initial search, but I realized that it was a simple procedure and mostly accomplished with some css.
mega menu screenshot
I’ll walk you through the process here and let you inspect the code yourself and see it in action on the demo page. Assign each ul to be a default width of 15em, then each li element we float:left and also give it a width of 15em. This way we can change the ul width to 30em and automatically I have 2 columns! Assigning the nested ul a specific width according to it’s class is done through css, mm-0 will be 15em and incrementally each next one will be 15em more. mm-1 is 30 and mm-2 is 45. Then we use jquery to determine the number of elements in the list and assign it a class accordingly. This involves some math and some preferences. Using the magic ui number 7, I determined that a menu with more than 7 elements should explode into multiple columns. So anything less than or equal to 7 I assign the class ‘mm-1′ which in the css sets the width to the standard 15em (ie 1 mega menu column). More than 7 should pop into columns no more than 8 tall. So dividing the total by 8 will give us the number of columns we want. We’ll add a class of mm-x, where x would be the number of columns. And the li elements will float to the left and fill in the space in columns.
One specific issue is the last element in the menu, sometimes we need to style that element differently. I’ll loop through each child of the nested ul element and if it is on the bottom row apply a class of ‘last’. But this was a little tricky in calculating which would be last because were never sure how many elements there will be or how many columns. I just used the remainder after dividing the total by the number of columns, then if the remainder could be used to know which elements are on the bottom row.

OK, now that that’s out of the way, let’s look at the code.

HTML

This I won’t show, you can inspect the source of the demo if you wish to see it, it a basic nested collection of unordered lists. It’s the standard that is created by magento, wordpress and most other CMS platforms.

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
html, body { margin:0; padding:0; }
ul { list-style:none; }

/********** < Navigation */
.nav-container { float:left; background: #186C94; margin: 10em 0; width: 960px; }
#nav { border: 0px none; padding:3px 0 2px 44px; margin:0; font-size:13px; }

/* All Levels */
#nav li { text-align:left; position:relative; }
#nav li.over { z-index:999; }
#nav li.parent {}
#nav li a { display:block; text-decoration:none; }
#nav li a:hover { text-decoration:none; }
#nav li a span { display:block; white-space:nowrap; cursor:pointer; }
#nav li ul a span { white-space:normal; }

/* 1st Level */
#nav li { float:left; }
#nav li a { float:left; padding:5px 10px; font-weight:normal; color: #fff; text-shadow: 1px 1px #111; }
#nav li a:hover { color: #fff; text-shadow: 1px 1px 3px #ccc; }
#nav li.over a,
#nav li.active a { color:#fff; }

/* 2nd Level */
#nav ul { position:absolute; width:15em; top:26px; left:-10000px; border:1px solid #104A65; border-width: 0 1px 2px 1px; background:#186C94; padding: 6px 0 6px; }
#nav ul div.col { float:left; width: 15em; }
#nav ul li { float:left; padding: 0; width: 15em; }
#nav ul li a { float:none; padding:6px 9px; font-weight:normal; color:#FFF !important; text-shadow: 1px 1px #111; border-bottom:1px solid #104A65; background:#186C94; }
#nav ul li a:hover { color:#fff !important; text-shadow: 1px 1px 3px #ccc; background: #135575; }
#nav ul li.last > a { border-bottom:0; }
#nav ul li.last.parent > a { border-bottom:0; }

#nav ul li.over > a  { font-weight:normal; color:#fff !important; background: #104A65; }
#nav ul.mm-1 { width: 15em; }
#nav ul.mm-2 { width: 30em; }
#nav ul.mm-3 { width: 45em; }
#nav ul.mm-4 { width: 60em; }
/* 3rd+ leven */
#nav ul ul { top:-6px; background: #104A65; }

/* Show Menu - uses built-in magento menu hovering */
#nav li.over > ul { left:0; }
#nav li.over > ul li.over > ul { left:14em; }
#nav li.over ul ul { left:-10000px; }

/* Show Menu - uses css only, not fully across all browsers but, for the purpose of the demo is fine by me */
#nav li:hover > ul { left:0; z-index: 100; }
#nav li:hover > ul li:hover > ul { left:14em; z-index: 200; }
#nav li:hover ul ul { left:-10000px; }

Javascript

Don’t forget to include jQuery (I prefer using the google hosted version at http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
jQuery(document).ready(function() {
    //clean up the row of the mega menu. add css class to each element on bottom row.
    //only if more than 7 elements. if more than 16, mm-3
    jQuery('#nav li ul').each(function(ulindex, ulele){
        $total = jQuery(this).children('li').size();
        if ($total <= 7) {
            jQuery(this).addClass('mm-1');
        }
        else {
            $cols = Math.floor(($total) / 8) + 1;
            $remainder = $total % $cols;
            jQuery(this).addClass('mm-' + $cols + ' total-' + $total + ' rem-'+$remainder );
           
            jQuery(this).children().each(function(liindex, liele){
                //alert("total: "+$total+", remainder: "+ $mod+", ulindex: "+ulindex+", liindex: "+liindex);   
                if( liindex + $remainder >= $total || $remainder == 0 && liindex + $cols >= $total ){
                    //alert("total: "+$total+", remainder: "+ $remainder+", index: "+liindex);
                    jQuery(this).addClass('last');
                }
            });
        }
    });
   
});

See the demo in action

  • del.icio.us
  • Digg
  • email
  • Facebook
  • Google Bookmarks
  • LinkedIn
  • Mixx
  • Print
  • PDF
  • StumbleUpon
  • Technorati
  • Twitter
  • RSS
12 Jul 2010

A simple mega menu implementation with CSS and jquery

Author: Evan Mullins | Filed under: tutorial

Interactive Design project for StomperNet’s tease of the announced reveal on 09/09/09 at 09:09:09!

“Online Marketing Changes Forever!”

stomper999-black
Wanted it to be unexpected, and I think we hit it! Check it out live at stomper999.com!
stomper999-white

Details:
For this project I used flash, html, css and javascript. Tweener for the fading effects. Found a nice stock flash from flashDen for the countdown and used jquery and the easing and color plugins.

  • del.icio.us
  • Digg
  • email
  • Facebook
  • Google Bookmarks
  • LinkedIn
  • Mixx
  • Print
  • PDF
  • StumbleUpon
  • Technorati
  • Twitter
  • RSS
24 Jul 2009

Stomper999

Author: Evan Mullins | Filed under: portfolio

If you didn’t know, Grant Skinner has introduced an interesting competition called tweetcoding!

Mixing as3 with the 140 character limit of tweeting he calls for the community to tweet visually interesting source code.

I’ve played a bit with it and tweeted my first #tweetcoding entry! See more tweetcoding here

1
g.clear(),o[++i]={x:mouseX,y:mouseY,c:r()*0xFFFFFF};for each(k in o)k.c*=.9,g.beginFill(k.c),ls(i,k.c),g.drawCircle(k.x,k.y,1),g.endFill();

Want to see my entry? Here it is!

tweetcode_circlecube_a png

  • del.icio.us
  • Digg
  • email
  • Facebook
  • Google Bookmarks
  • LinkedIn
  • Mixx
  • Print
  • PDF
  • StumbleUpon
  • Technorati
  • Twitter
  • RSS
27 Feb 2009

#tweetcoding

Author: Evan Mullins | Filed under: portfolio

I have had feedback that certain random movements I program are a bit “jumpy”. Such as my old brownian movement tutorial and I really noticed it in my last tutorial, the parallax 3d depth effect tutorial. I’ve been thinking about it and looking around at some code and now have this updated brownian movement example! Updated for as3 as well as making it less jumpy.

as3brownian thumb pngFirst I’ll explain what I’ve found to be the reason of the jumpiness. And then explain and show what can be done to make this movement be more smooth.

So to examine the old jumpy code. Jump back to the first version post here. I think my technique was well thought out here, but the application was poor. It was recalculating the velocities every single frame and then incrementing the coordinate positions by the newly calculated velocities… This is where the jumpiness comes in. Even though the random value was named velocity, it didn’t actually affect the dot’s velocity, it was just a variable that stored the random value used to move the current x/y coordinates.
To help the animation be more smooth, the velocity needs to be more smooth. The velocity, rather than calculating it fresh each frame, should be randomly modified each frame. And then the new velocity will calculate the new ‘random’ position. Another addition is to introduce another force to dampen the velocity over time, so things don’t get too crazy…

Steps:

  1. Modify velocity randomly
  2. With velocity and current position, calculate a new position
  3. Dampen the velocity

Example:

Here I have a velocity for the x coordinate as well as the y. I’m also experimenting with a z velocity. This adjusts the alpha and scale for depth perception. It doesn’t actually edit the depth or layer the dot shows up on the stage however… keyword here: experimenting. :)

Get Adobe Flash player

Actionscript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//number of balls
var numBalls:uint = 50;
var defaultBallSize:uint = 30;

//init
makeDots();

function makeDots():void {
    //create desired number of balls
    for (var ballNum:uint=0; ballNum<numBalls; ballNum++){
        var c1:Number = randomColor();
        var c2:Number = randomColor();
       
        //create ball
        var thisBall:MovieClip = new MovieClip();
        thisBall.graphics.beginFill(c1, .9);
        thisBall.graphics.lineStyle(defaultBallSize/3, c2, .9);
        thisBall.graphics.drawCircle(defaultBallSize, defaultBallSize, defaultBallSize);
        thisBall.graphics.endFill();
       
        addChild(thisBall);
       
        //coordinates
        thisBall.x = Math.random() * stage.stageWidth;
        thisBall.y = Math.random() * stage.stageHeight;
        //percieved depth
        thisBall.ballNum = ballNum;
        thisBall.depth = ballNum/numBalls;
        thisBall.scaleY = thisBall.scaleX = thisBall.alpha = ballNum/numBalls;
        //velocity
        thisBall.vx = 0;
        thisBall.vy = 0;
        thisBall.vz = 0;
       
        //ball animation
        thisBall.addEventListener(Event.ENTER_FRAME, animateBall);
    }
}

var dampen:Number = 0.95;
var maxScale:Number = 1.3;
var minScale:Number = .3;
var maxAlpha:Number = 1.3;
var minAlpha:Number = .3;
function animateBall(e:Event):void{
    var thisBall:Object = e.target;
    //apply randomness to velocity
    thisBall.vx += Math.random() * 0.2 - 0.1;
    thisBall.vy += Math.random() * 0.2 - 0.1;
    thisBall.vz += Math.random() * 0.002 - 0.001;
   
    thisBall.x += thisBall.vx;
    thisBall.y += thisBall.vy;
    thisBall.scaleX = thisBall.scaleY += thisBall.vz;
    thisBall.alpha += thisBall.vz;
    thisBall.vx *= dampen;
    thisBall.vy *= dampen;
    thisBall.vz *= dampen;
   
    if(thisBall.x > stage.stageWidth) {
        thisBall.x = 0 - thisBall.width;
    }
    else if(thisBall.x < 0 - thisBall.width) {
        thisBall.x = stage.stageWidth;
    }
    if(thisBall.y > stage.stageHeight) {
        thisBall.y = 0 - thisBall.height;
    }
    else if(thisBall.y < 0 - thisBall.height) {
        thisBall.y = stage.stageHeight;
    }
   
    if (thisBall.scaleX > maxScale){
        thisBall.scaleX = thisBall.scaleY = maxScale;
    }
    else if (thisBall.scaleX < minScale){
        thisBall.scaleX = thisBall.scaleY = minScale;
    }
    if (thisBall.alpha > maxAlpha){
        thisBall.alpha = maxAlpha;
    }
    else if (thisBall.alpha < minAlpha){
        thisBall.alpha = minAlpha;
    }
}

function randomColor():Number{
    return Math.floor(Math.random() * 16777215);
}

Source:

as3random_brownian_movement.fla

  • del.icio.us
  • Digg
  • email
  • Facebook
  • Google Bookmarks
  • LinkedIn
  • Mixx
  • Print
  • PDF
  • StumbleUpon
  • Technorati
  • Twitter
  • RSS
10 Feb 2009

Random Movement | Brownian revisited for as3

Author: Evan Mullins | Filed under: tutorial