jQuery 1.4: Skinning the Widget

Exclusive offer: get 50% off this eBook here
jQuery 1.4 Animation Techniques: Beginners Guide

jQuery 1.4 Animation Techniques: Beginners Guide — Save 50%

This book and eBook will enable you to quickly master all of jQuery’s animation methods and build a toolkit of ready-to-use animations using jQuery 1.4.

£14.99    £7.50
by Dan Wellman | April 2011 | Open Source Web Development

jQuery is a cross-browser JavaScript library designed to simplify the client-side scripting of HTML, and is the most popular JavaScript library in use today. Using the features offered by jQuery, developers are able to create dynamic web pages.

'There's more than one way to skin a cat' was once proclaimed, and this applies to widgets as well as cats.

In the previous article by Dan Wellman, author of jQuery 1.4 Animation Techniques: Beginners Guide, we saw how to animate an element's position. In this article we will add some custom styling to the widget to see how easy it is to make the widget attractive as well as functional.

 

jQuery 1.4 Animation Techniques: Beginners Guide

jQuery 1.4 Animation Techniques: Beginners Guide

Quickly master all of jQuery’s animation methods and build a toolkit of ready-to-use animations using jQuery 1.4

        Read more about this book      

(For more resources on jQuery, see here.)

Time for action – adding a new skin

At the bottom of the animate-position.css file, add the following code:

a { outline:0 none; }
#slider {
border:1px solid #999; -moz-border-radius:8px;
-webkit-border-radius:8px; border-radius:8px;
background-color:#ededed; -moz-box-shadow:0px 2px 7px #aaa;
-webkit-box-shadow:0px 2px 7px #aaa; box-shadow:0px 2px 7px #aaa;
}
#title, #slider ul { margin-top:10px; margin-bottom:12px; }
#title {
font:normal 22px "Nimbus Sans L", "Helvetica Neue", "Franklin
Gothic Medium", Sans-serif;
color:#444;
}
#viewer { border:1px solid #999; background-color:#fff; }
#slider ul { width:120px; }
#slider ul li a {
display:block; width:10px; height:10px; text-indent:-5000px;
text-decoration:none; border:2px solid #666;
-moz-border-radius:17px; -webkit-border-radius:17px;
border-radius:17px; background-color:#fff; text-align:center;
}
#slider #prev, #slider #next { margin:0; text-align:center; }
#slider #prev { left:10px; }
#slider #prev a, #slider #next a {
display:block; height:28px; width:28px; line-height:22px;
text-indent:0; border:1px solid #666; -moz-border-radius:17px;
-webkit-border-radius:17px; border-radius:17px;
background-color:#fff;
}
#prev a, #next a { font:bold 40px "Trebuchet MS"; color:#666; }
#slider ul li a.active { background-color:#F93; }

What just happened?

With this code we style all of the visual aspects of the widget without interfering with anything that controls how it works. We give it some nice rounded corners and add a drop-shadow to the widget, turn the numeric links into little clickable icons, and style the previous and next links. Colors and fonts are also set in this section as they too are obviously highly dependent on the theme.

These styles add a basic, neutral theme to the widget, as shown in the following screenshot:

jQuery 1.4: Skinning the Widget

The styles we used to create the theme are purely arbitrary and simply for the purpose of the example. They can be changed to whatever we need in any given implementation to suit other elements on the page, or the overall theme of the site.

Have a go hero – making the image viewer more scalable

In our animated content viewer, we had a fixed number of images and a hardcoded navigation structure to access them. Extend the content viewer so that it will work with an indeterminate number of images. To do this, you will need to complete the following tasks:

  • Determine the number of images in the content viewer at run time and set the width of the #slide wrapper element based on the number of images
  • Build the navigation links dynamically based on the number of images
  • Create the details object dynamically based on the number of images and set the correct left properties to show each image

Animating an element's size

Almost any style property that contains a purely numeric value may be animated with the animate() method.

We looked at animating an element's position by manipulating its left style property, so let's move on to look at animating an element's size by manipulating its height and width style properties.

In this example, we'll create image wrappers that can be used to display larger versions of any images on the page by manipulating the element's size.

Time for action – creating the underlying page and basic styling

First, we'll create the underlying page on which the example will run.

  1. Add the following HTML to the <body> of our template file:

    <article>
    <h1>The Article Title</h1>
    <p><img id="image1-thumb" class="expander" alt="An ASCII Zebra"
    src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="img/ascii.gif" width="150" height="100">Lorem ipsum
    dolor...</p>
    <p><img id="image2-thumb" class="expander" alt="An ASCII Zebra"
    src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="img/ascii2.gif" width="100" height="100">Lorem ipsum
    dolor...</p>
    </article>

  2. Save the example page as animate-size.html. We'll keep the styling light in this example; in a new file in your text editor, add the following code:

    article {
    display:block; width:800px; margin:auto; z-index:0;
    font:normal 18px "Nimbus Sans L", "Helvetica Neue", "Franklin
    Gothic Medium", sans-serif;
    }
    article p {
    margin:0 0 20px; width:800px; font:15px Verdana, sans-serif;
    line-height:20px;
    }
    article p #image2-thumb { float:right; margin:6px 0 0 30px; }
    img.expander { margin:6px 30px 1px 0; float:left; }
    .expander-wrapper { position:absolute; z-index:999; }
    .expander-wrapper img {
    cursor:pointer; margin:0; position:absolute;
    }
    .expander-wrapper .expanded { z-index:9999; }

  3. Save this file as animate-size.css in the css folder.

