Today we want to share one possible solution to the circle hovering problem. We’ll create a plugin that will take care of the ‘mouseenter’, ‘mouseleave’ and ‘click’ events to be triggered only on the circular shape of the element and not its bounding box.

Applying a :hover pseudo-class to an element is widely known as the classic “hovering” over an element on a web page. A problem that arose with the introduction of the border-radius property is the non-realistic triggering of the hover event when entering the bounding box of the element and not just the actual visible area. This becomes extreme when we create a circle by setting the border-radius of a square to 50% (half of its outer width and height).

Today we want to share one possible solution to the circle hovering problem. We’ll create a plugin that will take care of the ‘mouseenter’, ‘mouseleave’ and ‘click’ events to be triggered only on the circular shape of the element and not its bounding box.

CIRCULAR-Elements-With-jQuery

HOW IT WORKS

In our example, we’ll be creating a circle with some kind of hover effect. The structure will simply be:

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

And the style will be the following:

.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(HoverClickTriggerCircle.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;
}

Now, we will define a class for the hover effect but not a dynamic pseudo-class :hover. The idea is to apply this class then with jQuery when we enter the circular area of our element:

.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);
}

Only when we have JavaScript disabled, we’ll add the pseudo-class. This style can be found in the noscript.css:

.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);
}

THE JAVASCRIPT

We are going to create a simple plugin that basically “redefines” the three events mentioned earlier. We’ll make the events only applicable on the circular shape:

$.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 );
        // set the default cursor on the element
        this.$el.css( 'cursor', 'default' );
        this._initEvents();

    },
    _initEvents     : function() {
       var _self   = this;
       this.$el.on({
           'mouseenter.circlemouse'    : function( event ) {
               var el  = $(event.target),
               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
                   };

                // save cursor type
                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 ) {

                  // inside element / circle
                  el.css( 'cursor', el.data('cursor') ).data( 'inside', true );
                  _self.options.onMouseEnter( _self.$el );

                 }
                 else {

                   if( distance <= circlePos.radius && !el.data('inside') ) {                       // inside element / circle                       el.css( 'cursor', el.data('cursor') ).data( 'inside', true );                       _self.options.onMouseEnter( _self.$el );                                                   }                     else if( distance > circlePos.radius && el.data('inside') ) {

                      // inside element / outside circle
                      el.css( 'cursor', 'default' ).data( 'inside', false );
                      _self.options.onMouseLeave( _self.$el );
                    }
                   }
                }); 
            },
            'mouseleave.circlemouse'    : function( event ) {
              var el  = $(event.target);
              el.off('mousemove');
               if( el.data( 'inside' ) ) {
                  el.data( 'inside', false );
                  _self.options.onMouseLeave( _self.$el );
              }
             },
            'click.circlemouse'         : function( event ) {
              // allow the click only when inside the circle
                var el  = $(event.target);
                if( !el.data( 'inside' ) )
                    return false;
                else
                    _self.options.onClick( _self.$el );
            }
        });         
    },
    destroy             : function() {     
        this.$el.unbind('.circlemouse').removeData('inside').removeData('cursor'); 
    }
}

When we enter with the mouse in the square bounding box of our circle, we bind the ‘mousemove’ event to the element and like that we can track if the distance of the mouse to the center of the element if longer than the radius. If it is, we know that we are not yet hovering the circular area of the element.

hoverTrigger
Once the distance of the mouse is shorter than the radius, we know that we entered the circle and we trigger our custom ‘mouseenter’ event.
We also only allow the click event when the mouse is inside of the circle.
In our example we will then apply our plugin to the regarding element. In our case, we are adding the hover class on ‘mouseenter’ and removing it on ‘mouseleave’.

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

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

    },
    onMouseLeave    : function( el ) {

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

    },
    onClick         : function( el ) {

        alert('clicked');

    }
})

Remember that the “normal” pseudo hover class is also defined in the noscript.css which gets applied when JavaScript is disabled.

view demo

Your turn

I hope you enjoyed this article and the techniques I used. Please share your comments and questions below!

Posted by: Dhiraj kumar

You can support this website by sharing. Thank you!
Comments
  1. Shyam says:

    Nice example and explanation bro.

  2. Rameshwar says:

    good demo

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>