Search code examples
jqueryhtmlcssjquery-uiscale

How to scale down a div that contains text?


I am trying to shrink a circle by 50% upon mouse click. I did it by using jQuery UI's scale effect.

The div is

<div id='circle' class='circle'></div>

The Js is

var percent = 0.5;

$('#circle').click(function () {
    var height = $(this).height();
    var width = $(this).width();
    var centerX = $(this).position().left + $(this).width()/2.0;
    var centerY = $(this).position().top + $(this).height()/2.0;
    $(this).effect( "scale", { percent: percent * 100 }, 1000, function () {
        var newTop = centerY - (height * percent)/2.0;
        var newLeft = centerX - (width * percent)/2.0;
        $('#circle').offset({ 'top': newTop, 'left': newLeft });
        $('#circle').css({'height': height * percent, 'width': width * percent });
    });
});

That piece of code worked until i added some text on the circle like

<div id='circle' class='circle'>
  <span class="title">Title</span>
</div>

The title did scale down with the circle but upon completion it restored to the original size and made the circle a oval. Please try this fiddle: http://jsfiddle.net/marsant/Ycakg/

Is there a neat way to solve this problem other than manually tweaking the completion callback? Thanks!


Solution

  • You could make a quick fix by adding something like:

    $(this).find('*').filter(function(i) { return $(this).text != "" && !$(this).children().length }).each(function(i) {
        var curSize = parseFloat($(this).css('fontSize'));
        $(this).css('fontSize', curSize / 2);
    });
    
    • $(this).find('*'): get all inner elements of the circle div
    • .filter(function(i) { return $(this).text != "" && !$(this).children().length }): narrows our result to only inner elements that have text and no other inner elements
    • .each(function(i) {: begins going through each element so we can change it's font size
    • var curSize = parseFloat($(this).css('fontSize'));: get the current font size of the current inner element
    • $(this).css('fontSize', curSize / 2);: Set this inner elements font to a new font size that is half the old

    If you want to jazz it up a little to kind of match your reanimation you could go with:

    var curSize = parseFloat($(this).css('fontSize')),
            newSize = curSize / 2
        $(this).animate({ fontSize: newSize });
    

    Although if you want it to match exactly to the animation, you'll probably need to find a CSS solution or change your whole script a bit. I'll look, one sec ...

    WORKING EXAMPLE


    USING ANIMATE TO DO IT ALL AT ONCE:

    $('#circle').click(function () {
        var height = $(this).height(),
            newHeight = height / 2,
            width = $(this).width(),
            newWidth = width / 2,
            fontSize = parseFloat($(this).css('fontSize')),
            newFontSize = fontSize / 2,
            newLeft = parseFloat($(this).css('left')) + (newWidth / 2),
            newTop = parseFloat($(this).css('top')) + (newHeight / 2);
    
        $(this).animate({ 
            height: newHeight,
            fontSize: newFontSize,
            left: newLeft,
            top: newTop,
            width: newWidth 
        });
    });
    

    NOTE This requires slight change in CSS. I would change the .circle to have position relative and move the font-size: 80px; to the .circle:

    .circle {
        background:red;
        border-radius: 50%;
        height: 200px;
        width: 200px;
        display: table-cell;
        vertical-align: middle;
        text-align: center;
        top: 10px;
        left: 10px;
        font-size: 80px;    
        position: relative;
    }
    .title {
        color: #fff;
        font-family:'Helvetica';
    }
    

    WORKING EXAMPLE