Skip to content

Instantly share code, notes, and snippets.

@rlmcneary2
Created November 26, 2011 22:22
Show Gist options
  • Save rlmcneary2/1396405 to your computer and use it in GitHub Desktop.
Save rlmcneary2/1396405 to your computer and use it in GitHub Desktop.
Javascript menu with animated pointer and flag
@CHARSET "ISO-8859-1";
#menu {color:black;background-color:white;}
#menuBar {position:relative;top:-10px;left:0px;width:100%;height:30px;}
#pointer {position:relative;top:-18px;width:20px;height:20px;margin-left:auto;margin-right:auto;background-color:#8BBAE5;-o-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-webkit-transform:rotate(45deg);transform:rotate(45deg);}
#menuBarLower {position:relative;top:-10px;left:0px;width:100%;height:10px;background-color:#8BBAE5;}
#selectorOuter {position:relative;top:4px;width:20px;height:20px;margin-left:auto;margin-right:auto;background-color:#8BBAE5;-o-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-webkit-transform:rotate(45deg);transform:rotate(45deg);}
#selectorInner {position:relative;top:-12px;width:20px;height:20px;margin-left:auto;margin-right:auto;background-color:#FFFFFF;-o-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-webkit-transform:rotate(45deg);transform:rotate(45deg);}
#selectorBar {position:relative;top:-32px;width:100%;height:2px;background-color:#FFFFFF;}
#menuBarLowerThin {position:relative;width:100%;height:3px;background-color:#8BBAE5;}
#menuBarLowerWhite {position:relative;width:100%;height:2px;background-color:#FFFFFF;}
.menu_item {position:relative;width:100px;height:30px;float:left;background-color:transparent;cursor:pointer;}
.menu_item_text {position:relative;display:block;float:left;margin:0px;width:100px;line-height:30px;text-align:center;vertical-align:middle;cursor:pointer;}
.marker {position:relative;left:0px;top:0px;height:10px;width:100px;overflow:hidden;visibility:hidden;}
.markerSelector{top:-10px;height:10px;visibility:visible;}
.marker_move_right, .marker_move_left {-moz-animation-duration: 150ms;-moz-animation-name: moveRightKeyFrames;-moz-animation-timing-function:ease-in;-webkit-animation-duration: 150ms;-webkit-animation-name: moveRightKeyFrames;-webkit-animation-timing-function:ease-in;animation-duration: 150ms;animation-name: moveRightKeyFrames;animation-timing-function:ease-in;}
.marker_move_left {-moz-animation-name: moveLeftKeyFrames;-webkit-animation-name: moveLeftKeyFrames;animation-name: moveLeftKeyFrames;}
@-moz-keyframes moveRightKeyFrames { 0% {margin-left:0%;} 100% {margin-left:100px;}}
@-moz-keyframes moveLeftKeyFrames { 0% {margin-left: 0%;} 100% {margin-left: -100px;}}
@-webkit-keyframes moveRightKeyFrames { 0% {margin-left:0%;} 100% {margin-left:100px;}}
@-webkit-keyframes moveLeftKeyFrames { 0% {margin-left: 0%;} 100% {margin-left: -100px;}}
@keyframes moveRightKeyFrames { 0% {margin-left:0%;} 100% {margin-left:100px;}}
@keyframes moveLeftKeyFrames { 0% {margin-left: 0%;} 100% {margin-left: -100px;}}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="menu.css" />
</head>
<body>
<div id="menu">
<div id="pointerMarker" class="marker hidden">
<div id="pointer"></div>
</div>
<div id="menuBar">
<div class="menu_item">
<p class="menu_item_text">Main</p>
</div>
<div class="menu_item">
<p class="menu_item_text">Search</p>
</div>
<div class="menu_item">
<p class="menu_item_text">Contact</p>
</div>
</div>
<div id="menuBarLower">
<div id="menuBarLowerThin"></div>
<div id="menuBarLowerWhite"></div>
<div id="selectedMarker" class="marker markerSelector">
<div id="selectorOuter"></div>
<div id="selectorInner"></div>
<div id="selectorBar"></div>
</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
<script src="menu.js"></script>
<script type="text/javascript">
var pointerMarker = null;
var selectorMarker = null;
$(document).ready (function () {
pointerMarker = new MenuMarker ();
pointerMarker.setMarker ($("#pointerMarker")[0]);
selectorMarker = new MenuMarker ();
selectorMarker.setMarker ($("#selectedMarker")[0]);
selectorMarker.setAnimateEndedCallback (function (marker) {
//alert ($(marker.getActiveElement ()).children ()[0].innerHTML);
});
$("#menuBar").mouseleave (function () {
pointerMarker.hide ();
});
var buttons = $(".menu_item");
for (var i = 0; i < buttons.length; i++)
{
$(buttons[i]).mouseover (function (evt) {
pointerMarker.show (true, evt.delegateTarget, "marker_move_left", "marker_move_right");
});
$(buttons[i]).click (function (evt) {
selectorMarker.show (true, evt.delegateTarget, "marker_move_left", "marker_move_right");
});
}
});
</script>
</body>
</html>
function MenuMarker ()
{
this.isShown = false;
this.marker = null;
this.animateEndedCallback = null;
this.activeElement = null;
}
MenuMarker.prototype.setMarker = function (marker)
{
this.marker = marker;
this.isShown = "visible" == $(marker).css ("visibility");
}
MenuMarker.prototype.setAnimateEndedCallback = function (callback)
{
this.animateEndedCallback = callback;
}
MenuMarker.prototype.getActiveElement = function ()
{
return this.activeElement;
}
MenuMarker.prototype.isCssAnimationSupported = function (element)
{
if (element.style.animationName)
return true;
var domPrefixes = "Webkit Moz O ms Khtml".split(" ");
for (var i = 0; i < domPrefixes.length; i++)
{
if (element.style[domPrefixes[i] + "AnimationName"] !== undefined)
return true;
}
return false;
}
MenuMarker.prototype.show = function (isAnimated, destElement, moveLeftClassName, moveRightClassName)
{
this.activeElement = destElement;
var destLeftSide = $(destElement).position ().left;
if (this.isShown === true)
{
if (isAnimated)
{
var that = this;
// If CSS animation is available use that.
if (moveLeftClassName && moveRightClassName && this.isCssAnimationSupported (this.marker))
{
var cssLeft = parseFloat($(this.marker).css ("left"));
var aniClassName = cssLeft <= destLeftSide ? moveRightClassName : moveLeftClassName;
$("body").on("mozAnimationEnd webkitAnimationEnd animationend", "#" + this.marker.id, function (event){
$(this).css ("left", destLeftSide);
$(this).removeClass (aniClassName);
$("body").off ("mozAnimationEnd webkitAnimationEnd animationend", "#" + this.id);
if (that.animateEndedCallback)
that.animateEndedCallback (that);
return false;
});
$(this.marker).addClass (aniClassName);
}
else
{
// No CSS animation go ahead and use jQuery.
$(this.marker).animate ({left:destLeftSide}, 150, "swing", function () {
if (that.animateEndedCallback)
that.animateEndedCallback (that);
});
}
}
else
{
$(this.marker).css ("left", destLeftSide);
if (this.animateEndedCallback)
this.animateEndedCallback (this);
}
}
else
{
$(this.marker).css ("left", destLeftSide);
$(this.marker).css ("visibility","visible");
this.isShown = true;
}
}
MenuMarker.prototype.hide = function ()
{
$(this.marker).css ("visibility","hidden");
this.isShown = false;
}
@rlmcneary2
Copy link
Author

12-6-2011
Animation is now done with CSS if it is supported by the browser. If not jQuery is used to animate the menu pointers.

@rlmcneary2
Copy link
Author

12-27-2011
Fixed broken "menu" div style.

@rlmcneary2
Copy link
Author

01-02-2012
Menu.js - Determining which CSS animation (which direction to move the pointer) to use was wrong. it was using the element's offsetLeft position instead of the CSS left location. This problem was only seen when the menu was moved away from X's 0 origin in the window.

@rlmcneary2
Copy link
Author

01-02-2012
menu.css - Remove padding from the menu div.

@anthonyzz
Copy link

This tests awesome, quite different from the animations in menu control by C# I've experience with a WinForms UI Menu control. I think I've found what I eagerly need here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment