Триггер для событий hover и click в круглом элементе

Использование псевдо класса :hover широко известно как классический способ реагирования на наведение курсора мыши на элемент. Проблема проявляется при задействовании свойства border-radius для получения круглых элементов - событие hover генерируется при наведении курсора мыши на описывающий прямоугольник, а не только для действительно видимой области. 

В данном уроке мы разработаем вариант решения поставленной задачи. Будет создан плагин, который будет генерировать события ‘mouseenter’, ‘mouseleave’ и ‘click’ только для круглой формы элемента, а не для всего описывающего прямоугольника.

Как работает решение


В нашем примере мы создадим круг с эффектом для события hover. Структура разметки будет простой:

Code
<a href="#" id="circle" class="ec-circle">
  <h3>HOVER</h3>
</a>


Со следующими стилями:

Code
.ec-circle{
  width: 420px;
  height: 420px;
  -webkit-border-radius: 210px;
  -moz-border-radius: 210px;
  border-radius: 50%;
  text-align: center;
  overflow: hidden;
  font-family:'Kelly Slab', Georgia, serif;
  background: #dda994 url(../images/1.jpg) no-repeat center center;
  box-shadow:
  inset 0 0 1px 230px rgba(0,0,0,0.6),
  inset 0 0 0 7px #d5ad94;
  transition: box-shadow 400ms ease-in-out;
  display: block;
  outline: none;
}


Теперь определим класс для эффекта hover. Но данный класс будет простым, а не динамическим псевдо классом :hover. Идея заключается в применении данного класса с помощью кода jQuery, когда курсор мыши попадает внутрь круглой области элемента:

Code
.ec-circle-hover{
  box-shadow:
  inset 0 0 0 0 rgba(0,0,0,0.6),
  inset 0 0 0 20px #c18167,
  0 0 10px rgba(0,0,0,0.3);
}


Только для варианта с отключенным JavaScript мы добавим псевдо класс. Данный стиль можно найти в файле исходников noscript.css:

Code
.ec-circle:hover{
  box-shadow:
  inset 0 0 0 0 rgba(0,0,0,0.6),
  inset 0 0 0 20px #c18167,
  0 0 10px rgba(0,0,0,0.3);
}


JavaScript



Мы создадим простой плагин, который переопределяет три упомянутых ранее события. События будут применяться только для круглой формы:

Code
$.CircleEventManager = function( options, element ) {

  this.$el = $( element );
   
  this._init( options );
   
};

$.CircleEventManager.defaults = {
  onMouseEnter : function() { return false },
  onMouseLeave : function() { return false },
  onClick : function() { return false }
  };

$.CircleEventManager.prototype = {
  _init : function( options ) {
   
  this.options = $.extend( true, {}, $.CircleEventManager.defaults, options );
   
  // Устнавливаем курсор по умолчанию лоя элемента
  this.$el.css( 'cursor', 'default' );
   
  this._initEvents();
   
  },
  _initEvents : function() {
   
  var _self = this;
   
  this.$el.on({
  'mouseenter.circlemouse' : function( event ) {
   
  var el = $(this),
   
  circleWidth = el.outerWidth( true ),
  circleHeight = el.outerHeight( true ),
  circleLeft = el.offset().left,
  circleTop = el.offset().top,
  circlePos = {
  x : circleLeft + circleWidth / 2,
  y : circleTop + circleHeight / 2,
  radius: circleWidth / 2
  };
   
  // Сохраняем тип курсора
  var cursor = 'default';
   
  if( _self.$el.css('cursor') === 'pointer' || _self.$el.is('a') )
  cursor = 'pointer';
   
  el.data( 'cursor', cursor );
   
  el.on( 'mousemove.circlemouse', function( event ) {

  var distance = Math.sqrt( Math.pow( event.pageX - circlePos.x, 2 ) + Math.pow( event.pageY - circlePos.y, 2 ) );
   
  if( !Modernizr.borderradius ) {
   
  // Внутри элемента/круга
  el.css( 'cursor', el.data('cursor') ).data( 'inside', true );
  _self.options.onMouseEnter( _self.$el );
   
  }
  else {
   
  if( distance <= circlePos.radius && !el.data('inside') ) {
   
  // Внутри элемента/круга
  el.css( 'cursor', el.data('cursor') ).data( 'inside', true );
  _self.options.onMouseEnter( _self.$el );
   
  }
  else if( distance > circlePos.radius && el.data('inside') ) {
   
  // Внутри элемента / вне круга
  el.css( 'cursor', 'default' ).data( 'inside', false );
  _self.options.onMouseLeave( _self.$el );
   
  }
   
  }
   
  });  
   
  },
  'mouseleave.circlemouse' : function( event ) {
   
  var el = $(this);
   
  el.off('mousemove');
   
  if( el.data( 'inside' ) ) {
   
  el.data( 'inside', false );
  _self.options.onMouseLeave( _self.$el );
   
  }
   
  },
  'click.circlemouse' : function( event ) {
   
  // Разрешаем событие click только внутри круга
   
  var el = $(this);
   
  if( !el.data( 'inside' ) )
  return false;
  else
  _self.options.onClick( _self.$el );
   
  }
  });
   
  },
  destroy : function() {
   
  this.$el.unbind('.circlemouse').removeData('inside, cursor');

  }
};


Когда курсор мыши заходит в квадрат, описывающий наш круг, событие ‘mousemove’ привязывается к элементу, и мы можем отслеживать дистанцию от курсора мыши до центра круга. Если расстояние больше радиуса, то генерировать событие hover рано.



Как только дистанция становится меньше радиуса, значит курсор мыши находится в круге и пора генерировать событие ‘mouseenter’.

Также, событие 'click' может генерироваться только когда курсор мыши находится в круге.

В примере плагин применяется для соответствующего элемента. Класс hover добавляется по событию ‘mouseenter’ и удаляется по событию ‘mouseleave’.

Code
$('#circle').circlemouse({
  onMouseEnter : function( el ) {

  el.addClass('ec-circle-hover');

  },
  onMouseLeave : function( el ) {

  el.removeClass('ec-circle-hover');

  },
  onClick : function( el ) {

  alert('clicked');

  }
});



Помните, что мы определили "нормальный" псевдо класс hover в файле noscript.css, который применяется при отключенном JavaScript.

  • FalleN

  • 1743

  • 1

  • 204
Теги: Hover, триггер, Click

Ссылки на статью:

Похожие статьи: