views:

1440

answers:

3

I'm trying to make a menu that contains 5 items/icons with the selected one being in the center. Clicking to the left or right of this centered icon, rotates the menu left or right, wrapping round the edges and moving whichever item was closest to the edge back in through the opposite one. Clicking on the centered item takes you to its linked URL.

The menu should also magnify in a way similar to the OS X dock except the magnification levels are set based on position not mouseover.

I've made a diagram which is easier to understand than my ramblings.

alt text

I've managed to cobble together a simple jQuery version, where the items swap positions as needed, but can't figure out how to animate this movement, especially the wrap around the edges part, and change size based on position.

I'm guessing my code is probably not the best either :)

The HTML is as follows:

<div id="nav">
<div id="leftnav"></div>
<div id="rightnav"></div>
<div id="navblock1" class="navblock">
 one
</div>
<div id="navblock2" class="navblock">
 two
</div>
<div id="navblock3" class="navblock">
 three
</div>
<div id="navblock4" class="navblock">
 four
</div>
<div id="navblock5" class="navblock">
 five
</div>

And the JS:

function rotateNav(direction) {
var change = (direction=='left')?(-1):(+1);
$('div.navblock').each(function() {
    oldPos = parseInt($(this).attr('id').substr(9));
    newPos = oldPos+change;
    if (newPos == 0)
        newPos = 5;
    else if (newPos == 6)
        newPos = 1;
    $(this).attr('id','navblock'+newPos);
});
}
$(document).ready(function(){
$("#leftnav").click(function() {
    rotateNav('right');
});
$("#rightnav").click(function() {
    rotateNav('left');
});

});

All the .navblock elements are absolutely positionned. The #leftnav and #rightnav elements also and they have a higher z-index so float above the items/icons.

I've looked at various jQuery plugins but none seem close to what I need.

I'd appreciate any help or pointers I can get.

Thanks.

A: 

Instead of doing this yourself and wasting time on getting this to work properly I suggest you use existing solutions ones. Here a few pointers (I guess many more can be found by using google

jQuery: Mac-like Dock

Mac-like icon dock (v2)

MAC CSS Dock Menu

jQuery mimicking the OS X dock

Simple OSX-like dock with jQuery

iconDock jQuery Plugin

jitter
I've looked at most of those dock menus but, with my limited knowledge anyway, I can't see any way of making them rotate and especially wrap around.
Zoom
A: 

You seem to be on the right track. One issue is that this line

oldPos = parseInt($(this).attr('id').substr(9));

Should use 8 in the substr:

oldPos = parseInt($(this).attr('id').substr(8));
rosscj2533
Sorry, I copy pasted in the middle of a change, my bad. The ID used to be navblocks and now is navblock.
Zoom
+1  A: 

Instead of changing id attributes (which you really shouldn't do in the first place) you can change CSS classes and use jQuery UI's switchClass() method to animate the rotation.

You would also have to do a bit of clone()ing to make it look like the edge navblocks have rotated around to the other side of the widget and some queue()/dequeue()ing to handle multiple clicks.

Working Demo:

http://jsbin.com/ovemu (editable via http://jsbin.com/ovemu/edit)

Full Source:

JavaScript

function rotateNav(direction) {
if (direction === 'left') {
  var change = 1;
  $('.navblock5').clone()
    .removeClass('navblock5')
    .addClass('navblock0')
    .appendTo('#nav');
}
else {
  var change = -1;
  $('.navblock1').clone()
    .removeClass('navblock1')
    .addClass('navblock6')
    .appendTo('#nav');
}

$('div.navblock').each(function() {
  var oldClassName = this.className.split(' ')[1],
    oldPos = parseInt(oldClassName.substr(8)),
    newPos = oldPos + change;

    $(this).switchClass(
      oldClassName,
      'navblock'+newPos,
      'fast', 
      function () { 
        var animated = $('.navblock:animated').length;
        if (newPos === 6 || newPos === 0) {
          $(this).remove(); 
        } 
        if (animated === 1) {
          $('#nav').dequeue();
        }
      }
    );
});
}

$(document).ready(function(){
$("#leftnav").click(function() {
  $('#nav').queue(function(){rotateNav('right');});
});
$("#rightnav").click(function() {
  $('#nav').queue(function(){rotateNav('left');});
});
});

CSS

#nav { 
  width: 580px; height: 120px; 
  position: relative; left: 150px; 
  overflow: hidden; 
}

.navblock { 
  height: 100px; width: 100px; 
  position: absolute; top: 10px; z-index: 50;
  background-color: grey;
}
.navblock0 { left: -110px; }
.navblock1 { left: 10px; }
.navblock2 { left: 120px; }
.navblock3 { left: 230px; width: 120px; height: 120px; top: 0;}
.navblock4 { left: 360px; }
.navblock5 { left: 470px; }
.navblock6 { left: 590px; }

#leftnav, #rightnav { 
  position: absolute; z-index: 100; height: 120px; width: 228px;
}
#leftnav { left: 0; }
#rightnav { right: 0; }

/*Uncomment the following to help debug or see the inner workings */
/*
#nav { border: 1px solid green; overflow: visible; }
#leftnav, #rightnav { border: 1px solid blue; }
*/

HTML

<div id="nav">
<div id="leftnav"></div>
<div id="rightnav"></div>

<div class="navblock navblock1">one</div>
<div class="navblock navblock2">two</div>
<div class="navblock navblock3">three</div>
<div class="navblock navblock4">four</div>
<div class="navblock navblock5">five</div>
brianpeiris
Breaks immediately if you make a (not even particularly) fast double click on the leftnav or rightnav
jitter
Thanks a lot, that's much closer to what I'm trying to do.As Jitter said, it seems to go a bit crazy with multiple clicks but it also doesn't work on Safari. I'm going to dig a bit deeper, you've got me on the right track.
Zoom
The safari/chrome problem is a bug in jQuery UI. It's fixed in the latest trunk.
Zoom
I've updated my answer to fix the double-click bug. The new code uses jQuery's `queue()` and `dequeue()` methods to perform rotations sequentially and it seems to be pretty robust -- it can handle any number of fast or slow clicks. I've also updated the demo to use a snapshot, from a few minutes ago, of jquery.effects.core.js from the jQuery UI trunk so the demo works in webkit (I've tested it in Chrome 4).
brianpeiris
Great. Thanks again!
Zoom