colorBar

jscolorXS

This colorPicker is a re-thinking and re-codeing of the original http://jscolor.com (if you google 'javascript color picker', this one is always #1 (in June, July, August 2010)).
This should be a tutorial that shows, how code can get very compact, small and more efficient if you merge several thechniques.
Based on the brilliant jscolor.com I had some ideas of how to optimize it in many ways.

Table of contents:

Bookmark and Share

Main ideas:

^ back to top

Comparing the two pickers:

The original jscolor.com uses the following 5 files (in sum: 28.5kB):

The jscolorXS uses only one file:

So, all the images, the HTML and the CSS are packed into one javaScript file.
This makes the transfer to the end-user's browser way faster.
The compressed version (YUI-compression + packer) is only 7.08kB.

This version of jscolorXS is not finished and therefore doesn't have all the features of jscolor.com. This should only be a tutorial (without many words though,... just for comparing the source-codes) and show the main funcionality of the original idea.
CSS would have to be re-written (just a little) to make it work in quirks-mode as well.

Even though this version doesn't have all the features of the original one, there is still a 15.9kB (~56%) head room to give it even some more features... (the first, I think, would be: make it WYSIWYG by adding an other layer to both sliders ... see http://dematte.at/colorPicker)

You need the files hsb.png, twb.png, cross.gif, arrow.gif and blank.gif to get a fall-back system for IE 5.5 and IE 6. These browsers don't support half-transparent PNGs and no BASE64 decoding in CSS.

^ back to top

Demo:

^ back to top

Download:

Here is a more advanced (and optimized) version (14.0kB) (packed version: 8.04kB) that supports some attributes of the original jscolor at jscolor.com:

This version also works in quirks-mode now.
Still doesn't work for IE5.5, IE6 and I guess not even in IE7, but has preperations for that as commented code (CSS has to be re-written as well...).

{pickerBorder:3,pickerInset:10}
{pickerFace:20}
{pickerBorderColor:'red green blue yellow'}
{pickerInsetColor:'#9F9 #090 #090 #9F9'}
{pickerFaceColor:'#01BABE'}
{pickerFaceColor:'transparent',pickerFace:3,pickerBorder:0}
{pickerMode:'HVS',hash:false,caps:false,pickerFace:7,pickerInset:3} {changeFaceColor:true}

If you want to be able to bind additional input fields after pageLoad you'd have to take everything in the for loop in init() and make it a function like bind() and do quite the same in the build() function with the for loop that customizes the CSS and call it from the bind() function as well.

To make it work in IE5.5 and IE6 you'd have to change the div with the class 'layer tw' (in the left slider, that holds the semi-transparent PNG) via javaScript into an image, make 'blank.gif' the source and put the pre-prepared 'twf' or 'tbf' in the build() function as a filter on it.
Add an image on top of the right slider-div (calss="right tb") and do the same.
You might even rewrite the HTML in the code to be able to change without adding and changeing...

^ back to top

Future plans to this tutorial:

I'm planning to rewrite this tutorial for more information about BASE64 encoding and so on... in the future (as soon as I get some time left to do so and/or I get response if there is some interest at all).
I hope for now it's still a good help.

So, see you soon.

^ back to top

Some more tips for now:

Some example of rethinking just the most normal things:

document.getElementById('someID').style.backgroundColor = '#CC0000';
document.getElementById('someID').style.backgroundImage = 'url(images/pix.jpg)';
document.getElementById('someID').style.backgroundPosition = 'top right';
document.getElementById('someID').style.backgroundRepeat = 'no-repeat';
document.getElementById('someID').style.paddingLeft = '2px';
document.getElementById('someID').style.paddingTop = '12px';
document.getElementById('someID').style.paddingBottom = '2px';
document.getElementById('someID').style.paddingRight = '2px';
document.getElementById('someID').style.marginLeft = '3px';
document.getElementById('someID').style.marginTop = '12px';
document.getElementById('someID').style.marginBottom = '12px';
document.getElementById('someID').style.marginRight = '3px';

