mozilla

Revisão 467743 de ColorPicker

  • Slug da revisão: Web/CSS/Tools/ColorPicker_Tool
  • Título da revisão: ColorPicker
  • ID da revisão: 467743
  • Criado:
  • Criador: gabriel_ivanica
  • É a revisão atual? Não
  • Comentar
Etiquetas: 

Conteúdo da revisão

ColorPIcker Tool

HTML Content

    <div id="container">
        <div id="palette" class="block">
            <div id="color-palette"></div>
            <div id="color-info">
                <div class="title"> CSS Color </div>
            </div>
        </div>

        <div id="picker" class="block">
            <div class="ui-color-picker" data-topic="picker" data-mode="HSL"></div>
            <div id="picker-samples" sample-id="master"></div>
            <div id="controls">
                <div id="delete">
                    <div id="trash-can"></div>
                </div>
                <div id="void-sample" class="icon"></div>
            </div>
        </div>

        <div id="canvas" data-tutorial="drop">
            <div id="zindex" class="ui-input-slider" data-topic="z-index" data-info="z-index"
                data-max="20" data-sensivity="10"></div>
        </div>
    </div>

CSS Content

/*
 * COLOR PICKER TOOL
 */

.ui-color-picker {
	width: 420px;
	margin: 0;
	border: 1px solid #DDD;
	background-color: #FFF;
	display: table;

	-moz-user-select: none;
	-webkit-user-select: none;
	-ms-user-select: none;
	user-select: none;
}

.ui-color-picker .picking-area {
	width: 198px;
	height: 198px;
	margin: 5px;
	border: 1px solid #DDD;
	position: relative;
	float: left;
	display: table;
}

.ui-color-picker .picking-area:hover {
	cursor: default;
}

/* HSV format - Hue-Saturation-Value(Brightness) */
.ui-color-picker .picking-area {
	background: url('https://mdn.mozillademos.org/files/5707/picker_mask_200.png') center center;

	background: -moz-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%),
				-moz-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%);
	background: -webkit-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%),
				-webkit-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%);
	background: -ms-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%),
				-ms-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%);
	background: -o-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%),
				-o-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%);

	background-color: #F00;
}

/* HSL format - Hue-Saturation-Lightness */
.ui-color-picker[data-mode='HSL'] .picking-area {
	background: -moz-linear-gradient(top, hsl(0, 0%, 100%) 0%, hsla(0, 0%, 100%, 0) 50%,
									hsla(0, 0%, 0%, 0) 50%, hsl(0, 0%, 0%) 100%),
				-moz-linear-gradient(left, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%);
	background: -webkit-linear-gradient(top, hsl(0, 0%, 100%) 0%, hsla(0, 0%, 100%, 0) 50%,
									hsla(0, 0%, 0%, 0) 50%, hsl(0, 0%, 0%) 100%),
				-webkit-linear-gradient(left, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%);
	background: -ms-linear-gradient(top, hsl(0, 0%, 100%) 0%, hsla(0, 0%, 100%, 0) 50%,
									hsla(0, 0%, 0%, 0) 50%, hsl(0, 0%, 0%) 100%),
				-ms-linear-gradient(left, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%);
	background: -o-linear-gradient(top, hsl(0, 0%, 100%) 0%, hsla(0, 0%, 100%, 0) 50%,
									hsla(0, 0%, 0%, 0) 50%, hsl(0, 0%, 0%) 100%),
				-o-linear-gradient(left, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%);
	background-color: #F00;
}

.ui-color-picker .picker {
	width: 10px;
	height: 10px;
	border-radius: 50%;
	border: 1px solid #FFF;
	position: absolute;
	top: 45%;
	left: 45%;
}

.ui-color-picker .picker:before {
	width: 8px;
	height: 8px;
	content: "";
	position: absolute;
	border: 1px solid #999;
	border-radius: 50%;
}

.ui-color-picker .hue,
.ui-color-picker .alpha {
	width: 198px;
	height: 28px;
	margin: 5px;
	border: 1px solid #FFF;
	float: left;
}

.ui-color-picker .hue {
	background: url("https://mdn.mozillademos.org/files/5701/hue.png") center;
	background: -moz-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%,
				#00F 66.66%, #F0F 83.33%, #F00 100%);
	background: -webkit-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%,
				#00F 66.66%, #F0F 83.33%, #F00 100%);
	background: -ms-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%,
				#00F 66.66%, #F0F 83.33%, #F00 100%);
	background: -o-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%,
				#00F 66.66%, #F0F 83.33%, #F00 100%);
}

.ui-color-picker .alpha {
	border: 1px solid #CCC;
	background: url("https://mdn.mozillademos.org/files/5705/alpha.png");
}

.ui-color-picker .alpha-mask {
	width: 100%;
	height: 100%;
	background: url("https://mdn.mozillademos.org/files/6089/alpha_mask.png");
}

.ui-color-picker .slider-picker {
	width: 2px;
	height: 100%;
	border: 1px solid #777;
	background-color: #FFF;
	position: relative;
	top: -1px;
}

/* input HSV and RGB */

.ui-color-picker .info {
	width: 200px;
	margin: 5px;
	float: left;
}

.ui-color-picker .info * {
	float: left;
}

.ui-color-picker .input {
	width: 64px;
	margin: 5px 2px;
	float: left;
}

.ui-color-picker .input .name {
	height: 20px;
	width: 30px;
	text-align: center;
	font-size: 14px;
	line-height: 18px;
	float: left;
}

.ui-color-picker .input input {
	width: 30px;
	height: 18px;
	margin: 0;
	padding: 0;
	border: 1px solid #DDD;
	text-align: center;
	float: right;

	-moz-user-select: text;
	-webkit-user-select: text;
	-ms-user-select: text;
}

.ui-color-picker .input[data-topic="lightness"] {
	display: none;
}

.ui-color-picker[data-mode='HSL'] .input[data-topic="value"] {
	display: none;
}

.ui-color-picker[data-mode='HSL'] .input[data-topic="lightness"] {
	display: block;
}

.ui-color-picker .input[data-topic="alpha"] {
	margin-top: 10px;
	width: 93px;
}

.ui-color-picker .input[data-topic="alpha"] > .name {
	width: 60px;
}

.ui-color-picker .input[data-topic="alpha"] > input {
	float: right;
}

.ui-color-picker .input[data-topic="hexa"] {
	width: auto;
	float: right;
	margin: 6px 8px 0 0;
}

.ui-color-picker .input[data-topic="hexa"] > .name {
	display: none;
}

.ui-color-picker .input[data-topic="hexa"] > input {
	width: 90px;
	height: 24px;
	padding: 2px 0;
	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}

/* Preview color */
.ui-color-picker .preview {
	width: 95px;
	height: 53px;
	margin: 5px;
	margin-top: 10px;
	border: 1px solid #DDD;
	background-image: url("https://mdn.mozillademos.org/files/5705/alpha.png");
	float: left;
	position: relative;
}

.ui-color-picker .preview:before {
	height: 100%;
	width: 50%;
	left: 50%;
	top: 0;
	content: "";
	background: #FFF;
	position: absolute;
	z-index: 1;
}

.ui-color-picker .preview-color {
	width: 100%;
	height: 100%;
	background-color: rgba(255, 0, 0, 0.5);
	position: absolute;
	z-index: 1;
}

.ui-color-picker .switch_mode {
	width: 10px;
	height: 20px;
	position: relative;
	border-radius: 5px 0 0 5px;
	border: 1px solid #DDD;
	background-color: #EEE;
	left: -12px;
	top: -1px;
	z-index: 1;
	transition: all 0.5s;
}

.ui-color-picker .switch_mode:hover {
	background-color: #CCC;
	cursor: pointer;
}

/*
 * UI Component
 */

.ui-input-slider {
	height: 20px;
	font-family: "Segoe UI", Arial, Helvetica, sans-serif;
	-moz-user-select: none;
	user-select: none;
}

.ui-input-slider * {
	float: left;
	height: 100%;
	line-height: 100%;
}

/* Input Slider */

.ui-input-slider > input {
	margin: 0;
	padding: 0;
	width: 50px;
	text-align: center;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}

.ui-input-slider-info {
	width: 90px;
	padding: 0px 10px 0px 0px;
	text-align: right;
	text-transform: lowercase;
}

.ui-input-slider-left, .ui-input-slider-right {
	width: 16px;
	cursor: pointer;
	background: url("https://mdn.mozillademos.org/files/5679/arrows.png") center left no-repeat;
}

.ui-input-slider-right {
	background: url("https://mdn.mozillademos.org/files/5679/arrows.png") center right no-repeat;
}

.ui-input-slider-name {
	width: 90px;
	padding: 0 10px 0 0;
	text-align: right;
	text-transform: lowercase;
}

.ui-input-slider-btn-set {
	width: 25px;
	background-color: #2C9FC9;
	border-radius: 5px;
	color: #FFF;
	font-weight: bold;
	line-height: 14px;
	text-align: center;
}

.ui-input-slider-btn-set:hover {
	background-color: #379B4A;
	cursor: pointer;
}

/*
 * COLOR PICKER TOOL
 */

body {
	max-width: 1000px;
	margin: 0 auto;

	font-family: "Segoe UI", Arial, Helvetica, sans-serif;

	box-shadow: 0 0 5px 0 #999;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;

	-moz-user-select: none;
	-webkit-user-select: none;
	-ms-user-select: none;
	user-select: none;

}

/**
 * Resize Handle
 */
.resize-handle {
	width: 10px;
	height: 10px;
	background: url('https://mdn.mozillademos.org/files/6083/resize.png') center center no-repeat;
	position: absolute;
	bottom: 0;
	right: 0;
}

[data-resize='both']:hover {
	cursor: nw-resize !important;
}

[data-resize='width']:hover {
	cursor: w-resize !important;
}

[data-resize='height']:hover {
	cursor: n-resize !important;
}

[data-hidden='true'] {
	display: none;
}

[data-collapsed='true'] {
	height: 0 !important;
}

.block {
	display: table;
}


/**
 * 	Container
 */
#container {
	width: 100%;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;

	display: table;
}

/**
 * 	Picker Zone
 */

#picker {
	padding: 10px;
	width: 980px;
}

.ui-color-picker {
	padding: 3px 5px;
	float: left;
	border-color: #FFF;
}

.ui-color-picker .switch_mode {
	display: none;
}

.ui-color-picker .preview-color:hover {
	cursor: move;
}

/**
 * Picker Container
 */

#picker-samples {
	width: 375px;
	height: 114px;
	max-height: 218px;
	margin: 0 10px 0 30px;
	overflow: hidden;
	position: relative;
	float: left;

	transition: all 0.2s;
}

#picker-samples .sample {
	width: 40px;
	height: 40px;
	margin: 5px;
	border: 1px solid #DDD;
	position: absolute;
	float: left;
	transition: all 0.2s;
}

#picker-samples .sample:hover {
	cursor: pointer;
	border-color: #BBB;
	transform: scale(1.15);
	border-radius: 3px;
}

#picker-samples .sample[data-active='true'] {
	border-color: #999;
}

#picker-samples .sample[data-active='true']:after {
	content: "";
	position: absolute;
	background: url('https://mdn.mozillademos.org/files/6065/arrow.png') center no-repeat;
	width: 100%;
	height: 12px;
	top: -12px;
	z-index: 2;
}

#picker-samples #add-icon {
	width: 100%;
	height: 100%;
	position: relative;
	box-shadow: inset 0px 0px 2px 0px #DDD;
}

#picker-samples #add-icon:hover {
	cursor: pointer;
	border-color: #DDD;
	box-shadow: inset 0px 0px 5px 0px #CCC;
}

#picker-samples #add-icon:before,
#picker-samples #add-icon:after {
	content: "";
	position: absolute;
	background-color: #EEE;
	box-shadow: 0 0 1px 0 #EEE;
}

#picker-samples #add-icon:before {
	width: 70%;
	height: 16%;
	top: 42%;
	left: 15%;
}

#picker-samples #add-icon:after {
	width: 16%;
	height: 70%;
	top: 15%;
	left: 42%;
}

#picker-samples #add-icon:hover:before,
#picker-samples #add-icon:hover:after {
	background-color: #DDD;
	box-shadow: 0 0 1px 0 #DDD;
}

/**
 * 	Controls
 */

#controls {
	width: 110px;
	padding: 10px;
	float: right;
}

#controls #picker-switch {
	text-align: center;
	float: left;
}

#controls .icon {
	width: 48px;
	height: 48px;
	margin: 10px 0;
	background-repeat: no-repeat;
	background-position: center;
	border: 1px solid #DDD;
	display: table;
	float: left;
}

#controls .icon:hover {
	cursor: pointer;
}

#controls .picker-icon {
	background-image: url('https://mdn.mozillademos.org/files/6081/picker.png');
}

#controls #void-sample {
	margin-right: 10px;
	background-image: url('https://mdn.mozillademos.org/files/6087/void.png');
	background-position: center left;
}

#controls #void-sample[data-active='true'] {
	border-color: #CCC;
	background-position: center right;
}

#controls .switch {
	width: 106px;
	padding: 1px;
	border: 1px solid #CCC;
	font-size: 14px;
	text-align: center;
	line-height: 24px;
	overflow: hidden;
	float: left;
}

#controls .switch:hover {
	cursor: pointer;
}

#controls .switch > * {
	width: 50%;
	padding: 2px 0;
	background-color: #EEE;
	float: left;
}

#controls .switch [data-active='true'] {
	color: #FFF;
	background-image: url('https://mdn.mozillademos.org/files/6025/grain.png');
	background-color: #777;
}

/**
 * 	Trash Can
 */

#delete {
	width: 100%;
	height: 94px;
	background-color: #DDD;
	background-image: url('https://mdn.mozillademos.org/files/6025/grain.png');
	background-repeat: repeat;

	text-align: center;
	color: #777;

	position: relative;
	float: right;
}

#delete #trash-can {
	width: 80%;
	height: 80%;
	border: 2px dashed #FFF;
	border-radius: 5px;
	background: url('https://mdn.mozillademos.org/files/6085/trash-can.png') no-repeat center;

	position: absolute;
	top: 10%;
	left: 10%;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;

	transition: all 0.2s;
}

#delete[drag-state='enter'] {
	background-color: #999;
}

/**
 * 	Color Theme
 */

#color-theme {
	margin: 0 8px 0 0;
	border: 1px solid #EEE;
	display: inline-block;
	float: right;
}

#color-theme .box {
	width: 80px;
	height: 92px;
	float: left;
}

/**
 * Color info box
 */
#color-info {
	width: 360px;
	float: left;
}

#color-info .title {
	width: 100%;
	padding: 15px;
	font-size: 18px;
	text-align: center;
	background-image: url('https://mdn.mozillademos.org/files/6071/color-wheel.png');
	background-repeat:no-repeat;
	background-position: center left 30%;
}

#color-info .copy-container {
	position: absolute;
	top: -100%;
}

#color-info .property {
	min-width: 280px;
	height: 30px;
	margin: 10px 0;
	text-align: center;
	line-height: 30px;
}

#color-info .property > * {
	float: left;
}

#color-info .property .type {
	width: 60px;
	height: 100%;
	padding: 0 16px 0 0;
	text-align: right;
}

#color-info .property .value {
	width: 200px;
	height: 100%;
	padding: 0 10px;
	font-family: "Segoe UI", Arial, Helvetica, sans-serif;
	font-size: 16px;
	color: #777;
	text-align: center;
	background-color: #FFF;
	border: none;
}

#color-info .property .value:hover {
	color: #37994A;
}

#color-info .property .value:hover + .copy {
	background-position: center right;
}

#color-info .property .copy {
	width: 24px;
	height: 100%;
	padding: 0 5px;
	background-color: #FFF;
	background-image: url('https://mdn.mozillademos.org/files/6073/copy.png');
	background-repeat: no-repeat;
	background-position: center left;
	border-left: 1px solid #EEE;
	text-align: right;
	float: left;
}

#color-info .property .copy:hover {
	background-position: center right;
}


/**
 * 	Color Palette
 */

#palette {
	width: 1000px;
	padding: 10px 0;
	background-image: url('https://mdn.mozillademos.org/files/6025/grain.png');
	background-repeat: repeat;
	background-color: #EEE;
	color: #777;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}

#color-palette {
	width: 640px;
	font-family: Arial, Helvetica, sans-serif;
	color: #777;
	float: left;
}

#color-palette .container {
	width: 100%;
	height: 50px;
	line-height: 50px;
	overflow: hidden;
	float: left;
	transition: all 0.5s;
}

#color-palette .container > * {
	float: left;
}

#color-palette .title {
	width: 100px;
	padding: 0 10px;
	text-align: right;
	line-height: inherit;
}

#color-palette .palette {
	width: 456px;
	height: 38px;
	margin: 3px;
	padding: 3px;
	display: table;
	background-color: #FFF;
}

#color-palette .palette .sample {
	width: 30px;
	height: 30px;
	margin: 3px;
	position: relative;
	border: 1px solid #DDD;
	float: left;
	transition: all 0.2s;
}

#color-palette .palette .sample:hover {
	cursor: pointer;
	border-color: #BBB;
	transform: scale(1.15);
	border-radius: 3px;
}

#color-palette .controls {
}

#color-palette .controls > * {
	float: left;
}

#color-palette .controls > *:hover {
	cursor: pointer;
}

#color-palette .controls .lock {
	width: 24px;
	height: 24px;
	margin: 10px;
	padding: 3px;
	background-image: url('https://mdn.mozillademos.org/files/6077/lock.png');
	background-repeat: no-repeat;
	background-position: bottom right;
}

#color-palette .controls .lock:hover {
	/*background-image: url('images/unlocked-hover.png');*/
	background-position: bottom left;
}

#color-palette .controls .lock[locked-state='true'] {
	/*background-image: url('images/locked.png');*/
	background-position: top left ;
}

#color-palette .controls .lock[locked-state='true']:hover {
	/*background-image: url('images/lock-hover.png');*/
	background-position: top right;
}

/**
 * Canvas
 */

#canvas {
	width: 100%;
	height: 300px;
	min-height: 250px;
	border-top: 1px solid #DDD;
	background-image: url('https://mdn.mozillademos.org/files/6025/grain.png');
	background-repeat: repeat;
	position: relative;
	float: left;
}

#canvas[data-tutorial='drop'] {
	text-align: center;
	font-size: 30px;
	color: #777;
}

#canvas[data-tutorial='drop']:before {
	content: "Drop colors here to compare";
	width: 40%;
	padding: 30px 9% 70px 11%;

	background-image: url('https://mdn.mozillademos.org/files/6075/drop.png');
	background-repeat: no-repeat;
	background-position: left 35px top 60%;

	text-align: right;

	border: 3px dashed rgb(221, 221, 221);
	border-radius: 15px;

	position: absolute;
	top: 50px;
	left: 20%;
}

#canvas[data-tutorial='drop']:after {
	content: "ajust, change or modify";
	width: 40%;
	font-size: 24px;
	position: absolute;
	top: 130px;
	left: 32%;
	z-index: 2;
}

#canvas [data-tutorial='dblclick'] {
	background-color: #999 !important;
}

#canvas [data-tutorial='dblclick']:before {
	content: "double click to activate";
	width: 80px;
	color: #FFF;
	position: absolute;
	top: 10%;
	left: 20%;
	z-index: 2;
}

#canvas .sample {
	width: 100px;
	height: 100px;
	min-width: 20px;
	min-height: 20px;
	position: absolute;
	border: 1px solid rgba(255, 255, 255, 0.3);
}

#canvas .sample:hover {
	cursor: move;
}

#canvas .sample[data-active='true']:after {
	content: "";
	position: absolute;
	background: url('https://mdn.mozillademos.org/files/6065/arrow.png') center no-repeat;
	width: 100%;
	height: 12px;
	top: -12px;
	z-index: 2;
}

#canvas .sample:hover > * {
	cursor: pointer;
	display: block !important;
}

#canvas .sample .resize-handle {
	display: none;
}

#canvas .sample .pick {
	width: 10px;
	height: 10px;
	margin: 5px;
	background: url('https://mdn.mozillademos.org/files/6079/pick.png') center no-repeat;
	position: absolute;
	top: 0;
	left: 0;
	display: none;
}