What just happened?

The HTML could be any simple blog post consisting of some text and a couple of images. The points to note are that each image is given an id attribute so that it can be easily referenced, and that each image is actually the full-sized version of the image, scaled down with width and height attributes.

The styles used are purely to lay out the example; very little of the code is actually required to make the example work. The expander-wrapper styles are needed to position the overlaid images correctly, but other than that the styling is purely arbitrary.

We're floating the second image to the right. Again this isn't strictly necessary; it's used just to make the example a little more interesting.

Time for action – defining the full and small sizes of the images

First we need to specify the full and small sizes of each image:

var dims = {
image1: {
small: { width: 150, height: 100 },
big: { width: 600, height: 400 }
},
image2: {
small: { width: 100, height: 100 },
big: { width: 400, height: 400 }
}
},
webkit = ($("body").css("-webkit-appearance") !== "" && $("body").
css("-webkit-appearance") !== undefined) ? true : false;

What just happened?

We create an object which itself contains properties matching each image's filename. Each property contains another nested object which has small and big properties and the relevant integers as values. This is a convenient way to store structured information that can easily be accessed at different points in our script.

We also create a variable called webkit. There is a slight bug in how images floated to the right are treated in Webkit-based browsers such as Safari or Chrome. This variable will hold a Boolean that will indicate whether Webkit is in use.

A test is performed which tries to read the -webkit-appearance CSS property. In Webkit browsers, the test will return none as the property is not set, but other browsers will either return an empty string or the value undefined.

jQuery 1.4 Animation Techniques: Beginners Guide This book and eBook will enable you to quickly master all of jQuery’s animation methods and build a toolkit of ready-to-use animations using jQuery 1.4.
Published: March 2011
eBook Price: £14.99
Book Price: £24.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on jQuery, see here.)

Time for action – creating the overlay images

Next we should create an almost exact copy of each image on the page to use as an overlay:

