Use the HSL color picker to create harmony colors.
This example takes advantage of the dial
and slider
widgets. We will use the dial widget to represent and select the hue from the 360 degree color wheel.
Next we will use two sliders to select the saturation and luminance.
<!-- HSL Color Picker --> <div class="picker"> <div id="hue-dial"></div> <div class="sliders"> <div id="sat-slider"><strong>Saturation: <span></span></strong></div> <div id="lum-slider"><strong>Luminance: <span></span></strong></div> </div> <div class="color"></div> </div> <!-- Picker Output --> <div class="harmonies picker-output"> <ul> <li><strong>Complementary:</strong> <span id="h-complementary"></span></li> <li><strong>Split Complementary:</strong> <span id="h-split-complementary"></span></li> <li><strong>Analogous:</strong> <span id="h-analogous"></span></li> <li><strong>Triad:</strong> <span id="h-triad"></span></li> <li><strong>Square:</strong> <span id="h-square"></span></li> <li><strong>Tetrad:</strong> <span id="h-tetrad"></span></li> <li><strong>Monochromatic:</strong> <span id="h-monochromatic"></span></li> <li><strong>Similar:</strong> <span id="h-similar"></span></li> </ul> </div>
This could use a little CSS for positioning, so let's get to that next.
/** HSL Color Picker **/ .picker { padding: 15px; background: #efefef; border: 1px solid #ddd; } #hue-dial, .sliders, .color { display: inline-block; zoom: 1; *display: inline; vertical-align: middle; } #hue-dial .yui3-dial-ring { background: url(../assets/color/colorwheel.png) -25px -25px no-repeat; } .sliders { margin: 0 30px; } .sliders strong { font-weight: 600; display: block; } .sliders strong span { font-weight: 300; } .sliders div + div { margin-top: 1em; } .color { width: 100px; height: 100px; border: 1px solid rgba(0, 0, 0, 0.5); -webkit-box-shadow: 1px 1px 2px 0px rgba(0, 0, 0, 0.3); -moz-box-shadow: 1px 1px 2px 0px rgba(0, 0, 0, 0.3); box-shadow: 1px 1px 2px 0px rgba(0, 0, 0, 0.3); } /** Output Styles **/ .picker-output { margin: 15px; } .picker-output ul { margin: 0; padding: 0; } .picker-output li { list-style: none; line-height: 1.8em; } .picker-output .swatch { width: 1em; height: 1em; margin-left: 0.5em; vertical-align: middle; position: relative; } .tooltip { position: absolute; top: 1.3em; left: 0; background: #ffefc2; border: 1px solid #f5b400; padding: 10px; z-index: 10; } .tooltip li { white-space: nowrap; }
Now we need to create our YUI instance and tell it to load the color
, slider
, dial
and event-valuechange
modules.
YUI().use('dial', 'slider', 'event-valuechange', 'color', function (Y) { // Code Here. });
First things first, we need to make sure our picker UI has the sam skin class applied.
Next, we create a dial for the hue from 0 to 360. Then create a slider from 0 to 100 for saturation and luminance.
We also want to maintain a reference to the nodes where the saturation and luminance value can be read and the color swatch that will be updated from the UI.
Y.one('.picker').addClass('yui3-skin-sam'); var hue = new Y.Dial({ min: 0, max: 360, stepsPerRevolution: 360, continuous: true, centerButtonDiameter: 0.4, render: '#hue-dial' }), sat = new Y.Slider({ min: 0, max: 100, value: 100, render: '#sat-slider' }), lum = new Y.Slider({ min: 0, max: 100, value: 50, render: '#lum-slider' }), satValue = Y.one('#sat-slider span'), lumValue = Y.one('#lum-slider span'), color = Y.one('.color');
After the UI components are initialized, we need to bind their respective change methods to update the UI. For dial, this is valueChange
. For a slider, we use thumbMove
.
hue.after('valueChange', function(e) { updatePickerUI(); }); sat.after('thumbMove', function(e) { updatePickerUI(); }); lum.after('thumbMove', function(e) { lumValue.set('text', lum.get('value') + '%'); updatePickerUI(); });
Finally, we create two methods: setPickerUI
and updatePickerUI
.
setPickerUI
will allow us to send an Object with h
, s
and l
values to update the UI positions.
updatePickerUI
will process the values for hue, saturation and luminance and update the color swatch. updatePickerUI
will also call updateOutput
that we will define next.
function setPickerUI(hsl) { if (typeof hsl.h !== 'undefined') { hue.set('value', +hsl.h); } if (typeof hsl.s !== 'undefined') { sat.set('value', +hsl.s); } if (typeof hsl.l !== 'undefined') { lum.set('value', +hsl.l); } } function updatePickerUI() { var h = hue.get('value'), s = sat.get('value'), l = lum.get('value'), hslString = Y.Color.fromArray([h, s, l], Y.Color.TYPES.HSL), hexString = Y.Color.toHex(hslString); satValue.set('text', s + '%'); lumValue.set('text', l + '%'); color.setStyle('backgroundColor', hexString); updateOutput(hslString); }
var complementary = Y.one('#h-complementary'), split = Y.one('#h-split-complementary'), analogous = Y.one('#h-analogous'), triad = Y.one('#h-triad'), square = Y.one('#h-square'), tetrad = Y.one('#h-tetrad'), mono = Y.one('#h-monochromatic'), similar = Y.one('#h-similar'), swatchTip = Y.Node.create('<div class="tooltip"></div>');
function updateOutput(hslString) { swatchTip.remove(); clearColorSwatches(); makeColorSwatches(hslString); } function clearColorSwatches() { complementary.empty(); split.empty(); analogous.empty(); triad.empty(); square.empty(); tetrad.empty(); mono.empty(); similar.empty(); } function makeColorSwatches(hslString) { // complementary swatches Y.Array.each(Y.Color.getComplementary(hslString), function(color) { complementary.append(getColorSwatch(color)); }); // split complementary swatches Y.Array.each(Y.Color.getSplit(hslString), function(color){ split.append(getColorSwatch(color)); }); // analogous swatches Y.Array.each(Y.Color.getAnalogous(hslString), function(color) { analogous.append(getColorSwatch(color)); }); // triad swatches Y.Array.each(Y.Color.getTriad(hslString), function(color) { triad.append(getColorSwatch(color)); }); // square swatches Y.Array.each(Y.Color.getSquare(hslString), function(color) { square.append(getColorSwatch(color)); }); // tetrad swatches Y.Array.each(Y.Color.getTetrad(hslString), function(color) { tetrad.append(getColorSwatch(color)); }); // monochrome swatches Y.Array.each(Y.Color.getMonochrome(hslString), function(color) { mono.append(getColorSwatch(color)); }); // similar swatches Y.Array.each(Y.Color.getSimilar(hslString), function(color) { similar.append(getColorSwatch(color)); }); } function getColorSwatch(color) { color = Y.Color.toHex(color); return '<span class="color swatch" style="background-color:' + color + '" title="' + color + '"></span>'; }
Let's be honest, having a bunch of colors show up on the screen isn't really useful if you cannot get the value easily.
One solution is to provide a tooltip with the hex, rgb, and hsl values when the user clicks on the swatch. So let's set that up.
Y.one('.picker-output').delegate('click', function(e) { swatchTip.empty(); var str = '<ul>', swatch = e.currentTarget, color = swatch.get('title'); if (swatch.contains(swatchTip)) { swatchTip.remove(); } else { str += '<li><strong>Hex: </strong> ' + Y.Color.toHex(color) + '</li>'; str += '<li><strong>RGB: </strong> ' + Y.Color.toRGB(color) + '</li>'; str += '<li><strong>HSL: </strong> ' + Y.Color.toHSL(color) + '</li>'; str += '</ul>'; swatch.append(swatchTip); swatchTip.setHTML(str); }; }, '.swatch');
Our last step is to make sure we set the initial view of the UI when everything has loaded. We can do this by simply calling updatePickerUI
.
updatePickerUI();