#canvas .sample .delete {
	width: 10px;
	height: 10px;
	margin: 5px;
	background: url('https://mdn.mozillademos.org/files/6069/close.png') center no-repeat;
	position: absolute;
	top: 0;
	right: 0;
	display: none;
}


/**
 * Canvas controls
 */

#canvas .toggle-bg {
	width: 16px;
	height: 16px;
	margin: 5px;
	background: url("images/canvas-controls.png") center left no-repeat;
	position: absolute;
	top: 0;
	right: 0;
}

#canvas .toggle-bg:hover {
	cursor: pointer;
}

#canvas[data-bg='true'] {
	background: none;
}

#canvas[data-bg='true'] .toggle-bg {
	background: url('https://mdn.mozillademos.org/files/6067/canvas-controls.png') center right no-repeat;
}

#zindex {
	height: 20px;
	margin: 5px;
	font-size: 16px;
	position: absolute;
	opacity: 0;
	top: -10000px;
	left: 0;
	color: #777;
	float: left;
	transition: opacity 1s;
}

#zindex input {
	border: 1px solid #DDD;
	font-size: 16px;
	color: #777;
}

#zindex .ui-input-slider-info {
	width: 60px;
}

#zindex[data-active='true'] {
	top: 0;
	opacity: 1;
}

JavaScript Content

'use strict';

