Developing an ASP.NET ColorPicker Server Control using jQuery
As the title implies, today’s post is dedicated to developing a custom ASP.NET server control that lets the user pick up a given color from a predefined color set. Please note that I’m not going to mimic Adobe Photoshop’s color picker, since it’s what jPicker and colorPicker do.
I just wanted a simple, well-written server control that uses the amazing jQuery framework to get the job done. The above mentioned color picker plug-ins don’t (usually) fit the real-world application needs, since people do not want to interact with those complexities just to pick up a color of a message or a label. So I decided to roll-up my sleeves and write my own from scratch.
This paper is not meant, however, to be an all-in-one tutorial for developing ASP.NET Server Controls. With this information in hand, let’s give it a live try. If you like it read on.
Step 1. Planning
Well, we need to create a jQuery plug-in that handles most of the hard work on client’s machine. A popup window displaying the color palette has to be opened up upon a button click, and dismissed upon either a color selection or by a press of ESC key on the keyboard.
The color set has to be customizable on demand and from the server code so that one can modify it to match the project needs without altering the client-side script. The end-user should notice the currently selected color in the palette and the currently hovered color has to have a title attribute attached indicating its RGB value.
There are also some events that we are interested in them, including onHide, onShow and onSelectedColorChanged. Finally, the selected color has to be kept in a hidden html element for future postbacks to the server.
Step2. The HTML
I always want to keep HTMLs as easy as possible. Here’s no exception. It contains the minimum necessary elements I really wanted. Here’s the bare-bone structure of the HTML we will use:
<div class="colorPicker"> <div></div> <input type="hidden" value="#000000" /> <table border="0" cellpadding="1" cellspacing="1"> <tbody> <tr> <td style="background-color: white;"></td> <td style="background-color: black;"></td> <td style="background-color: #333333;"></td> <td style="background-color: #666666;"></td> <td style="background-color: #999999;"></td> <td style="background-color: #cccccc;"></td> <td style="background-color: #cccc99;"></td> <td style="background-color: #9999cc;"></td> <td style="background-color: #666699;"></td> </tr> </tbody> </table> </div>
As you see, each cell doesn’t contain a “title” attribute since this will make the HTML complicated and requires more band-width from the server’s point of view. On the other hand, the color info of each cell is already there so we don’t need to duplicate this info. As you’ll see shortly, we will use jQuery to add the title attribute of each cell.
Step 3. The CSS
The style sheet is simple, so I will leave it to you to understand the subtle nuances of how it works.
.colorPicker { background: transparent url("colorPicker.png"); position: relative; width: 16px; height: 16px; cursor: pointer; display: inline-block; } .colorPicker div { background: transparent url("colorPicker.png") repeat scroll center center; width: 12px; height: 12px; position: relative; left: 2px; top: 2px; } .colorPicker > table { position: absolute; overflow: hidden; left: 2px; border: 1px solid #999; background-color: #fff; display: none; } .colorPicker > table td { cursor: default; width: 16px; height: 16px; border: 1px solid #000; } .colorPicker > table td:hover { cursor: pointer; border: 1px solid #fff; } .colorPicker > table td.selected { border: 1px solid #fff; }
Please note the above ‘colorPicker.png’ image file. It’s the background-image that represents the color picker’s button and is actually borrowed from here. You can modify it to whatever you like.
Step 4. The JavaScript
If you’ve read the Bear Bibeault and Yehuda Katz’s book, the jQuery in Action, you already know that the bare-bone structure of developing a jQuery plug-in is as follow:
(function($) { $.fn.colorPicker = function(settings) { settings = $.extend({}, settings); return this.each(function() { //Whatever the plugin does... }); }; })(jQuery);
This actually returns a jQuery object so that it doesn’t break the object chains. For the performance reasons as well as writing a reusable, comprehensible code, we cache some of those frequently used objects first:
var $colorPicker = $(this); var $control = $colorPicker.find('>div'); var $value = $colorPicker.find('input:hidden'); var bgColor = 'background-color'; var selectedColorClassName = 'selected'; var $table = $colorPicker.find('>table').hide();
The bgColor actually addresses the code minification issues. Since I use that over and over again, it’s better to cache the style name and use the variable instead of repeating the same string over and over again through the entire code. The $table variable represents the popup control and is already hide out. The rest is crystal clear.
Now, we need to set the popup’s width and height based on the above CSS. It’s actually done in this line of code:
$table.css({ 'width': $table.find('tr:first td').length * (18 + 2), 'height': $table.find('tr').length * 18 });
This code uses the total number of rows and columns of the color palette to set the width/height of the popup window. Then we need to find out what color is already selected (if any) using the hidden input element we already talked about and set the button’s background-color using this value. This is what the following portion of code does:
var defaultColor = $value.val(); if (defaultColor) { $control.css(bgColor, defaultColor); }
Now we need to have a mechanism to handle palettes’ popup. The first click on the color picker button has to open up the popup while any color selection dismisses it. This is perfectly done using the toggle method. To understand what I’ve done in the code, please take a precise look to the following code-snippet:
$colorPicker.toggle(function (e) { var $target = $(e.target); if ($target[0].tagName == 'DIV' && $table.is(':hidden')) { //Set the visibility style of the popup control to hidden $table.css('visibility', 'hidden').show(); //Calculate popup position... var top = $control.offset().top; var bottom = $(window).height() - (top + $control.outerHeight() + 4); var topPos = $control.outerHeight() + 4; /*If there's not enough space below the button, display the popup above it*/ if (bottom < $table.outerHeight() && bottom < top) { topPos = -$table.outerHeight(); } //Set the visibility style to visible $table.css({ 'top': topPos, 'visibility': 'visible' }); //Fire the onShow event (if any) onShow(); //Make sure that the ESC key will close the popup $(document).bind('keydown.cp', function (e) { if ((e.which && e.which == 27) || (e.keyCode && e.keyCode == 27)) { $(document).click(); } }); } }, function (e) { var $target = $(e.target); if ($target[0].tagName == 'TD') { //Make sure the selected table cell has the selected class applied. $(this).find('table tr td.' + selectedColorClassName).removeClass(selectedColorClassName); $target.addClass(selectedColorClassName); //Set the hidden input value's to currently selected color var color = rgbToHex($target.css(bgColor)); $value.val(color); //Fire the onSelectedColorChanged event (if any) onSelectedColorChanged(color); } else { //Rollback to the previously selected color $control.css(bgColor, $value.val()); } //Close the popup window $table.hide(); //Cancel the ESC key listener $(document).unbind('keydown.cp'); //Fire the onHide event (if any) onHide(); });
Please note that the toggle method is called on $(this). In other words, instead of toggling into each cell of the palette that sucks from the performance point of view, I attached the toggle event to the parent element and checked what element is actually clicked (using the e.target). The rest is pretty straight forward and needs no description.
There are still two things that have to be done. First, we need to set the title attribute of each cell to the desired value. This is what the following code does:
.find('table tr td').each(function() { //Set the cell's title var color = $(this).css(bgColor), hex = rgbToHex(color); $(this).attr('title', hex); //Select the default color if (defaultColor == hex) { $(this).addClass(selectedColorClassName); } });
Please note that the css method of the jQuery returns the color in RGB format. However, I needed to display the title in HTML format, say, #FF0000 instead of rgb(255, 0, 0). That’s the conversion that rgbToHex function does. The next portion of the code makes sure that the default selected color is already selected and have the selected class selector applied.
The second thing we need to do is to modify the button’s background color based on currently hovered item. This is what the following code-snippet does:
.parent().mouseover(function(e) { var $target = $(e.target); if ($target[0].tagName == 'TD') { //Make sure the button's background color is the same as the hovered item in the palette $control.css(bgColor, $target.css(bgColor)); } });
Finally, we need some utility function we’ve used lately, say, rgbToHex, onShow, onHide and onSelectedColorChanged. Let’s take a look at three latter functions:
function onShow() { if ($.isFunction(settings.onShow)) { settings.onShow.call(); } }; function onHide() { if ($.isFunction(settings.onHide)) { settings.onHide.call(); } }; function onSelectedColorChanged(color) { if ($.isFunction(settings.onSelectedColorChanged)) { settings.onSelectedColorChanged.call(this, color); } };
You see, they are pretty straight forward where each of which makes sure that the name is actually a function and uses the call method to call the corresponding method. You know event handling is possible in many ways, one of which is to use the trigger method to address the issue. However, I preferred to use the settings parameter of the plug-in to handle the events.
Finally, the rgbToHex method comes into play:
function rgbToHex(color) { var m = /rgba?((d+),s*(d+),s*(d+)/.exec(color); return m ? '#' + toHex(m[1]) + toHex(m[2]) + toHex(m[3]) : color; }; function toHex(color) { if (color == null) { return '00'; } color = parseInt(color); if (color == 0 || isNaN(color)) { return '00'; } color = Math.min(Math.max(0, color), 255); var hexVals = '0123456789ABCDEF'; return hexVals.charAt((color - color % 16) / 16) + hexVals.charAt(color % 16); };
It uses a regular expression to make the conversion as well as a utility function to ease the conversion.
Step 5 – How to use this plug-in
It’s the easy part. All you have to do is add the jQuery library to the head section of the page as well as the colorPicker.js and colorPicker.css. Here’s a sample:
$(function() { $('div.colorPicker').colorPicker({ 'onShow': function() { alert('colorPicker is shown...'); }, 'onHide': function() { alert('colorPicker is gone...'); }, 'onSelectedColorChanged': function(color) { alert('Selected color: ' + color); } }); });
You can also ignore the settings if you don’t plan to use them. i.e., you can call the colorPicker this way:
$('div.colorPicker').colorPicker();
You can use the colorPicker plug-in under PHP, Java, ASP.NET, or whatever HTML Server technology that you are interested in. The rest of the article, however, is dedicated to creating an ASP.NET server control based on this plug-in.
Step 6 – Developing the ASP.NET server control
To start, open up Visual Studio 2010; from the File menu select New > Project. In the Project types pane select Visual C# and the Web item. In the right pane, select ASP.NET Server Control. Enter the UIControls in the Name edit box and make sure the “create directory for solution” item is checked. Press OK to have the code base created. Please note that the sample is based on .NET Framework 3.5, however, you can change the target framework if desired.
Now, remove the “ServerControl1.cs” file from the Solution Explorer. Right-Click on the project name, say, UIControls, and from the context menu, select Add > Class. Enter ColorPicker as the new class name and press the Add button.
Then create three folders named Images, JScripts, and Styles. The Images directory is where the color picker’s background-image is placed while the JScripts is used to host the jQuery.colorPicker.js file that we’ve already developed using jQuery. Finally the Styles folder is used to host the colorPicker.css file. So the Solution Explorer looks like this:
Having these files in place we can now focus on the actual problem: developing the server control. The ColorPicker class is derived from the System.Web.UI.Control. Despite of many web controls out there it’s not derived from the System.Web.UI.WebControls.WebControl class since I didn’t need those properties and/or methods on the WebControl class.
On the other hand, it implements the IPostBackDataHandler interface since it needs to automatically load postback data that’s the color being selected. This interface contains two methods, LoadPostData and RaisePostDataChangedEvent. The LoadPostData is where we need to examine the posted data by the control and is implemented as follows:
public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection) { bool raisePostDataChangedEvent = false; Color postedColor = ColorTranslator.FromHtml(postCollection[this.selectedColorUniqueId]); if (postedColor != SelectedColor) { SelectedColor = postedColor; raisePostDataChangedEvent = true; } return raisePostDataChangedEvent; }
You see, there is nothing special in this implementation. It just examines the postCollection to get the selected color and makes sure the color is actually changed. If so, it saves the new SelectedColor in the ViewState and returns true to signal the controller has to call the RaisePostDataChangedEvent method respectively:
public void RaisePostDataChangedEvent() { OnSelectedColorChanged(EventArgs.Empty); }
This method in turn simply invokes a protected virtual member of the class that raises the SelectedColorChanged event.
The next important member of the class is Render that has to be overridden to provide the actual rendering facility of the control. Let’s have a look to this method:
protected override void Render(HtmlTextWriter writer) { writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID); writer.AddAttribute(HtmlTextWriterAttribute.Name, UniqueID); writer.AddAttribute(HtmlTextWriterAttribute.Class, "colorPicker" + (!string.IsNullOrEmpty(this.cssClass) ? " " + this.cssClass : string.Empty)); writer.RenderBeginTag(HtmlTextWriterTag.Div); //Color selection button... writer.RenderBeginTag(HtmlTextWriterTag.Div); writer.RenderEndTag(); //Hidden field used to store the color selection... writer.AddAttribute(HtmlTextWriterAttribute.Type, "hidden"); writer.AddAttribute(HtmlTextWriterAttribute.Id, this.selectedColorClientId); writer.AddAttribute(HtmlTextWriterAttribute.Name, this.selectedColorUniqueId); writer.AddAttribute(HtmlTextWriterAttribute.Value, ColorTranslator.ToHtml(SelectedColor)); writer.RenderBeginTag(HtmlTextWriterTag.Input); writer.RenderEndTag(); //Render color table... Table table = new Table(); table.CellSpacing = 1; table.CellPadding = 1; List<color> colors = Colors; for (int i = 0; i < TotalRowColors; i++) { TableRow row = new TableRow(); table.Rows.Add(row); for (int j = 0; j < TotalColColors; j++) { TableCell cell = new TableCell(); cell.BackColor = colors[(i * TotalColColors) + j]; row.Cells.Add(cell); } } table.RenderControl(writer); writer.RenderEndTag(); base.Render(writer); } </color>
The most important part of this implementation is assigning the control a unique ID and a name. This way, we can retrieve the selected value from the postCollection formal parameter of the LoadPostData method. The remaining is simple, the Render method just renders a table as desired.
Next, open up the AssemblyInfo.cs file under Properties and add these lines there:
[assembly: System.Web.UI.WebResource("UIControls.JScripts.jquery.colorPicker.js", "text/js")] [assembly: System.Web.UI.WebResource("UIControls.Images.colorPicker.png", "img/png")] [assembly: System.Web.UI.WebResource("UIControls.Styles.colorPicker.css", "text/css", PerformSubstitution = true)]
This indicates that there are 3 web resources associated with the control so they’ll be addressed correctly using the WebResource.axd (For more information on Web Resources, please refer to MSDN). Please however note that the colorPicker.css is decoreated with the PerformSubstitutio flag which indicates the file has to be modified before being severed to the client. Open up the colorPicker.css file and make sure the first two styles look like this:
.colorPicker { background: transparent url(<%=WebResource("UIControls.Images.colorPicker.png")%>); position: relative; width: 16px; height: 16px; cursor: pointer; display: inline-block; } .colorPicker div { background: transparent url(<%=WebResource("UIControls.Images.colorPicker.png")%>) repeat scroll center center; width: 12px; height: 12px; position: relative; left: 2px; top: 2px; }
Finally, right click on colorPicker.css and change the “Build Action” to Embedded Resource. You need to do the same for jquery.colorPicker.js and colorPicker.png files.
Step 7 – Enough said, how am I supposed to start using this ASP.NET control?
Well, to start using the ColorPicker control you need to include the jQuery library in the header section of the page. Then add the reference of the UIControls to your project. Place the control on the page(which registers the control using the Register directive), subscribe to the “SelectedColorChanged” event (if necessary) and make sure your desired color is selected by default if it suits your needs.
Finally, you need to initialize the ColorPicker control in the ready handler of the jQuery. That’s all it takes to use the control.
Wrapping up
In this article you have seen how to develop a simple jQuery plugin. I’ve also shown you how to develop an ASP.NET Server Control that wraps the jQuery plugin.
For your convenience, I’ve zipped up all the necessary files (including the Server-Side control as well as the test application) into a single package which can be downloaded here.
You can also download the colorPicker plugin (including html, css and the plugin itself) if you are not interested in the ASP.NET Server Control.
That’s all for now, folks!
2 Responses to Developing an ASP.NET ColorPicker Server Control using jQuery
Leave a Reply Cancel reply
Sponsors
Circle up with me on Google+
Hi,
Thank you for your good site,it’s very helpful:Rose:
Good Luck!
hello, i see your profile in barnamenevis.org, I understand that you programming in different fields and hope you help to other users for Develop their own ideas.