ColorPicker = new Class({
initialize: function(objParent, InitialColor){
//Check to see if the browser supports the canvas element.
testcanvas = document.createElement("canvas");
if(testcanvas.getContext){
this.supportsCanvas = true;
delete testelement;
}else{
this.supportsCanvas = false;
delete testelement;
}
//if this is a color us it if not try to make a color out of it.
if(InitialColor.isColor)
this.CurColor = InitialColor;
else
this.CurColor = new Color(InitialColor);
//If the object was passed as a string get and Element with that ID otherwise use the element.
if(typeof objParent == 'string')
this.Parent = $(objParent);
else
this.Parent = objParent;
//These are member variables to hold function pointers to be called with the
//buttons in the color dialog.
this.OKCallback = null;
this.CancelCallback = null;
//Create the main container for our color picker.
this.Container = new Element("div");
this.Container.setStyle("border", "solid 1px #000000");
this.Container.setStyle("background-color", "#aaa");
this.Container.setStyle("width", "460px");
this.Container.setStyle("padding", "5px");
this.Parent.appendChild(this.Container);
//If the browser supports the canvas element create one instead of a container
//for child divs
if(this.supportsCanvas){
//create the canvas Saturation Value Box.
this.HueBar = new Element("canvas");
this.HueBar.setStyle("cssFloat", "left");
this.HueBar.setStyle("styleFloat", "left");
this.HueBar.setStyle("margin-right", "5px");
this.HueBar.width=30;
this.HueBar.height=360;
//Attach the event for clicks to the canvas element
this.HueBar.addEvent("click", this.setCurrentHue.bind(this));
this.Container.appendChild(this.HueBar);
}else{
//create the container for the hue bar.
this.HueBar = new Element("div");
this.HueBar.setStyle("width", "30px");
this.HueBar.setStyle("cssFloat", "left");
this.HueBar.setStyle("styleFloat", "left");
this.HueBar.setStyle("margin-right", "5px");
this.Container.appendChild(this.HueBar);
}
//If the browser supports the canvas element create one instead of a container
//for child divs
if(this.supportsCanvas){
//create the canvas Saturation Value Box.
this.SVBox = new Element("canvas");
this.SVBox.setStyle("cssFloat", "left");
this.SVBox.setStyle("styleFloat", "left");
this.SVBox.width=350;
this.SVBox.height=360;
//Attach the event for clicks and mouse move to the canvas element
this.SVBox.addEvent("click", this.setSelectedColor.bind(this));
this.SVBox.addEvent("mousemove", this.setPreviewColor.bind(this));
this.Container.appendChild(this.SVBox);
}else{
//create the container for the Saturation Value Box.
this.SVBox = new Element("div");
this.SVBox.setStyle("cssFloat", "left");
this.SVBox.setStyle("styleFloat", "left");
this.Container.appendChild(this.SVBox);
}
//create the container for the Color Swatches and Text Boxes.
this.ColorInfo = new Element("div");
this.ColorInfo.setStyle("cssFloat", "left");
this.ColorInfo.setStyle("styleFloat", "left");
this.ColorInfo.setStyle("text-align", "center");
this.ColorInfo.setStyle("margin-left", "3px");
this.Container.appendChild(this.ColorInfo);
//Add an empty div to the end to clear the floats.
this.ClearBreak = new Element("div");
this.ClearBreak.setStyle("clear", "both");
this.Container.appendChild(this.ClearBreak);
//create the color swatches.
this.SelectedColorLable = new Element("text");
this.SelectedColorLable.textContent = "Color:";
this.SelectedColor = new Element("div");
this.SelectedColor.setStyle("width", "50px");
this.SelectedColor.setStyle("height", "50px");
this.SelectedColor.setStyle("margin-left", "auto");
this.SelectedColor.setStyle("margin-right", "auto");
this.ColorInfo.appendChild(this.SelectedColorLable);
this.ColorInfo.appendChild(this.SelectedColor);
this.PreviewColorLable = new Element("text");
this.PreviewColorLable.textContent = "Preview:";
this.PreviewColor = new Element("div");
this.PreviewColor.setStyle("width", "50px");
this.PreviewColor.setStyle("height", "50px");
this.PreviewColor.setStyle("margin-left", "auto");
this.PreviewColor.setStyle("margin-right", "auto");
this.ColorInfo.appendChild(this.PreviewColorLable);
this.ColorInfo.appendChild(this.PreviewColor);
//Create the container for the hsv and rgb text boxes
this.ColorInputsContainer = new Element("div");
this.ColorInputsContainer.setStyle("width", "100%");
this.ColorInputsContainer.setStyle("text-align", "left");
this.ColorInputsContainer.setStyle("font-family", "Arial, Helvetica, sans-serif");
this.ColorInputsContainer.setStyle("margin-left", "5px");
this.ColorInfo.appendChild(this.ColorInputsContainer);
//Create the hsv and rgb text fields.
this.hLabel = new Element("text");
this.hLabel.textContent = "H:";
this.hInput = new Element("input");
this.hInput.size = "3";
this.hInput.name = "h";
this.hInput.type = "text";
this.hInput.addEvent('keyup', this.setHSL.bind(this));
this.ColorInputsContainer.appendChild(new Element("br"));
this.ColorInputsContainer.appendChild(this.hLabel);
this.ColorInputsContainer.appendChild(this.hInput);
this.ColorInputsContainer.appendChild(new Element("br"));
this.sLabel = new Element("text");
this.sLabel.textContent = "S:";
this.sInput = new Element("input");
this.sInput.size = "3";
this.sInput.name = "s";
this.sInput.type = "text";
this.sInput.addEvent('keyup', this.setHSL.bind(this));
this.ColorInputsContainer.appendChild(this.sLabel);
this.ColorInputsContainer.appendChild(this.sInput);
this.ColorInputsContainer.appendChild(new Element("br"));
this.vLabel = new Element("text");
this.vLabel.textContent = "V:";
this.vInput = new Element("input");
this.vInput.size = "3";
this.vInput.name = "v";
this.vInput.type = "text";
this.vInput.addEvent('keyup', this.setHSL.bind(this));
this.ColorInputsContainer.appendChild(this.vLabel);
this.ColorInputsContainer.appendChild(this.vInput);
this.ColorInputsContainer.appendChild(new Element("br"));
this.rLabel = new Element("text");
this.rLabel.textContent = "R:";
this.rInput = new Element("input");
this.rInput.size = "3";
this.rInput.name = "r";
this.rInput.type = "text";
this.rInput.addEvent('keyup', this.setRGB.bind(this));
this.ColorInputsContainer.appendChild(new Element("br"));
this.ColorInputsContainer.appendChild(this.rLabel);
this.ColorInputsContainer.appendChild(this.rInput);
this.ColorInputsContainer.appendChild(new Element("br"));
this.gLabel = new Element("text");
this.gLabel.textContent = "G:";
this.gInput = new Element("input");
this.gInput.size = "3";
this.gInput.name = "g";
this.gInput.type = "text";
this.gInput.addEvent('keyup', this.setRGB.bind(this));
this.ColorInputsContainer.appendChild(this.gLabel);
this.ColorInputsContainer.appendChild(this.gInput);
this.ColorInputsContainer.appendChild(new Element("br"));
this.bLabel = new Element("text");
this.bLabel.textContent = "B:";
this.bInput = new Element("input");
this.bInput.size = "3";
this.bInput.name = "b";
this.bInput.type = "text";
this.bInput.addEvent('keyup', this.setRGB.bind(this));
this.ColorInputsContainer.appendChild(this.bLabel);
this.ColorInputsContainer.appendChild(this.bInput);
this.ColorInputsContainer.appendChild(new Element("br"));
//create the ok button and set its onclick callback
this.okInput = new Element("input");
this.okInput.name = "OK";
this.okInput.value = "OK";
this.okInput.type = "button";
this.okInput.addEvent('click', this.handleOK.bind(this));
this.ColorInputsContainer.appendChild(this.okInput);
this.ColorInputsContainer.appendChild(new Element("br"));
//create the ok button and set its onclick callback
this.cancelInput = new Element("input");
this.cancelInput.name = "Cancel";
this.cancelInput.value = "Cancel";
this.cancelInput.type = "button";
this.cancelInput.addEvent('click', this.handleCancel.bind(this));
this.ColorInputsContainer.appendChild(this.cancelInput);
this.ColorInputsContainer.appendChild(new Element("br"));
//Draw the Hue Bar
this.drawHueBar();
//Draw the SVBox
this.drawSVBox();
},
//Iterates through all 360 hues and creates a 1px by 30px div for each hue.
drawHueBar: function (){
if(this.supportsCanvas){
//get the multiplyer for the hue range based on the height of the hue bar.
hSteps = 360 / this.HueBar.height;
hColor = new Color([0,100,100], 'hsb');
//Get a 2d context to the hue bar canvas element.
myCTX = this.HueBar.getContext('2d');
strhHex = "";
//Iterate over the hight of the hue bar filling 1px tall areas
//with the proper hue.
for(hi = this.HueBar.height; hi > 0; hi--){
//Get the color for the hew at this iteration.
hColor.changeHue(hi*hSteps);
//Get the hex string of the color.
strhHex = hColor.rgbToHex();
//Set the context's fillStyle to the color.
myCTX.fillStyle = strhHex;
//fill from the left of the hue bar, to the width of the hue bar
//with the offset hi pixels from the bottom with a height of 1px.
myCTX.fillRect(0, this.HueBar.height-hi, this.HueBar.width, 1);
}
}else{
//Create a new color with hue at 0 and S and V at 100%
hsvColor = new Color([0,100,100], 'hsb');
//Create the one Hue element and set it's styles.
fcoDiv = new Element("div");
fcoDiv.setStyle("width","30px");
fcoDiv.setStyle("height","1px");
//Loop through the hues
for(ci = 0; ci < 360; ci++){
//User the changeHue to change the existing color object's hue.
hsvColor.changeHue(ci);
//Clone the Hue element and inject it inside the Hue Bar.
coDiv = fcoDiv.clone().injectInside(this.HueBar);
//Set the huse of the new Hue Element
coDiv.setStyle("background-color", hsvColor);
//Set the onClick callback function for the new Hue element.
coDiv.addEvent('click', this.setCurrentHue.bind(this));
}
}
},
//Draw a SV box that is as tall as the HUE Bar.
drawSVBox: function(objsvDiv){
if(this.supportsCanvas){
//Get the rgb multiplyer for the number of steps over the height of the SVBox
vSteps = 255 / this.SVBox.height;
//Get the value multiplyer for the number of steps over the height of the SVBox
svSteps = 100 / this.SVBox.height;
//Create a new color for calculating each rows color ranges.
svColor = new Color([this.CurColor.hsb[0], 100, 100], "hsb");
//Get a 2d context to the SVBox canvas element.
myCTX = this.SVBox.getContext('2d');
strsvHex = "";
//Iterate over the hieght of the SVBox.
for(vi = this.SVBox.height; vi > 0; vi--){
//Set the brightness for this row
svColor.changeBrightness(vi*svSteps);
//Get the hex string for the current brightness.
strsvHex = svColor.rgbToHex();
//Create a new linear Gradient from the canvas context that goes
//from the left to the right.
myLinearGrad = myCTX.createLinearGradient(0, 0, this.SVBox.width, 0);
//Add a color stop to the gradient that is the current
//bright ness no need to to the HSV conversion here
myLinearGrad.addColorStop(0, "rgb("+vi+","+vi+","+vi+")");
//Add a color stop that is based on the current Hue
myLinearGrad.addColorStop(1, strsvHex);
//Set the canvas context's fill style to our current gradient.
myCTX.fillStyle = myLinearGrad;
//Fill the row at 1px high.
myCTX.fillRect(0, this.SVBox.height-vi, this.SVBox.height, 1);
}
}else{
//Specify the size of the SV Box svSize is used for both width and height.
svSize = 35;
//Set the size of the "pixels" for the SVBox.
pixelSize = 10;
//Get the multiple required to go from 0 to 100 is svSize steps.
svStep = 100/svSize;
//Create the color we will use to set the color of the SV Pixels
svColor = new Color([this.CurColor[0],this.CurColor[1],this.CurColor[2]]);
//Create a div that will hold 1 row of pixels.
// this is done to prevent to reduce the number of
// appends into the document.
rcDiv = new Element("div");
rcDiv.style.clear = "left";
rcDiv.style.width = (svSize*pixelSize)+"px";
rcDiv.style.height = pixelSize+"px";
//Create the one pixel that we will clone for each pixel.
fcoDiv = new Element("div");
fcoDiv.setStyle("width", pixelSize + "px");
fcoDiv.setStyle("height", pixelSize + "px");
fcoDiv.setStyle("cssFloat", "left");
fcoDiv.setStyle("styleFloat", "left");
//Iterate over each step in the row injecting cloaned divs into it.
for(ei = 0; ei < svSize; ei++){
fcoDiv.clone().injectInside(rcDiv);
}
//Iterate over the height of the SV box setting each rows colors.
for(vi = svSize; vi >= 0; vi -= 1){
//set the brightness for this row.
svColor.changeBrightness(vi*svStep);
//Cloan the row into the SVBox container.
trcDiv = rcDiv.clone().injectInside(this.SVBox);
//Get the children of this row.
arChildren = trcDiv.getChildren();
//Iterate the children of this row.
for(ci = 0; ci < arChildren.length; ci++){
//Change the saturation for each pixe.
svColor.changeSaturation(ci*svStep);
arChildren[ci].setStyle("background-color", svColor);
//Set the events for each pixels for color choice and preview.
arChildren[ci].addEvent('click', this.setSelectedColor.bind(this));
arChildren[ci].addEvent('mouseover', this.setPreviewColor.bind(this));
}
}
}
},
//Update the pixels in the SVBox when the hue is clicked.
UpdateSVBox: function (){
if(this.supportsCanvas){
vSteps = 255 / this.SVBox.height;
svSteps = 100 / this.SVBox.height;
svColor = new Color([this.CurColor.hsb[0], 100, 100], "hsb");
myCTX = this.SVBox.getContext('2d');
strsvHex = "";
for(vi = this.SVBox.height; vi > 0; vi--){
svColor.changeBrightness(vi*svSteps);
strsvHex = svColor.rgbToHex();
myLinearGrad = myCTX.createLinearGradient(0, 0, this.SVBox.width, 0);
myLinearGrad.addColorStop(0, "rgb("+vi+","+vi+","+vi+")");
myLinearGrad.addColorStop(1, strsvHex);
myCTX.fillStyle = myLinearGrad;
myCTX.fillRect(0, this.SVBox.height-vi, this.SVBox.height, 1);
}
}else{
//Get the child rows in the SVBox
arSVRows = this.SVBox.getChildren();
//set the svSize to the number of rows.
svSize = arSVRows.length;
//Get the multiple required to go from 0 to 100 is svSize steps.
svStep = 100/svSize;
//Create a color for calculating the HSV of each pixel.
svColor = new Color([this.CurColor[0],this.CurColor[1],this.CurColor[2]]);
//Loop over all of the rows.
for(vi = svSize - 1; vi >= 0; vi -= 1){
//set the brightness for this row.
svColor.changeBrightness(vi*svStep);
//Get the children of the row.
siChildren = arSVRows[svSize - vi - 1].getChildren();
//Iterate the children of this row.
for(si = 0; si < siChildren.length; si++){
//Change the saturation for each pixe.
svColor.changeSaturation(si*svStep);
siChildren[si].setStyle("background-color", svColor);
}
}
}
},
setCurrentHue: function (e){
//IE uses srcElement instead of target to specify the
//element that was clicked.
if(!e.target)
e.target = e.srcElement;
if(this.supportsCanvas){
//Get a 2d context to the SVBox canvas element.
myCTX = this.HueBar.getContext('2d');
//Get the coordinates for our hue bar.
hBoxCoords = this.HueBar.getCoordinates();
//subtract the left and top of the hue bar from the event.clentX and y then add the window.scrollX and Y
// to get the click position in the Hue bar and pass those in to the contexts getImageData function.
myImageData = myCTX.getImageData(e.clientX - hBoxCoords.left + window.scrollX, e.clientY - hBoxCoords.top + window.scrollY, 1, 1);
//Create a hue color based of the ImageData returned by the getImageData function.
CurHueColor = new Color([myImageData.data[0], myImageData.data[1], myImageData.data[2]]);
}else{
//Create a color object from the background of the target so we can
//get its Hue.
CurHueColor = new Color(e.target.getStyle("background-color"));
}
//Set the Hue of the current color.
this.CurColor.changeHue(CurHueColor.hsb[0]);
//Tell the SVBox to update.
this.UpdateSVBox();
//Set the selected color to the current color.
this.SelectedColor.setStyle("background-color", this.CurColor);
//Update the hsv and rgb text boxes.
this.hInput.value = this.CurColor.hsb[0];
this.sInput.value = this.CurColor.hsb[1];
this.vInput.value = this.CurColor.hsb[2];
this.rInput.value = this.CurColor[0];
this.gInput.value = this.CurColor[1];
this.bInput.value = this.CurColor[2];
},
setPreviewColor: function (e){
//IE uses srcElement instead of target to specify the
//element that was clicked.
if(!e.target)
e.target = e.srcElement;
if(this.supportsCanvas){
myCTX = this.SVBox.getContext('2d');
SVBoxCoords = this.SVBox.getCoordinates();
myImageData = myCTX.getImageData(e.clientX - SVBoxCoords.left + window.scrollX, e.clientY - SVBoxCoords.top + window.scrollY, 1, 1);
nColor = new Color([myImageData.data[0], myImageData.data[1], myImageData.data[2]]);
this.PreviewColor.setStyle("background-color", nColor);
}else{
nColor = new Color(e.target.getStyle("background-color"));
this.PreviewColor.setStyle("background-color", nColor);
}
},
setSelectedColor: function (e){
//IE uses srcElement instead of target to specify the
//element that was clicked.
if(!e.target)
e.target = e.srcElement;
if(this.supportsCanvas){
myCTX = this.SVBox.getContext('2d');
SVBoxCoords = this.SVBox.getCoordinates();
myImageData = myCTX.getImageData(e.clientX - SVBoxCoords.left + window.scrollX, e.clientY - SVBoxCoords.top + window.scrollY, 1, 1);
nColor = new Color([myImageData.data[0], myImageData.data[1], myImageData.data[2]]);
}else{
nColor = new Color(e.target.getStyle("background-color"));
}
//nColor = new Color(e.target.getStyle("background-color"));
this.CurColor = nColor;
this.SelectedColor.setStyle("background-color", nColor);
this.hInput.value = nColor.hsb[0];
this.sInput.value = nColor.hsb[1];
this.vInput.value = nColor.hsb[2];
this.rInput.value = nColor[0];
this.gInput.value = nColor[1];
this.bInput.value = nColor[2];
},
setRGB: function (){
nc = new Color([this.rInput.value, this.gInput.value, this.bInput.value]);
this.CurColor = nc;
this.hInput.value = nc.hsb[0];
this.sInput.value = nc.hsb[1];
this.vInput.value = nc.hsb[2];
this.SelectedColor.setStyle("background-color", nc);
this.PreviewColor.setStyle("background-color", nc);
this.UpdateSVBox();
},
setHSL: function (){
nc = new Color([this.hInput.value, this.sInput.value, this.vInput.value], 'hsb');
this.CurColor = nc;
this.rInput.value = nc[0];
this.gInput.value = nc[1];
this.bInput.value = nc[2];
this.SelectedColor.setStyle("background-color", nc);
this.PreviewColor.setStyle("background-color", nc);
this.UpdateSVBox();
},
//When the ok button is clicked call this.OKCallBack();
handleOK: function (){
if(this.OKCallback != null)
this.OKCallback();
},
//When the ok button is clicked call this.CancelCallback();
handleCancel: function (){
if(this.CancelCallback != null)
this.CancelCallback();
}
});