var UIColorPicker = (function UIColorPicker() {

	function getElemById(id) {
		return document.getElementById(id);
	}

	var subscribers = [];
	var pickers = [];

	/**
	 * RGBA Color class
	 *
	 * HSV/HSB and HSL (hue, saturation, value / brightness, lightness)
	 * @param hue			0-360
	 * @param saturation	0-100
	 * @param value 		0-100
	 * @param lightness		0-100
	 */

	function Color(color) {

		if(color instanceof Color === true) {
			this.copy(color);
			return;
		}

		this.r = 0;
		this.g = 0;
		this.b = 0;
		this.a = 1;
		this.hue = 0;
		this.saturation = 0;
		this.value = 0;
		this.lightness = 0;
		this.format = 'HSV';
	}

	function RGBColor(r, g, b) {
		var color = new Color();
		color.setRGBA(r, g, b, 1);
		return color;
	}

	function RGBAColor(r, g, b, a) {
		var color = new Color();
		color.setRGBA(r, g, b, a);
		return color;
	}

	function HSVColor(h, s, v) {
		var color = new Color();
		color.setHSV(h, s, v);
		return color;
	}

	function HSVAColor(h, s, v, a) {
		var color = new Color();
		color.setHSV(h, s, v);
		color.a = a;
		return color;
	}

	function HSLColor(h, s, l) {
		var color = new Color();
		color.setHSL(h, s, l);
		return color;
	}

	function HSLAColor(h, s, l, a) {
		var color = new Color();
		color.setHSL(h, s, l);
		color.a = a;
		return color;
	}

	Color.prototype.copy = function copy(obj) {
		if(obj instanceof Color !== true) {
			console.log('Typeof parameter not Color');
			return;
		}

		this.r = obj.r;
		this.g = obj.g;
		this.b = obj.b;
		this.a = obj.a;
		this.hue = obj.hue;
		this.saturation = obj.saturation;
		this.value = obj.value;
		this.format = '' + obj.format;
		this.lightness = obj.lightness;
	};

	Color.prototype.setFormat = function setFormat(format) {
		if (format === 'HSV')
			this.format = 'HSV';
		if (format === 'HSL')
			this.format = 'HSL';
	};

	/*========== Methods to set Color Properties ==========*/

	Color.prototype.isValidRGBValue = function isValidRGBValue(value) {
		return (typeof(value) === 'number' && isNaN(value) === false &&
			value >= 0 && value <= 255);
	};

	Color.prototype.setRGBA = function setRGBA(red, green, blue, alpha) {
		if (this.isValidRGBValue(red) === false ||
			this.isValidRGBValue(green) === false ||
			this.isValidRGBValue(blue) === false)
			return;

			this.r = red | 0;
			this.g = green | 0;
			this.b = blue | 0;

		if (this.isValidRGBValue(alpha) === true)
			this.a = alpha | 0;
	};

	Color.prototype.setByName = function setByName(name, value) {
		if (name === 'r' || name === 'g' || name === 'b') {
			if(this.isValidRGBValue(value) === false)
				return;

			this[name] = value;
			this.updateHSX();
		}
	};

	Color.prototype.setHSV = function setHSV(hue, saturation, value) {
		this.hue = hue;
		this.saturation = saturation;
		this.value = value;
		this.HSVtoRGB();
	};

	Color.prototype.setHSL = function setHSL(hue, saturation, lightness) {
		this.hue = hue;
		this.saturation = saturation;
		this.lightness = lightness;
		this.HSLtoRGB();
	};

	Color.prototype.setHue = function setHue(value) {
		if (typeof(value) !== 'number' || isNaN(value) === true ||
			value < 0 || value > 359)
			return;
		this.hue = value;
		this.updateRGB();
	};

	Color.prototype.setSaturation = function setSaturation(value) {
		if (typeof(value) !== 'number' || isNaN(value) === true ||
			value < 0 || value > 100)
			return;
		this.saturation = value;
		this.updateRGB();
	};

	Color.prototype.setValue = function setValue(value) {
		if (typeof(value) !== 'number' || isNaN(value) === true ||
			value < 0 || value > 100)
			return;
		this.value = value;
		this.HSVtoRGB();
	};

	Color.prototype.setLightness = function setLightness(value) {
		if (typeof(value) !== 'number' || isNaN(value) === true ||
			value < 0 || value > 100)
			return;
		this.lightness = value;
		this.HSLtoRGB();
	};

	Color.prototype.setHexa = function setHexa(value) {
		var valid  = /(^#{0,1}[0-9A-F]{6}$)|(^#{0,1}[0-9A-F]{3}$)/i.test(value);

		if (valid !== true)
			return;

		if (value[0] === '#')
			value = value.slice(1, value.length);

		if (value.length === 3)
			value = value.replace(/([0-9A-F])([0-9A-F])([0-9A-F])/i,'$1$1$2$2$3$3');

		this.r = parseInt(value.substr(0, 2), 16);
		this.g = parseInt(value.substr(2, 2), 16);
		this.b = parseInt(value.substr(4, 2), 16);

		this.alpha	= 1;
		this.RGBtoHSV();
	};

	/*========== Conversion Methods ==========*/

	Color.prototype.convertToHSL = function convertToHSL() {
		if (this.format === 'HSL')
			return;

		this.setFormat('HSL');
		this.RGBtoHSL();
	};

	Color.prototype.convertToHSV = function convertToHSV() {
		if (this.format === 'HSV')
			return;

		this.setFormat('HSV');
		this.RGBtoHSV();
	};

	/*========== Update Methods ==========*/

	Color.prototype.updateRGB = function updateRGB() {
		if (this.format === 'HSV') {
			this.HSVtoRGB();
			return;
		}

		if (this.format === 'HSL') {
			this.HSLtoRGB();
			return;
		}
	};

	Color.prototype.updateHSX = function updateHSX() {
		if (this.format === 'HSV') {
			this.RGBtoHSV();
			return;
		}

		if (this.format === 'HSL') {
			this.RGBtoHSL();
			return;
		}
	};

	Color.prototype.HSVtoRGB = function HSVtoRGB() {
		var sat = this.saturation / 100;
		var value = this.value / 100;
		var C = sat * value;
		var H = this.hue / 60;
		var X = C * (1 - Math.abs(H % 2 - 1));
		var m = value - C;
		var precision = 255;

		C = (C + m) * precision | 0;
		X = (X + m) * precision | 0;
		m = m * precision | 0;

		if (H >= 0 && H < 1) {	this.setRGBA(C, X, m);	return; }
		if (H >= 1 && H < 2) {	this.setRGBA(X, C, m);	return; }
		if (H >= 2 && H < 3) {	this.setRGBA(m, C, X);	return; }
		if (H >= 3 && H < 4) {	this.setRGBA(m, X, C);	return; }
		if (H >= 4 && H < 5) {	this.setRGBA(X, m, C);	return; }
		if (H >= 5 && H < 6) {	this.setRGBA(C, m, X);	return; }
	};

	Color.prototype.HSLtoRGB = function HSLtoRGB() {
		var sat = this.saturation / 100;
		var light = this.lightness / 100;
		var C = sat * (1 - Math.abs(2 * light - 1));
		var H = this.hue / 60;
		var X = C * (1 - Math.abs(H % 2 - 1));
		var m = light - C/2;
		var precision = 255;

		C = (C + m) * precision | 0;
		X = (X + m) * precision | 0;
		m = m * precision | 0;

		if (H >= 0 && H < 1) {	this.setRGBA(C, X, m);	return; }
		if (H >= 1 && H < 2) {	this.setRGBA(X, C, m);	return; }
		if (H >= 2 && H < 3) {	this.setRGBA(m, C, X);	return; }
		if (H >= 3 && H < 4) {	this.setRGBA(m, X, C);	return; }
		if (H >= 4 && H < 5) {	this.setRGBA(X, m, C);	return; }
		if (H >= 5 && H < 6) {	this.setRGBA(C, m, X);	return; }
	};

	Color.prototype.RGBtoHSV = function RGBtoHSV() {
		var red		= this.r / 255;
		var green	= this.g / 255;
		var blue	= this.b / 255;

		var cmax = Math.max(red, green, blue);
		var cmin = Math.min(red, green, blue);
		var delta = cmax - cmin;
		var hue = 0;
		var saturation = 0;

		if (delta) {
			if (cmax === red ) { hue = ((green - blue) / delta); }
			if (cmax === green ) { hue = 2 + (blue - red) / delta; }
			if (cmax === blue ) { hue = 4 + (red - green) / delta; }
			if (cmax) saturation = delta / cmax;
		}

		this.hue = 60 * hue | 0;
		if (this.hue < 0) this.hue += 360;
		this.saturation = (saturation * 100) | 0;
		this.value = (cmax * 100) | 0;
	};

	Color.prototype.RGBtoHSL = function RGBtoHSL() {
		var red		= this.r / 255;
		var green	= this.g / 255;
		var blue	= this.b / 255;

		var cmax = Math.max(red, green, blue);
		var cmin = Math.min(red, green, blue);
		var delta = cmax - cmin;
		var hue = 0;
		var saturation = 0;
		var lightness = (cmax + cmin) / 2;
		var X = (1 - Math.abs(2 * lightness - 1));

		if (delta) {
			if (cmax === red ) { hue = ((green - blue) / delta); }
			if (cmax === green ) { hue = 2 + (blue - red) / delta; }
			if (cmax === blue ) { hue = 4 + (red - green) / delta; }
			if (cmax) saturation = delta / X;
		}

		this.hue = 60 * hue | 0;
		if (this.hue < 0) this.hue += 360;
		this.saturation = (saturation * 100) | 0;
		this.lightness = (lightness * 100) | 0;
	};

	/*========== Get Methods ==========*/

	Color.prototype.getHexa = function getHexa() {
		var r = this.r.toString(16);
		var g = this.g.toString(16);
		var b = this.b.toString(16);
		if (this.r < 16) r = '0' + r;
		if (this.g < 16) g = '0' + g;
		if (this.b < 16) b = '0' + b;
		var value = '#' + r + g + b;
		return value.toUpperCase();
	};

	Color.prototype.getRGBA = function getRGBA() {

		var rgb = '(' + this.r + ', ' + this.g + ', ' + this.b;
		var a = '';
		var v = '';
		var x = parseFloat(this.a);
		if (x !== 1) {
			a = 'a';
			v = ', ' + x;
		}

		var value = 'rgb' + a + rgb + v + ')';
		return value;
	};

	Color.prototype.getHSLA = function getHSLA() {
		if (this.format === 'HSV') {
			var color = new Color(this);
			color.setFormat('HSL');
			color.updateHSX();
			return color.getHSLA();
		}

		var a = '';
		var v = '';
		var hsl = '(' + this.hue + ', ' + this.saturation + '%, ' + this.lightness +'%';
		var x = parseFloat(this.a);
		if (x !== 1) {
			a = 'a';
			v = ', ' + x;
		}

		var value = 'hsl' + a + hsl + v + ')';
		return value;
	};

	Color.prototype.getColor = function getColor() {
		if (this.a | 0 === 1)
			return this.getHexa();
		return this.getRGBA();
	};

	/*=======================================================================*/
	/*=======================================================================*/

	/*========== Capture Mouse Movement ==========*/

	var setMouseTracking = function setMouseTracking(elem, callback) {
		elem.addEventListener('mousedown', function(e) {
			callback(e);
			document.addEventListener('mousemove', callback);
		});

		document.addEventListener('mouseup', function(e) {
			document.removeEventListener('mousemove', callback);
		});
	};

	/*====================*/
	// Color Picker Class
	/*====================*/

	function ColorPicker(node) {
		this.color = new Color();
		this.node = node;
		this.subscribers = [];

		var type = this.node.getAttribute('data-mode');
		var topic = this.node.getAttribute('data-topic');

		this.topic = topic;
		this.picker_mode = (type === 'HSL') ? 'HSL' : 'HSV';
		this.color.setFormat(this.picker_mode);

		this.createPickingArea();
		this.createHueArea();

		this.newInputComponent('H', 'hue', this.inputChangeHue.bind(this));
		this.newInputComponent('S', 'saturation', this.inputChangeSaturation.bind(this));
		this.newInputComponent('V', 'value', this.inputChangeValue.bind(this));
		this.newInputComponent('L', 'lightness', this.inputChangeLightness.bind(this));

		this.createAlphaArea();

		this.newInputComponent('R', 'red', this.inputChangeRed.bind(this));
		this.newInputComponent('G', 'green', this.inputChangeGreen.bind(this));
		this.newInputComponent('B', 'blue', this.inputChangeBlue.bind(this));

		this.createPreviewBox();
		this.createChangeModeButton();

		this.newInputComponent('alpha', 'alpha', this.inputChangeAlpha.bind(this));
		this.newInputComponent('hexa', 'hexa', this.inputChangeHexa.bind(this));

		this.setColor(this.color);
		pickers[topic] = this;
	}

	/*************************************************************************/
	//				Function for generating the color-picker
	/*************************************************************************/

	ColorPicker.prototype.createPickingArea = function createPickingArea() {
		var area = document.createElement('div');
		var picker = document.createElement('div');

		area.className = 'picking-area';
		picker.className = 'picker';

		this.picking_area = area;
		this.color_picker = picker;
		setMouseTracking(area, this.updateColor.bind(this));

		area.appendChild(picker);
		this.node.appendChild(area);
	};

	ColorPicker.prototype.createHueArea = function createHueArea() {
		var area = document.createElement('div');
		var picker = document.createElement('div');

		area.className = 'hue';
		picker.className ='slider-picker';

		this.hue_area = area;
		this.hue_picker = picker;
		setMouseTracking(area, this.updateHueSlider.bind(this));

		area.appendChild(picker);
		this.node.appendChild(area);
	};

	ColorPicker.prototype.createAlphaArea = function createAlphaArea() {
		var area = document.createElement('div');
		var mask = document.createElement('div');
		var picker = document.createElement('div');

		area.className = 'alpha';
		mask.className = 'alpha-mask';
		picker.className = 'slider-picker';

		this.alpha_area = area;
		this.alpha_mask = mask;
		this.alpha_picker = picker;
		setMouseTracking(area, this.updateAlphaSlider.bind(this));

		area.appendChild(mask);
		mask.appendChild(picker);
		this.node.appendChild(area);
	};

	ColorPicker.prototype.createPreviewBox = function createPreviewBox(e) {
		var preview_box = document.createElement('div');
		var preview_color = document.createElement('div');

		preview_box.className = 'preview';
		preview_color.className = 'preview-color';

		this.preview_color = preview_color;

		preview_box.appendChild(preview_color);
		this.node.appendChild(preview_box);
	};

	ColorPicker.prototype.newInputComponent = function newInputComponent(title, topic, onChangeFunc) {
		var wrapper = document.createElement('div');
		var input = document.createElement('input');
		var info = document.createElement('span');

		wrapper.className = 'input';
		wrapper.setAttribute('data-topic', topic);
		info.textContent = title;
		info.className = 'name';
		input.setAttribute('type', 'text');

		wrapper.appendChild(info);
		wrapper.appendChild(input);
		this.node.appendChild(wrapper);

		input.addEventListener('change', onChangeFunc);
		input.addEventListener('click', function() {
			this.select();
		});

		this.subscribe(topic, function(value) {
			input.value = value;
		});
	};

	ColorPicker.prototype.createChangeModeButton = function createChangeModeButton() {

		var button = document.createElement('div');
		button.className = 'switch_mode';
		button.addEventListener('click', function() {
			if (this.picker_mode === 'HSV')
				this.setPickerMode('HSL');
			else
				this.setPickerMode('HSV');

		}.bind(this));

		this.node.appendChild(button);
	};

	/*************************************************************************/
	//					Updates properties of UI elements
	/*************************************************************************/

	ColorPicker.prototype.updateColor = function updateColor(e) {
		var x = e.pageX - this.picking_area.offsetLeft;
		var y = e.pageY - this.picking_area.offsetTop;
		var picker_offset = 5;

		// width and height should be the same
		var size = this.picking_area.clientWidth;

		if (x > size) x = size;
		if (y > size) y = size;
		if (x < 0) x = 0;
		if (y < 0) y = 0;

		var value = 100 - (y * 100 / size) | 0;
		var saturation = x * 100 / size | 0;

		if (this.picker_mode === 'HSV')
			this.color.setHSV(this.color.hue, saturation, value);
		if (this.picker_mode === 'HSL')
			this.color.setHSL(this.color.hue, saturation, value);

		this.color_picker.style.left = x - picker_offset + 'px';
		this.color_picker.style.top = y - picker_offset + 'px';

		this.updateAlphaGradient();
		this.updatePreviewColor();

		this.notify('value', value);
		this.notify('lightness', value);
		this.notify('saturation', saturation);

		this.notify('red', this.color.r);
		this.notify('green', this.color.g);
		this.notify('blue', this.color.b);
		this.notify('hexa', this.color.getHexa());

		notify(this.topic, this.color);
	};

	ColorPicker.prototype.updateHueSlider = function updateHueSlider(e) {
		var x = e.pageX - this.hue_area.offsetLeft;
		var width = this.hue_area.clientWidth;

		if (x < 0) x = 0;
		if (x > width) x = width;

		// TODO 360 => 359
		var hue = ((359 * x) / width) | 0;
		// if (hue === 360) hue = 359;

		this.updateSliderPosition(this.hue_picker, x);
		this.setHue(hue);
	};

	ColorPicker.prototype.updateAlphaSlider = function updateAlphaSlider(e) {
		var x = e.pageX - this.alpha_area.offsetLeft;
		var width = this.alpha_area.clientWidth;

		if (x < 0) x = 0;
		if (x > width) x = width;

		this.color.a = (x / width).toFixed(2);

		this.updateSliderPosition(this.alpha_picker, x);
		this.updatePreviewColor();

		this.notify('alpha', this.color.a);
		notify(this.topic, this.color);
	};

	ColorPicker.prototype.setHue = function setHue(value) {
		this.color.setHue(value);

		this.updatePickerBackground();
		this.updateAlphaGradient();
		this.updatePreviewColor();

		this.notify('red', this.color.r);
		this.notify('green', this.color.g);
		this.notify('blue', this.color.b);
		this.notify('hexa', this.color.getHexa());
		this.notify('hue', this.color.hue);

		notify(this.topic, this.color);
	};

	// Updates when one of Saturation/Value/Lightness changes
	ColorPicker.prototype.updateSLV = function updateSLV() {
		this.updatePickerPosition();
		this.updateAlphaGradient();
		this.updatePreviewColor();

		this.notify('red', this.color.r);
		this.notify('green', this.color.g);
		this.notify('blue', this.color.b);
		this.notify('hexa', this.color.getHexa());

		notify(this.topic, this.color);
	};

	/*************************************************************************/
	//				Update positions of various UI elements
	/*************************************************************************/

	ColorPicker.prototype.updatePickerPosition = function updatePickerPosition() {
		var size = this.picking_area.clientWidth;
		var value = 0;
		var offset = 5;

		if (this.picker_mode === 'HSV')
			value = this.color.value;
		if (this.picker_mode === 'HSL')
			value = this.color.lightness;

		var x = (this.color.saturation * size / 100) | 0;
		var y = size - (value * size / 100) | 0;

		this.color_picker.style.left = x - offset + 'px';
		this.color_picker.style.top = y - offset + 'px';
	};

	ColorPicker.prototype.updateSliderPosition = function updateSliderPosition(elem, pos) {
		elem.style.left = Math.max(pos - 3, -2) + 'px';
	};

	ColorPicker.prototype.updateHuePicker = function updateHuePicker() {
		var size = this.hue_area.clientWidth;
		var offset = 1;
		var pos = (this.color.hue * size / 360 ) | 0;
		this.hue_picker.style.left = pos - offset + 'px';
	};

	ColorPicker.prototype.updateAlphaPicker = function updateAlphaPicker() {
		var size = this.alpha_area.clientWidth;
		var offset = 1;
		var pos = (this.color.a * size) | 0;
		this.alpha_picker.style.left = pos - offset + 'px';
	};

	/*************************************************************************/
	//						Update background colors
	/*************************************************************************/

	ColorPicker.prototype.updatePickerBackground = function updatePickerBackground() {
		var nc = new Color(this.color);
		nc.setHSV(nc.hue, 100, 100);
		this.picking_area.style.backgroundColor = nc.getHexa();
	};

	ColorPicker.prototype.updateAlphaGradient = function updateAlphaGradient() {
		this.alpha_mask.style.backgroundColor = this.color.getHexa();
	};

	ColorPicker.prototype.updatePreviewColor = function updatePreviewColor() {
		this.preview_color.style.backgroundColor = this.color.getColor();
	};

	/*************************************************************************/
	//						Update input elements
	/*************************************************************************/

	ColorPicker.prototype.inputChangeHue = function inputChangeHue(e) {
		var value = parseInt(e.target.value);
		this.setHue(value);
		this.updateHuePicker();
	};

	ColorPicker.prototype.inputChangeSaturation = function inputChangeSaturation(e) {
		var value = parseInt(e.target.value);
		this.color.setSaturation(value);
		e.target.value = this.color.saturation;
		this.updateSLV();
	};

	ColorPicker.prototype.inputChangeValue = function inputChangeValue(e) {
		var value = parseInt(e.target.value);
		this.color.setValue(value);
		e.target.value = this.color.value;
		this.updateSLV();
	};

	ColorPicker.prototype.inputChangeLightness = function inputChangeLightness(e) {
		var value = parseInt(e.target.value);
		this.color.setLightness(value);
		e.target.value = this.color.lightness;
		this.updateSLV();
	};

	ColorPicker.prototype.inputChangeRed = function inputChangeRed(e) {
		var value = parseInt(e.target.value);
		this.color.setByName('r', value);
		e.target.value = this.color.r;
		this.setColor(this.color);
	};

	ColorPicker.prototype.inputChangeGreen = function inputChangeGreen(e) {
		var value = parseInt(e.target.value);
		this.color.setByName('g', value);
		e.target.value = this.color.g;
		this.setColor(this.color);
	};

	ColorPicker.prototype.inputChangeBlue = function inputChangeBlue(e) {
		var value = parseInt(e.target.value);
		this.color.setByName('b', value);
		e.target.value = this.color.b;
		this.setColor(this.color);
	};

	ColorPicker.prototype.inputChangeAlpha = function inputChangeAlpha(e) {
		var value = parseFloat(e.target.value);

		if (typeof value === 'number' && isNaN(value) === false &&
			value >= 0 && value <= 1)
			this.color.a = value.toFixed(2);

		e.target.value = this.color.a;
		this.updateAlphaPicker();
	};

	ColorPicker.prototype.inputChangeHexa = function inputChangeHexa(e) {
		var value = e.target.value;
		this.color.setHexa(value);
		this.setColor(this.color);
	};

	/*************************************************************************/
	//							Internal Pub/Sub
	/*************************************************************************/

	ColorPicker.prototype.subscribe = function subscribe(topic, callback) {
		this.subscribers[topic] = callback;
	};

	ColorPicker.prototype.notify = function notify(topic, value) {
		if (this.subscribers[topic])
			this.subscribers[topic](value);
	};

	/*************************************************************************/
	//							Set Picker Properties
	/*************************************************************************/

	ColorPicker.prototype.setColor = function setColor(color) {
		if(color instanceof Color !== true) {
			console.log('Typeof parameter not Color');
			return;
		}

		if (color.format !== this.picker_mode) {
			color.setFormat(this.picker_mode);
			color.updateHSX();
		}

		this.color.copy(color);
		this.updateHuePicker();
		this.updatePickerPosition();
		this.updatePickerBackground();
		this.updateAlphaPicker();
		this.updateAlphaGradient();
		this.updatePreviewColor();

		this.notify('red', this.color.r);
		this.notify('green', this.color.g);
		this.notify('blue', this.color.b);

		this.notify('hue', this.color.hue);
		this.notify('saturation', this.color.saturation);
		this.notify('value', this.color.value);
		this.notify('lightness', this.color.lightness);

		this.notify('alpha', this.color.a);
		this.notify('hexa', this.color.getHexa());
		notify(this.topic, this.color);
	};

	ColorPicker.prototype.setPickerMode = function setPickerMode(mode) {
		if (mode !== 'HSV' && mode !== 'HSL')
			return;

		this.picker_mode = mode;
		this.node.setAttribute('data-mode', this.picker_mode);
		this.setColor(this.color);
	};

	/*************************************************************************/
	//								UNUSED
	/*************************************************************************/

	var setPickerMode = function setPickerMode(topic, mode) {
		if (pickers[topic])
			pickers[topic].setPickerMode(mode);
	};

	var setColor = function setColor(topic, color) {
		if (pickers[topic])
			pickers[topic].setColor(color);
	};

	var getColor = function getColor(topic) {
		if (pickers[topic])
			return new Color(pickers[topic].color);
	};

	var subscribe = function subscribe(topic, callback) {
		if (subscribers[topic] === undefined)
			subscribers[topic] = [];

		subscribers[topic].push(callback);
	};

	var unsubscribe = function unsubscribe(callback) {
		subscribers.indexOf(callback);
		subscribers.splice(index, 1);
	};

	var notify = function notify(topic, value) {
		if (subscribers[topic] === undefined || subscribers[topic].length === 0)
			return;

		var color = new Color(value);
		for (var i in subscribers[topic])
			subscribers[topic][i](color);
	};

	var init = function init() {
		var elem = document.querySelectorAll('.ui-color-picker');
		var size = elem.length;
		for (var i = 0; i < size; i++)
			new ColorPicker(elem[i]);
	};

	return {
		init : init,
		Color : Color,
		RGBColor : RGBColor,
		RGBAColor : RGBAColor,
		HSVColor : HSVColor,
		HSVAColor : HSVAColor,
		HSLColor : HSLColor,
		HSLAColor : HSLAColor,
		setColor : setColor,
		getColor : getColor,
		subscribe : subscribe,
		unsubscribe : unsubscribe,
		setPickerMode : setPickerMode
	};

})();



/**
 * UI-SlidersManager
 */

var InputSliderManager = (function InputSliderManager() {

	var subscribers = {};
	var sliders = [];

	var InputComponent = function InputComponent(obj) {
		var input = document.createElement('input');
		input.setAttribute('type', 'text');
		input.style.width = 50 + obj.precision * 10 + 'px';

		input.addEventListener('click', function(e) {
			this.select();
		});

		input.addEventListener('change', function(e) {
			var value = parseFloat(e.target.value);

			if (isNaN(value) === true)
				setValue(obj.topic, obj.value);
			else
				setValue(obj.topic, value);
		});

		return input;
	};

	var SliderComponent = function SliderComponent(obj, sign) {
		var slider = document.createElement('div');
		var startX = null;
		var start_value = 0;

		slider.addEventListener("click", function(e) {
			document.removeEventListener("mousemove", sliderMotion);
			setValue(obj.topic, obj.value + obj.step * sign);
		});

		slider.addEventListener("mousedown", function(e) {
			startX = e.clientX;
			start_value = obj.value;
			document.body.style.cursor = "e-resize";

			document.addEventListener("mouseup", slideEnd);
			document.addEventListener("mousemove", sliderMotion);
		});

		var slideEnd = function slideEnd(e) {
			document.removeEventListener("mousemove", sliderMotion);
			document.body.style.cursor = "auto";
			slider.style.cursor = "pointer";
		};

		var sliderMotion = function sliderMotion(e) {
			slider.style.cursor = "e-resize";
			var delta = (e.clientX - startX) / obj.sensivity | 0;
			var value = delta * obj.step + start_value;
			setValue(obj.topic, value);
		};

		return slider;
	};

	var InputSlider = function(node) {
		var min		= parseFloat(node.getAttribute('data-min'));
		var max		= parseFloat(node.getAttribute('data-max'));
		var step	= parseFloat(node.getAttribute('data-step'));
		var value	= parseFloat(node.getAttribute('data-value'));
		var topic	= node.getAttribute('data-topic');
		var unit	= node.getAttribute('data-unit');
		var name 	= node.getAttribute('data-info');
		var sensivity = node.getAttribute('data-sensivity') | 0;
		var precision = node.getAttribute('data-precision') | 0;

		this.min = isNaN(min) ? 0 : min;
		this.max = isNaN(max) ? 100 : max;
		this.precision = precision >= 0 ? precision : 0;
		this.step = step < 0 || isNaN(step) ? 1 : step.toFixed(precision);
		this.topic = topic;
		this.node = node;
		this.unit = unit === null ? '' : unit;
		this.sensivity = sensivity > 0 ? sensivity : 5;
		value = isNaN(value) ? this.min : value;

		var input = new InputComponent(this);
		var slider_left  = new SliderComponent(this, -1);
		var slider_right = new SliderComponent(this,  1);

		slider_left.className = 'ui-input-slider-left';
		slider_right.className = 'ui-input-slider-right';

		if (name) {
			var info = document.createElement('span');
			info.className = 'ui-input-slider-info';
			info.textContent = name;
			node.appendChild(info);
		}

		node.appendChild(slider_left);
		node.appendChild(input);
		node.appendChild(slider_right);

		this.input = input;
		sliders[topic] = this;
		setValue(topic, value);
	};

	InputSlider.prototype.setInputValue = function setInputValue() {
		this.input.value = this.value.toFixed(this.precision) + this.unit;
	};

	var setValue = function setValue(topic, value, send_notify) {
		var slider = sliders[topic];
		if (slider === undefined)
			return;

		value = parseFloat(value.toFixed(slider.precision));

		if (value > slider.max) value = slider.max;
		if (value < slider.min)	value = slider.min;

		slider.value = value;
		slider.node.setAttribute('data-value', value);

		slider.setInputValue();

		if (send_notify === false)
			return;

		notify.call(slider);
	};

	var setMax = function setMax(topic, value) {
		var slider = sliders[topic];
		if (slider === undefined)
			return;

		slider.max = value;
		setValue(topic, slider.value);
	};

	var setMin = function setMin(topic, value) {
		var slider = sliders[topic];
		if (slider === undefined)
			return;

		slider.min = value;
		setValue(topic, slider.value);
	};

	var setUnit = function setUnit(topic, unit) {
		var slider = sliders[topic];
		if (slider === undefined)
			return;

		slider.unit = unit;
		setValue(topic, slider.value);
	};

	var setStep = function setStep(topic, value) {
		var slider = sliders[topic];
		if (slider === undefined)
			return;

		slider.step = parseFloat(value);
		setValue(topic, slider.value);
	};

	var setPrecision = function setPrecision(topic, value) {
		var slider = sliders[topic];
		if (slider === undefined)
			return;

		value = value | 0;
		slider.precision = value;

		var step = parseFloat(slider.step.toFixed(value));
		if (step === 0)
			slider.step = 1 / Math.pow(10, value);

		setValue(topic, slider.value);
	};

	var setSensivity = function setSensivity(topic, value) {
		var slider = sliders[topic];
		if (slider === undefined)
			return;

		value = value | 0;

		slider.sensivity = value > 0 ? value : 5;
	};

	var getNode =  function getNode(topic) {
		return sliders[topic].node;
	};

	var getPrecision =  function getPrecision(topic) {
		return sliders[topic].precision;
	};

	var getStep =  function getStep(topic) {
		return sliders[topic].step;
	};

	var subscribe = function subscribe(topic, callback) {
		if (subscribers[topic] === undefined)
			subscribers[topic] = [];
		subscribers[topic].push(callback);
	};

	var unsubscribe = function unsubscribe(topic, callback) {
		subscribers[topic].indexOf(callback);
		subscribers[topic].splice(index, 1);
	};

	var notify = function notify() {
		if (subscribers[this.topic] === undefined)
			return;
		for (var i = 0; i < subscribers[this.topic].length; i++)
			subscribers[this.topic][i](this.value);
	};

	var createSlider = function createSlider(topic, label) {
		var slider = document.createElement('div');
		slider.className = 'ui-input-slider';
		slider.setAttribute('data-topic', topic);

		if (label !== undefined)
			slider.setAttribute('data-info', label);

		new InputSlider(slider);
		return slider;
	};

	var init = function init() {
		var elem = document.querySelectorAll('.ui-input-slider');
		var size = elem.length;
		for (var i = 0; i < size; i++)
			new InputSlider(elem[i]);
	};

	return {
		init : init,
		setMax : setMax,
		setMin : setMin,
		setUnit : setUnit,
		setStep : setStep,
		getNode : getNode,
		getStep : getStep,
		setValue : setValue,
		subscribe : subscribe,
		unsubscribe : unsubscribe,
		setPrecision : setPrecision,
		setSensivity : setSensivity,
		getPrecision : getPrecision,
		createSlider : createSlider,
	};

})();


'use strict';

window.addEventListener("load", function() {
	ColorPickerTool.init();
});

var ColorPickerTool = (function ColorPickerTool() {

	/*========== Get DOM Element By ID ==========*/

	function getElemById(id) {
		return document.getElementById(id);
	}

	function allowDropEvent(e) {
		e.preventDefault();
	}

	/*========== Make an element resizable relative to it's parent ==========*/

	var UIComponent = (function UIComponent() {

		function makeResizable(elem, axis) {
			var valueX = 0;
			var valueY = 0;
			var action = 0;

			var resizeStart = function resizeStart(e) {
				e.stopPropagation();
				e.preventDefault();
				if (e.button !== 0)
					return;

				valueX = e.clientX - elem.clientWidth;
				valueY = e.clientY - elem.clientHeight;

				document.body.setAttribute('data-resize', axis);
				document.addEventListener('mousemove', mouseMove);
				document.addEventListener('mouseup', resizeEnd);
			};

			var mouseMove = function mouseMove(e) {
				if (action >= 0)
					elem.style.width = e.clientX - valueX + 'px';
				if (action <= 0)
					elem.style.height = e.clientY - valueY + 'px';
			};

			var resizeEnd = function resizeEnd(e) {
				if (e.button !== 0)
					return;

				document.body.removeAttribute('data-resize', axis);
				document.removeEventListener('mousemove', mouseMove);
				document.removeEventListener('mouseup', resizeEnd);
			};

			var handle = document.createElement('div');
			handle.className = 'resize-handle';

			if (axis === 'width') action = 1;
			else if (axis === 'height') action = -1;
			else axis = 'both';

			handle.className = 'resize-handle';
			handle.setAttribute('data-resize', axis);
			handle.addEventListener('mousedown', resizeStart);
			elem.appendChild(handle);
		};

		/*========== Make an element draggable relative to it's parent ==========*/

		var makeDraggable = function makeDraggable(elem, endFunction) {

			var offsetTop;
			var offsetLeft;

			elem.setAttribute('data-draggable', 'true');

			var dragStart = function dragStart(e) {
				e.preventDefault();
				e.stopPropagation();

				if (e.target.getAttribute('data-draggable') !== 'true' ||
					e.target !== elem || e.button !== 0)
					return;

				offsetLeft = e.clientX - elem.offsetLeft;
				offsetTop = e.clientY - elem.offsetTop;

				document.addEventListener('mousemove', mouseDrag);
				document.addEventListener('mouseup', dragEnd);
			};

			var dragEnd = function dragEnd(e) {
				if (e.button !== 0)
					return;

				document.removeEventListener('mousemove', mouseDrag);
				document.removeEventListener('mouseup', dragEnd);
			};

			var mouseDrag = function mouseDrag(e) {
				elem.style.left = e.clientX - offsetLeft + 'px';
				elem.style.top = e.clientY - offsetTop + 'px';
			};

			elem.addEventListener('mousedown', dragStart, false);
		};

		return {
			makeResizable : makeResizable,
			makeDraggable : makeDraggable
		};

	})();

	/*========== Color Class ==========*/

	var Color = UIColorPicker.Color;
	var HSLColor = UIColorPicker.HSLColor;

	/**
	 * ColorPalette
	 */
	var ColorPalette = (function ColorPalette() {

		var samples = [];
		var color_palette;
		var complementary;

		var hideNode = function(node) {
			node.setAttribute('data-hidden', 'true');
		};

		var ColorSample = function ColorSample(id) {
			var node = document.createElement('div');
			node.className = 'sample';

			this.uid = samples.length;
			this.node = node;
			this.color = new Color();

			node.setAttribute('sample-id', this.uid);
			node.setAttribute('draggable', 'true');
			node.addEventListener('dragstart', this.dragStart.bind(this));
			node.addEventListener('click', this.pickColor.bind(this));

			samples.push(this);
		};

		ColorSample.prototype.updateBgColor = function updateBgColor() {
			this.node.style.backgroundColor = this.color.getColor();
		};

		ColorSample.prototype.updateColor = function updateColor(color) {
			this.color.copy(color);
			this.updateBgColor();
		};

		ColorSample.prototype.updateHue = function updateHue(color, degree, steps) {
			this.color.copy(color);
			var hue = (steps * degree + this.color.hue) % 360;
			if (hue < 0) hue += 360;
			this.color.setHue(hue);
			this.updateBgColor();
		};

		ColorSample.prototype.updateSaturation = function updateSaturation(color, value, steps) {
			var saturation = color.saturation + value * steps;
			if (saturation <= 0) {
				this.node.setAttribute('data-hidden', 'true');
				return;
			}

			this.node.removeAttribute('data-hidden');
			this.color.copy(color);
			this.color.setSaturation(saturation);
			this.updateBgColor();
		};

		ColorSample.prototype.updateLightness = function updateLightness(color, value, steps) {
			var lightness = color.lightness + value * steps;
			if (lightness <= 0) {
				this.node.setAttribute('data-hidden', 'true');
				return;
			}
			this.node.removeAttribute('data-hidden');
			this.color.copy(color);
			this.color.setLightness(lightness);
			this.updateBgColor();
		};

		ColorSample.prototype.updateBrightness = function updateBrightness(color, value, steps) {
			var brightness = color.value + value * steps;
			if (brightness <= 0) {
				this.node.setAttribute('data-hidden', 'true');
				return;
			}
			this.node.removeAttribute('data-hidden');
			this.color.copy(color);
			this.color.setValue(brightness);
			this.updateBgColor();
		};

		ColorSample.prototype.updateAlpha = function updateAlpha(color, value, steps) {
			var alpha = parseFloat(color.a) + value * steps;
			if (alpha <= 0) {
				this.node.setAttribute('data-hidden', 'true');
				return;
			}
			this.node.removeAttribute('data-hidden');
			this.color.copy(color);
			this.color.a = parseFloat(alpha.toFixed(2));
			this.updateBgColor();
		};

		ColorSample.prototype.pickColor = function pickColor() {
			UIColorPicker.setColor('picker', this.color);
		};

		ColorSample.prototype.dragStart = function dragStart(e) {
			e.dataTransfer.setData('sampleID', this.uid);
			e.dataTransfer.setData('location', 'palette-samples');
		};

		var Palette = function Palette(text, size) {
			this.samples = [];
			this.locked = false;

			var palette = document.createElement('div');
			var title = document.createElement('div');
			var controls = document.createElement('div');
			var container = document.createElement('div');
			var lock = document.createElement('div');

			container.className = 'container';
			title.className = 'title';
			palette.className = 'palette';
			controls.className = 'controls';
			lock.className = 'lock';
			title.textContent = text;

			controls.appendChild(lock);
			container.appendChild(title);
			container.appendChild(controls);
			container.appendChild(palette);

			lock.addEventListener('click', function () {
				this.locked = !this.locked;
				lock.setAttribute('locked-state', this.locked);
			}.bind(this));

			for(var i = 0; i < size; i++) {
				var sample = new ColorSample();
				this.samples.push(sample);
				palette.appendChild(sample.node);
			}

			this.container = container;
			this.title = title;
		};

		var createHuePalette = function createHuePalette() {
			var palette = new Palette('Hue', 12);

			UIColorPicker.subscribe('picker', function(color) {
				if (palette.locked === true)
					return;

				for(var i = 0; i < 12; i++) {
					palette.samples[i].updateHue(color, 30, i);
				}
			});

			color_palette.appendChild(palette.container);
		};

		var createSaturationPalette = function createSaturationPalette() {
			var palette = new Palette('Saturation', 11);

			UIColorPicker.subscribe('picker', function(color) {
				if (palette.locked === true)
					return;

				for(var i = 0; i < 11; i++) {
					palette.samples[i].updateSaturation(color, -10, i);
				}
			});

			color_palette.appendChild(palette.container);
		};

		/* Brightness or Lightness - depends on the picker mode */
		var createVLPalette = function createSaturationPalette() {
			var palette = new Palette('Lightness', 11);

			UIColorPicker.subscribe('picker', function(color) {
				if (palette.locked === true)
					return;

				if(color.format === 'HSL') {
					for(var i = 0; i < 11; i++)
						palette.samples[i].updateLightness(color, -10, i);
				}
				else {
					for(var i = 0; i < 11; i++)
						palette.samples[i].updateBrightness(color, -10, i);
				}
			});

			color_palette.appendChild(palette.container);
		};

		var isBlankPalette = function isBlankPalette(container, value) {
			if (value === 0) {
				container.setAttribute('data-collapsed', 'true');
				return true;
			}

			container.removeAttribute('data-collapsed');
			return false;
		};

		var createAlphaPalette = function createAlphaPalette() {
			var palette = new Palette('Alpha', 10);

			UIColorPicker.subscribe('picker', function(color) {
				if (palette.locked === true)
					return;

				for(var i = 0; i < 10; i++) {
					palette.samples[i].updateAlpha(color, -0.1, i);
				}
			});

			color_palette.appendChild(palette.container);
		};

		var getSampleColor = function getSampleColor(id) {
			if (samples[id] !== undefined && samples[id]!== null)
				return new Color(samples[id].color);
		};

		var init = function init() {
			color_palette = getElemById('color-palette');

			createHuePalette();
			createSaturationPalette();
			createVLPalette();
			createAlphaPalette();

		};

		return {
			init : init,
			getSampleColor : getSampleColor
		};

	})();

	/**
	 * ColorInfo
	 */
	var ColorInfo = (function ColorInfo() {

		var info_box;
		var select;
		var RGBA;
		var HEXA;
		var HSLA;

		var updateInfo = function updateInfo(color) {
			if (color.a | 0 === 1) {
				RGBA.info.textContent = 'RGB';
				HSLA.info.textContent = 'HSL';
			}
			else {
				RGBA.info.textContent = 'RGBA';
				HSLA.info.textContent = 'HSLA';
			}

			RGBA.value.value = color.getRGBA();
			HSLA.value.value = color.getHSLA();
			HEXA.value.value = color.getHexa();
		};

		var InfoProperty = function InfoProperty(info) {

			var node = document.createElement('div');
			var title = document.createElement('div');
			var value = document.createElement('input');
			var copy = document.createElement('div');

			node.className = 'property';
			title.className = 'type';
			value.className = 'value';
			copy.className = 'copy';

			title.textContent = info;
			value.setAttribute('type', 'text');

			copy.addEventListener('click', function() {
				value.select();
			});

			node.appendChild(title);
			node.appendChild(value);
			node.appendChild(copy);

			this.node = node;
			this.value = value;
			this.info = title;

			info_box.appendChild(node);
		};

		var init = function init() {

			info_box = getElemById('color-info');

			RGBA = new InfoProperty('RGBA');
			HSLA = new InfoProperty('HSLA');
			HEXA = new InfoProperty('HEXA');

			UIColorPicker.subscribe('picker', updateInfo);

		};

		return {
			init: init
		};

	})();

	/**
	 * ColorPicker Samples
	 */
	var ColorPickerSamples = (function ColorPickerSamples() {

		var samples = [];
		var nr_samples = 0;
		var active = null;
		var container = null;
		var	samples_per_line = 10;
		var trash_can = null;
		var base_color = new HSLColor(0, 50, 100);
		var add_btn;
		var add_btn_pos;

		var ColorSample = function ColorSample() {
			var node = document.createElement('div');
			node.className = 'sample';

			this.uid = samples.length;
			this.index = nr_samples++;
			this.node = node;
			this.color = new Color(base_color);

			node.setAttribute('sample-id', this.uid);
			node.setAttribute('draggable', 'true');

			node.addEventListener('dragstart', this.dragStart.bind(this));
			node.addEventListener('dragover' , allowDropEvent);
			node.addEventListener('drop'     , this.dragDrop.bind(this));

			this.updatePosition(this.index);
			this.updateBgColor();
			samples.push(this);
		};

		ColorSample.prototype.updateBgColor = function updateBgColor() {
			this.node.style.backgroundColor = this.color.getColor();
		};

		ColorSample.prototype.updatePosition = function updatePosition(index) {
			this.index = index;
			this.posY = 5 + ((index / samples_per_line) | 0) * 52;
			this.posX = 5 + ((index % samples_per_line) | 0) * 52;
			this.node.style.top  = this.posY + 'px';
			this.node.style.left = this.posX + 'px';
		};

		ColorSample.prototype.updateColor = function updateColor(color) {
			this.color.copy(color);
			this.updateBgColor();
		};

		ColorSample.prototype.activate = function activate() {
			UIColorPicker.setColor('picker', this.color);
			this.node.setAttribute('data-active', 'true');
		};

		ColorSample.prototype.deactivate = function deactivate() {
			this.node.removeAttribute('data-active');
		};

		ColorSample.prototype.dragStart = function dragStart(e) {
			e.dataTransfer.setData('sampleID', this.uid);
			e.dataTransfer.setData('location', 'picker-samples');
		};

		ColorSample.prototype.dragDrop = function dragDrop(e) {
			e.stopPropagation();
			this.color = Tool.getSampleColorFrom(e);
			this.updateBgColor();
		};

		ColorSample.prototype.deleteSample = function deleteSample() {
			container.removeChild(this.node);
			samples[this.uid] = null;
			nr_samples--;
		};

		var updateUI = function updateUI() {
			updateContainerProp();

			var index = 0;
			var nr = samples.length;
			for (var i=0; i < nr; i++)
				if (samples[i] !== null) {
					samples[i].updatePosition(index);
					index++;
				}

			AddSampleButton.updatePosition(index);
		};

		var deleteSample = function deleteSample(e) {
			trash_can.parentElement.setAttribute('drag-state', 'none');

			var location = e.dataTransfer.getData('location');
			if (location !== 'picker-samples')
				return;

			var sampleID = e.dataTransfer.getData('sampleID');
			samples[sampleID].deleteSample();
			console.log(samples);

			updateUI();
		};

		var createDropSample = function createDropSample() {
			var sample = document.createElement('div');
			sample.id = 'drop-effect-sample';
			sample.className = 'sample';
			container.appendChild(sample);
		};

		var setActivateSample = function setActivateSample(e) {
			if (e.target.className !== 'sample')
				return;

			unsetActiveSample(active);
			Tool.unsetVoidSample();
			CanvasSamples.unsetActiveSample();
			active = samples[e.target.getAttribute('sample-id')];
			active.activate();
		};

		var unsetActiveSample = function unsetActiveSample() {
			if (active)
				active.deactivate();
			active = null;
		};

		var getSampleColor = function getSampleColor(id) {
			if (samples[id] !== undefined && samples[id]!== null)
				return new Color(samples[id].color);
		};

		var updateContainerProp = function updateContainerProp() {
			samples_per_line = ((container.clientWidth - 5) / 52) | 0;
			var height = 52 * (1 + (nr_samples / samples_per_line) | 0);
			container.style.height = height + 10 + 'px';
		};

		var AddSampleButton = (function AddSampleButton() {
			var node;
			var _index = 0;
			var _posX;
			var _posY;

			var updatePosition = function updatePosition(index) {
				_index = index;
				_posY = 5 + ((index / samples_per_line) | 0) * 52;
				_posX = 5 + ((index % samples_per_line) | 0) * 52;

				node.style.top  = _posY + 'px';
				node.style.left = _posX + 'px';
			};

			var addButtonClick = function addButtonClick() {
				var sample = new ColorSample();
				container.appendChild(sample.node);
				updatePosition(_index + 1);
				updateUI();
			};

			var init = function init() {
				node = document.createElement('div');
				var icon = document.createElement('div');

				node.className = 'sample';
				icon.id = 'add-icon';
				node.appendChild(icon);
				node.addEventListener('click', addButtonClick);

				updatePosition(0);
				container.appendChild(node);
			};

			return {
				init : init,
				updatePosition : updatePosition
			};
		})();

		var init = function init() {
			container = getElemById('picker-samples');
			trash_can = getElemById('trash-can');

			AddSampleButton.init();

			for (var i=0; i<16; i++) {
				var sample = new ColorSample();
				container.appendChild(sample.node);
			}

			AddSampleButton.updatePosition(samples.length);
			updateUI();

			active = samples[0];
			active.activate();

			container.addEventListener('click', setActivateSample);

			trash_can.addEventListener('dragover', allowDropEvent);
			trash_can.addEventListener('dragenter', function() {
				this.parentElement.setAttribute('drag-state', 'enter');
			});
			trash_can.addEventListener('dragleave', function(e) {
				this.parentElement.setAttribute('drag-state', 'none');
			});
			trash_can.addEventListener('drop', deleteSample);

			UIColorPicker.subscribe('picker', function(color) {
				if (active)
					active.updateColor(color);
			});

		};

		return {
			init : init,
			getSampleColor : getSampleColor,
			unsetActiveSample : unsetActiveSample
		};

	})();

	/**
	 * Canvas Samples
	 */
	var CanvasSamples = (function CanvasSamples() {

		var active = null;
		var canvas = null;
		var samples = [];
		var zindex = null;
		var tutorial = true;

		var CanvasSample = function CanvasSample(color, posX, posY) {

			var node = document.createElement('div');
			var pick = document.createElement('div');
			var delete_btn = document.createElement('div');
			node.className = 'sample';
			pick.className = 'pick';
			delete_btn.className = 'delete';

			this.uid = samples.length;
			this.node = node;
			this.color = color;
			this.updateBgColor();
			this.zIndex = 1;

			node.style.top = posY - 50 + 'px';
			node.style.left = posX - 50 + 'px';
			node.setAttribute('sample-id', this.uid);

			node.appendChild(pick);
			node.appendChild(delete_btn);

			var activate = function activate() {
				setActiveSample(this);
			}.bind(this);

			node.addEventListener('dblclick', activate);
			pick.addEventListener('click', activate);
			delete_btn.addEventListener('click', this.deleteSample.bind(this));

			UIComponent.makeDraggable(node);
			UIComponent.makeResizable(node);

			samples.push(this);
			canvas.appendChild(node);
			return this;
		};

		CanvasSample.prototype.updateBgColor = function updateBgColor() {
			this.node.style.backgroundColor = this.color.getColor();
		};

		CanvasSample.prototype.updateColor = function updateColor(color) {
			this.color.copy(color);
			this.updateBgColor();
		};

		CanvasSample.prototype.updateZIndex = function updateZIndex(value) {
			this.zIndex = value;
			this.node.style.zIndex = value;
		};

		CanvasSample.prototype.activate = function activate() {
			this.node.setAttribute('data-active', 'true');
			zindex.setAttribute('data-active', 'true');

			UIColorPicker.setColor('picker', this.color);
			InputSliderManager.setValue('z-index', this.zIndex);
		};

		CanvasSample.prototype.deactivate = function deactivate() {
			this.node.removeAttribute('data-active');
			zindex.removeAttribute('data-active');
		};

		CanvasSample.prototype.deleteSample = function deleteSample() {
			if (active === this)
				unsetActiveSample();
			canvas.removeChild(this.node);
			samples[this.uid] = null;
		};

		CanvasSample.prototype.updatePosition = function updatePosition(posX, posY) {
			this.node.style.top = posY - this.startY + 'px';
			this.node.style.left = posX - this.startX + 'px';
		};

		var canvasDropEvent = function canvasDropEvent(e) {
			var color = Tool.getSampleColorFrom(e);

			if (color) {
				var offsetX = e.pageX - canvas.offsetLeft;
				var offsetY = e.pageY - canvas.offsetTop;
				var sample = new CanvasSample(color, offsetX, offsetY);
				if (tutorial) {
					tutorial = false;
					canvas.removeAttribute('data-tutorial');
					var info = new CanvasSample(new Color(), 100, 100);
					info.node.setAttribute('data-tutorial', 'dblclick');
				}
			}

		};

		var setActiveSample = function setActiveSample(sample) {
			ColorPickerSamples.unsetActiveSample();
			Tool.unsetVoidSample();
			unsetActiveSample();
			active = sample;
			active.activate();
		};

		var unsetActiveSample = function unsetActiveSample() {
			if (active)
				active.deactivate();
			active = null;
		};

		var createToggleBgButton = function createToggleBgButton() {
			var button = document.createElement('div');
			var state = false;
			button.className = 'toggle-bg';
			canvas.appendChild(button);

			button.addEventListener('click', function() {
				console.log(state);
				state = !state;
				canvas.setAttribute('data-bg', state);
			});
		};

		var init = function init() {
			canvas = getElemById('canvas');
			zindex = getElemById('zindex');

			canvas.addEventListener('dragover', allowDropEvent);
			canvas.addEventListener('drop', canvasDropEvent);

			createToggleBgButton();

			UIColorPicker.subscribe('picker', function(color) {
				if (active)	active.updateColor(color);
			});

			InputSliderManager.subscribe('z-index', function (value) {
				if (active)	active.updateZIndex(value);
			});

			UIComponent.makeResizable(canvas, 'height');
		};

		return {
			init : init,
			unsetActiveSample : unsetActiveSample
		};

	})();

	var StateButton = function StateButton(node, state) {
		this.state = false;
		this.callback = null;

		node.addEventListener('click', function() {
			this.state = !this.state;
			if (typeof this.callback === "function")
				this.callback(this.state);
		}.bind(this));
	};

	StateButton.prototype.set = function set() {
		this.state = true;
		if (typeof this.callback === "function")
			this.callback(this.state);
	};

	StateButton.prototype.unset = function unset() {
		this.state = false;
		if (typeof this.callback === "function")
			this.callback(this.state);
	};

	StateButton.prototype.subscribe = function subscribe(func) {
		this.callback = func;
	};


	/**
	 * Tool
	 */
	var Tool = (function Tool() {

		var samples = [];
		var controls = null;
		var void_sw;

		var createPickerModeSwitch = function createPickerModeSwitch() {
			var parent = getElemById('controls');
			var icon = document.createElement('div');
			var button = document.createElement('div');
			var hsv = document.createElement('div');
			var hsl = document.createElement('div');
			var active = null;

			icon.className = 'icon picker-icon';
			button.className = 'switch';
			button.appendChild(hsv);
			button.appendChild(hsl);

			hsv.textContent = 'HSV';
			hsl.textContent = 'HSL';

			active = hsl;
			active.setAttribute('data-active', 'true');

			function switchPickingModeTo(elem) {
				active.removeAttribute('data-active');
				active = elem;
				active.setAttribute('data-active', 'true');
				UIColorPicker.setPickerMode('picker', active.textContent);
			};

			var picker_sw = new StateButton(icon);
			picker_sw.subscribe(function() {
				if (active === hsv)
					switchPickingModeTo(hsl);
				else
					switchPickingModeTo(hsv);
			});

			hsv.addEventListener('click', function() {
				switchPickingModeTo(hsv);
			});
			hsl.addEventListener('click', function() {
				switchPickingModeTo(hsl);
			});

			parent.appendChild(icon);
			parent.appendChild(button);
		};

		var setPickerDragAndDrop = function setPickerDragAndDrop() {
			var preview = document.querySelector('#picker .preview-color');
			var picking_area = document.querySelector('#picker .picking-area');

			preview.setAttribute('draggable', 'true');
			preview.addEventListener('drop', drop);
			preview.addEventListener('dragstart', dragStart);
			preview.addEventListener('dragover', allowDropEvent);

			picking_area.addEventListener('drop', drop);
			picking_area.addEventListener('dragover', allowDropEvent);

			function drop(e) {
				var color = getSampleColorFrom(e);
				UIColorPicker.setColor('picker', color);
			};

			function dragStart(e) {
				e.dataTransfer.setData('sampleID', 'picker');
				e.dataTransfer.setData('location', 'picker');
			};
		};

		var getSampleColorFrom = function getSampleColorFrom(e) {
			var sampleID = e.dataTransfer.getData('sampleID');
			var location = e.dataTransfer.getData('location');

			if (location === 'picker')
				return UIColorPicker.getColor(sampleID);
			if (location === 'picker-samples')
				return ColorPickerSamples.getSampleColor(sampleID);
			if (location === 'palette-samples')
				return ColorPalette.getSampleColor(sampleID);
		};

		var setVoidSwitch = function setVoidSwitch() {
			var void_sample = getElemById('void-sample');
			void_sw = new StateButton(void_sample);
			void_sw.subscribe( function (state) {
				void_sample.setAttribute('data-active', state);
				if (state === true) {
					ColorPickerSamples.unsetActiveSample();
					CanvasSamples.unsetActiveSample();
				}
			});
		};

		var unsetVoidSample = function unsetVoidSample() {
			void_sw.unset();
		};

		var init = function init() {
			controls = getElemById('controls');

			var color = new Color();
			color.setHSL(0, 51, 51);
			UIColorPicker.setColor('picker', color);

			setPickerDragAndDrop();
			createPickerModeSwitch();
			setVoidSwitch();
		};

		return {
			init : init,
			unsetVoidSample : unsetVoidSample,
			getSampleColorFrom : getSampleColorFrom
		};

	})();

	var init = function init() {
		UIColorPicker.init();
		InputSliderManager.init();
		ColorInfo.init();
		ColorPalette.init();
		ColorPickerSamples.init();
		CanvasSamples.init();
		Tool.init();
	};

	return {
		init : init
	};

})();

This tool lets you define custom web colors.

The tool also provides an easy conversion between varius CSS color formats: HEXA colors, RGB (Red Green Blue) and HSL (Hue Staturation Lightness). Alpha channel is also supported on RGB (rgba) and HSL (hsla) formats.

Each color is preseted in all 3 standard web CSS formats.

Based on the current color a color palette for Hue, Staturation, Lightness/Brightness and Alpha will be generated.

The picker can be set to HSL or HSV (hue, staturation, value) format.

{{ EmbedLiveSample('ColorPIcker_Tool', '100%', '900') }}

 

Fonte da revisão

<!-- WRAPPER - DISPLAY STATE -->
<div style="display: none;">
  <h2 id="ColorPIcker_Tool" name="ColorPIcker_Tool">ColorPIcker Tool</h2>
  <h3 id="HTML_Content">HTML Content</h3>
  <pre class="brush: html">
&nbsp;&nbsp;&nbsp; &lt;div id="container"&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="palette" class="block"&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="color-palette"&gt;&lt;/div&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="color-info"&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div class="title"&gt; CSS Color &lt;/div&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;

&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="picker" class="block"&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div class="ui-color-picker" data-topic="picker" data-mode="HSL"&gt;&lt;/div&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="picker-samples" sample-id="master"&gt;&lt;/div&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="controls"&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="delete"&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="trash-can"&gt;&lt;/div&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="void-sample" class="icon"&gt;&lt;/div&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;

&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="canvas" data-tutorial="drop"&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;div id="zindex" class="ui-input-slider" data-topic="z-index" data-info="z-index"
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;data-max="20" data-sensivity="10"&gt;&lt;/div&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/div&gt;
&nbsp;&nbsp; &nbsp;&lt;/div&gt;

</pre>
  <h3 id="CSS_Content">CSS Content</h3>
  <pre class="brush: css">
/*
 * COLOR PICKER TOOL
 */

.ui-color-picker {
	width: 420px;
	margin: 0;
	border: 1px solid #DDD;
	background-color: #FFF;
	display: table;

	-moz-user-select: none;
	-webkit-user-select: none;
	-ms-user-select: none;
	user-select: none;
}

.ui-color-picker .picking-area {
	width: 198px;
	height: 198px;
	margin: 5px;
	border: 1px solid #DDD;
	position: relative;
	float: left;
	display: table;
}

.ui-color-picker .picking-area:hover {
	cursor: default;
}

/* HSV format - Hue-Saturation-Value(Brightness) */
.ui-color-picker .picking-area {
	background: url('https://mdn.mozillademos.org/files/5707/picker_mask_200.png') center center;

	background: -moz-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%),
				-moz-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%);
	background: -webkit-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%),
				-webkit-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%);
	background: -ms-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%),
				-ms-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%);
	background: -o-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%),
				-o-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%);

	background-color: #F00;
}