$(".expander").each(function(i) {

var expander = $(this),
coords = expander.offset(),
copy = $("<img>", {
id: expander.attr("id").split("-")[0],
src: expander.attr("src"),
width: expander.width(),
height: expander.height()
});

What just happened?

In this part of the <script>, we select each image on the page and process them using jQuery's each() method. We set some variables, caching a reference to the current image and storing its coordinates on the page relative to the document using the jQuery offset() method.

We then create a new image for each existing image on the page, giving it an id attribute that pairs it with the image it is overlaying, the src of the original image, and the width and height of the original image. We use the JavaScript split() function to remove the part of the string that says thumb when we set the id of the new image.

Note that the previous code does not represent an entire snippet of fully-functional code. The outer function passed to the each() method has not yet been closed as we need to add some additional code after these variables.

Time for action – creating the overlay wrappers

We now need to create the wrappers for each of the overlay images (note that this code is still within the each() method and so will be executed for each of the images that have the expanded class name):

$("<div></div>", {
"class": "expander-wrapper",
css: {
top: coords.top,
left: (webkit === true && expander.css("float") === "right") ?
(coords.left + expander.width()) : coords.left,
direction: (expander.css("float") === "right") ? "rtl" :
"ltr"
},
html: copy,
width: expander.width(),
height: expander.height(),
click: function() {

var img = $(this).find("img"),
id = img.attr("id");

if (!img.hasClass("expanded")) {
img.addClass("expanded").animate({
width: dims[id].big.width,
height: dims[id].big.height
}, {
queue: false
});
} else {
img.animate({
width: dims[id].small.width,
height: dims[id].small.height
}, {
queue: false,
complete: function() {
$(this).removeClass("expanded");
}
});
}
}
}).appendTo("body");

What just happened?

In this section of code, we create the wrapper element for the new image. We give it a new class name so that it can be positioned correctly.

Quoting the class property
We need to use quotes around the property name class so that it works correctly in Internet Explorer. If we fail to quote it, IE will throw a script error stating that it expected an identifier, string, or number.

We set the position of the wrapper element using the css property in conjunction with the coordinates we obtained from the offset() method earlier.

When setting the left position of the wrapper element, we need to check our webkit variable to see if Safari is in use. If this variable is set to true, and if the image is floated to the right, we position the overlay according to the cords.left value in addition to the width of the original image. If the webkit variable is false, or if the original image is floated left, we just set the left position of the wrapper to the value stored in coords.left.

We also need to set the direction property of any images that are floated right. We check the float style property and set the direction to rtl if the image is floated right, or ltr if not. This is done using JavaScript's ternary conditional.

This check is done so that the wrapper expands from right-to-left when the image is floated right. If we didn't set this, the wrapper would open up from left-to-right, which could make the full-sized image overflow the viewport or the content container resulting in scroll bars.

We add the new image to the wrapper by passing a reference to it into the jQuery html() method, and set the width of the wrapper to the width of the original (and new) image. This is necessary for the overlay to be positioned correctly over any images that are floated right.

Next we add a click handler to the wrapper. Within the anonymous function passed as the value of the click() method, we first cache a reference to the image within the wrapper that was clicked, and get the id of the image for convenience. Remember, the id of the overlay image will be the same as the original image it is covering minus the text string -thumb.

We then check whether the image has the class name expanded. If it doesn't, we add the class name and then animate the image to its full size using the second format of the animate() method. We pass two objects into the method as arguments; the first contains the CSS properties we wish to animate, in this case the width and height of the image.

The correct width and height to increase the image to are retrieved from the dims object using the id of the image that was clicked as the key. In the second object passed to the animate() method, we set the queue property to false. This has the same effect as using the stop() method directly before the animate() method and ensures that nothing bad happens if the overlay wrapper is repeatedly clicked.

If the image already has the class name expanded, we animate the image back to its small size. Again we use the two-object format of the animate() method, supplying false as the value of the queue property, and removing the class name expanded in an anonymous callback function passed to the complete property. Once the wrapper has been created, we append it to the <body> of the page.

At this point the code we've written will work as intended—clicking an image will result in the expanded version being animated to its full size. However, if the page is resized at all, the overlays will no longer be overlaying their images.

Time for action – maintaining the overlay positions

Because the overlays are positioned absolutely, we need to prevent them from becoming misaligned if the window is resized:

$(window).resize(function() {

$("div.expander-wrapper").each(function(i) {

var newCoords = $("#image" + (i + 1) + "-thumb").offset();

$(this).css({
top: newCoords.top,
left: newCoords.left
});
});
});

What just happened?

All we need to do is make sure the overlay images stay directly on top of the original images when the page resizes, which we can achieve by binding a handler for the resize event to the window object. In the handler function, we just get the new coordinates of the underlying image, and set the top and left properties of the wrapper accordingly. Note that we don't animate the repositioning of the overlays.

Save the file and preview it in your browser. We should find that we can click on either image and it will expand to show a full-sized version of the image, with the first image expanding to the right, and the second expanding to the left:

(Move the mouse over the image to enlarge it.)

In the previous screenshot we see the first image as it expands to its full size.

Have a go hero – doing away with the hardcoded dims object

In the previous example, we hardcoded an image into the top of our script that was used to tell the animate() method what size the image should be animated to. While this was fine for the purpose of the example, it doesn't really scale well as a long-term solution as we would have to remember to set this every time we used the script (or otherwise ensure our images are always a fixed size).

The problem is that we have no way to programmatically get both the full size and thumb size from a single image. The good news is that any data that can be stored in a JavaScript object can also be passed across a network for consumption as a JSON object. Extend this example so that when the page loads, it passes the src attributes of the images on the page to the server, which returns a JSON object containing the small and large image sizes. An image manipulation library, like GD or ImageMagick, for PHP, or the System.Drawing. Image type in .Net, will be your friend here.

Summary

In this article we saw how to make the widget attractive as well as functional.


Further resources on this subject:

jQuery 1.4 Animation Techniques: Beginners Guide This book and eBook will enable you to quickly master all of jQuery’s animation methods and build a toolkit of ready-to-use animations using jQuery 1.4.
Published: March 2011
eBook Price: £14.99
Book Price: £24.99
See more
Select your format and quantity:

About the Author :


Dan Wellman

Dan Wellman is an author and frontend engineer living on the South Coast of the UK and working in London. By day he works for Skype and has a blast writing application-grade JavaScript. By night he writes books and tutorials focused mainly on frontend web development. He is also a staff writer for the Tuts+ arm of the Envato network, and occasionally writes for .Net magazine. He's the proud father of four amazing children, and the grateful husband of a wonderful wife.

Books From Packt


jQuery 1.4 Reference Guide
jQuery 1.4 Reference Guide

Django JavaScript Integration: AJAX and jQuery
Django JavaScript Integration: AJAX and jQuery

jQuery Plugin Development Beginner's Guide
jQuery Plugin Development Beginner's Guide

PHP jQuery Cookbook
PHP jQuery Cookbook

CMS Design Using PHP and jQuery
CMS Design Using PHP and jQuery

WordPress 3.0 jQuery
WordPress 3.0 jQuery

Joomla! 1.5 JavaScript jQuery
Joomla! 1.5 JavaScript jQuery

jQuery UI 1.7: The User Interface Library for jQuery
jQuery UI 1.7: The User Interface Library for jQuery


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software