Monday, September 13, 2010

A sample paint application using jQuery

In today's post, I am going show how one can associate mouse events to an html element using jQuery. JQuery allows us to bind a large number of events to objects fetched by using a jQuery selector.

The following is the list of events that are recognized by jQuery :
blur, focus, focusin, focusout, load, resize, scroll, unload, click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave, change, select, submit, keydown, keypress, keyup, error.

Binding events to jQuery usually means making the selected Dom Object aware of the event and take necessary actions based upon it.

The primary function that jQuery uses to perform these binding is called (surprisingly!) the bind() function.

The syntax of the bind function is simple. For a given selected set of jQuery object, you indicate the function that needs to be called when a particular event takes place on that DOM object.

So, basically, its an eventname - handler function() duo. Occasionally, you may also need to pass additional parameters to the handler function. That is done by passing a map of the parameters in the arguments of the bind function.

Following is the basic syntax of the function.

.bind( eventType, [ eventData ], handler(eventObject) )


However, for most tasks, you would be using the following version of the function

.bind( eventType, handler(eventObject) )

In this post, I am going to create a simple application that acts like a very very primitive version of MS Paint. Here's the basic idea : -

I am going to create a div, that will act as a canvas. Using the mouse, the user should be able to draw curves on the screen as he drags the mouse on the canvas, just like the way we do using pencil and paper. The only difference is that instead of the pen, you use the mouse, and instead of the paper, you have a div(to which I will assign appropriate dimensions) on which to draw.
To make things a bit more interesting, (just a bit more), i will allow the user to choose a color for the paintbrush.

The body of my html page has 2 parts- the canvas, and the color palette.

green
blue
red
black


The div that I am going to use as a canvas has been given an id if "canvas".
The palette contains four div's that act as buttons that can be used to select the color. The content of the 4 div's is nothing but the name of the color the div represents.

So, here's the basic plan to achieve what i want to do : -
  1. Track the movement of the mouse, the moment it is pressed, and stop tracking it the moment it is released. This will be achieved by binding appropriate handlers to the mousedown event, the mousemove event and the mouseup event.
  2. When the mouse is being dragged on the canvas, i need to create a dot at the position of the mouse. In this example, i am going to create a 4 pixel dot. This dot is nothing but an span element having absolute positioning. A new span will be created for every position that my mouse cursor moves over in the area described in my canvas.


Here is the basic CSS that I will be using to achieve the desired layout.

.canvasStyle{
 width:500px;
 height:500px;
 background-color:#cfcfcf;
 float:left;
}

.dots{
 width:4px;
 height:4px;
 position:absolute;
}


.palleteStyle{
 float:left;
 padding:10px;
 position:relative;
 text-align:center;
}

.colorChooser{
 border:solid 1px #000000;
 -moz-border-radius: 8px;
 -webkit-border-radius: 8px;
 border-radius: 8px;
 margin:5px;
 padding-bottom:8px;
 width:100px;
 height:12px;
}


The css is pretty simple. I have a class 'canvasStyle' to define the layout of my canvas. Then I have a class 'dots' to define the layout of my dots. Then a class 'palleteStyle' to define the layout of my color palette. And then a class 'colorChooser'.

Now lets talk about the javascript. All my code is in the jQuery onload function. Since this is the only functionality of my sample web page, I have taken the liberty to use global variables within this function. You may have to use a more structured approach if you want such functionality to coexist with your existing code. (making a widget would be a good idea, but we shall see about that later)

The only global variable that i am going to use here is the color of the brush. Initially, I set it to black. Here is the code for it.


$(function(){
 var bkcolor="black"; 
});

Now, the first thing i need to do is to bind the mousedown and mouseup event of the canvas to a particular function in which i will do my additional tasks.

Fortunately, the code for binding mouse events in jQuery is simpler than you can even imagine.

$("#canvas").bind('mousedown',function(event){
 
});


$("#canvas").bind('mouseup',function(){
 
});

The next thing that i need to do is to enable the user to click on any of the four div's on my color palette and be able to set the color variable based upon his selection. Since the color is the same as the inner html of the div's the code to set the color of the brush is pretty trivial. (dont look at me like that, i did this to make my life a bit easier!)

$(".palleteStyle").click(function(event){
 $target=$(event.target);
 bkcolor=$target.html();
});

In the above code, as you can see, instead of binding a separate function to each of my coloring div's, i chose to bind the click event handler to the parent container, i.e. my color palette. Inside the event handler, I determine the target of the click by using the 'target' property of the event object that jQuery allows me to pass to my event handling function. Once I get hold of my target, all I need to do is to set the value of the global variable to the html of the selected div.

Well, now there are only 2 important things remaining. Binding and unbinding the mousemove event on mouseup and mousedown. The other thing is to add a span to my canvas at the position of the mouse cursor.

First things first. Lets see the code for binding and unbinding the mousemove events.

$("#canvas").bind('mousedown',function(event){
 $(this).bind('mousemove',function(event){
         //some code goes here
 });
});


$("#canvas").bind('mouseup',function(){
 $(this).unbind('mousemove');
});


Well, quite simple eh? Ok then, lets move on to the next task of adding a span.

For adding a span, we first need to identify the position of the mouse cursor. This task will be handled in the mousemove handler function. As you can see above, the handler function takes and event variable as an argument. This variable can be used to identify the x and y coordinates of the mouse as and when it moves.
the X and y coordinates of the mouse can be retrieved from the pageX and pageY attributes of the event object. After that, all we need to do is to add the span to the dom inside the canvas. We achieve that by using the append() function. That said, the following code should be easily understandable.

$("#canvas").bind('mousedown',function(event){
 $(this).bind('mousemove',function(event){
  var dot ="";
  $(this).append(dot);
 });
});

The above code simply creates a span and sets the left and right css attributes to the pageX and pageY. And of course I set the background color to the bkcolor global variable.


Now, just to add a little more spice, ill change the visual appearance of the color selection div's based upon the color the represent. Here's the code for it.

$(".colorChooser").each(function(){
 $this = $(this);
 var bkcolor=$this.html();
 $this.css({"background-color":bkcolor,"color":"white","opacity":"0.8"});
});

Ya, I know, I unnecessarily made it fancy, but believe, you got my point.

Time to see the entire javascript for this example in one huge chunk. So, here goes nothing : -

$(function(){
 var bkcolor="black";
 $("#canvas").bind('mousedown',function(event){
  $(this).bind('mousemove',function(event){
   var dot ="";
   $(this).append(dot);
  });
 });
    
 
 $("#canvas").bind('mouseup',function(){
  $(this).unbind('mousemove');
 });
 
 $(".colorChooser").each(function(){
  $this = $(this);
  var bkcolor=$this.html();
  $this.css({"background-color":bkcolor,"color":"white","opacity":"0.8"});
 });
 
 $(".palleteStyle").click(function(event){
  $target=$(event.target);
  bkcolor=$target.html();
 });
});

Thats pretty much it takes to make something as simple as a bare bones paint application.
Here is the screenshot of how it looks in Chrome on my pc.



Forgive me, my calligraphy with the mouse ain't so good. But its kinda fun, especially if it can be done in a browser! And of course, jQuery makes it unbelievably easy :)

Cheers!
Happy Programming :)
Signing Off
Ryan