Enlarge text/image on hover/focus (bubble-up / fisheye ?)

UselesswithJS picture UselesswithJS · Nov 24, 2010 · Viewed 7.6k times · Source

The desired effect is what seems to be termed as/similar to Bubble-up or FishEye examples:

I've seen a few examples/plugins, but all had issues/limitations the most notable ones being:

  • Not keyboard accessible Requires
  • Preset height/width Affects
  • Preceeding/following items/elements
  • Browser compatibility issues

I have tweaked some of the existing examples but I get the distinct impression that it isn't as streamlined as it ought to be, and that there are little bugs with it's behaviour.

Ideally the following will work;
1) It will permit a scale for enlargement
2) It will permit you to specify any element to be affected
3) It will handle Height/Width/other properties automatically
4) It will manage if a property is not present/empty
5) It will not affect surrounding/preceding elements (positioned absolute whilst leaving clone/holder element)

Here's the code I have so far:

<script type="text/javascript">
//<![CDATA[
$(document).ready(function() {

// NOTE: the element to become enlarged must have a z-index value!  (even if you set it as 1)
$(function(){
  function fatOnHover($elements, zoomSize, animationSpeed){
  $elements.each(function(i){
     var $wrap, height, width, left, bigWidth, bigHeight, $that = $(this);

  // Get the item height/width, and create the enlarged dimensions
     height = $that.height();
     width = $that.width();
  bigWidth = (width / 100) * zoomSize;
     bigHeight = (height / 100) * zoomSize;

  // Calculate the positioning (negative pull) based on the size difference of normal to enlarged
  left = (bigWidth - width) / 2;
  top = (bigHeight - height) / 2;

  // Addition for Text enlargening (gets font-size and sets enlarged font-size) (should accept any measurement (px/em etc.))
  //currFontSize = $that.css("font-size");
  //fontSize = parseFloat(currFontSize, 10);
  //fontEnding = currFontSize.slice(-2);
  //bigfontsize = (fontSize / 100) * zoomSize;

  // Get and Set the z-index = MUST make sure the item to be enlarged has a z-index (even if set to 1)
  // Ideally - should detect if there is a value, if not, set one
  currzindex = parseInt($that.css('z-index'));
  //currzindex = 100;
  zindexoffset = 900;
  bigZindex = currzindex + zindexoffset;



  // Insert div before/around the item to be enlarged (and to the same height/width)
      $wrap = "<div style='width: " + width + "px; height: " + height + "px; position: relative;'></div>",

   // Actually - no idea what all of this is for :D
      $that.data({"width": width, "height": height, "bigWidth": bigWidth, "bigHeight": bigHeight, "left": left, "top": top, /*"fontSize": fontSize, "bigfontsize": bigfontsize, "fontEnding": fontEnding,*/ "currzindex": currzindex, "bigZindex": bigZindex})
          .wrap($wrap)
   })

   // Define function/behavious for focus/hover
   .bind('mouseenter mouseover focus',
     function(){
        var $that = $(this);
        $that.stop().css('z-index', $that.data("bigZindex")).animate({"width": $that.data("bigWidth"), "height": $that.data("bigHeight"), "left": -$that.data("left"), "top": -$that.data("top")/*, "fontSize": $that.data("bigfontsize")+$that.data("fontEnding")*/}, animationSpeed);
     })

   // Define function/behavious for loss of focus/hover (normal)
 .bind('mouseleave mouseout blur',
     function(){
        var $that = $(this);
        $that.stop().css('z-index', $that.data("currzindex")).animate({"width": $that.data("width"), "height": $that.data("height"), "left": '0', "top": '0'/*, "fontSize": $that.data("fontSize")+$that.data("fontEnding")*/}, animationSpeed);
     })

  // Assigns position absolute to item to be enlarged
  .css("position", "absolute")
   }
   fatOnHover($('#nav li a'), 135, 900);
})

});
//]]>
</script>

I have commented out some of the code (such as the font-size stuff). That is due to one of the "bugs" I have.

I think I've done it right to work with keyboard/mouse.
I think I've managed to handle some of the additional properties (such as z-index and font-size) - but only up to a point

Issues.
1) The script requires the item to be affected to have a z-index defined. Is it possible for this to be checked for, and if no z-index is defined, the script to set one?
2) Font resizing seems to cause issues - the resized text on hover is huge, not what I would have assumed as "to scale" (I set the fs as em, resize the text, and it's massive on hover, and doesn't return to normal-size after hover)
3) The code seems bloated? I'm assuming there are better ways of doing some of this stuff.
4) Speed for animation in and animation out - is it possible?

Answer

Stephen picture Stephen · Nov 24, 2010

The first problem I see is that you have a DOM ready event inside of a DOM ready event.

Here's my version of your code with optimizations commented. I've introduced more local variables to clean up the global scope. I've removed Hungarian notation, but you can put it back in if you like:

//<![CDATA[
    $(function() {
        var fatOnHover = function(elements, zoomSize, animationSpeed) {
            elements.each(function() {
                var wrap, options, tempZ, currFontSize, zindexoffset = 900, element = $(this);
                tempZ = element.css('z-index');
                currFontSize = element.css('font-size')
                options = {
                    height : element.height(),
                    width : element.width(),
                    fontSize : parseFloat(currFontSize, 10),
                    fontEnding : currFontSize.slice(-2),
                    currzindex : (tempZ === undefined || tempZ === 'auto') ? 100 : parseInt(tempZ)
                };
                $.extend(options, {
                    bigWidth : (options.width / 100) * zoomSize,
                    bigHeight : (options.height / 100) * zoomSize,
                    bigZindex : options.currzindex + zindexoffset,
                    bigfontsize : (options.fontSize / 100) * zoomSize
                });
                $.extend(options, {
                    left : (options.bigWidth - options.width) / 2,
                    top : (options.bigHeight - options.height) / 2
                });

                wrap = ['<div style="height:',options.height,'px;width:',options.width,'px;position:relative;"></div>'].join('');
                element.data(options).wrap(wrap);
            })
            // Define function/behavious for focus/hover
            .bind('mouseenter mouseover focus', function() {
                var element = $(this);
                element
                    .css('z-index', element.data('bigZindex'))
                    .stop()
                    .animate({
                        'width':element.data('bigWidth'),
                        'height':element.data('bigHeight'),
                        'left':-element.data('left'),
                        'top':-element.data('top'),
                        'fontSize':[
                            element.data('bigfontsize'),
                            element.data('fontEnding')
                        ].join('')
                    }, animationSpeed);
            })
            // Define function/behavious for loss of focus/hover (normal)
            .bind('mouseleave mouseout blur',
                function() {
                    var element = $(this);
                    element
                        .css('z-index', element.data('currzindex'))
                        .stop()
                        .animate({
                            'width':element.data('width'),
                            'height':element.data('height'),
                            'left':'0',
                            'top':'0',
                            'fontSize':[
                                element.data('fontSize'),
                                element.data('fontEnding')
                            ].join('')
                        }, animationSpeed);
            })
            // Assigns position absolute to item to be enlarged
            .css('position', 'absolute')
        };
        fatOnHover($('#nav li a'), 200, 100);
    });
    //]]>  

The above code animates text no problem. Tested in FF, Chrome and IE7.