Problog
This blog cover the following topics:
- How to write a jQuery Plug-in
- What is a floating object and where it can be used
- How to move a DOM object using jQuery
- Implementing a class in javascript
One of the things that I really like about jQuery is its huge community that develops plug-ins for the framework. Being a big fan of client side and especially rich UI, I cannot ignore the power that jQuery provides and it shows in the amazing plug-ins users have developed for it. I’ve decided that I need to understand how to write a UI plug-in and on the way contribute something back to the community.
I don’t remember exactly why I needed a floating object/div code, but not long ago I’ve search for such implementation. I wanted an implementation that will allow me to select a div object and make it float on the screen to follow wherever the user scrolls to (more like an annoying friend that doesn’t let you go).
I found a few implementation for it, and even some were jQuery plug-ins, but I didn’t like any of the implementations since some didn’t exactly do what I wanted, or some were just written badly in a way that if there was a code inspection police it would get a fine, and to be honest I saw some code that could get the writer arrested. There is nothing worse than reading a spaghetti code, well, maybe eating coded spaghetti (whatever that is…). But hey, i guess most of the developers that will read my code will say the same about mine, right?
Anyway I decided for the practice that I will implement it on my own, and I will show you exactly how I did it.
For those of you who just can’t wait till the end – here is a demo of the plug-in.
Before I go into details about the implementation I need to answer an important question my wife asked me when I showed her the demo for the first time – “why on earth anyone might use this thing?”. Other than my usual answer to almost everything I do – “cause its cool” I think there are a few interesting usage for this plug-in:
- Floating Menu – I’ve came across a few websites that allowed you to scroll thru the content while the site menu chase them while the scroll down and up.
- Floating Headers – Sometimes it make sense to make a table header float. This is true when the table is long and the user needs to scroll way up just to see the name of each column.
- Floating Ads – for those of you who are anxious to make some bucks out of advertisements on their website – don’t let you users run away from your ads – make your ads run after your users. I know its lame, but hey, there are some desperate people out there (and i’m not far from joining that group)
I guess there are more interesting usage for such a plug-in, so if you think of using this plug-in, please drop me a line about how you used it – it will give me something to show the misses.
jQuery Plug-in Conventions
Scope
jQuery uses the $ sign, but to avoid conflict with other libraries it allows the user to change the $ sign. In order to keep your code working even in this cases, you should encapsulate the $ sign in a function like so:
(function($){
//now its safe to use the $ sign
})(jQuery);
Adding a Method
According to the jQuery documentation they way to add a new method is by using the $.fn. The following is an example for adding a simple method to the jQuery object:
$.fn.myFunc = myFunction(a,b,c){return this;}
I’ve checked the jQuery code to see what is $.fn and I found that it’s actually the prototype, as you can see in the following code taken from the jQuery implementation:
jQuery.fn = jQuery.prototype = { …
The returned this refers to the selected jQuery objects. In our case, there is no reason to work on all the selected, so I trim down the selection into only the first selected object. I do this using the jQuery.eq method. It is also recommended to return the selected object at the end of the function since jQuery allows you to call methods in a chain. Here is the implementation for the main method I’ve added:
$.fn.makeFloat = function(params) {
var obj = this.eq(0); //we only operate on the first selected object;
$.floatMgr.initializeFO(obj,params);
if( $.floatMgr.timer == null ) $.floatMgr.adjustFO();
return obj;
};
Floating Div – The Logic
So how this plug-in really works? The user provides the location (x,y) of the floating object. This is saved as the original x,y. (origX,origY). From that moment on I always calculate the updated location (updatedX,updatedY) that the object needs to be according to the vertical and horizontal scrolling that was made.
this.updatedX = $(window).scrollLeft() + this.origX; this.updatedY = $(window).scrollTop()+ this.origY;
After calculating the new location, I check to see what is the difference or delta that the updated location has from the current location (currentX,currentY). If this number is not zero, than we need to move the object one step towards the updated location.
this.dx = Math.abs(this.updatedX - this.currentX ); this.dy = Math.abs(this.updatedY - this.currentY ); return this.dx || this.dy;
As you can see the updateLocation method return true if we need to move the object and false if the delta is zero for both the X and Y.
The method that is in charge of the moving calculates the amount of pixels that the object needs to moved according to the speed parameter that was passed by the user. In order to make the moving smooth, I make sure that on the last step the object will advance only by one pixel at a time.
Floating Div – Animation
The movement/animation of the DOM object on the screen is being done by adjusting the object top and left properties. In this case i used the jQuery.css method:
this.jqObj.css({'left':this.currentX, 'top': this.currentY });
In order to keep on moving the object, I used the setTimeout function whenever the updateLocation methods returns true. This way I make sure that the object will keep on going until it reaches its final location.
Floating Div – Object Oriented
Being a C++ programmer for many years (I wonder if it’s still being used these days) I always try to design my code according to the object oriented methodology. This is what I did here. I created the FloatObject class which is responsible for all the calculation and the movement of a single DOM object. It has only two methods: updateLocation and move.
Here is the complete code for the FloatObject:
function FloatObject(jqObj, params)
{
this.jqObj = jqObj;
switch(params.speed)
{
case 'fast': this.steps = 5; break;
case 'normal': this.steps = 10; break;
case 'slow': this.steps = 20; break;
default: this.steps = 10;
};
var offset = this.jqObj.offset();
this.currentX = offset.left;
this.currentY = offset.top;
this.origX = typeof(params.x) == "string" ? this.currentX : params.x;
this.origY = typeof(params.y) == "string" ? this.currentY : params.y;
//if( params.y) this.origY = params.y;
//now we make sure the object is in absolute positions.
this.jqObj.css({'position':'absolute' , 'top':this.currentY ,'left':this.currentX});
}
FloatObject.prototype.updateLocation = function()
{
this.updatedX = $(window).scrollLeft() + this.origX;
this.updatedY = $(window).scrollTop()+ this.origY;
this.dx = Math.abs(this.updatedX - this.currentX );
this.dy = Math.abs(this.updatedY - this.currentY );
return this.dx || this.dy;
}
FloatObject.prototype.move = function()
{
if( this.jqObj.css("position") != "absolute" ) return;
var cx = 0;
var cy = 0;
if( this.dx > 0 )
{
if( this.dx < this.steps / 2 )
cx = (this.dx >= 1) ? 1 : 0;
else
cx = Math.round(this.dx/this.steps);
if( this.currentX < this.updatedX )
this.currentX += cx;
else
this.currentX -= cx;
}
if( this.dy > 0 )
{
if( this.dy < this.steps / 2 )
cy = (this.dy >= 1) ? 1 : 0;
else
cy = Math.round(this.dy/this.steps);
if( this.currentY < this.updatedY )
this.currentY += cy;
else
this.currentY -= cy;
}
this.jqObj.css({'left':this.currentX, 'top': this.currentY });
}
In order to manage all the movements of all the floating objects I extended the jQuery object by adding a float manager object. Since there is only one manager, there is no point of creating a class for it, so i created an opject and attached it to the jQuery instance.
This object keeps an array of all the floating objects that the user has selected, and to invoke their methods. The manager is also responsible to register to the resize and scroll events in order to instruct the floating objects to recalculate their locations.
Here is the complete code of the manager object:
$.floatMgr = {
FOArray: new Array() ,
timer: null ,
initializeFO: function(jqObj,params)
{
var settings = $.extend({
x: 0 ,
y: 0 ,
speed: 'normal' },params||{});
var newFO = new FloatObject(jqObj,settings);
$.floatMgr.FOArray.push(newFO);
if( !$.floatMgr.timer ) $.floatMgr.adjustFO();
//now making sure we are registered to all required window events
if( !$.floatMgr.registeredEvents )
{
$(window).bind("resize", $.floatMgr.onChange);
$(window).bind("scroll", $.floatMgr.onChange);
$.floatMgr.registeredEvents = true;
}
} ,
adjustFO: function()
{
$.floatMgr.timer = null;
var moveFO = false;
for( var i = 0 ; i < $.floatMgr.FOArray.length ; i++ )
{
FO = $.floatMgr.FOArray[i];
if( FO.updateLocation() ) moveFO = true;
}
if( moveFO )
{
for( var i = 0 ; i < $.floatMgr.FOArray.length ; i++ )
{
FO = $.floatMgr.FOArray[i];
FO.move();
}
if( !$.floatMgr.timer ) $.floatMgr.timer = setTimeout($.floatMgr.adjustFO,50);
}
} ,
onChange: function()
{
if( !$.floatMgr.timer ) $.floatMgr.adjustFO();
}
};
Documentation
Now I will explain how to use the plug-in within a project. The plug-in has only one method:
$.makeFloat(params);
The method only works on the first matched element within the jQuery object.
Params
This is an object that direct the method where to place the floating object and how fast it should move.
x: could be either numerical for the actual location on the X axis or the string ‘current’ to indicate the floating manager to use the current location as the base location.
y: the same is x.
Speed: ’slow’, ‘normal’ ,’fast’.
All the parameters are optional, and default params are set in case any parameter is being left out.
Usage
All you need to do is to select the object you want and specify the location and speed, and the rest is being done automatically – that’s it.
$(document).ready(main);
function main()
{
$("#video").makeFloat({x:"current",y:"current"});
}
You can see a demo of this plug-in in this demo page.
Download the recent version of the plug-in.
You can also check out the plug-in in jQuery plug-in section