/* HSL format - Hue-Saturation-Lightness */
.ui-color-picker[data-mode='HSL'] .picking-area {
	background: -moz-linear-gradient(top, hsl(0, 0%, 100%) 0%, hsla(0, 0%, 100%, 0) 50%,
									hsla(0, 0%, 0%, 0) 50%, hsl(0, 0%, 0%) 100%),
				-moz-linear-gradient(left, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%);
	background: -webkit-linear-gradient(top, hsl(0, 0%, 100%) 0%, hsla(0, 0%, 100%, 0) 50%,
									hsla(0, 0%, 0%, 0) 50%, hsl(0, 0%, 0%) 100%),
				-webkit-linear-gradient(left, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%);
	background: -ms-linear-gradient(top, hsl(0, 0%, 100%) 0%, hsla(0, 0%, 100%, 0) 50%,
									hsla(0, 0%, 0%, 0) 50%, hsl(0, 0%, 0%) 100%),
				-ms-linear-gradient(left, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%);
	background: -o-linear-gradient(top, hsl(0, 0%, 100%) 0%, hsla(0, 0%, 100%, 0) 50%,
									hsla(0, 0%, 0%, 0) 50%, hsl(0, 0%, 0%) 100%),
				-o-linear-gradient(left, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%);
	background-color: #F00;
}

