| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- ;(function($, window, document, undefined){
- var pluginName = 'circleMenu',
- defaults = {
- depth: 0,
- item_diameter: 30,
- circle_radius: 80,
- angle:{
- start: 0,
- end: 90
- },
- speed: 500,
- delay: 1000,
- step_out: 20,
- step_in: -20,
- trigger: 'hover',
- border: 'round',
- close_event: 'click',
- transition_function: 'ease'
- };
- function vendorPrefixes(items,prop,value){
- ['-webkit-','-moz-','-o-','-ms-',''].forEach(function(prefix){
- items.css(prefix+prop,value);
- });
- }
- function CircleMenu(element, options){
- this._timeouts = [];
- this.element = $(element);
- this.options = $.extend({}, defaults, options);
- this._defaults = defaults;
- this._name = pluginName;
- this.init();
- this.hook();
- }
- CircleMenu.prototype.init = function(){
- var self = this,
- directions = {
- 'vertical':[-400,0],
- 'vertical-top':[-800,0],
- 'horizontal':[400,0],
- 'bottom-left':[180,90],
- 'bottom':[135,45],
- 'right':[-45,45],
- 'left':[225,135],
- 'top':[225,315],
- 'bottom-half':[180,0],
- 'right-half':[-90,90],
- 'left-half':[270,90],
- 'top-half':[180,360],
- 'top-left':[270,180],
- 'top-right':[270,360],
- 'full':[-90,270-Math.floor(360/(self.element.children('li').length - 1))],
- 'bottom-right':[0,90]
- },
- dir;
- self._state = 'closed';
- self._locked = false;
- self.element.addClass(pluginName+'-closed');
- if(typeof self.options.direction === 'string'){
- dir = directions[self.options.direction.toLowerCase()];
- if(dir){
- self.options.angle.start = dir[0];
- self.options.angle.end = dir[1];
- }
- }
- self.menu_items = self.element.children('li:not(:first-child)');
- self.initCss();
- self.item_count = self.menu_items.length;
- self._step = (self.options.angle.end - self.options.angle.start) / (self.item_count-1);
- self.menu_items.each(function(index){
- var $item = $(this),
- angle = (self.options.angle.start + (self._step * index)) * (Math.PI/180),
- x = Math.round(self.options.circle_radius * Math.cos(angle)),
- y = Math.round(self.options.circle_radius * Math.sin(angle));
- // linear hack
- if (self.options.angle.start<-360) {x = 0; y = index * self.options.circle_radius +self.options.circle_radius;}
- if (self.options.angle.start>360) {x = index * self.options.circle_radius + self.options.circle_radius;y = 0;}
- if (self.options.angle.start<-790) {x = 0; y = -(index * self.options.circle_radius +self.options.circle_radius);} //vertical-top
- $item.data('plugin_'+pluginName+'-pos-x', x);
- $item.data('plugin_'+pluginName+'-pos-y', y);
- $item.on(self.options.close_event, function(){
- self.select(index+2);
- });
- });
- // Initialize event hooks from options
- ['open','close','init','select'].forEach(function(evt){
- var fn;
- if(self.options[evt]){
- fn = self.options[evt];
- self.element.on(pluginName+'-'+evt, function(){
- return fn.apply(self,arguments);
- });
- delete self.options[evt];
- }
- });
- self.submenus = self.menu_items.children('ul');
- self.submenus.circleMenu($.extend({},self.options,{depth:self.options.depth+1}));
- self.trigger('init');
- };
- CircleMenu.prototype.trigger = function(){
- var args = [],
- i, len;
- for(i = 0, len = arguments.length; i < len; i++){
- args.push(arguments[i]);
- }
- this.element.trigger(pluginName+'-'+args.shift(), args);
- };
- CircleMenu.prototype.hook = function(){
- var self = this;
- if(self.options.trigger === 'hover'){
- self.element.on('mouseenter',function(evt){
- self.open();
- }).on('mouseleave',function(evt){
- self.close();
- });
- }else if(self.options.trigger === 'click'){
- self.element.children('li:first-child').children().addBack()
- .on('clicked click',function(evt){
- evt.preventDefault();
- if(self._locked === false){
- self._locked = true;
- if(self._state === 'closed' || self._state === 'closing'){
- self.open();
- }else{
- self.close(true);
- }
- setTimeout( function() {
- self._locked = false;
- }, 350);
- }
- return false;
- });
- }else if(self.options.trigger === 'none'){
- // Do nothing
- }
- };
- CircleMenu.prototype.open = function(){
- var self = this,
- $self = this.element,
- start = 0,
- set;
- self.clearTimeouts();
- if(self._state === 'open') return self;
- $self.addClass(pluginName+'-open');
- $self.removeClass(pluginName+'-closed');
- if(self.options.step_out >= 0){
- set = self.menu_items;
- }else{
- set = $(self.menu_items.get().reverse());
- }
- set.each(function(index){
- var $item = $(this);
- self._timeouts.push(setTimeout(function(){
- $item.css({
- left: $item.data('plugin_'+pluginName+'-pos-x')+'px',
- top: $item.data('plugin_'+pluginName+'-pos-y')+'px'
- });
- vendorPrefixes($item,'transform','scale(1)');
- }, start + Math.abs(self.options.step_out) * index));
- });
- self._timeouts.push(setTimeout(function(){
- if(self._state === 'opening') self.trigger('open');
- self._state = 'open';
- },start+Math.abs(self.options.step_out) * set.length));
- self._state = 'opening';
- return self;
- };
- CircleMenu.prototype.close = function(immediate){
- var self = this,
- $self = this.element,
- do_animation = function do_animation(){
- var start = 0,
- set;
- self.submenus.circleMenu('close');
- self.clearTimeouts();
- if(self._state === 'closed') return self;
- if(self.options.step_in >= 0){
- set = self.menu_items;
- }else{
- set = $(self.menu_items.get().reverse());
- }
- set.each(function(index){
- var $item = $(this);
- self._timeouts.push(setTimeout(function(){
- $item.css({top:0,left:0});
- vendorPrefixes($item,'transform','scale(0)');
- }, start + Math.abs(self.options.step_in) * index));
- });
- self._timeouts.push(setTimeout(function(){
- if(self._state === 'closing') self.trigger('close');
- self._state = 'closed';
- },start+Math.abs(self.options.step_in) * set.length));
- $self.removeClass(pluginName+'-open');
- $self.addClass(pluginName+'-closed');
- self._state = 'closing';
- return self;
- };
- if(immediate){
- do_animation();
- }else{
- self._timeouts.push(setTimeout(do_animation,self.options.delay));
- }
- return this;
- };
- CircleMenu.prototype.select = function(index){
- var self = this,
- selected, set_other;
- if(self._state === 'open' || self._state === 'opening'){
- self.clearTimeouts();
- set_other = self.element.children('li:not(:nth-child('+index+'),:first-child)');
- selected = self.element.children('li:nth-child('+index+')');
- self.trigger('select',selected);
- vendorPrefixes(selected.add(set_other), 'transition', 'all 500ms ease-out');
- vendorPrefixes(selected, 'transform', 'scale(0)');
- vendorPrefixes(set_other, 'transform', 'scale(0)');
- selected.css('opacity','0');
- set_other.css('opacity','0');
- self.element.removeClass(pluginName+'-open');
- setTimeout(function(){self.initCss();},500);
- }
- };
- CircleMenu.prototype.clearTimeouts = function(){
- var timeout;
- while(timeout = this._timeouts.shift()){
- clearTimeout(timeout);
- }
- };
- CircleMenu.prototype.initCss = function(){
- var self = this,
- $items;
- var value = String(self.options.item_diameter);
- var unit = ( value.match(/^.*(px|%|em)$/) ) ? '' : 'px';
- self._state = 'closed';
- self.element.removeClass(pluginName+'-open');
- self.element.css({
- 'list-style': 'none',
- 'margin': 0,
- 'padding': 0,
- 'width': self.options.item_diameter + unit
- });
- $items = self.element.children('li');
- $items.attr('style','');
- $items.css({
- 'display': 'block',
- 'width': (self.options.item_width) ? self.options.item_width : '4em',
- 'height': (self.options.item_height) ? self.options.item_height : self.options.item_diameter + unit,
- 'text-align': 'center',
- 'line-height': self.options.item_diameter + unit,
- 'position': 'absolute',
- 'z-index': 1,
- 'opacity': ''
- });
- self.element.children('li:first-child').css({'z-index': 1000-self.options.depth, 'background-color':'transparent' });
- self.menu_items.css({
- top:0,
- left:0
- });
- if ( self.options.border === 'square')
- vendorPrefixes($items, 'border-radius', self.options.item_diameter/5 + unit);
- else
- vendorPrefixes($items, 'border-radius', self.options.item_diameter + unit);
- vendorPrefixes(self.menu_items, 'transform', 'scale(0)');
- setTimeout(function(){
- vendorPrefixes($items, 'transition', 'all '+self.options.speed+'ms '+self.options.transition_function);
- },0);
- };
- $.fn[pluginName] = function(options){
- return this.each(function(){
- var obj = $.data(this, 'plugin_'+pluginName),
- commands = {
- 'init':function(){obj.init();},
- 'open':function(){obj.open();},
- 'close':function(){obj.close(true);}
- };
- if(typeof options === 'string' && obj && commands[options]){
- commands[options]();
- }
- if(!obj){
- $.data(this, 'plugin_' + pluginName, new CircleMenu(this, options));
- }
- });
- };
- })(jQuery, window, document);
|