#

Jump to Table of Contents

# Example: HSL Harmony

Use the HSL color picker to create harmony colors.

Saturation:
Luminance:

- Complementary:
- Split Complementary:
- Analogous:
- Triad:
- Square:
- Tetrad:
- Monochromatic:
- Similar:

### Setting Up the HSL Picker UI

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;
    }

### Setting Up the YUI Instance

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.
    });

#### Building The Color Picker

##### Initializing UI Variables

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');

##### Binding Events

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();
    });

##### Useful Functions

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);

        satValue.set('text', s + '%');
        lumValue.set('text', l + '%');

        color.setStyle('backgroundColor', hslString);

        updateOutput(hslString);
    }

#### Building The Picker's Output

##### Initializing Output Variables

    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>');

##### Ouput Functions

    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) {
        return '<span class="color swatch" style="background-color:' + color + '" title="' + color + '"></span>';
    }

##### Provide Useful Information

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');

#### Get It Started

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();