.ui-color-picker .picker {
	width: 10px;
	height: 10px;
	border-radius: 50%;
	border: 1px solid #FFF;
	position: absolute;
	top: 45%;
	left: 45%;
}

.ui-color-picker .picker:before {
	width: 8px;
	height: 8px;
	content: "";
	position: absolute;
	border: 1px solid #999;
	border-radius: 50%;
}

.ui-color-picker .hue,
.ui-color-picker .alpha {
	width: 198px;
	height: 28px;
	margin: 5px;
	border: 1px solid #FFF;
	float: left;
}

.ui-color-picker .hue {
	background: url("https://mdn.mozillademos.org/files/5701/hue.png") center;
	background: -moz-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%,
				#00F 66.66%, #F0F 83.33%, #F00 100%);
	background: -webkit-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%,
				#00F 66.66%, #F0F 83.33%, #F00 100%);
	background: -ms-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%,
				#00F 66.66%, #F0F 83.33%, #F00 100%);
	background: -o-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%,
				#00F 66.66%, #F0F 83.33%, #F00 100%);
}

.ui-color-picker .alpha {
	border: 1px solid #CCC;
	background: url("https://mdn.mozillademos.org/files/5705/alpha.png");
}

.ui-color-picker .alpha-mask {
	width: 100%;
	height: 100%;
	background: url("https://mdn.mozillademos.org/files/6089/alpha_mask.png");
}

.ui-color-picker .slider-picker {
	width: 2px;
	height: 100%;
	border: 1px solid #777;
	background-color: #FFF;
	position: relative;
	top: -1px;
}

/* input HSV and RGB */

.ui-color-picker .info {
	width: 200px;
	margin: 5px;
	float: left;
}

.ui-color-picker .info * {
	float: left;
}

.ui-color-picker .input {
	width: 64px;
	margin: 5px 2px;
	float: left;
}

.ui-color-picker .input .name {
	height: 20px;
	width: 30px;
	text-align: center;
	font-size: 14px;
	line-height: 18px;
	float: left;
}

.ui-color-picker .input input {
	width: 30px;
	height: 18px;
	margin: 0;
	padding: 0;
	border: 1px solid #DDD;
	text-align: center;
	float: right;

	-moz-user-select: text;
	-webkit-user-select: text;
	-ms-user-select: text;
}

.ui-color-picker .input[data-topic="lightness"] {
	display: none;
}

.ui-color-picker[data-mode='HSL'] .input[data-topic="value"] {
	display: none;
}

.ui-color-picker[data-mode='HSL'] .input[data-topic="lightness"] {
	display: block;
}

.ui-color-picker .input[data-topic="alpha"] {
	margin-top: 10px;
	width: 93px;
}

.ui-color-picker .input[data-topic="alpha"] &gt; .name {
	width: 60px;
}

.ui-color-picker .input[data-topic="alpha"] &gt; input {
	float: right;
}

.ui-color-picker .input[data-topic="hexa"] {
	width: auto;
	float: right;
	margin: 6px 8px 0 0;
}

.ui-color-picker .input[data-topic="hexa"] &gt; .name {
	display: none;
}

.ui-color-picker .input[data-topic="hexa"] &gt; input {
	width: 90px;
	height: 24px;
	padding: 2px 0;
	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}

/* Preview color */
.ui-color-picker .preview {
	width: 95px;
	height: 53px;
	margin: 5px;
	margin-top: 10px;
	border: 1px solid #DDD;
	background-image: url("https://mdn.mozillademos.org/files/5705/alpha.png");
	float: left;
	position: relative;
}

.ui-color-picker .preview:before {
	height: 100%;
	width: 50%;
	left: 50%;
	top: 0;
	content: "";
	background: #FFF;
	position: absolute;
	z-index: 1;
}

.ui-color-picker .preview-color {
	width: 100%;
	height: 100%;
	background-color: rgba(255, 0, 0, 0.5);
	position: absolute;
	z-index: 1;
}

.ui-color-picker .switch_mode {
	width: 10px;
	height: 20px;
	position: relative;
	border-radius: 5px 0 0 5px;
	border: 1px solid #DDD;
	background-color: #EEE;
	left: -12px;
	top: -1px;
	z-index: 1;
	transition: all 0.5s;
}

.ui-color-picker .switch_mode:hover {
	background-color: #CCC;
	cursor: pointer;
}

/*
 * UI Component
 */

.ui-input-slider {
	height: 20px;
	font-family: "Segoe UI", Arial, Helvetica, sans-serif;
	-moz-user-select: none;
	user-select: none;
}

.ui-input-slider * {
	float: left;
	height: 100%;
	line-height: 100%;
}

/* Input Slider */

.ui-input-slider &gt; input {
	margin: 0;
	padding: 0;
	width: 50px;
	text-align: center;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}

.ui-input-slider-info {
	width: 90px;
	padding: 0px 10px 0px 0px;
	text-align: right;
	text-transform: lowercase;
}

.ui-input-slider-left, .ui-input-slider-right {
	width: 16px;
	cursor: pointer;
	background: url("https://mdn.mozillademos.org/files/5679/arrows.png") center left no-repeat;
}

.ui-input-slider-right {
	background: url("https://mdn.mozillademos.org/files/5679/arrows.png") center right no-repeat;
}

.ui-input-slider-name {
	width: 90px;
	padding: 0 10px 0 0;
	text-align: right;
	text-transform: lowercase;
}

.ui-input-slider-btn-set {
	width: 25px;
	background-color: #2C9FC9;
	border-radius: 5px;
	color: #FFF;
	font-weight: bold;
	line-height: 14px;
	text-align: center;
}

.ui-input-slider-btn-set:hover {
	background-color: #379B4A;
	cursor: pointer;
}

/*
 * COLOR PICKER TOOL
 */

body {
	max-width: 1000px;
	margin: 0 auto;

	font-family: "Segoe UI", Arial, Helvetica, sans-serif;

	box-shadow: 0 0 5px 0 #999;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;

	-moz-user-select: none;
	-webkit-user-select: none;
	-ms-user-select: none;
	user-select: none;

}

/**
 * Resize Handle
 */
.resize-handle {
	width: 10px;
	height: 10px;
	background: url('https://mdn.mozillademos.org/files/6083/resize.png') center center no-repeat;
	position: absolute;
	bottom: 0;
	right: 0;
}

[data-resize='both']:hover {
	cursor: nw-resize !important;
}

[data-resize='width']:hover {
	cursor: w-resize !important;
}

[data-resize='height']:hover {
	cursor: n-resize !important;
}

[data-hidden='true'] {
	display: none;
}

[data-collapsed='true'] {
	height: 0 !important;
}

.block {
	display: table;
}


/**
 * 	Container
 */
#container {
	width: 100%;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;

	display: table;
}

/**
 * 	Picker Zone
 */

#picker {
	padding: 10px;
	width: 980px;
}

.ui-color-picker {
	padding: 3px 5px;
	float: left;
	border-color: #FFF;
}

.ui-color-picker .switch_mode {
	display: none;
}

.ui-color-picker .preview-color:hover {
	cursor: move;
}

/**
 * Picker Container
 */

#picker-samples {
	width: 375px;
	height: 114px;
	max-height: 218px;
	margin: 0 10px 0 30px;
	overflow: hidden;
	position: relative;
	float: left;

	transition: all 0.2s;
}

#picker-samples .sample {
	width: 40px;
	height: 40px;
	margin: 5px;
	border: 1px solid #DDD;
	position: absolute;
	float: left;
	transition: all 0.2s;
}

#picker-samples .sample:hover {
	cursor: pointer;
	border-color: #BBB;
	transform: scale(1.15);
	border-radius: 3px;
}

#picker-samples .sample[data-active='true'] {
	border-color: #999;
}

#picker-samples .sample[data-active='true']:after {
	content: "";
	position: absolute;
	background: url('https://mdn.mozillademos.org/files/6065/arrow.png') center no-repeat;
	width: 100%;
	height: 12px;
	top: -12px;
	z-index: 2;
}

#picker-samples #add-icon {
	width: 100%;
	height: 100%;
	position: relative;
	box-shadow: inset 0px 0px 2px 0px #DDD;
}

#picker-samples #add-icon:hover {
	cursor: pointer;
	border-color: #DDD;
	box-shadow: inset 0px 0px 5px 0px #CCC;
}

#picker-samples #add-icon:before,
#picker-samples #add-icon:after {
	content: "";
	position: absolute;
	background-color: #EEE;
	box-shadow: 0 0 1px 0 #EEE;
}

#picker-samples #add-icon:before {
	width: 70%;
	height: 16%;
	top: 42%;
	left: 15%;
}

#picker-samples #add-icon:after {
	width: 16%;
	height: 70%;
	top: 15%;
	left: 42%;
}

#picker-samples #add-icon:hover:before,
#picker-samples #add-icon:hover:after {
	background-color: #DDD;
	box-shadow: 0 0 1px 0 #DDD;
}

/**
 * 	Controls
 */

#controls {
	width: 110px;
	padding: 10px;
	float: right;
}

#controls #picker-switch {
	text-align: center;
	float: left;
}

#controls .icon {
	width: 48px;
	height: 48px;
	margin: 10px 0;
	background-repeat: no-repeat;
	background-position: center;
	border: 1px solid #DDD;
	display: table;
	float: left;
}

#controls .icon:hover {
	cursor: pointer;
}

#controls .picker-icon {
	background-image: url('https://mdn.mozillademos.org/files/6081/picker.png');
}

#controls #void-sample {
	margin-right: 10px;
	background-image: url('https://mdn.mozillademos.org/files/6087/void.png');
	background-position: center left;
}

#controls #void-sample[data-active='true'] {
	border-color: #CCC;
	background-position: center right;
}

#controls .switch {
	width: 106px;
	padding: 1px;
	border: 1px solid #CCC;
	font-size: 14px;
	text-align: center;
	line-height: 24px;
	overflow: hidden;
	float: left;
}

#controls .switch:hover {
	cursor: pointer;
}

#controls .switch &gt; * {
	width: 50%;
	padding: 2px 0;
	background-color: #EEE;
	float: left;
}

#controls .switch [data-active='true'] {
	color: #FFF;
	background-image: url('https://mdn.mozillademos.org/files/6025/grain.png');
	background-color: #777;
}

/**
 * 	Trash Can
 */

#delete {
	width: 100%;
	height: 94px;
	background-color: #DDD;
	background-image: url('https://mdn.mozillademos.org/files/6025/grain.png');
	background-repeat: repeat;

	text-align: center;
	color: #777;

	position: relative;
	float: right;
}

#delete #trash-can {
	width: 80%;
	height: 80%;
	border: 2px dashed #FFF;
	border-radius: 5px;
	background: url('https://mdn.mozillademos.org/files/6085/trash-can.png') no-repeat center;

	position: absolute;
	top: 10%;
	left: 10%;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;

	transition: all 0.2s;
}

#delete[drag-state='enter'] {
	background-color: #999;
}

/**
 * 	Color Theme
 */

#color-theme {
	margin: 0 8px 0 0;
	border: 1px solid #EEE;
	display: inline-block;
	float: right;
}

#color-theme .box {
	width: 80px;
	height: 92px;
	float: left;
}

/**
 * Color info box
 */
#color-info {
	width: 360px;
	float: left;
}

#color-info .title {
	width: 100%;
	padding: 15px;
	font-size: 18px;
	text-align: center;
	background-image: url('https://mdn.mozillademos.org/files/6071/color-wheel.png');
	background-repeat:no-repeat;
	background-position: center left 30%;
}

#color-info .copy-container {
	position: absolute;
	top: -100%;
}

#color-info .property {
	min-width: 280px;
	height: 30px;
	margin: 10px 0;
	text-align: center;
	line-height: 30px;
}

#color-info .property &gt; * {
	float: left;
}

#color-info .property .type {
	width: 60px;
	height: 100%;
	padding: 0 16px 0 0;
	text-align: right;
}

#color-info .property .value {
	width: 200px;
	height: 100%;
	padding: 0 10px;
	font-family: "Segoe UI", Arial, Helvetica, sans-serif;
	font-size: 16px;
	color: #777;
	text-align: center;
	background-color: #FFF;
	border: none;
}

#color-info .property .value:hover {
	color: #37994A;
}

#color-info .property .value:hover + .copy {
	background-position: center right;
}

#color-info .property .copy {
	width: 24px;
	height: 100%;
	padding: 0 5px;
	background-color: #FFF;
	background-image: url('https://mdn.mozillademos.org/files/6073/copy.png');
	background-repeat: no-repeat;
	background-position: center left;
	border-left: 1px solid #EEE;
	text-align: right;
	float: left;
}

#color-info .property .copy:hover {
	background-position: center right;
}


/**
 * 	Color Palette
 */

#palette {
	width: 1000px;
	padding: 10px 0;
	background-image: url('https://mdn.mozillademos.org/files/6025/grain.png');
	background-repeat: repeat;
	background-color: #EEE;
	color: #777;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}

#color-palette {
	width: 640px;
	font-family: Arial, Helvetica, sans-serif;
	color: #777;
	float: left;
}

#color-palette .container {
	width: 100%;
	height: 50px;
	line-height: 50px;
	overflow: hidden;
	float: left;
	transition: all 0.5s;
}

#color-palette .container &gt; * {
	float: left;
}

#color-palette .title {
	width: 100px;
	padding: 0 10px;
	text-align: right;
	line-height: inherit;
}

#color-palette .palette {
	width: 456px;
	height: 38px;
	margin: 3px;
	padding: 3px;
	display: table;
	background-color: #FFF;
}

#color-palette .palette .sample {
	width: 30px;
	height: 30px;
	margin: 3px;
	position: relative;
	border: 1px solid #DDD;
	float: left;
	transition: all 0.2s;
}

#color-palette .palette .sample:hover {
	cursor: pointer;
	border-color: #BBB;
	transform: scale(1.15);
	border-radius: 3px;
}

#color-palette .controls {
}

#color-palette .controls &gt; * {
	float: left;
}

#color-palette .controls &gt; *:hover {
	cursor: pointer;
}

#color-palette .controls .lock {
	width: 24px;
	height: 24px;
	margin: 10px;
	padding: 3px;
	background-image: url('https://mdn.mozillademos.org/files/6077/lock.png');
	background-repeat: no-repeat;
	background-position: bottom right;
}

#color-palette .controls .lock:hover {
	/*background-image: url('images/unlocked-hover.png');*/
	background-position: bottom left;
}

#color-palette .controls .lock[locked-state='true'] {
	/*background-image: url('images/locked.png');*/
	background-position: top left ;
}

#color-palette .controls .lock[locked-state='true']:hover {
	/*background-image: url('images/lock-hover.png');*/
	background-position: top right;
}

/**
 * Canvas
 */

#canvas {
	width: 100%;
	height: 300px;
	min-height: 250px;
	border-top: 1px solid #DDD;
	background-image: url('https://mdn.mozillademos.org/files/6025/grain.png');
	background-repeat: repeat;
	position: relative;
	float: left;
}

#canvas[data-tutorial='drop'] {
	text-align: center;
	font-size: 30px;
	color: #777;
}

#canvas[data-tutorial='drop']:before {
	content: "Drop colors here to compare";
	width: 40%;
	padding: 30px 9% 70px 11%;

	background-image: url('https://mdn.mozillademos.org/files/6075/drop.png');
	background-repeat: no-repeat;
	background-position: left 35px top 60%;

	text-align: right;

	border: 3px dashed rgb(221, 221, 221);
	border-radius: 15px;

	position: absolute;
	top: 50px;
	left: 20%;
}

#canvas[data-tutorial='drop']:after {
	content: "ajust, change or modify";
	width: 40%;
	font-size: 24px;
	position: absolute;
	top: 130px;
	left: 32%;
	z-index: 2;
}

#canvas [data-tutorial='dblclick'] {
	background-color: #999 !important;
}

#canvas [data-tutorial='dblclick']:before {
	content: "double click to activate";
	width: 80px;
	color: #FFF;
	position: absolute;
	top: 10%;
	left: 20%;
	z-index: 2;
}

#canvas .sample {
	width: 100px;
	height: 100px;
	min-width: 20px;
	min-height: 20px;
	position: absolute;
	border: 1px solid rgba(255, 255, 255, 0.3);
}

#canvas .sample:hover {
	cursor: move;
}

#canvas .sample[data-active='true']:after {
	content: "";
	position: absolute;
	background: url('https://mdn.mozillademos.org/files/6065/arrow.png') center no-repeat;
	width: 100%;
	height: 12px;
	top: -12px;
	z-index: 2;
}

#canvas .sample:hover &gt; * {
	cursor: pointer;
	display: block !important;
}

#canvas .sample .resize-handle {
	display: none;
}

#canvas .sample .pick {
	width: 10px;
	height: 10px;
	margin: 5px;
	background: url('https://mdn.mozillademos.org/files/6079/pick.png') center no-repeat;
	position: absolute;
	top: 0;
	left: 0;
	display: none;
}

#canvas .sample .delete {
	width: 10px;
	height: 10px;
	margin: 5px;
	background: url('https://mdn.mozillademos.org/files/6069/close.png') center no-repeat;
	position: absolute;
	top: 0;
	right: 0;
	display: none;
}


/**
 * Canvas controls
 */

#canvas .toggle-bg {
	width: 16px;
	height: 16px;
	margin: 5px;
	background: url("images/canvas-controls.png") center left no-repeat;
	position: absolute;
	top: 0;
	right: 0;
}

