Team:Brown-Stanford/Outreach/menu.js

From 2011.igem.org

(Difference between revisions)
(Created page with "/*! * jQuery Radmenu (Radial Menu) Plugin * version: 1.0.0 (14-MAY-2011) * @requires v1.4.2 or later * * Author: Nirvana Tikku - ntikku@gmail.com - @ntikku * Documentation...")
(Blanked the page)
 
(3 intermediate revisions not shown)
Line 1: Line 1:
-
/*!
 
-
* jQuery Radmenu (Radial Menu) Plugin
 
-
* version: 1.0.0 (14-MAY-2011)
 
-
* @requires v1.4.2 or later
 
-
*
 
-
* Author: Nirvana Tikku - ntikku@gmail.com - @ntikku
 
-
* Documentation:
 
-
* http://www.tikku.com/jquery-radmenu-plugin
 
-
*
 
-
* Dual licensed under the MIT and GPL licenses:
 
-
*  http://www.opensource.org/licenses/mit-license.php
 
-
*  http://www.gnu.org/licenses/gpl.html
 
-
*
 
-
*/
 
-
;(function($){
 
-
 
-
// radmenu namespace
 
-
 
-
var RADMENU = ".radmenu", // events are radmenu.{event} - guarantee no NS collision
 
-
 
-
OPTS = "options"+RADMENU,
 
-
 
-
PREVOPTS = "prevoptions"+RADMENU,
 
-
 
-
RADMENU_CLASS = "ui-radmenu-parent";
 
-
 
-
// private defaults
 
-
var defaults = {
 
-
 
-
// radial menu container properties
 
-
 
-
listClass: "list",
 
-
 
-
itemClass: "item",
 
-
 
-
activeItemClass: "active",
 
-
 
-
// active item selection properties
 
-
 
-
selectEvent: null, // click, mouseenter etc
 
-
 
-
onSelect: function($selected){},
 
-
 
-
// initial setup properties
 
-
 
-
radius: 10, // in pixels
 
-
 
-
angleOffset: 0, // in degrees
 
-
 
-
centerX: 0,
 
-
 
-
centerY: 0,
 
-
 
-
// animation properties
 
-
 
-
animSpeed: 500,
 
-
 
-
animEasing: "swing",
 
-
 
-
// scaling properties and method
 
-
 
-
initialScale: 1,
 
-
 
-
scaleAnimSpeed: 0,
 
-
 
-
scaleAnimEasing: "swing",
 
-
 
-
scaleAnimOpts: {},
 
-
 
-
// example onScaleItem: $item.css("font-size", factor+"em");
 
-
onScaleItem: function($item, factor, coords){},
 
-
 
-
// public events
 
-
 
-
afterAnimation: function($m){},
 
-
 
-
onShow: function($items){$items.show();},
 
-
 
-
onHide: function($items){$items.hide();},
 
-
 
-
onNext: function($items){return true;},
 
-
 
-
onPrev: function($items){return true;},
 
-
 
-
// rotation property and fine-tuning event
 
-
 
-
rotate: false,
 
-
 
-
getRotation: function(degrees, index, numItems){return degrees;}
 
-
 
-
};
 
-
 
-
// radial menu container setup defaults
 
-
$.radmenu = {
 
-
 
-
container: {
 
-
 
-
html: "<div></div>",
 
-
 
-
css: { "position": "relative" },
 
-
 
-
clz: "radial_div",
 
-
 
-
itemClz: "radial_div_item"
 
-
 
-
}
 
-
 
-
};
 
-
 
-
/**
 
-
* jQuery Radmenu Plugin
 
-
* @params
 
-
* > input, dealt with by type
 
-
* if empty - assumes initialization
 
-
* if object - assumes initialization
 
-
* if string - assumes trigger method
 
-
* if number - select a particular menu item
 
-
*/
 
-
$.fn.radmenu = function(input, param){
 
-
 
-
try {
 
-
 
-
var $this = $(this);
 
-
 
-
var type = typeof input;
 
-
 
-
if(arguments.length==0 || type=="object")
 
-
 
-
return init($this, input);
 
-
 
-
else if(type=="string")
 
-
 
-
return (input=="items" || input=="opts") ?
 
-
$this.triggerHandler(input+RADMENU) :
 
-
$this.trigger(input+RADMENU, param || null);
 
-
 
-
else if(type=="number")
 
-
 
-
return $this.trigger("select"+RADMENU,input);
 
-
 
-
} catch (e) {
 
-
 
-
return "error : "+e;
 
-
 
-
}
 
-
 
-
};
 
-
 
-
/**
 
-
* private :: init fn
 
-
* @params
 
-
* $menu - the jQuery obj / array w/ menu target
 
-
*  opts - options object, to be merged with defaults
 
-
*/
 
-
function init($menu, opts){
 
-
 
-
var o = $.extend({}, defaults, opts);
 
-
 
-
return $menu.each(function(m){
 
-
 
-
var $this = $(this);
 
-
 
-
if(!$this.hasClass(RADMENU_CLASS)) {
 
-
 
-
var $list = $this.find("."+o.listClass);
 
-
 
-
$list.find("."+o.itemClass).hide(); // ensure its hidden
 
-
 
-
// set the options within the data for the elem & bind evts
 
-
$this.data(OPTS, updateRadius(o, o.initialScale, o.radius));
 
-
 
-
for(e in MENU)
 
-
$this.bind(e+RADMENU, $this, MENU[e]);
 
-
 
-
$this.addClass(RADMENU_CLASS);
 
-
 
-
}
 
-
 
-
});
 
-
 
-
};
 
-
 
-
/**
 
-
* selects a menu item - this method provides
 
-
* functionality for nested radial menus
 
-
* @param
 
-
* evt - the event object
 
-
* triggers select event on radmenu container
 
-
* using the index of the 'target object'
 
-
*/
 
-
function selectMenuitem(evt){
 
-
 
-
var $this = $(this);
 
-
 
-
var $element = $(evt.target);
 
-
 
-
var container = $.radmenu.container;
 
-
 
-
if(!$element.hasClass(container.itemClz))
 
-
$element = $element.closest("."+container.itemClz);
 
-
 
-
var isInNested = $element.parents("."+container.itemClz).length>0;
 
-
 
-
var index = $element.index();
 
-
 
-
if(!isInNested)
 
-
$this.parents("."+container.clz).radmenu(index);
 
-
 
-
else
 
-
$this.radmenu(index);
 
-
 
-
cancelBubble(evt);
 
-
 
-
};
 
-
 
-
/**
 
-
* cancel event bubbling - x-browser friendly
 
-
* @param
 
-
* evt - the event object
 
-
*/
 
-
function cancelBubble(evt){
 
-
 
-
if(!$.support.opacity)
 
-
window.event.cancelBubble = true;
 
-
 
-
else
 
-
evt.stopPropagation();
 
-
 
-
};
 
-
 
-
/**
 
-
* All the events bound to the radial menu instance
 
-
*/
 
-
var MENU = {
 
-
opts: function(evt) {
 
-
 
-
return getMenu(evt).opts;
 
-
 
-
},
 
-
show: function(evt, fn){ // fn = user input onshow
 
-
 
-
var $m = getMenu(evt);
 
-
 
-
var container = $.radmenu.container;
 
-
 
-
// clear any existing radial menus within the menu
 
-
$m.menu.find("."+container.clz).remove();
 
-
 
-
// grab the desired menu items to be used in building the radmenu
 
-
var $menuitems = $m.menu.find("."+$m.opts.itemClass);
 
-
 
-
// create a div that will be the radmenu & create the HTML for the items
 
-
var $radialMenu = $(container.html)
 
-
.addClass(container.clz)
 
-
.css(container.css)
 
-
.html(buildMenuHTML($menuitems, $m.opts));
 
-
 
-
// assign a selection event if the user has specified something
 
-
var $menuitems = $radialMenu.find("."+container.itemClz);
 
-
 
-
if($m.opts.selectEvent!=null)
 
-
$menuitems.bind($m.opts.selectEvent,selectMenuitem);
 
-
 
-
// append the radmenu items inside the menu
 
-
$radialMenu.appendTo($m.menu);
 
-
 
-
if(typeof(fn) == "function")
 
-
fn($menuitems); // allow passing in a method
 
-
 
-
else
 
-
$m.opts.onShow($menuitems); // user can do what they want
 
-
 
-
cancelBubble(evt);
 
-
 
-
},
 
-
hide: function(evt){
 
-
 
-
var $m = getMenu(evt);
 
-
 
-
// remove the radmenu that was built and appended inside the menu
 
-
var $menu = $m.menu.find("."+$.radmenu.container.clz);
 
-
 
-
$m.opts.onHide($menu.find("."+$.radmenu.container.itemClz));
 
-
 
-
$menu.remove();
 
-
 
-
cancelBubble(evt);
 
-
 
-
},
 
-
select: function(evt, selectIndex){
 
-
 
-
var $m = getMenu(evt);
 
-
 
-
// with a specific index specified, grab the item
 
-
var $selected = $($m.raditems().get(selectIndex));
 
-
 
-
// remove the active class on the elements siblings
 
-
$selected.siblings().removeClass($m.opts.activeItemClass);
 
-
 
-
// add the active class on the selected item
 
-
$selected.addClass($m.opts.activeItemClass);
 
-
 
-
// pass the selected item to a customizable function
 
-
$m.opts.onSelect($selected);
 
-
 
-
cancelBubble(evt);
 
-
 
-
},
 
-
next: function(evt){ // clockwise
 
-
 
-
var $m = getMenu(evt);
 
-
 
-
if( !$m.opts.onNext($m) ) return;
 
-
 
-
// switch the first and last items and then animate
 
-
switchItems($m, $m.raditems().length-1, 0);
 
-
 
-
},
 
-
prev: function(evt){ // anticlockwise
 
-
 
-
var $m = getMenu(evt);
 
-
 
-
if( !$m.opts.onPrev($m) ) return;
 
-
 
-
// switch the last and first items and then animate
 
-
switchItems($m, 0, $m.raditems().length-1);
 
-
 
-
},
 
-
shuffle: function(evt){
 
-
 
-
var $m = getMenu(evt);
 
-
 
-
var len = $m.raditems().length;
 
-
 
-
// swap some random item with another random item, and add some shuffling effects
 
-
switchItems($m, rnd(len), rnd(len));
 
-
 
-
},
 
-
destroy: function(evt){
 
-
 
-
var $m = getMenu(evt);
 
-
 
-
$m.menu.data(OPTS, null)
 
-
.data(PREVOPTS, null)
 
-
.removeClass(RADMENU_CLASS)
 
-
.unbind(RADMENU);
 
-
 
-
return $m.menu;
 
-
 
-
},
 
-
items: function(evt){
 
-
 
-
return getMenu(evt).raditems();
 
-
 
-
},
 
-
scale: function(evt, factor){
 
-
 
-
var $m = getMenu(evt);
 
-
 
-
if(factor){
 
-
 
-
var o = $m.opts;
 
-
 
-
var container = $.radmenu.container;
 
-
 
-
var prevOpts = $m.menu.data(PREVOPTS);
 
-
 
-
if(!prevOpts) $m.menu.data(PREVOPTS, prevOpts=o);
 
-
 
-
// get the radial menu items
 
-
var $items = $m.menu.find("."+container.itemClz);
 
-
 
-
var updatedRadiusOpts = updateRadius(o, factor, prevOpts.radius);
 
-
 
-
$m.menu.data(OPTS, updatedRadiusOpts); // save the radius for anim purposes
 
-
 
-
$items.each(function(i){ // for each item update the x,y + css
 
-
 
-
var $this = $(this);
 
-
 
-
var coords = getCoords(i, $items.length, updatedRadiusOpts);
 
-
 
-
var animOpts = {
 
-
 
-
top: coords.top,
 
-
 
-
left: coords.left
 
-
 
-
};
 
-
 
-
if(typeof(o.scaleAnimOpts) == "object") {
 
-
 
-
animOpts = $.extend({}, o.scaleAnimOpts, animOpts);
 
-
 
-
}
 
-
 
-
$this.animate(animOpts, o.scaleAnimSpeed, o.scaleAnimEasing);
 
-
 
-
$m.opts.onScaleItem($this, factor, coords);
 
-
 
-
});
 
-
 
-
}
 
-
 
-
return $m.menu;
 
-
}
 
-
};
 
-
 
-
// simply multiples the radius by a factor
 
-
function updateRadius(opts, radius, factor){
 
-
 
-
return $.extend({},opts,{radius:(factor*radius)});
 
-
 
-
};
 
-
 
-
// random int offset
 
-
function rnd(i){
 
-
 
-
return parseInt( Math.random() * i );
 
-
 
-
};
 
-
 
-
/**
 
-
* getMenu - this is a method that returns all
 
-
* the required objects within a given method
 
-
* that is subscribed to the radmenu object.
 
-
*
 
-
* @params
 
-
* evt - the event object
 
-
* @return
 
-
* Object
 
-
* > menu - jQueryfied menu
 
-
* > opts - the options
 
-
* > raditems - the radial menu items
 
-
*/
 
-
function getMenu(evt){
 
-
 
-
var $menu = evt.data;
 
-
 
-
return {
 
-
 
-
menu: $menu,
 
-
 
-
opts: $menu.data(OPTS),
 
-
 
-
raditems: function(){
 
-
 
-
// you will want to trigger raditems() if the contents get modified
 
-
return $menu.find("."+$.radmenu.container.itemClz);
 
-
 
-
}
 
-
 
-
};
 
-
};
 
-
 
-
/**
 
-
* Switch Items -- this method is used in re-evaluating the (x,y) coords
 
-
* as a result of swapping the position of items. The intent with this
 
-
* is that the plugin will reoganize the items (in the container,
 
-
* as opposed to the original dom elements) such that the elements
 
-
* positions, when selected, remains fixed around the circle.
 
-
* Based on given indexes the items are swapped and then animated. The
 
-
* most typical case involves removing the first and swapping the last
 
-
* and vice versa.
 
-
*
 
-
* @params
 
-
* $m - the menu package
 
-
* remove - the index of the menuitem to replace in the swap
 
-
* add - the index of the menuitem to use in the swap (a placeholder)
 
-
*/
 
-
function switchItems($m, remove, add){
 
-
 
-
if(remove==add) add = remove - 1; // ensure that we don't lose any items
 
-
 
-
var $remove = $($m.raditems()[remove]); // grab the replacement item
 
-
 
-
var toAddto = $m.raditems()[add]; // grab the placeholder
 
-
 
-
// insertion is dependent on index of items
 
-
if(remove>add)
 
-
$remove.insertBefore(toAddto);
 
-
 
-
else
 
-
$remove.insertAfter(toAddto);
 
-
 
-
animateWheel($m, (remove<add)); // posOffset = 5:neat, 10:fireworksesque, 15:subtleish
 
-
 
-
};
 
-
 
-
/**
 
-
* buildMenuHTML - returns string instead of objects
 
-
* for performance
 
-
*
 
-
* @params
 
-
* $menuitems - the jQueryified menu items
 
-
* opts - the radial menu's options
 
-
* @return
 
-
* String
 
-
* > each item is wrapped with an
 
-
* absolute positioned div at an
 
-
* offset determined by it's location
 
-
* on a circle
 
-
*/
 
-
function buildMenuHTML($menuitems, opts){
 
-
 
-
var ret = [];
 
-
 
-
$menuitems.each(function(i){ // for each item we will want to build the HTML
 
-
 
-
var $this = $(this);
 
-
 
-
var coords = getCoords(i, $menuitems.length, opts); // each item has a position
 
-
 
-
var rotationHTML = "transform:rotate("+coords.angle+"deg); ";
 
-
 
-
ret.push("<div class='"+$.radmenu.container.itemClz+"' "); // outer container for the div
 
-
 
-
// after getting the coordinates, absolute position element at (x,y)
 
-
ret.push("style='");
 
-
ret.push("position:absolute;display:none;");
 
-
ret.push("left:"+coords.left+"px;");
 
-
ret.push("top:"+coords.top+"px;");
 
-
 
-
if(opts.rotate) {
 
-
 
-
for(rot in XForm.opts)
 
-
ret.push(XForm.opts[rot]+rotationHTML);
 
-
 
-
}
 
-
 
-
ret.push("'>");
 
-
 
-
ret.push($this.html()); // append the HTML _within_ the user's defined 'item'
 
-
 
-
ret.push("</div>");
 
-
 
-
});
 
-
 
-
return ret.join("");
 
-
 
-
};
 
-
 
-
/**
 
-
* Get the radians value of an angle given a
 
-
* particular slice of the selection
 
-
*
 
-
* @params
 
-
* iIdx - the instance index
 
-
* iNum - the number of menu items
 
-
*/
 
-
function getAngleAtIndex(iIdx, iNum){
 
-
 
-
return 2 * Math.PI * parseFloat(iIdx/iNum); // radians
 
-
 
-
};
 
-
 
-
/**
 
-
* getCoords - returns coordinates for menuitems, as
 
-
* well as an animation object with the appropriate rotation
 
-
* as per config
 
-
*
 
-
* @params
 
-
* iIdx - the instance index (1st, 2nd, 3rd, etc..)
 
-
* iNum - the number of menuitems to distribute
 
-
* oOpts - the options provided by the user customizations
 
-
* bClockwise - a flag for the animation object
 
-
* @return
 
-
* Object - (x, y) coords & the angle in degrees
 
-
*/
 
-
function getCoords(iIdx, iNum, oOpts, bClockwise){
 
-
 
-
var radius = oOpts.radius; // user specified radius
 
-
 
-
var angle = getAngleAtIndex(iIdx, iNum);
 
-
 
-
angle += toRadians(oOpts.angleOffset); // provide flexibility of angle
 
-
 
-
// assuming: hypotenuse (hyp) = radius
 
-
//
 
-
// opposite |\ hypotenuse
 
-
// | \
 
-
// 90deg |__\ (*theta* - angle)
 
-
// adjacent
 
-
//
 
-
// x-axis offset: cos(theta) = adjacent / hypotenuse
 
-
// ==> adjacent = left = cos(theta) * radius
 
-
// y-axis offset: sin(theta) = opposite / hypotenuse
 
-
// ==> opposite = top = sin(theta) * radius
 
-
 
-
var l = oOpts.centerX + ( Math.cos( angle ) * radius ), // "left"
 
-
// angle is rounded to 2dp to fix a bug
 
-
t = oOpts.centerY + ( Math.sin( parseInt(angle*100)/100 ) * radius ); // "top"
 
-
 
-
var degrees = oOpts.rotate ? oOpts.getRotation( angle * 180 / Math.PI, iIdx, iNum ) : 0;
 
-
 
-
// NOTE: why not just simply rotate to the angle? buggy
 
-
// the element that gets shifted cycles through an unnecessary revolution
 
-
// i.e. >360deg -> >0 deg
 
-
var slice = oOpts.rotate ? ( getAngleAtIndex(1, iNum) * 180 / Math.PI ) : 0;
 
-
 
-
var rotation = ( bClockwise==true ? "-=" : "+=" ) + slice;
 
-
 
-
return {
 
-
 
-
left: l,
 
-
 
-
top: t,
 
-
 
-
angle: degrees,
 
-
 
-
animObj:{
 
-
 
-
left: l,
 
-
 
-
top: t,
 
-
 
-
radrotate: rotation
 
-
 
-
}
 
-
 
-
}; // return the x,y coords
 
-
 
-
};
 
-
 
-
/**
 
-
* simple method to convert degrees to radians
 
-
*/
 
-
function toRadians(degrees){
 
-
 
-
return degrees * Math.PI / 180;
 
-
 
-
};
 
-
 
-
/**
 
-
* animateWheel - performs animation on menu items within
 
-
* the container elements
 
-
*
 
-
* @params
 
-
* $m - object holding menu & options
 
-
* iPosOffset - the position offset for the initial menuitem
 
-
* bClockwise - for the animation, clockwise or counter
 
-
*/
 
-
function animateWheel($m, bClockwise){
 
-
 
-
// get the menu from the $m menu package
 
-
var $menuitems = $m.raditems();
 
-
 
-
// get a handle on the number of items
 
-
var len = $menuitems.length;
 
-
 
-
// for each item, we're going to animate left/top attributes
 
-
$menuitems.each(function(i){
 
-
 
-
var $this = $(this);
 
-
 
-
// establish the new coordinates with a customizable offset
 
-
var coords = getCoords(i, len, $m.opts, bClockwise);
 
-
 
-
// playing with this is fun - this basically just
 
-
// performs the animation with new coordinates
 
-
 
-
$this.animate(
 
-
coords.animObj,
 
-
$m.opts.animSpeed,
 
-
$m.opts.animEasing,
 
-
function(){
 
-
if(i==(len-1) ){
 
-
// allow the user to do something after completing an animation
 
-
$m.opts.afterAnimation($m);
 
-
}
 
-
}
 
-
);
 
-
});
 
-
};
 
-
 
-
/**
 
-
* Transform Utils
 
-
*/
 
-
var XForm = {};
 
-
 
-
// local cache of the appropriate transform to use
 
-
XForm.attr = undefined;
 
-
 
-
// Safari, Chrome, FF 3.5+, IE 9+, and Opera 11+
 
-
XForm.opts = ["","-webkit-","-moz-","-ms-","-o-"];
 
-
XForm.cssattrs = ["","Webkit","Moz","ms","O"];
 
-
 
-
/**
 
-
* Get the relevant CSS attr and cache it
 
-
*/
 
-
XForm.getCSSAttr = function($elm){
 
-
 
-
if( this.attr )
 
-
return this.attr;
 
-
 
-
return this.attr = (function(){
 
-
 
-
for(var ii=0; ii<XForm.cssattrs.length; ii++){
 
-
 
-
var opt = XForm.cssattrs[ii]+"Transform";
 
-
 
-
if( $elm[0].style[opt] )
 
-
return opt;
 
-
 
-
}
 
-
 
-
return "transform";
 
-
 
-
})();
 
-
 
-
};
 
-
 
-
/**
 
-
* Deduce which transform is applicable
 
-
* and extract the attr's value
 
-
* @params
 
-
*   $elm - jQuerified element which the
 
-
* css attribute is evaluated against
 
-
*/
 
-
XForm.getTransformValue = function($elm){
 
-
 
-
return jQuery.style( $elm[0], XForm.getCSSAttr($elm) );
 
-
 
-
};
 
-
 
-
/**
 
-
* jQuery Proxy object
 
-
*/
 
-
var _ = {};
 
-
 
-
_.cur = $.fx.prototype.cur;
 
-
 
-
/**
 
-
* jQuery Proxy Method:
 
-
* We need to override this method in order for the "rotate([x]deg)"
 
-
* css value to be parsed and passed through to the step fn numerically
 
-
*
 
-
* Credit due: Zachary Johnson www.zachstronaut.com
 
-
* from https://github.com/zachstronaut/jquery-animate-css-rotate-scale
 
-
*/
 
-
    $.fx.prototype.cur = function() {
 
-
 
-
        if ( this.prop == "radrotate" ) {
 
-
 
-
var $elm = $(this.elem);
 
-
 
-
var style = XForm.getTransformValue($elm) || 'none';
 
-
 
-
        if (style) {
 
-
 
-
                var m = style.match(/rotate\(([^)]+)\)/);
 
-
 
-
                if (m && m[1]) {
 
-
 
-
return parseFloat( m[1] );
 
-
 
-
}
 
-
 
-
            }
 
-
 
-
            return 0;
 
-
 
-
        }
 
-
 
-
        return _.cur.apply(this, arguments);
 
-
 
-
    };
 
-
 
-
//
 
-
// use a custom animation property - radrotate
 
-
//
 
-
$.fx.step.radrotate = function(fx) {
 
-
 
-
var $elm = $(fx.elem);
 
-
 
-
        $elm.css(XForm.getCSSAttr($elm), "rotate("+ fx.now +"deg)");
 
-
 
-
    };
 
-
 
-
})(jQuery);
 

Latest revision as of 21:15, 8 July 2011