document.getElementById('otherID').style.fontStyle = 'normal';
document.getElementById('otherID').style.fontVariant = 'small-caps';
document.getElementById('otherID').style.fontWeight = 'bold';
document.getElementById('otherID').style.fontSize = '75%';
document.getElementById('otherID').style.lineHeight = '85%';
document.getElementById('otherID').style.fontFamily = 'Georgia, "Times New Roman", Times, serif';

...can also be as short as:

var someIDStyle = document.getElementById('someID').style;
someIDStyle.background = '#C00 url(images/pix.jpg) no-repeat top right';
someIDStyle.padding = '12px 2px 2px';
someIDStyle.margin = '12px 3px';

document.getElementById('otherID').style.font = 'normal small-caps bold 75%/85% Georgia,"Times New Roman",Times,serif';

Here you see some usage of short hand declarations of styles and the usage of a pointer to the style of an object that makes code just shorter and more effective.

You could even put those styles into your CSS (.someStyles{...}) and go like:

document.getElementById('someID').className = 'someStyles';
document.getElementById('otherID').className = 'someOtherStyles';

...if that suits your code ;o)

^ back to top

Another code example (javaScript):

You all probably know the javaScript framework 'prototype' and it function $.
I'll show you with an old version of it how code can be way faster, shorter and takes less memory (the new version 1.7 is even worse...). So here the original code from around 2005:

function $() {
  var elements = new Array();
  for (var i = 0; i < arguments.length; i++) {
    var element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);
    if (arguments.length == 1)
      return element;
    elements.push(element);
  }
  return elements;
}

So here we got quite a fiew problems (almost as many as lines ;o):

So, thinking of all this would lead to a function like this:

function $() {
  for (var i = arguments.length; i--;)
    if (typeof arguments[i] == 'string')
      arguments[i] = document.getElementById(arguments[i]);
  return arguments[1] ? arguments : arguments[0];
}

This function does exactly the same. It just has less function calls, less variables, less assignments and smarter routines, and therefore way faster, not to mention that it's minified 246:172 Bytes which is a big benefit if you write long code.

An even shorter but slower variant would be this:

function $() {
  for (var a = arguments, i = a.length; i--;)
    a[i] = document.getElementById(a[i].id || a[i]);
  return a[1] ? a : a[0];
}

112 Bytes... just to think of it. It though causes an error if you send an object that doesn't exist...

One last one for today, a very popular toggle script I found:

function toggle(obj) {
  var el = document.getElementById(obj);
  if ( el.style.display != 'none' ) {
    el.style.display = 'none';
  } else {
    el.style.display = '';
  }
}

It seems to be so simple and logic,... nothing possible to make wrong. Even the assignment of the el seems to be smart and correct,... but..

function toggle(obj) {
  var elS = document.getElementById(obj).style;
  elS.display = elS.display == 'none' ? '' : 'none';
}

...this is just a little faster because asking for .style cost every time and the original askes 2 times.
Ratio: 138:106Bytes (even if I skip the curly brackets of the first example)

An other very interesting one from Apple Computer, Inc.:

var ie = (document.all) ? true : false;

function setStyleByClass(t,c,p,v){
  var elements;
  if(t == '*') {
    elements = (ie) ? document.all : document.getElementsByTagName('*');
  } else {
    elements = document.getElementsByTagName(t);
  }
  for(var i = 0; i < elements.length; i++){
    var node = elements.item(i);
    for(var j = 0; j < node.attributes.length; j++) {
      if(node.attributes.item(j).nodeName == 'class') {
        if(node.attributes.item(j).nodeValue == c) {
         eval('node.style.' + p + " = '" +v + "'");
        }
      }
    }
  }
}

Here we can skip 2 variables, speed up some 'for' loops and get rid of 'eval':

function setStyleByClass(t,c,p,v){
  var elements = (t == '*') ? document.all || document.getElementsByTagName('*') :
      document.getElementsByTagName(t);
  for(var i = elements.length; i--;){
    for(var j = elements[i].attributes.length; j--;) {
      if(elements[i].attributes[j].nodeName == 'class' &&          elements[i].attributes[j].nodeValue == c) elements[i].style[p] = v;
    }
  }
}

^ back to top
dematte