#canvas .toggle-bg:hover {
	cursor: pointer;
}

#canvas[data-bg='true'] {
	background: none;
}

#canvas[data-bg='true'] .toggle-bg {
	background: url('https://mdn.mozillademos.org/files/6067/canvas-controls.png') center right no-repeat;
}

#zindex {
	height: 20px;
	margin: 5px;
	font-size: 16px;
	position: absolute;
	opacity: 0;
	top: -10000px;
	left: 0;
	color: #777;
	float: left;
	transition: opacity 1s;
}

#zindex input {
	border: 1px solid #DDD;
	font-size: 16px;
	color: #777;
}

#zindex .ui-input-slider-info {
	width: 60px;
}

#zindex[data-active='true'] {
	top: 0;
	opacity: 1;
}

</pre>
  <h3 id="JavaScript_Content">JavaScript Content</h3>
  <pre class="brush: js">
'use strict';

var UIColorPicker = (function UIColorPicker() {

	function getElemById(id) {
		return document.getElementById(id);
	}

	var subscribers = [];
	var pickers = [];

	/**
	 * RGBA Color class
	 *
	 * HSV/HSB and HSL (hue, saturation, value / brightness, lightness)
	 * @param hue			0-360
	 * @param saturation	0-100
	 * @param value 		0-100
	 * @param lightness		0-100
	 */

	function Color(color) {

		if(color instanceof Color === true) {
			this.copy(color);
			return;
		}

		this.r = 0;
		this.g = 0;
		this.b = 0;
		this.a = 1;
		this.hue = 0;
		this.saturation = 0;
		this.value = 0;
		this.lightness = 0;
		this.format = 'HSV';
	}

	function RGBColor(r, g, b) {
		var color = new Color();
		color.setRGBA(r, g, b, 1);
		return color;
	}

	function RGBAColor(r, g, b, a) {
		var color = new Color();
		color.setRGBA(r, g, b, a);
		return color;
	}

	function HSVColor(h, s, v) {
		var color = new Color();
		color.setHSV(h, s, v);
		return color;
	}

	function HSVAColor(h, s, v, a) {
		var color = new Color();
		color.setHSV(h, s, v);
		color.a = a;
		return color;
	}

	function HSLColor(h, s, l) {
		var color = new Color();
		color.setHSL(h, s, l);
		return color;
	}

	function HSLAColor(h, s, l, a) {
		var color = new Color();
		color.setHSL(h, s, l);
		color.a = a;
		return color;
	}

	Color.prototype.copy = function copy(obj) {
		if(obj instanceof Color !== true) {
			console.log('Typeof parameter not Color');
			return;
		}

		this.r = obj.r;
		this.g = obj.g;
		this.b = obj.b;
		this.a = obj.a;
		this.hue = obj.hue;
		this.saturation = obj.saturation;
		this.value = obj.value;
		this.format = '' + obj.format;
		this.lightness = obj.lightness;
	};

	Color.prototype.setFormat = function setFormat(format) {
		if (format === 'HSV')
			this.format = 'HSV';
		if (format === 'HSL')
			this.format = 'HSL';
	};

	/*========== Methods to set Color Properties ==========*/

	Color.prototype.isValidRGBValue = function isValidRGBValue(value) {
		return (typeof(value) === 'number' &amp;&amp; isNaN(value) === false &amp;&amp;
			value &gt;= 0 &amp;&amp; value &lt;= 255);
	};

	Color.prototype.setRGBA = function setRGBA(red, green, blue, alpha) {
		if (this.isValidRGBValue(red) === false ||
			this.isValidRGBValue(green) === false ||
			this.isValidRGBValue(blue) === false)
			return;

			this.r = red | 0;
			this.g = green | 0;
			this.b = blue | 0;

		if (this.isValidRGBValue(alpha) === true)
			this.a = alpha | 0;
	};

	Color.prototype.setByName = function setByName(name, value) {
		if (name === 'r' || name === 'g' || name === 'b') {
			if(this.isValidRGBValue(value) === false)
				return;

			this[name] = value;
			this.updateHSX();
		}
	};

	Color.prototype.setHSV = function setHSV(hue, saturation, value) {
		this.hue = hue;
		this.saturation = saturation;
		this.value = value;
		this.HSVtoRGB();
	};

	Color.prototype.setHSL = function setHSL(hue, saturation, lightness) {
		this.hue = hue;
		this.saturation = saturation;
		this.lightness = lightness;
		this.HSLtoRGB();
	};

	Color.prototype.setHue = function setHue(value) {
		if (typeof(value) !== 'number' || isNaN(value) === true ||
			value &lt; 0 || value &gt; 359)
			return;
		this.hue = value;
		this.updateRGB();
	};

	Color.prototype.setSaturation = function setSaturation(value) {
		if (typeof(value) !== 'number' || isNaN(value) === true ||
			value &lt; 0 || value &gt; 100)
			return;
		this.saturation = value;
		this.updateRGB();
	};

	Color.prototype.setValue = function setValue(value) {
		if (typeof(value) !== 'number' || isNaN(value) === true ||
			value &lt; 0 || value &gt; 100)
			return;
		this.value = value;
		this.HSVtoRGB();
	};

	Color.prototype.setLightness = function setLightness(value) {
		if (typeof(value) !== 'number' || isNaN(value) === true ||
			value &lt; 0 || value &gt; 100)
			return;
		this.lightness = value;
		this.HSLtoRGB();
	};

	Color.prototype.setHexa = function setHexa(value) {
		var valid  = /(^#{0,1}[0-9A-F]{6}$)|(^#{0,1}[0-9A-F]{3}$)/i.test(value);

		if (valid !== true)
			return;

		if (value[0] === '#')
			value = value.slice(1, value.length);

		if (value.length === 3)
			value = value.replace(/([0-9A-F])([0-9A-F])([0-9A-F])/i,'$1$1$2$2$3$3');

		this.r = parseInt(value.substr(0, 2), 16);
		this.g = parseInt(value.substr(2, 2), 16);
		this.b = parseInt(value.substr(4, 2), 16);

		this.alpha	= 1;
		this.RGBtoHSV();
	};

	/*========== Conversion Methods ==========*/

	Color.prototype.convertToHSL = function convertToHSL() {
		if (this.format === 'HSL')
			return;

		this.setFormat('HSL');
		this.RGBtoHSL();
	};

	Color.prototype.convertToHSV = function convertToHSV() {
		if (this.format === 'HSV')
			return;

		this.setFormat('HSV');
		this.RGBtoHSV();
	};

	/*========== Update Methods ==========*/

	Color.prototype.updateRGB = function updateRGB() {
		if (this.format === 'HSV') {
			this.HSVtoRGB();
			return;
		}

		if (this.format === 'HSL') {
			this.HSLtoRGB();
			return;
		}
	};

	Color.prototype.updateHSX = function updateHSX() {
		if (this.format === 'HSV') {
			this.RGBtoHSV();
			return;
		}

		if (this.format === 'HSL') {
			this.RGBtoHSL();
			return;
		}
	};

	Color.prototype.HSVtoRGB = function HSVtoRGB() {
		var sat = this.saturation / 100;
		var value = this.value / 100;
		var C = sat * value;
		var H = this.hue / 60;
		var X = C * (1 - Math.abs(H % 2 - 1));
		var m = value - C;
		var precision = 255;

		C = (C + m) * precision | 0;
		X = (X + m) * precision | 0;
		m = m * precision | 0;

		if (H &gt;= 0 &amp;&amp; H &lt; 1) {	this.setRGBA(C, X, m);	return; }
		if (H &gt;= 1 &amp;&amp; H &lt; 2) {	this.setRGBA(X, C, m);	return; }
		if (H &gt;= 2 &amp;&amp; H &lt; 3) {	this.setRGBA(m, C, X);	return; }
		if (H &gt;= 3 &amp;&amp; H &lt; 4) {	this.setRGBA(m, X, C);	return; }
		if (H &gt;= 4 &amp;&amp; H &lt; 5) {	this.setRGBA(X, m, C);	return; }
		if (H &gt;= 5 &amp;&amp; H &lt; 6) {	this.setRGBA(C, m, X);	return; }
	};

	Color.prototype.HSLtoRGB = function HSLtoRGB() {
		var sat = this.saturation / 100;
		var light = this.lightness / 100;
		var C = sat * (1 - Math.abs(2 * light - 1));
		var H = this.hue / 60;
		var X = C * (1 - Math.abs(H % 2 - 1));
		var m = light - C/2;
		var precision = 255;

		C = (C + m) * precision | 0;
		X = (X + m) * precision | 0;
		m = m * precision | 0;

		if (H &gt;= 0 &amp;&amp; H &lt; 1) {	this.setRGBA(C, X, m);	return; }
		if (H &gt;= 1 &amp;&amp; H &lt; 2) {	this.setRGBA(X, C, m);	return; }
		if (H &gt;= 2 &amp;&amp; H &lt; 3) {	this.setRGBA(m, C, X);	return; }
		if (H &gt;= 3 &amp;&amp; H &lt; 4) {	this.setRGBA(m, X, C);	return; }
		if (H &gt;= 4 &amp;&amp; H &lt; 5) {	this.setRGBA(X, m, C);	return; }
		if (H &gt;= 5 &amp;&amp; H &lt; 6) {	this.setRGBA(C, m, X);	return; }
	};

	Color.prototype.RGBtoHSV = function RGBtoHSV() {
		var red		= this.r / 255;
		var green	= this.g / 255;
		var blue	= this.b / 255;

		var cmax = Math.max(red, green, blue);
		var cmin = Math.min(red, green, blue);
		var delta = cmax - cmin;
		var hue = 0;
		var saturation = 0;

		if (delta) {
			if (cmax === red ) { hue = ((green - blue) / delta); }
			if (cmax === green ) { hue = 2 + (blue - red) / delta; }
			if (cmax === blue ) { hue = 4 + (red - green) / delta; }
			if (cmax) saturation = delta / cmax;
		}

		this.hue = 60 * hue | 0;
		if (this.hue &lt; 0) this.hue += 360;
		this.saturation = (saturation * 100) | 0;
		this.value = (cmax * 100) | 0;
	};

	Color.prototype.RGBtoHSL = function RGBtoHSL() {
		var red		= this.r / 255;
		var green	= this.g / 255;
		var blue	= this.b / 255;

		var cmax = Math.max(red, green, blue);
		var cmin = Math.min(red, green, blue);
		var delta = cmax - cmin;
		var hue = 0;
		var saturation = 0;
		var lightness = (cmax + cmin) / 2;
		var X = (1 - Math.abs(2 * lightness - 1));

		if (delta) {
			if (cmax === red ) { hue = ((green - blue) / delta); }
			if (cmax === green ) { hue = 2 + (blue - red) / delta; }
			if (cmax === blue ) { hue = 4 + (red - green) / delta; }
			if (cmax) saturation = delta / X;
		}

		this.hue = 60 * hue | 0;
		if (this.hue &lt; 0) this.hue += 360;
		this.saturation = (saturation * 100) | 0;
		this.lightness = (lightness * 100) | 0;
	};

	/*========== Get Methods ==========*/

	Color.prototype.getHexa = function getHexa() {
		var r = this.r.toString(16);
		var g = this.g.toString(16);
		var b = this.b.toString(16);
		if (this.r &lt; 16) r = '0' + r;
		if (this.g &lt; 16) g = '0' + g;
		if (this.b &lt; 16) b = '0' + b;
		var value = '#' + r + g + b;
		return value.toUpperCase();
	};

	Color.prototype.getRGBA = function getRGBA() {

		var rgb = '(' + this.r + ', ' + this.g + ', ' + this.b;
		var a = '';
		var v = '';
		var x = parseFloat(this.a);
		if (x !== 1) {
			a = 'a';
			v = ', ' + x;
		}

		var value = 'rgb' + a + rgb + v + ')';
		return value;
	};

	Color.prototype.getHSLA = function getHSLA() {
		if (this.format === 'HSV') {
			var color = new Color(this);
			color.setFormat('HSL');
			color.updateHSX();
			return color.getHSLA();
		}

		var a = '';
		var v = '';
		var hsl = '(' + this.hue + ', ' + this.saturation + '%, ' + this.lightness +'%';
		var x = parseFloat(this.a);
		if (x !== 1) {
			a = 'a';
			v = ', ' + x;
		}

		var value = 'hsl' + a + hsl + v + ')';
		return value;
	};

	Color.prototype.getColor = function getColor() {
		if (this.a | 0 === 1)
			return this.getHexa();
		return this.getRGBA();
	};

	/*=======================================================================*/
	/*=======================================================================*/

	/*========== Capture Mouse Movement ==========*/

	var setMouseTracking = function setMouseTracking(elem, callback) {
		elem.addEventListener('mousedown', function(e) {
			callback(e);
			document.addEventListener('mousemove', callback);
		});

		document.addEventListener('mouseup', function(e) {
			document.removeEventListener('mousemove', callback);
		});
	};

	/*====================*/
	// Color Picker Class
	/*====================*/

	function ColorPicker(node) {
		this.color = new Color();
		this.node = node;
		this.subscribers = [];

		var type = this.node.getAttribute('data-mode');
		var topic = this.node.getAttribute('data-topic');

		this.topic = topic;
		this.picker_mode = (type === 'HSL') ? 'HSL' : 'HSV';
		this.color.setFormat(this.picker_mode);

		this.createPickingArea();
		this.createHueArea();

		this.newInputComponent('H', 'hue', this.inputChangeHue.bind(this));
		this.newInputComponent('S', 'saturation', this.inputChangeSaturation.bind(this));
		this.newInputComponent('V', 'value', this.inputChangeValue.bind(this));
		this.newInputComponent('L', 'lightness', this.inputChangeLightness.bind(this));

		this.createAlphaArea();

		this.newInputComponent('R', 'red', this.inputChangeRed.bind(this));
		this.newInputComponent('G', 'green', this.inputChangeGreen.bind(this));
		this.newInputComponent('B', 'blue', this.inputChangeBlue.bind(this));

		this.createPreviewBox();
		this.createChangeModeButton();

		this.newInputComponent('alpha', 'alpha', this.inputChangeAlpha.bind(this));
		this.newInputComponent('hexa', 'hexa', this.inputChangeHexa.bind(this));

		this.setColor(this.color);
		pickers[topic] = this;
	}

	/*************************************************************************/
	//				Function for generating the color-picker
	/*************************************************************************/

	ColorPicker.prototype.createPickingArea = function createPickingArea() {
		var area = document.createElement('div');
		var picker = document.createElement('div');

		area.className = 'picking-area';
		picker.className = 'picker';

		this.picking_area = area;
		this.color_picker = picker;
		setMouseTracking(area, this.updateColor.bind(this));

		area.appendChild(picker);
		this.node.appendChild(area);
	};

	ColorPicker.prototype.createHueArea = function createHueArea() {
		var area = document.createElement('div');
		var picker = document.createElement('div');

		area.className = 'hue';
		picker.className ='slider-picker';

		this.hue_area = area;
		this.hue_picker = picker;
		setMouseTracking(area, this.updateHueSlider.bind(this));

		area.appendChild(picker);
		this.node.appendChild(area);
	};

	ColorPicker.prototype.createAlphaArea = function createAlphaArea() {
		var area = document.createElement('div');
		var mask = document.createElement('div');
		var picker = document.createElement('div');

		area.className = 'alpha';
		mask.className = 'alpha-mask';
		picker.className = 'slider-picker';

		this.alpha_area = area;
		this.alpha_mask = mask;
		this.alpha_picker = picker;
		setMouseTracking(area, this.updateAlphaSlider.bind(this));

		area.appendChild(mask);
		mask.appendChild(picker);
		this.node.appendChild(area);
	};

	ColorPicker.prototype.createPreviewBox = function createPreviewBox(e) {
		var preview_box = document.createElement('div');
		var preview_color = document.createElement('div');

		preview_box.className = 'preview';
		preview_color.className = 'preview-color';

		this.preview_color = preview_color;

		preview_box.appendChild(preview_color);
		this.node.appendChild(preview_box);
	};

	ColorPicker.prototype.newInputComponent = function newInputComponent(title, topic, onChangeFunc) {
		var wrapper = document.createElement('div');
		var input = document.createElement('input');
		var info = document.createElement('span');

		wrapper.className = 'input';
		wrapper.setAttribute('data-topic', topic);
		info.textContent = title;
		info.className = 'name';
		input.setAttribute('type', 'text');

		wrapper.appendChild(info);
		wrapper.appendChild(input);
		this.node.appendChild(wrapper);

		input.addEventListener('change', onChangeFunc);
		input.addEventListener('click', function() {
			this.select();
		});

		this.subscribe(topic, function(value) {
			input.value = value;
		});
	};

	ColorPicker.prototype.createChangeModeButton = function createChangeModeButton() {

		var button = document.createElement('div');
		button.className = 'switch_mode';
		button.addEventListener('click', function() {
			if (this.picker_mode === 'HSV')
				this.setPickerMode('HSL');
			else
				this.setPickerMode('HSV');

		}.bind(this));

		this.node.appendChild(button);
	};

	/*************************************************************************/
	//					Updates properties of UI elements
	/*************************************************************************/

	ColorPicker.prototype.updateColor = function updateColor(e) {
		var x = e.pageX - this.picking_area.offsetLeft;
		var y = e.pageY - this.picking_area.offsetTop;
		var picker_offset = 5;

		// width and height should be the same
		var size = this.picking_area.clientWidth;

		if (x &gt; size) x = size;
		if (y &gt; size) y = size;
		if (x &lt; 0) x = 0;
		if (y &lt; 0) y = 0;

		var value = 100 - (y * 100 / size) | 0;
		var saturation = x * 100 / size | 0;

		if (this.picker_mode === 'HSV')
			this.color.setHSV(this.color.hue, saturation, value);
		if (this.picker_mode === 'HSL')
			this.color.setHSL(this.color.hue, saturation, value);

		this.color_picker.style.left = x - picker_offset + 'px';
		this.color_picker.style.top = y - picker_offset + 'px';

		this.updateAlphaGradient();
		this.updatePreviewColor();

		this.notify('value', value);
		this.notify('lightness', value);
		this.notify('saturation', saturation);

		this.notify('red', this.color.r);
		this.notify('green', this.color.g);
		this.notify('blue', this.color.b);
		this.notify('hexa', this.color.getHexa());

		notify(this.topic, this.color);
	};

	ColorPicker.prototype.updateHueSlider = function updateHueSlider(e) {
		var x = e.pageX - this.hue_area.offsetLeft;
		var width = this.hue_area.clientWidth;

		if (x &lt; 0) x = 0;
		if (x &gt; width) x = width;

		// TODO 360 =&gt; 359
		var hue = ((359 * x) / width) | 0;
		// if (hue === 360) hue = 359;

		this.updateSliderPosition(this.hue_picker, x);
		this.setHue(hue);
	};

	ColorPicker.prototype.updateAlphaSlider = function updateAlphaSlider(e) {
		var x = e.pageX - this.alpha_area.offsetLeft;
		var width = this.alpha_area.clientWidth;

		if (x &lt; 0) x = 0;
		if (x &gt; width) x = width;

		this.color.a = (x / width).toFixed(2);

		this.updateSliderPosition(this.alpha_picker, x);
		this.updatePreviewColor();

		this.notify('alpha', this.color.a);
		notify(this.topic, this.color);
	};

	ColorPicker.prototype.setHue = function setHue(value) {
		this.color.setHue(value);

		this.updatePickerBackground();
		this.updateAlphaGradient();
		this.updatePreviewColor();

		this.notify('red', this.color.r);
		this.notify('green', this.color.g);
		this.notify('blue', this.color.b);
		this.notify('hexa', this.color.getHexa());
		this.notify('hue', this.color.hue);

		notify(this.topic, this.color);
	};

	// Updates when one of Saturation/Value/Lightness changes
	ColorPicker.prototype.updateSLV = function updateSLV() {
		this.updatePickerPosition();
		this.updateAlphaGradient();
		this.updatePreviewColor();

		this.notify('red', this.color.r);
		this.notify('green', this.color.g);
		this.notify('blue', this.color.b);
		this.notify('hexa', this.color.getHexa());

		notify(this.topic, this.color);
	};

	/*************************************************************************/
	//				Update positions of various UI elements
	/*************************************************************************/

	ColorPicker.prototype.updatePickerPosition = function updatePickerPosition() {
		var size = this.picking_area.clientWidth;
		var value = 0;
		var offset = 5;

		if (this.picker_mode === 'HSV')
			value = this.color.value;
		if (this.picker_mode === 'HSL')
			value = this.color.lightness;

		var x = (this.color.saturation * size / 100) | 0;
		var y = size - (value * size / 100) | 0;

		this.color_picker.style.left = x - offset + 'px';
		this.color_picker.style.top = y - offset + 'px';
	};

	ColorPicker.prototype.updateSliderPosition = function updateSliderPosition(elem, pos) {
		elem.style.left = Math.max(pos - 3, -2) + 'px';
	};

	ColorPicker.prototype.updateHuePicker = function updateHuePicker() {
		var size = this.hue_area.clientWidth;
		var offset = 1;
		var pos = (this.color.hue * size / 360 ) | 0;
		this.hue_picker.style.left = pos - offset + 'px';
	};

	ColorPicker.prototype.updateAlphaPicker = function updateAlphaPicker() {
		var size = this.alpha_area.clientWidth;
		var offset = 1;
		var pos = (this.color.a * size) | 0;
		this.alpha_picker.style.left = pos - offset + 'px';
	};

	/*************************************************************************/
	//						Update background colors
	/*************************************************************************/

	ColorPicker.prototype.updatePickerBackground = function updatePickerBackground() {
		var nc = new Color(this.color);
		nc.setHSV(nc.hue, 100, 100);
		this.picking_area.style.backgroundColor = nc.getHexa();
	};

	ColorPicker.prototype.updateAlphaGradient = function updateAlphaGradient() {
		this.alpha_mask.style.backgroundColor = this.color.getHexa();
	};

	ColorPicker.prototype.updatePreviewColor = function updatePreviewColor() {
		this.preview_color.style.backgroundColor = this.color.getColor();
	};

	/*************************************************************************/
	//						Update input elements
	/*************************************************************************/

	ColorPicker.prototype.inputChangeHue = function inputChangeHue(e) {
		var value = parseInt(e.target.value);
		this.setHue(value);
		this.updateHuePicker();
	};

	ColorPicker.prototype.inputChangeSaturation = function inputChangeSaturation(e) {
		var value = parseInt(e.target.value);
		this.color.setSaturation(value);
		e.target.value = this.color.saturation;
		this.updateSLV();
	};

	ColorPicker.prototype.inputChangeValue = function inputChangeValue(e) {
		var value = parseInt(e.target.value);
		this.color.setValue(value);
		e.target.value = this.color.value;
		this.updateSLV();
	};

	ColorPicker.prototype.inputChangeLightness = function inputChangeLightness(e) {
		var value = parseInt(e.target.value);
		this.color.setLightness(value);
		e.target.value = this.color.lightness;
		this.updateSLV();
	};

	ColorPicker.prototype.inputChangeRed = function inputChangeRed(e) {
		var value = parseInt(e.target.value);
		this.color.setByName('r', value);
		e.target.value = this.color.r;
		this.setColor(this.color);
	};

	ColorPicker.prototype.inputChangeGreen = function inputChangeGreen(e) {
		var value = parseInt(e.target.value);
		this.color.setByName('g', value);
		e.target.value = this.color.g;
		this.setColor(this.color);
	};

	ColorPicker.prototype.inputChangeBlue = function inputChangeBlue(e) {
		var value = parseInt(e.target.value);
		this.color.setByName('b', value);
		e.target.value = this.color.b;
		this.setColor(this.color);
	};

	ColorPicker.prototype.inputChangeAlpha = function inputChangeAlpha(e) {
		var value = parseFloat(e.target.value);

		if (typeof value === 'number' &amp;&amp; isNaN(value) === false &amp;&amp;
			value &gt;= 0 &amp;&amp; value &lt;= 1)
			this.color.a = value.toFixed(2);

		e.target.value = this.color.a;
		this.updateAlphaPicker();
	};

	ColorPicker.prototype.inputChangeHexa = function inputChangeHexa(e) {
		var value = e.target.value;
		this.color.setHexa(value);
		this.setColor(this.color);
	};

	/*************************************************************************/
	//							Internal Pub/Sub
	/*************************************************************************/

	ColorPicker.prototype.subscribe = function subscribe(topic, callback) {
		this.subscribers[topic] = callback;
	};

	ColorPicker.prototype.notify = function notify(topic, value) {
		if (this.subscribers[topic])
			this.subscribers[topic](value);
	};

	/*************************************************************************/
	//							Set Picker Properties
	/*************************************************************************/

	ColorPicker.prototype.setColor = function setColor(color) {
		if(color instanceof Color !== true) {
			console.log('Typeof parameter not Color');
			return;
		}

		if (color.format !== this.picker_mode) {
			color.setFormat(this.picker_mode);
			color.updateHSX();
		}

		this.color.copy(color);
		this.updateHuePicker();
		this.updatePickerPosition();
		this.updatePickerBackground();
		this.updateAlphaPicker();
		this.updateAlphaGradient();
		this.updatePreviewColor();

		this.notify('red', this.color.r);
		this.notify('green', this.color.g);
		this.notify('blue', this.color.b);

		this.notify('hue', this.color.hue);
		this.notify('saturation', this.color.saturation);
		this.notify('value', this.color.value);
		this.notify('lightness', this.color.lightness);

		this.notify('alpha', this.color.a);
		this.notify('hexa', this.color.getHexa());
		notify(this.topic, this.color);
	};

	ColorPicker.prototype.setPickerMode = function setPickerMode(mode) {
		if (mode !== 'HSV' &amp;&amp; mode !== 'HSL')
			return;

		this.picker_mode = mode;
		this.node.setAttribute('data-mode', this.picker_mode);
		this.setColor(this.color);
	};

	/*************************************************************************/
	//								UNUSED
	/*************************************************************************/

	var setPickerMode = function setPickerMode(topic, mode) {
		if (pickers[topic])
			pickers[topic].setPickerMode(mode);
	};

	var setColor = function setColor(topic, color) {
		if (pickers[topic])
			pickers[topic].setColor(color);
	};

	var getColor = function getColor(topic) {
		if (pickers[topic])
			return new Color(pickers[topic].color);
	};

	var subscribe = function subscribe(topic, callback) {
		if (subscribers[topic] === undefined)
			subscribers[topic] = [];

		subscribers[topic].push(callback);
	};

	var unsubscribe = function unsubscribe(callback) {
		subscribers.indexOf(callback);
		subscribers.splice(index, 1);
	};

	var notify = function notify(topic, value) {
		if (subscribers[topic] === undefined || subscribers[topic].length === 0)
			return;

		var color = new Color(value);
		for (var i in subscribers[topic])
			subscribers[topic][i](color);
	};

	var init = function init() {
		var elem = document.querySelectorAll('.ui-color-picker');
		var size = elem.length;
		for (var i = 0; i &lt; size; i++)
			new ColorPicker(elem[i]);
	};

	return {
		init : init,
		Color : Color,
		RGBColor : RGBColor,
		RGBAColor : RGBAColor,
		HSVColor : HSVColor,
		HSVAColor : HSVAColor,
		HSLColor : HSLColor,
		HSLAColor : HSLAColor,
		setColor : setColor,
		getColor : getColor,
		subscribe : subscribe,
		unsubscribe : unsubscribe,
		setPickerMode : setPickerMode
	};

})();



/**
 * UI-SlidersManager
 */

var InputSliderManager = (function InputSliderManager() {

	var subscribers = {};
	var sliders = [];

	var InputComponent = function InputComponent(obj) {
		var input = document.createElement('input');
		input.setAttribute('type', 'text');
		input.style.width = 50 + obj.precision * 10 + 'px';

		input.addEventListener('click', function(e) {
			this.select();
		});

		input.addEventListener('change', function(e) {
			var value = parseFloat(e.target.value);

			if (isNaN(value) === true)
				setValue(obj.topic, obj.value);
			else
				setValue(obj.topic, value);
		});

		return input;
	};

	var SliderComponent = function SliderComponent(obj, sign) {
		var slider = document.createElement('div');
		var startX = null;
		var start_value = 0;

		slider.addEventListener("click", function(e) {
			document.removeEventListener("mousemove", sliderMotion);
			setValue(obj.topic, obj.value + obj.step * sign);
		});

		slider.addEventListener("mousedown", function(e) {
			startX = e.clientX;
			start_value = obj.value;
			document.body.style.cursor = "e-resize";

			document.addEventListener("mouseup", slideEnd);
			document.addEventListener("mousemove", sliderMotion);
		});

		var slideEnd = function slideEnd(e) {
			document.removeEventListener("mousemove", sliderMotion);
			document.body.style.cursor = "auto";
			slider.style.cursor = "pointer";
		};

		var sliderMotion = function sliderMotion(e) {
			slider.style.cursor = "e-resize";
			var delta = (e.clientX - startX) / obj.sensivity | 0;
			var value = delta * obj.step + start_value;
			setValue(obj.topic, value);
		};

		return slider;
	};

	var InputSlider = function(node) {
		var min		= parseFloat(node.getAttribute('data-min'));
		var max		= parseFloat(node.getAttribute('data-max'));
		var step	= parseFloat(node.getAttribute('data-step'));
		var value	= parseFloat(node.getAttribute('data-value'));
		var topic	= node.getAttribute('data-topic');
		var unit	= node.getAttribute('data-unit');
		var name 	= node.getAttribute('data-info');
		var sensivity = node.getAttribute('data-sensivity') | 0;
		var precision = node.getAttribute('data-precision') | 0;

		this.min = isNaN(min) ? 0 : min;
		this.max = isNaN(max) ? 100 : max;
		this.precision = precision &gt;= 0 ? precision : 0;
		this.step = step &lt; 0 || isNaN(step) ? 1 : step.toFixed(precision);
		this.topic = topic;
		this.node = node;
		this.unit = unit === null ? '' : unit;
		this.sensivity = sensivity &gt; 0 ? sensivity : 5;
		value = isNaN(value) ? this.min : value;

		var input = new InputComponent(this);
		var slider_left  = new SliderComponent(this, -1);
		var slider_right = new SliderComponent(this,  1);

		slider_left.className = 'ui-input-slider-left';
		slider_right.className = 'ui-input-slider-right';

		if (name) {
			var info = document.createElement('span');
			info.className = 'ui-input-slider-info';
			info.textContent = name;
			node.appendChild(info);
		}

		node.appendChild(slider_left);
		node.appendChild(input);
		node.appendChild(slider_right);

		this.input = input;
		sliders[topic] = this;
		setValue(topic, value);
	};

	InputSlider.prototype.setInputValue = function setInputValue() {
		this.input.value = this.value.toFixed(this.precision) + this.unit;
	};

	var setValue = function setValue(topic, value, send_notify) {
		var slider = sliders[topic];
		if (slider === undefined)
			return;

		value = parseFloat(value.toFixed(slider.precision));

		if (value &gt; slider.max) value = slider.max;
		if (value &lt; slider.min)	value = slider.min;

		slider.value = value;
		slider.node.setAttribute('data-value', value);

		slider.setInputValue();

		if (send_notify === false)
			return;

		notify.call(slider);
	};

	var setMax = function setMax(topic, value) {
		var slider = sliders[topic];
		if (slider === undefined)
			return;

		slider.max = value;
		setValue(topic, slider.value);
	};

	var setMin = function setMin(topic, value) {
		var slider = sliders[topic];
		if (slider === undefined)
			return;

		slider.min = value;
		setValue(topic, slider.value);
	};

	var setUnit = function setUnit(topic, unit) {
		var slider = sliders[topic];
		if (slider === undefined)
			return;

		slider.unit = unit;
		setValue(topic, slider.value);
	};

	var setStep = function setStep(topic, value) {
		var slider = sliders[topic];
		if (slider === undefined)
			return;

		slider.step = parseFloat(value);
		setValue(topic, slider.value);
	};

	var setPrecision = function setPrecision(topic, value) {
		var slider = sliders[topic];
		if (slider === undefined)
			return;

		value = value | 0;
		slider.precision = value;

		var step = parseFloat(slider.step.toFixed(value));
		if (step === 0)
			slider.step = 1 / Math.pow(10, value);

		setValue(topic, slider.value);
	};

	var setSensivity = function setSensivity(topic, value) {
		var slider = sliders[topic];
		if (slider === undefined)
			return;

		value = value | 0;

		slider.sensivity = value &gt; 0 ? value : 5;
	};

	var getNode =  function getNode(topic) {
		return sliders[topic].node;
	};

	var getPrecision =  function getPrecision(topic) {
		return sliders[topic].precision;
	};

	var getStep =  function getStep(topic) {
		return sliders[topic].step;
	};

	var subscribe = function subscribe(topic, callback) {
		if (subscribers[topic] === undefined)
			subscribers[topic] = [];
		subscribers[topic].push(callback);
	};

	var unsubscribe = function unsubscribe(topic, callback) {
		subscribers[topic].indexOf(callback);
		subscribers[topic].splice(index, 1);
	};

	var notify = function notify() {
		if (subscribers[this.topic] === undefined)
			return;
		for (var i = 0; i &lt; subscribers[this.topic].length; i++)
			subscribers[this.topic][i](this.value);
	};

	var createSlider = function createSlider(topic, label) {
		var slider = document.createElement('div');
		slider.className = 'ui-input-slider';
		slider.setAttribute('data-topic', topic);

		if (label !== undefined)
			slider.setAttribute('data-info', label);

		new InputSlider(slider);
		return slider;
	};

	var init = function init() {
		var elem = document.querySelectorAll('.ui-input-slider');
		var size = elem.length;
		for (var i = 0; i &lt; size; i++)
			new InputSlider(elem[i]);
	};

	return {
		init : init,
		setMax : setMax,
		setMin : setMin,
		setUnit : setUnit,
		setStep : setStep,
		getNode : getNode,
		getStep : getStep,
		setValue : setValue,
		subscribe : subscribe,
		unsubscribe : unsubscribe,
		setPrecision : setPrecision,
		setSensivity : setSensivity,
		getPrecision : getPrecision,
		createSlider : createSlider,
	};

})();


'use strict';

window.addEventListener("load", function() {
	ColorPickerTool.init();
});

var ColorPickerTool = (function ColorPickerTool() {

	/*========== Get DOM Element By ID ==========*/

	function getElemById(id) {
		return document.getElementById(id);
	}

	function allowDropEvent(e) {
		e.preventDefault();
	}

	/*========== Make an element resizable relative to it's parent ==========*/

	var UIComponent = (function UIComponent() {

		function makeResizable(elem, axis) {
			var valueX = 0;
			var valueY = 0;
			var action = 0;

			var resizeStart = function resizeStart(e) {
				e.stopPropagation();
				e.preventDefault();
				if (e.button !== 0)
					return;

				valueX = e.clientX - elem.clientWidth;
				valueY = e.clientY - elem.clientHeight;

				document.body.setAttribute('data-resize', axis);
				document.addEventListener('mousemove', mouseMove);
				document.addEventListener('mouseup', resizeEnd);
			};

			var mouseMove = function mouseMove(e) {
				if (action &gt;= 0)
					elem.style.width = e.clientX - valueX + 'px';
				if (action &lt;= 0)
					elem.style.height = e.clientY - valueY + 'px';
			};

			var resizeEnd = function resizeEnd(e) {
				if (e.button !== 0)
					return;

				document.body.removeAttribute('data-resize', axis);
				document.removeEventListener('mousemove', mouseMove);
				document.removeEventListener('mouseup', resizeEnd);
			};

			var handle = document.createElement('div');
			handle.className = 'resize-handle';

			if (axis === 'width') action = 1;
			else if (axis === 'height') action = -1;
			else axis = 'both';

			handle.className = 'resize-handle';
			handle.setAttribute('data-resize', axis);
			handle.addEventListener('mousedown', resizeStart);
			elem.appendChild(handle);
		};

		/*========== Make an element draggable relative to it's parent ==========*/

		var makeDraggable = function makeDraggable(elem, endFunction) {

			var offsetTop;
			var offsetLeft;

			elem.setAttribute('data-draggable', 'true');

			var dragStart = function dragStart(e) {
				e.preventDefault();
				e.stopPropagation();

				if (e.target.getAttribute('data-draggable') !== 'true' ||
					e.target !== elem || e.button !== 0)
					return;

				offsetLeft = e.clientX - elem.offsetLeft;
				offsetTop = e.clientY - elem.offsetTop;

				document.addEventListener('mousemove', mouseDrag);
				document.addEventListener('mouseup', dragEnd);
			};

			var dragEnd = function dragEnd(e) {
				if (e.button !== 0)
					return;

				document.removeEventListener('mousemove', mouseDrag);
				document.removeEventListener('mouseup', dragEnd);
			};

			var mouseDrag = function mouseDrag(e) {
				elem.style.left = e.clientX - offsetLeft + 'px';
				elem.style.top = e.clientY - offsetTop + 'px';
			};

			elem.addEventListener('mousedown', dragStart, false);
		};

		return {
			makeResizable : makeResizable,
			makeDraggable : makeDraggable
		};

	})();

	/*========== Color Class ==========*/

	var Color = UIColorPicker.Color;
	var HSLColor = UIColorPicker.HSLColor;

	/**
	 * ColorPalette
	 */
	var ColorPalette = (function ColorPalette() {

		var samples = [];
		var color_palette;
		var complementary;

		var hideNode = function(node) {
			node.setAttribute('data-hidden', 'true');
		};

		var ColorSample = function ColorSample(id) {
			var node = document.createElement('div');
			node.className = 'sample';

			this.uid = samples.length;
			this.node = node;
			this.color = new Color();

			node.setAttribute('sample-id', this.uid);
			node.setAttribute('draggable', 'true');
			node.addEventListener('dragstart', this.dragStart.bind(this));
			node.addEventListener('click', this.pickColor.bind(this));

			samples.push(this);
		};

		ColorSample.prototype.updateBgColor = function updateBgColor() {
			this.node.style.backgroundColor = this.color.getColor();
		};

		ColorSample.prototype.updateColor = function updateColor(color) {
			this.color.copy(color);
			this.updateBgColor();
		};

		ColorSample.prototype.updateHue = function updateHue(color, degree, steps) {
			this.color.copy(color);
			var hue = (steps * degree + this.color.hue) % 360;
			if (hue &lt; 0) hue += 360;
			this.color.setHue(hue);
			this.updateBgColor();
		};

		ColorSample.prototype.updateSaturation = function updateSaturation(color, value, steps) {
			var saturation = color.saturation + value * steps;
			if (saturation &lt;= 0) {
				this.node.setAttribute('data-hidden', 'true');
				return;
			}

			this.node.removeAttribute('data-hidden');
			this.color.copy(color);
			this.color.setSaturation(saturation);
			this.updateBgColor();
		};

		ColorSample.prototype.updateLightness = function updateLightness(color, value, steps) {
			var lightness = color.lightness + value * steps;
			if (lightness &lt;= 0) {
				this.node.setAttribute('data-hidden', 'true');
				return;
			}
			this.node.removeAttribute('data-hidden');
			this.color.copy(color);
			this.color.setLightness(lightness);
			this.updateBgColor();
		};

		ColorSample.prototype.updateBrightness = function updateBrightness(color, value, steps) {
			var brightness = color.value + value * steps;
			if (brightness &lt;= 0) {
				this.node.setAttribute('data-hidden', 'true');
				return;
			}
			this.node.removeAttribute('data-hidden');
			this.color.copy(color);
			this.color.setValue(brightness);
			this.updateBgColor();
		};

		ColorSample.prototype.updateAlpha = function updateAlpha(color, value, steps) {
			var alpha = parseFloat(color.a) + value * steps;
			if (alpha &lt;= 0) {
				this.node.setAttribute('data-hidden', 'true');
				return;
			}
			this.node.removeAttribute('data-hidden');
			this.color.copy(color);
			this.color.a = parseFloat(alpha.toFixed(2));
			this.updateBgColor();
		};

		ColorSample.prototype.pickColor = function pickColor() {
			UIColorPicker.setColor('picker', this.color);
		};

		ColorSample.prototype.dragStart = function dragStart(e) {
			e.dataTransfer.setData('sampleID', this.uid);
			e.dataTransfer.setData('location', 'palette-samples');
		};

		var Palette = function Palette(text, size) {
			this.samples = [];
			this.locked = false;

			var palette = document.createElement('div');
			var title = document.createElement('div');
			var controls = document.createElement('div');
			var container = document.createElement('div');
			var lock = document.createElement('div');

			container.className = 'container';
			title.className = 'title';
			palette.className = 'palette';
			controls.className = 'controls';
			lock.className = 'lock';
			title.textContent = text;

			controls.appendChild(lock);
			container.appendChild(title);
			container.appendChild(controls);
			container.appendChild(palette);

			lock.addEventListener('click', function () {
				this.locked = !this.locked;
				lock.setAttribute('locked-state', this.locked);
			}.bind(this));

			for(var i = 0; i &lt; size; i++) {
				var sample = new ColorSample();
				this.samples.push(sample);
				palette.appendChild(sample.node);
			}

			this.container = container;
			this.title = title;
		};

		var createHuePalette = function createHuePalette() {
			var palette = new Palette('Hue', 12);

			UIColorPicker.subscribe('picker', function(color) {
				if (palette.locked === true)
					return;

				for(var i = 0; i &lt; 12; i++) {
					palette.samples[i].updateHue(color, 30, i);
				}
			});

			color_palette.appendChild(palette.container);
		};

		var createSaturationPalette = function createSaturationPalette() {
			var palette = new Palette('Saturation', 11);

			UIColorPicker.subscribe('picker', function(color) {
				if (palette.locked === true)
					return;

				for(var i = 0; i &lt; 11; i++) {
					palette.samples[i].updateSaturation(color, -10, i);
				}
			});

			color_palette.appendChild(palette.container);
		};

		/* Brightness or Lightness - depends on the picker mode */
		var createVLPalette = function createSaturationPalette() {
			var palette = new Palette('Lightness', 11);

			UIColorPicker.subscribe('picker', function(color) {
				if (palette.locked === true)
					return;

				if(color.format === 'HSL') {
					for(var i = 0; i &lt; 11; i++)
						palette.samples[i].updateLightness(color, -10, i);
				}
				else {
					for(var i = 0; i &lt; 11; i++)
						palette.samples[i].updateBrightness(color, -10, i);
				}
			});

			color_palette.appendChild(palette.container);
		};

		var isBlankPalette = function isBlankPalette(container, value) {
			if (value === 0) {
				container.setAttribute('data-collapsed', 'true');
				return true;
			}

			container.removeAttribute('data-collapsed');
			return false;
		};

		var createAlphaPalette = function createAlphaPalette() {
			var palette = new Palette('Alpha', 10);

			UIColorPicker.subscribe('picker', function(color) {
				if (palette.locked === true)
					return;

				for(var i = 0; i &lt; 10; i++) {
					palette.samples[i].updateAlpha(color, -0.1, i);
				}
			});

			color_palette.appendChild(palette.container);
		};

		var getSampleColor = function getSampleColor(id) {
			if (samples[id] !== undefined &amp;&amp; samples[id]!== null)
				return new Color(samples[id].color);
		};

		var init = function init() {
			color_palette = getElemById('color-palette');

			createHuePalette();
			createSaturationPalette();
			createVLPalette();
			createAlphaPalette();

		};

		return {
			init : init,
			getSampleColor : getSampleColor
		};

	})();

	/**
	 * ColorInfo
	 */
	var ColorInfo = (function ColorInfo() {

		var info_box;
		var select;
		var RGBA;
		var HEXA;
		var HSLA;

		var updateInfo = function updateInfo(color) {
			if (color.a | 0 === 1) {
				RGBA.info.textContent = 'RGB';
				HSLA.info.textContent = 'HSL';
			}
			else {
				RGBA.info.textContent = 'RGBA';
				HSLA.info.textContent = 'HSLA';
			}

			RGBA.value.value = color.getRGBA();
			HSLA.value.value = color.getHSLA();
			HEXA.value.value = color.getHexa();
		};

		var InfoProperty = function InfoProperty(info) {

			var node = document.createElement('div');
			var title = document.createElement('div');
			var value = document.createElement('input');
			var copy = document.createElement('div');

			node.className = 'property';
			title.className = 'type';
			value.className = 'value';
			copy.className = 'copy';

			title.textContent = info;
			value.setAttribute('type', 'text');

			copy.addEventListener('click', function() {
				value.select();
			});

			node.appendChild(title);
			node.appendChild(value);
			node.appendChild(copy);

			this.node = node;
			this.value = value;
			this.info = title;

			info_box.appendChild(node);
		};

		var init = function init() {

			info_box = getElemById('color-info');

			RGBA = new InfoProperty('RGBA');
			HSLA = new InfoProperty('HSLA');
			HEXA = new InfoProperty('HEXA');

			UIColorPicker.subscribe('picker', updateInfo);

		};

		return {
			init: init
		};

	})();

	/**
	 * ColorPicker Samples
	 */
	var ColorPickerSamples = (function ColorPickerSamples() {

		var samples = [];
		var nr_samples = 0;
		var active = null;
		var container = null;
		var	samples_per_line = 10;
		var trash_can = null;
		var base_color = new HSLColor(0, 50, 100);
		var add_btn;
		var add_btn_pos;

		var ColorSample = function ColorSample() {
			var node = document.createElement('div');
			node.className = 'sample';

			this.uid = samples.length;
			this.index = nr_samples++;
			this.node = node;
			this.color = new Color(base_color);

			node.setAttribute('sample-id', this.uid);
			node.setAttribute('draggable', 'true');

			node.addEventListener('dragstart', this.dragStart.bind(this));
			node.addEventListener('dragover' , allowDropEvent);
			node.addEventListener('drop'     , this.dragDrop.bind(this));

			this.updatePosition(this.index);
			this.updateBgColor();
			samples.push(this);
		};

		ColorSample.prototype.updateBgColor = function updateBgColor() {
			this.node.style.backgroundColor = this.color.getColor();
		};

		ColorSample.prototype.updatePosition = function updatePosition(index) {
			this.index = index;
			this.posY = 5 + ((index / samples_per_line) | 0) * 52;
			this.posX = 5 + ((index % samples_per_line) | 0) * 52;
			this.node.style.top  = this.posY + 'px';
			this.node.style.left = this.posX + 'px';
		};

		ColorSample.prototype.updateColor = function updateColor(color) {
			this.color.copy(color);
			this.updateBgColor();
		};

		ColorSample.prototype.activate = function activate() {
			UIColorPicker.setColor('picker', this.color);
			this.node.setAttribute('data-active', 'true');
		};

		ColorSample.prototype.deactivate = function deactivate() {
			this.node.removeAttribute('data-active');
		};

		ColorSample.prototype.dragStart = function dragStart(e) {
			e.dataTransfer.setData('sampleID', this.uid);
			e.dataTransfer.setData('location', 'picker-samples');
		};

		ColorSample.prototype.dragDrop = function dragDrop(e) {
			e.stopPropagation();
			this.color = Tool.getSampleColorFrom(e);
			this.updateBgColor();
		};

		ColorSample.prototype.deleteSample = function deleteSample() {
			container.removeChild(this.node);
			samples[this.uid] = null;
			nr_samples--;
		};

		var updateUI = function updateUI() {
			updateContainerProp();

			var index = 0;
			var nr = samples.length;
			for (var i=0; i &lt; nr; i++)
				if (samples[i] !== null) {
					samples[i].updatePosition(index);
					index++;
				}

			AddSampleButton.updatePosition(index);
		};

		var deleteSample = function deleteSample(e) {
			trash_can.parentElement.setAttribute('drag-state', 'none');

			var location = e.dataTransfer.getData('location');
			if (location !== 'picker-samples')
				return;

			var sampleID = e.dataTransfer.getData('sampleID');
			samples[sampleID].deleteSample();
			console.log(samples);

			updateUI();
		};

		var createDropSample = function createDropSample() {
			var sample = document.createElement('div');
			sample.id = 'drop-effect-sample';
			sample.className = 'sample';
			container.appendChild(sample);
		};

		var setActivateSample = function setActivateSample(e) {
			if (e.target.className !== 'sample')
				return;

			unsetActiveSample(active);
			Tool.unsetVoidSample();
			CanvasSamples.unsetActiveSample();
			active = samples[e.target.getAttribute('sample-id')];
			active.activate();
		};

		var unsetActiveSample = function unsetActiveSample() {
			if (active)
				active.deactivate();
			active = null;
		};

		var getSampleColor = function getSampleColor(id) {
			if (samples[id] !== undefined &amp;&amp; samples[id]!== null)
				return new Color(samples[id].color);
		};

		var updateContainerProp = function updateContainerProp() {
			samples_per_line = ((container.clientWidth - 5) / 52) | 0;
			var height = 52 * (1 + (nr_samples / samples_per_line) | 0);
			container.style.height = height + 10 + 'px';
		};

		var AddSampleButton = (function AddSampleButton() {
			var node;
			var _index = 0;
			var _posX;
			var _posY;

			var updatePosition = function updatePosition(index) {
				_index = index;
				_posY = 5 + ((index / samples_per_line) | 0) * 52;
				_posX = 5 + ((index % samples_per_line) | 0) * 52;

				node.style.top  = _posY + 'px';
				node.style.left = _posX + 'px';
			};

			var addButtonClick = function addButtonClick() {
				var sample = new ColorSample();
				container.appendChild(sample.node);
				updatePosition(_index + 1);
				updateUI();
			};

			var init = function init() {
				node = document.createElement('div');
				var icon = document.createElement('div');

				node.className = 'sample';
				icon.id = 'add-icon';
				node.appendChild(icon);
				node.addEventListener('click', addButtonClick);

				updatePosition(0);
				container.appendChild(node);
			};

			return {
				init : init,
				updatePosition : updatePosition
			};
		})();

		var init = function init() {
			container = getElemById('picker-samples');
			trash_can = getElemById('trash-can');

			AddSampleButton.init();

			for (var i=0; i&lt;16; i++) {
				var sample = new ColorSample();
				container.appendChild(sample.node);
			}

			AddSampleButton.updatePosition(samples.length);
			updateUI();

			active = samples[0];
			active.activate();

			container.addEventListener('click', setActivateSample);

			trash_can.addEventListener('dragover', allowDropEvent);
			trash_can.addEventListener('dragenter', function() {
				this.parentElement.setAttribute('drag-state', 'enter');
			});
			trash_can.addEventListener('dragleave', function(e) {
				this.parentElement.setAttribute('drag-state', 'none');
			});
			trash_can.addEventListener('drop', deleteSample);

			UIColorPicker.subscribe('picker', function(color) {
				if (active)
					active.updateColor(color);
			});

		};

		return {
			init : init,
			getSampleColor : getSampleColor,
			unsetActiveSample : unsetActiveSample
		};

	})();

	/**
	 * Canvas Samples
	 */
	var CanvasSamples = (function CanvasSamples() {

		var active = null;
		var canvas = null;
		var samples = [];
		var zindex = null;
		var tutorial = true;

		var CanvasSample = function CanvasSample(color, posX, posY) {

			var node = document.createElement('div');
			var pick = document.createElement('div');
			var delete_btn = document.createElement('div');
			node.className = 'sample';
			pick.className = 'pick';
			delete_btn.className = 'delete';

			this.uid = samples.length;
			this.node = node;
			this.color = color;
			this.updateBgColor();
			this.zIndex = 1;

			node.style.top = posY - 50 + 'px';
			node.style.left = posX - 50 + 'px';
			node.setAttribute('sample-id', this.uid);

			node.appendChild(pick);
			node.appendChild(delete_btn);

			var activate = function activate() {
				setActiveSample(this);
			}.bind(this);

			node.addEventListener('dblclick', activate);
			pick.addEventListener('click', activate);
			delete_btn.addEventListener('click', this.deleteSample.bind(this));

			UIComponent.makeDraggable(node);
			UIComponent.makeResizable(node);

			samples.push(this);
			canvas.appendChild(node);
			return this;
		};

		CanvasSample.prototype.updateBgColor = function updateBgColor() {
			this.node.style.backgroundColor = this.color.getColor();
		};

		CanvasSample.prototype.updateColor = function updateColor(color) {
			this.color.copy(color);
			this.updateBgColor();
		};

		CanvasSample.prototype.updateZIndex = function updateZIndex(value) {
			this.zIndex = value;
			this.node.style.zIndex = value;
		};

		CanvasSample.prototype.activate = function activate() {
			this.node.setAttribute('data-active', 'true');
			zindex.setAttribute('data-active', 'true');

			UIColorPicker.setColor('picker', this.color);
			InputSliderManager.setValue('z-index', this.zIndex);
		};

		CanvasSample.prototype.deactivate = function deactivate() {
			this.node.removeAttribute('data-active');
			zindex.removeAttribute('data-active');
		};

		CanvasSample.prototype.deleteSample = function deleteSample() {
			if (active === this)
				unsetActiveSample();
			canvas.removeChild(this.node);
			samples[this.uid] = null;
		};

		CanvasSample.prototype.updatePosition = function updatePosition(posX, posY) {
			this.node.style.top = posY - this.startY + 'px';
			this.node.style.left = posX - this.startX + 'px';
		};

		var canvasDropEvent = function canvasDropEvent(e) {
			var color = Tool.getSampleColorFrom(e);

			if (color) {
				var offsetX = e.pageX - canvas.offsetLeft;
				var offsetY = e.pageY - canvas.offsetTop;
				var sample = new CanvasSample(color, offsetX, offsetY);
				if (tutorial) {
					tutorial = false;
					canvas.removeAttribute('data-tutorial');
					var info = new CanvasSample(new Color(), 100, 100);
					info.node.setAttribute('data-tutorial', 'dblclick');
				}
			}

		};

		var setActiveSample = function setActiveSample(sample) {
			ColorPickerSamples.unsetActiveSample();
			Tool.unsetVoidSample();
			unsetActiveSample();
			active = sample;
			active.activate();
		};

		var unsetActiveSample = function unsetActiveSample() {
			if (active)
				active.deactivate();
			active = null;
		};

		var createToggleBgButton = function createToggleBgButton() {
			var button = document.createElement('div');
			var state = false;
			button.className = 'toggle-bg';
			canvas.appendChild(button);

			button.addEventListener('click', function() {
				console.log(state);
				state = !state;
				canvas.setAttribute('data-bg', state);
			});
		};

		var init = function init() {
			canvas = getElemById('canvas');
			zindex = getElemById('zindex');

			canvas.addEventListener('dragover', allowDropEvent);
			canvas.addEventListener('drop', canvasDropEvent);

			createToggleBgButton();

			UIColorPicker.subscribe('picker', function(color) {
				if (active)	active.updateColor(color);
			});

			InputSliderManager.subscribe('z-index', function (value) {
				if (active)	active.updateZIndex(value);
			});

			UIComponent.makeResizable(canvas, 'height');
		};

		return {
			init : init,
			unsetActiveSample : unsetActiveSample
		};

	})();

	var StateButton = function StateButton(node, state) {
		this.state = false;
		this.callback = null;

		node.addEventListener('click', function() {
			this.state = !this.state;
			if (typeof this.callback === "function")
				this.callback(this.state);
		}.bind(this));
	};

	StateButton.prototype.set = function set() {
		this.state = true;
		if (typeof this.callback === "function")
			this.callback(this.state);
	};

	StateButton.prototype.unset = function unset() {
		this.state = false;
		if (typeof this.callback === "function")
			this.callback(this.state);
	};

	StateButton.prototype.subscribe = function subscribe(func) {
		this.callback = func;
	};


	/**
	 * Tool
	 */
	var Tool = (function Tool() {

		var samples = [];
		var controls = null;
		var void_sw;

		var createPickerModeSwitch = function createPickerModeSwitch() {
			var parent = getElemById('controls');
			var icon = document.createElement('div');
			var button = document.createElement('div');
			var hsv = document.createElement('div');
			var hsl = document.createElement('div');
			var active = null;

			icon.className = 'icon picker-icon';
			button.className = 'switch';
			button.appendChild(hsv);
			button.appendChild(hsl);

			hsv.textContent = 'HSV';
			hsl.textContent = 'HSL';

			active = hsl;
			active.setAttribute('data-active', 'true');

			function switchPickingModeTo(elem) {
				active.removeAttribute('data-active');
				active = elem;
				active.setAttribute('data-active', 'true');
				UIColorPicker.setPickerMode('picker', active.textContent);
			};

			var picker_sw = new StateButton(icon);
			picker_sw.subscribe(function() {
				if (active === hsv)
					switchPickingModeTo(hsl);
				else
					switchPickingModeTo(hsv);
			});

			hsv.addEventListener('click', function() {
				switchPickingModeTo(hsv);
			});
			hsl.addEventListener('click', function() {
				switchPickingModeTo(hsl);
			});

			parent.appendChild(icon);
			parent.appendChild(button);
		};

		var setPickerDragAndDrop = function setPickerDragAndDrop() {
			var preview = document.querySelector('#picker .preview-color');
			var picking_area = document.querySelector('#picker .picking-area');

			preview.setAttribute('draggable', 'true');
			preview.addEventListener('drop', drop);
			preview.addEventListener('dragstart', dragStart);
			preview.addEventListener('dragover', allowDropEvent);

			picking_area.addEventListener('drop', drop);
			picking_area.addEventListener('dragover', allowDropEvent);

			function drop(e) {
				var color = getSampleColorFrom(e);
				UIColorPicker.setColor('picker', color);
			};

			function dragStart(e) {
				e.dataTransfer.setData('sampleID', 'picker');
				e.dataTransfer.setData('location', 'picker');
			};
		};

		var getSampleColorFrom = function getSampleColorFrom(e) {
			var sampleID = e.dataTransfer.getData('sampleID');
			var location = e.dataTransfer.getData('location');

			if (location === 'picker')
				return UIColorPicker.getColor(sampleID);
			if (location === 'picker-samples')
				return ColorPickerSamples.getSampleColor(sampleID);
			if (location === 'palette-samples')
				return ColorPalette.getSampleColor(sampleID);
		};

		var setVoidSwitch = function setVoidSwitch() {
			var void_sample = getElemById('void-sample');
			void_sw = new StateButton(void_sample);
			void_sw.subscribe( function (state) {
				void_sample.setAttribute('data-active', state);
				if (state === true) {
					ColorPickerSamples.unsetActiveSample();
					CanvasSamples.unsetActiveSample();
				}
			});
		};

		var unsetVoidSample = function unsetVoidSample() {
			void_sw.unset();
		};

		var init = function init() {
			controls = getElemById('controls');

			var color = new Color();
			color.setHSL(0, 51, 51);
			UIColorPicker.setColor('picker', color);

			setPickerDragAndDrop();
			createPickerModeSwitch();
			setVoidSwitch();
		};

		return {
			init : init,
			unsetVoidSample : unsetVoidSample,
			getSampleColorFrom : getSampleColorFrom
		};

	})();

	var init = function init() {
		UIColorPicker.init();
		InputSliderManager.init();
		ColorInfo.init();
		ColorPalette.init();
		ColorPickerSamples.init();
		CanvasSamples.init();
		Tool.init();
	};

	return {
		init : init
	};

})();

</pre>
</div>
<!-- WRAPPER - DISPLAY STATE -->
<p>This tool lets you define custom web colors.</p>
<p>The tool also provides an easy conversion between varius CSS color formats: HEXA colors, RGB (Red Green Blue) and HSL (Hue Staturation Lightness). Alpha channel is also supported on RGB (rgba) and HSL (hsla) formats.</p>
<p>Each color is preseted in all 3 standard web CSS formats.</p>
<p>Based on the current color a color palette for Hue, Staturation, Lightness/Brightness and Alpha will be generated.</p>
<p>The picker can be set to HSL or HSV (hue, staturation, value) format.</p>
<p>{{ EmbedLiveSample('ColorPIcker_Tool', '100%', '900') }}</p>
<p>&nbsp;</p>
Reverter para esta revisão