Commit 4cb0d2a4 authored by Sanket Joshi's avatar Sanket Joshi Committed by Commit Bot

Add support for the HSL color format to the new color picker.

Prior to this CL, the new color picker supported the HEX and RGB color
formats. Now, users can also view and/or manually change the selected
color in the HSL color format.

Users can switch between the HEX, RGB and HSL by clicking on the format
toggler. To make it easier to translate values from one format to
another, additional helper functions like rgbToHSL and hslToHex are
being added to the Color class.
Update hex format toggle test and add hsl format toggle test.

Change-Id: I7a215af1788018c5a895b76c71a02c9aeeb987bd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1731777Reviewed-by: default avatarMason Freed <masonfreed@chromium.org>
Reviewed-by: default avatarKent Tamura <tkent@chromium.org>
Commit-Queue: Sanket Joshi <sajos@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#684033}
parent e3d16e3d
...@@ -74,8 +74,12 @@ class Color { ...@@ -74,8 +74,12 @@ class Color {
[this.rValue_, this.gValue_, this.bValue_] = [this.rValue_, this.gValue_, this.bValue_] =
colorStringOrFormat.substring(4, colorStringOrFormat.length - 1) colorStringOrFormat.substring(4, colorStringOrFormat.length - 1)
.split(',').map(Number); .split(',').map(Number);
} else if (colorStringOrFormat.startsWith('hsl')) {
colorStringOrFormat = colorStringOrFormat.replace(/%|\s+/g, '');
[this.hValue_, this.sValue_, this.lValue_] =
colorStringOrFormat.substring(4, colorStringOrFormat.length - 1)
.split(',').map(Number);
} }
// TODO(crbug.com/982088): Add support for HSL
} else { } else {
switch(colorStringOrFormat) { switch(colorStringOrFormat) {
case ColorFormat.HEX: case ColorFormat.HEX:
...@@ -84,7 +88,9 @@ class Color { ...@@ -84,7 +88,9 @@ class Color {
case ColorFormat.RGB: case ColorFormat.RGB:
[this.rValue_, this.gValue_, this.bValue_] = colorValues.map(Number); [this.rValue_, this.gValue_, this.bValue_] = colorValues.map(Number);
break; break;
// TODO(crbug.com/982088): Add support for HSL case ColorFormat.HSL:
[this.hValue_, this.sValue_, this.lValue_] = colorValues.map(Number);
break;
} }
} }
} }
...@@ -110,8 +116,10 @@ class Color { ...@@ -110,8 +116,10 @@ class Color {
} else if (this.rValue_ !== undefined) { } else if (this.rValue_ !== undefined) {
this.hexValue_ = this.hexValue_ =
Color.rgbToHex(this.rValue_, this.gValue_, this.bValue_); Color.rgbToHex(this.rValue_, this.gValue_, this.bValue_);
} else if (this.hValue_ !== undefined) {
this.hexValue_ =
Color.hslToHex(this.hValue_, this.sValue_, this.lValue_);
} }
// TODO(crbug.com/982088): Add support for HSL
} }
asHex() { asHex() {
...@@ -148,8 +156,11 @@ class Color { ...@@ -148,8 +156,11 @@ class Color {
} else if (this.hexValue_ !== undefined) { } else if (this.hexValue_ !== undefined) {
[this.rValue_, this.gValue_, this.bValue_] = [this.rValue_, this.gValue_, this.bValue_] =
Color.hexToRGB(this.hexValue_); Color.hexToRGB(this.hexValue_);
} else if (this.hValue_ !== undefined) {
[this.rValue_, this.gValue_, this.bValue_] =
Color.hslToRGB(this.hValue_, this.sValue_, this.lValue_)
.map(Math.round);
} }
// TODO(crbug.com/982088): Add support for HSL
} }
rgbValues() { rgbValues() {
...@@ -160,6 +171,51 @@ class Color { ...@@ -160,6 +171,51 @@ class Color {
return 'rgb(' + this.rgbValues().join() + ')'; return 'rgb(' + this.rgbValues().join() + ')';
} }
/**
* @returns {number} between 0 and 359
*/
get hValue() {
this.computeHSLValues_();
return this.hValue_;
}
/**
* @returns {number} between 0 and 100
*/
get sValue() {
this.computeHSLValues_();
return this.sValue_;
}
/**
* @returns {number} between 0 and 100
*/
get lValue() {
this.computeHSLValues_();
return this.lValue_;
}
computeHSLValues_() {
if (this.hValue_ !== undefined) {
// Already computed.
} else if (this.rValue_ !== undefined) {
[this.hValue_, this.sValue_, this.lValue_] =
Color.rgbToHSL(this.rValue_, this.gValue_, this.bValue_)
.map(Math.round);
} else if (this.hexValue_ !== undefined) {
[this.hValue_, this.sValue_, this.lValue_] =
Color.hexToHSL(this.hexValue_).map(Math.round);
}
}
hslValues() {
return [this.hValue, this.sValue, this.lValue];
}
asHSL() {
return 'hsl(' + this.hValue + ',' + this.sValue + '%,' + this.lValue + '%)';
}
/** /**
* @param {string} hexValue * @param {string} hexValue
* @returns {number[]} * @returns {number[]}
...@@ -184,6 +240,108 @@ class Color { ...@@ -184,6 +240,108 @@ class Color {
return (cumulativeHexValue + hexValue); return (cumulativeHexValue + hexValue);
}, ''); }, '');
} }
/**
* The algorithm has been written based on the mathematical formula found at:
* https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB.
* @param {...number} hslValues
* @returns {number[]}
*/
static hslToRGB(...hslValues) {
let [hValue, sValue, lValue] = hslValues;
hValue /= 60;
sValue /= 100;
lValue /= 100;
let rValue = lValue;
let gValue = lValue;
let bValue = lValue;
let match = 0;
if (sValue !== 0) {
const chroma = (1 - Math.abs(2 * lValue - 1)) * sValue;
const x = chroma * (1 - Math.abs(hValue % 2 - 1));
match = lValue - chroma / 2;
if ((0 <= hValue) && (hValue <= 1)) {
rValue = chroma;
gValue = x;
bValue = 0;
} else if ((1 < hValue) && (hValue <= 2)) {
rValue = x;
gValue = chroma;
bValue = 0;
} else if ((2 < hValue) && (hValue <= 3)) {
rValue = 0;
gValue = chroma;
bValue = x;
} else if ((3 < hValue) && (hValue <= 4)) {
rValue = 0;
gValue = x;
bValue = chroma;
} else if ((4 < hValue) && (hValue <= 5)) {
rValue = x;
gValue = 0;
bValue = chroma;
} else {
// (5 < hValue) && (hValue < 6)
rValue = chroma;
gValue = 0;
bValue = x;
}
}
rValue = (rValue + match) * 255;
gValue = (gValue + match) * 255;
bValue = (bValue + match) * 255;
return [rValue, gValue, bValue];
}
/**
* The algorithm has been written based on the mathematical formula found at:
* https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB.
* @param {...number} rgbValues
* @returns {number[]}
*/
static rgbToHSL(...rgbValues) {
const [rValue, gValue, bValue] = rgbValues.map((value) => value / 255);
const max = Math.max(rValue, gValue, bValue);
const min = Math.min(rValue, gValue, bValue);
let hValue = 0;
let sValue = 0;
let lValue = (max + min) / 2;
if (max !== min) {
const diff = max - min;
if (max === rValue) {
hValue = ((gValue - bValue) / diff);
} else if (max === gValue) {
hValue = ((bValue - rValue) / diff) + 2;
} else {
// max === bValue
hValue = ((rValue - gValue) / diff) + 4;
}
hValue *= 60;
if (hValue < 0) {
hValue += 360;
}
sValue = (diff / (1 - Math.abs(2 * lValue - 1))) * 100;
}
lValue *= 100;
return [hValue, sValue, lValue];
}
/**
* @param {...number} rgbValues
* @returns {string}
*/
static hslToHex(...hslValues) {
return Color.rgbToHex(...Color.hslToRGB(...hslValues).map(Math.round));
}
/**
* @param {string} hexValue
* @returns {...number}
*/
static hexToHSL(hexValue) {
return Color.rgbToHSL(...Color.hexToRGB(hexValue));
}
} }
/** /**
...@@ -290,30 +448,27 @@ class ManualColorPicker extends HTMLElement { ...@@ -290,30 +448,27 @@ class ManualColorPicker extends HTMLElement {
initialColor); initialColor);
this.rgbValueContainer_ = new ColorValueContainer(ColorFormat.RGB, this.rgbValueContainer_ = new ColorValueContainer(ColorFormat.RGB,
initialColor); initialColor);
this.hslValueContainer_ = new ColorValueContainer(ColorFormat.HSL,
initialColor);
this.colorValueContainers_ = [ this.colorValueContainers_ = [
this.hexValueContainer_, this.hexValueContainer_,
this.rgbValueContainer_, this.rgbValueContainer_,
// TODO(crbug.com/982088): Add support for HSL this.hslValueContainer_,
]; ];
this.formatToggler_ = new FormatToggler(ColorFormat.RGB); this.currentColorFormat_ = ColorFormat.RGB;
this.adjustValueContainerVisibility_();
this.formatToggler_ = new FormatToggler(this.currentColorFormat_);
this.append(...this.colorValueContainers_, this.formatToggler_); this.append(...this.colorValueContainers_, this.formatToggler_);
this.hexValueContainer_.hide();
this.rgbValueContainer_.show();
this.formatToggler_ this.formatToggler_
.addEventListener('format-change', this.onFormatChange_); .addEventListener('format-change', this.onFormatChange_);
this.addEventListener('manual-color-change', this.onManualColorChange_); this.addEventListener('manual-color-change', this.onManualColorChange_);
} }
/** adjustValueContainerVisibility_() {
* @param {!Event} event
*/
onFormatChange_ = (event) => {
const newColorFormat = event.detail.colorFormat;
this.colorValueContainers_.forEach((colorValueContainer) => { this.colorValueContainers_.forEach((colorValueContainer) => {
if (colorValueContainer.colorFormat === newColorFormat) { if (colorValueContainer.colorFormat === this.currentColorFormat_) {
colorValueContainer.show(); colorValueContainer.show();
} else { } else {
colorValueContainer.hide(); colorValueContainer.hide();
...@@ -321,6 +476,14 @@ class ManualColorPicker extends HTMLElement { ...@@ -321,6 +476,14 @@ class ManualColorPicker extends HTMLElement {
}); });
} }
/**
* @param {!Event} event
*/
onFormatChange_ = (event) => {
this.currentColorFormat_ = event.detail.colorFormat;
this.adjustValueContainerVisibility_();
}
/** /**
* @param {!Event} event * @param {!Event} event
*/ */
...@@ -360,8 +523,17 @@ class ColorValueContainer extends HTMLElement { ...@@ -360,8 +523,17 @@ class ColorValueContainer extends HTMLElement {
this.channelValueContainers_.push(rValueContainer, this.channelValueContainers_.push(rValueContainer,
gValueContainer, gValueContainer,
bValueContainer); bValueContainer);
} else if (this.colorFormat_ === ColorFormat.HSL) {
const hValueContainer = new ChannelValueContainer(ColorChannel.H,
initialColor);
const sValueContainer = new ChannelValueContainer(ColorChannel.S,
initialColor);
const lValueContainer = new ChannelValueContainer(ColorChannel.L,
initialColor);
this.channelValueContainers_.push(hValueContainer,
sValueContainer,
lValueContainer);
} }
// TODO(crbug.com/982088): Add support for HSL
this.append(...this.channelValueContainers_); this.append(...this.channelValueContainers_);
this.channelValueContainers_.forEach((channelValueContainer) => this.channelValueContainers_.forEach((channelValueContainer) =>
...@@ -427,9 +599,16 @@ class ChannelValueContainer extends HTMLInputElement { ...@@ -427,9 +599,16 @@ class ChannelValueContainer extends HTMLInputElement {
case ColorChannel.R: case ColorChannel.R:
case ColorChannel.G: case ColorChannel.G:
case ColorChannel.B: case ColorChannel.B:
this.setAttribute('maxLength', '3'); this.setAttribute('maxlength', '3');
break;
case ColorChannel.H:
this.setAttribute('maxlength', '3');
break;
case ColorChannel.S:
case ColorChannel.L:
// up to 3 digits plus '%'
this.setAttribute('maxlength', '4');
break; break;
// TODO(crbug.com/982088): Add support for HSL
} }
this.setValue(initialColor); this.setValue(initialColor);
...@@ -469,7 +648,24 @@ class ChannelValueContainer extends HTMLInputElement { ...@@ -469,7 +648,24 @@ class ChannelValueContainer extends HTMLInputElement {
this.value = this.channelValue_; this.value = this.channelValue_;
} }
break; break;
// TODO(crbug.com/982088): Add support for HSL case ColorChannel.H:
if (this.channelValue_ !== color.hValue) {
this.channelValue_ = color.hValue;
this.value = this.channelValue_;
}
break;
case ColorChannel.S:
if (this.channelValue_ !== color.sValue) {
this.channelValue_ = color.sValue;
this.value = this.channelValue_ + '%';
}
break;
case ColorChannel.L:
if (this.channelValue_ !== color.lValue) {
this.channelValue_ = color.lValue;
this.value = this.channelValue_ + '%';
}
break;
} }
} }
...@@ -495,7 +691,20 @@ class ChannelValueContainer extends HTMLInputElement { ...@@ -495,7 +691,20 @@ class ChannelValueContainer extends HTMLInputElement {
this.channelValue_ = Number(value); this.channelValue_ = Number(value);
} }
break; break;
// TODO(crbug.com/982088): Add support for HSL case ColorChannel.H:
if (value.match(/^\d+$/) && (0 <= value) && (value < 360)) {
this.channelValue_ = Number(value);
}
break;
case ColorChannel.S:
case ColorChannel.L:
if (value.endsWith('%')) {
value = value.substring(0, value.length - 1);
if (value.match(/^\d+$/) && (0 <= value) && (value <= 100)) {
this.channelValue_ = Number(value);
}
}
break;
} }
} }
} }
...@@ -517,12 +726,13 @@ class FormatToggler extends HTMLElement { ...@@ -517,12 +726,13 @@ class FormatToggler extends HTMLElement {
this.currentColorFormat_ = initialColorFormat; this.currentColorFormat_ = initialColorFormat;
this.hexFormatLabel_ = new FormatLabel(ColorFormat.HEX); this.hexFormatLabel_ = new FormatLabel(ColorFormat.HEX);
this.rgbFormatLabel_ = new FormatLabel(ColorFormat.RGB); this.rgbFormatLabel_ = new FormatLabel(ColorFormat.RGB);
this.hslFormatLabel_ = new FormatLabel(ColorFormat.HSL);
this.colorFormatLabels_ = [ this.colorFormatLabels_ = [
this.hexFormatLabel_, this.hexFormatLabel_,
this.rgbFormatLabel_, this.rgbFormatLabel_,
// TODO(crbug.com/982088): Add support for HSL this.hslFormatLabel_,
]; ];
this.adjustFormatLabelVisibility(); this.adjustFormatLabelVisibility_();
this.upDownIcon_ = document.createElement('span'); this.upDownIcon_ = document.createElement('span');
this.upDownIcon_.innerHTML = this.upDownIcon_.innerHTML =
...@@ -539,7 +749,7 @@ class FormatToggler extends HTMLElement { ...@@ -539,7 +749,7 @@ class FormatToggler extends HTMLElement {
this.addEventListener('mousedown', (event) => event.preventDefault()); this.addEventListener('mousedown', (event) => event.preventDefault());
} }
adjustFormatLabelVisibility() { adjustFormatLabelVisibility_() {
this.colorFormatLabels_.forEach((colorFormatLabel) => { this.colorFormatLabels_.forEach((colorFormatLabel) => {
if (colorFormatLabel.colorFormat === this.currentColorFormat_) { if (colorFormatLabel.colorFormat === this.currentColorFormat_) {
colorFormatLabel.show(); colorFormatLabel.show();
...@@ -553,10 +763,11 @@ class FormatToggler extends HTMLElement { ...@@ -553,10 +763,11 @@ class FormatToggler extends HTMLElement {
if (this.currentColorFormat_ == ColorFormat.HEX) { if (this.currentColorFormat_ == ColorFormat.HEX) {
this.currentColorFormat_ = ColorFormat.RGB; this.currentColorFormat_ = ColorFormat.RGB;
} else if (this.currentColorFormat_ == ColorFormat.RGB) { } else if (this.currentColorFormat_ == ColorFormat.RGB) {
this.currentColorFormat_ = ColorFormat.HSL;
} else if (this.currentColorFormat_ == ColorFormat.HSL) {
this.currentColorFormat_ = ColorFormat.HEX; this.currentColorFormat_ = ColorFormat.HEX;
} }
// TODO(crbug.com/982088): Add support for HSL this.adjustFormatLabelVisibility_();
this.adjustFormatLabelVisibility();
this.dispatchEvent(new CustomEvent('format-change', { this.dispatchEvent(new CustomEvent('format-change', {
detail: { detail: {
...@@ -581,15 +792,21 @@ class FormatLabel extends HTMLElement { ...@@ -581,15 +792,21 @@ class FormatLabel extends HTMLElement {
if (colorFormat === ColorFormat.HEX) { if (colorFormat === ColorFormat.HEX) {
this.hexChannelLabel_ = new ChannelLabel(ColorChannel.HEX); this.hexChannelLabel_ = new ChannelLabel(ColorChannel.HEX);
this.append(this.hexChannelLabel_); this.append(this.hexChannelLabel_);
} else { } else if (colorFormat === ColorFormat.RGB) {
this.rChannelLabel_ = new ChannelLabel(ColorChannel.R); this.rChannelLabel_ = new ChannelLabel(ColorChannel.R);
this.gChannelLabel_ = new ChannelLabel(ColorChannel.G); this.gChannelLabel_ = new ChannelLabel(ColorChannel.G);
this.bChannelLabel_ = new ChannelLabel(ColorChannel.B); this.bChannelLabel_ = new ChannelLabel(ColorChannel.B);
this.append(this.rChannelLabel_, this.append(this.rChannelLabel_,
this.gChannelLabel_, this.gChannelLabel_,
this.bChannelLabel_); this.bChannelLabel_);
} else if (colorFormat === ColorFormat.HSL) {
this.hChannelLabel_ = new ChannelLabel(ColorChannel.H);
this.sChannelLabel_ = new ChannelLabel(ColorChannel.S);
this.lChannelLabel_ = new ChannelLabel(ColorChannel.L);
this.append(this.hChannelLabel_,
this.sChannelLabel_,
this.lChannelLabel_);
} }
// TODO(crbug.com/982088): Add support for HSL
} }
get colorFormat() { get colorFormat() {
...@@ -624,8 +841,13 @@ class ChannelLabel extends HTMLElement { ...@@ -624,8 +841,13 @@ class ChannelLabel extends HTMLElement {
this.textContent = 'G'; this.textContent = 'G';
} else if (colorChannel === ColorChannel.B) { } else if (colorChannel === ColorChannel.B) {
this.textContent = 'B'; this.textContent = 'B';
} else if (colorChannel === ColorChannel.H) {
this.textContent = 'H';
} else if (colorChannel === ColorChannel.S) {
this.textContent = 'S';
} else if (colorChannel === ColorChannel.L) {
this.textContent = 'L';
} }
// TODO(crbug.com/982088): Add support for HSL
} }
} }
window.customElements.define('channel-label', ChannelLabel); window.customElements.define('channel-label', ChannelLabel);
......
...@@ -20,7 +20,8 @@ function openPickerSuccessfulCallback() { ...@@ -20,7 +20,8 @@ function openPickerSuccessfulCallback() {
popupWindow.focus(); popupWindow.focus();
const popupDocument = popupWindow.document; const popupDocument = popupWindow.document;
const formatToggler = popupDocument.querySelector('format-toggler'); const formatToggler = popupDocument.querySelector('format-toggler');
formatToggler.click(); formatToggler.click(); // first click changes format to HSL
formatToggler.click(); // second click changes format to Hex
testRunner.notifyDone(); testRunner.notifyDone();
} }
</script> </script>
......
<!DOCTYPE html>
<html>
<head>
<script>
testRunner.setUseMockTheme(false);
testRunner.waitUntilDone();
</script>
<script src='../../../forms/resources/picker-common.js'></script>
</head>
<body>
<input type='color' id='color' value='#7EFFC9'>
<p id='description' style='opacity: 0'></p>
<div id='console' style='opacity: 0'></div>
<script>
openPicker(document.getElementById('color'), openPickerSuccessfulCallback, () => testRunner.notifyDone());
function openPickerSuccessfulCallback() {
popupWindow.focus();
const popupDocument = popupWindow.document;
const formatToggler = popupDocument.querySelector('format-toggler');
formatToggler.click();
testRunner.notifyDone();
}
</script>
</body>
</html>
\ No newline at end of file
...@@ -20,6 +20,9 @@ let hexValueContainer = new ChannelValueContainer(ColorChannel.HEX, new Color('# ...@@ -20,6 +20,9 @@ let hexValueContainer = new ChannelValueContainer(ColorChannel.HEX, new Color('#
let rValueContainer = new ChannelValueContainer(ColorChannel.R, new Color('#7effc9')); let rValueContainer = new ChannelValueContainer(ColorChannel.R, new Color('#7effc9'));
let gValueContainer = new ChannelValueContainer(ColorChannel.G, new Color('#7effc9')); let gValueContainer = new ChannelValueContainer(ColorChannel.G, new Color('#7effc9'));
let bValueContainer = new ChannelValueContainer(ColorChannel.B, new Color('#7effc9')); let bValueContainer = new ChannelValueContainer(ColorChannel.B, new Color('#7effc9'));
let hValueContainer = new ChannelValueContainer(ColorChannel.H, new Color('#7effc9'));
let sValueContainer = new ChannelValueContainer(ColorChannel.S, new Color('#7effc9'));
let lValueContainer = new ChannelValueContainer(ColorChannel.L, new Color('#7effc9'));
function setContainerValue(valueContainer, value) { function setContainerValue(valueContainer, value) {
valueContainer.value = value; valueContainer.value = value;
...@@ -42,6 +45,15 @@ function resetContainerValues(...valueContainers) { ...@@ -42,6 +45,15 @@ function resetContainerValues(...valueContainers) {
case ColorChannel.B: case ColorChannel.B:
setContainerValue(valueContainer, '201'); setContainerValue(valueContainer, '201');
break; break;
case ColorChannel.H:
setContainerValue(valueContainer, '155');
break;
case ColorChannel.S:
setContainerValue(valueContainer, '100%');
break;
case ColorChannel.L:
setContainerValue(valueContainer, '75%');
break;
} }
}); });
} }
...@@ -51,6 +63,9 @@ test(() => { ...@@ -51,6 +63,9 @@ test(() => {
assert_equals(rValueContainer.channelValue_, 126); assert_equals(rValueContainer.channelValue_, 126);
assert_equals(gValueContainer.channelValue_, 255); assert_equals(gValueContainer.channelValue_, 255);
assert_equals(bValueContainer.channelValue_, 201); assert_equals(bValueContainer.channelValue_, 201);
assert_equals(hValueContainer.channelValue_, 155);
assert_equals(sValueContainer.channelValue_, 100);
assert_equals(lValueContainer.channelValue_, 75);
}, 'initial values'); }, 'initial values');
test(() => { test(() => {
...@@ -154,6 +169,82 @@ test(() => { ...@@ -154,6 +169,82 @@ test(() => {
setContainerValue(bValueContainer, ''); setContainerValue(bValueContainer, '');
assert_equals(bValueContainer.channelValue_, 201); assert_equals(bValueContainer.channelValue_, 201);
}, 'rgbValueContainers onValueChange_ empty values'); }, 'rgbValueContainers onValueChange_ empty values');
test(() => {
resetContainerValues(hValueContainer, sValueContainer, lValueContainer);
setContainerValue(hValueContainer, '275');
assert_equals(hValueContainer.channelValue_, 275);
setContainerValue(sValueContainer, '86%');
assert_equals(sValueContainer.channelValue_, 86);
setContainerValue(lValueContainer, '7%');
assert_equals(lValueContainer.channelValue_, 7);
}, 'hslValueContainers onValueChange_ valid change');
test(() => {
resetContainerValues(hValueContainer, sValueContainer, lValueContainer);
setContainerValue(hValueContainer, '018');
assert_equals(hValueContainer.channelValue_, 18);
setContainerValue(sValueContainer, '005%');
assert_equals(sValueContainer.channelValue_, 5);
setContainerValue(lValueContainer, '099%');
assert_equals(lValueContainer.channelValue_, 99);
}, 'hslValueContainers onValueChange_ leading zero values');
test(() => {
resetContainerValues(hValueContainer, sValueContainer, lValueContainer);
setContainerValue(hValueContainer, '-1');
assert_equals(hValueContainer.channelValue_, 155);
setContainerValue(sValueContainer, '-10%');
assert_equals(sValueContainer.channelValue_, 100);
setContainerValue(lValueContainer, '-0%');
assert_equals(lValueContainer.channelValue_, 75);
}, 'hslValueContainers onValueChange_ negative values');
test(() => {
resetContainerValues(hValueContainer, sValueContainer, lValueContainer);
setContainerValue(hValueContainer, '%^&');
assert_equals(hValueContainer.channelValue_, 155);
setContainerValue(sValueContainer, 'ABC');
assert_equals(sValueContainer.channelValue_, 100);
setContainerValue(lValueContainer, ',){^');
assert_equals(lValueContainer.channelValue_, 75);
}, 'hslValueContainers onValueChange_ non number values');
test(() => {
resetContainerValues(hValueContainer, sValueContainer, lValueContainer);
setContainerValue(hValueContainer, '3.2');
assert_equals(hValueContainer.channelValue_, 155);
setContainerValue(sValueContainer, '5.0%');
assert_equals(sValueContainer.channelValue_, 100);
setContainerValue(lValueContainer, '9.9%');
assert_equals(lValueContainer.channelValue_, 75);
}, 'hslValueContainers onValueChange_ decimal values');
test(() => {
resetContainerValues(hValueContainer, sValueContainer, lValueContainer);
setContainerValue(hValueContainer, '');
assert_equals(hValueContainer.channelValue_, 155);
setContainerValue(sValueContainer, '');
assert_equals(sValueContainer.channelValue_, 100);
setContainerValue(lValueContainer, '');
assert_equals(lValueContainer.channelValue_, 75);
}, 'hslValueContainers onValueChange_ empty values');
test(() => {
resetContainerValues(sValueContainer, lValueContainer);
setContainerValue(sValueContainer, '%');
assert_equals(sValueContainer.channelValue_, 100);
setContainerValue(lValueContainer, '%');
assert_equals(lValueContainer.channelValue_, 75);
}, 'slValueContainers onValueChange_ only \'%\'');
test(() => {
resetContainerValues(sValueContainer, lValueContainer);
setContainerValue(sValueContainer, '97');
assert_equals(sValueContainer.channelValue_, 100);
setContainerValue(lValueContainer, '34');
assert_equals(lValueContainer.channelValue_, 75);
}, 'slValueContainers onValueChange_ without \'%\'');
</script> </script>
</body> </body>
</html> </html>
\ No newline at end of file
...@@ -18,11 +18,17 @@ ...@@ -18,11 +18,17 @@
testEquals(); testEquals();
testHexToRGB(); testHexToRGB();
testRGBToHex() testRGBToHex();
testRGBToHSL();
testHSLToRGB();
testHexToHSL();
testHSLToHex();
testHexValueGetter(); testHexValueGetter();
testRGBValueGetters(); testRGBValueGetters();
testHSLValueGetters();
testAsHex(); testAsHex();
testAsRGB(); testAsRGB();
testAsHSL();
function testEquals() { function testEquals() {
test(() => { test(() => {
...@@ -33,6 +39,10 @@ function testEquals() { ...@@ -33,6 +39,10 @@ function testEquals() {
assert_true(new Color('rgb(255,255,255)').equals(new Color(ColorFormat.RGB, 255, 255, 255))); assert_true(new Color('rgb(255,255,255)').equals(new Color(ColorFormat.RGB, 255, 255, 255)));
}, 'new Color(\'rgb(255,255,255)\').equals(new Color(ColorFormat.RGB, 255, 255, 255))'); }, 'new Color(\'rgb(255,255,255)\').equals(new Color(ColorFormat.RGB, 255, 255, 255))');
test(() => {
assert_true(new Color('hsl(117,82%,55%)').equals(new Color(ColorFormat.HSL, 117, 82, 55)));
}, 'new Color(\'hsl(117,82%,55%)\').equals(new Color(ColorFormat.RGB, 117, 82, 55))');
test(() => { test(() => {
assert_true(new Color('#caebca').equals(new Color(ColorFormat.RGB, 202, 235, 202))); assert_true(new Color('#caebca').equals(new Color(ColorFormat.RGB, 202, 235, 202)));
}, 'new Color(\'#caebca\').equals(new Color(ColorFormat.RGB, 202, 235, 202))'); }, 'new Color(\'#caebca\').equals(new Color(ColorFormat.RGB, 202, 235, 202))');
...@@ -40,6 +50,22 @@ function testEquals() { ...@@ -40,6 +50,22 @@ function testEquals() {
test(() => { test(() => {
assert_true(new Color(ColorFormat.RGB, 46, 224, 255).equals(new Color('#2ee0ff'))); assert_true(new Color(ColorFormat.RGB, 46, 224, 255).equals(new Color('#2ee0ff')));
}, 'new Color(\'new Color(\'rgb(46,224,255)\').equals(new Color(\'#2ee0ff\')))'); }, 'new Color(\'new Color(\'rgb(46,224,255)\').equals(new Color(\'#2ee0ff\')))');
test(() => {
assert_true(new Color('hsl(195, 100%, 50%)').equals(new Color(ColorFormat.HEX, '00bfff')));
}, 'new Color(\'hsl(195, 100%, 50%)\').equals(new Color(ColorFormat.HEX, \'00bfff\'))');
test(() => {
assert_true(new Color('#140221').equals(new Color(ColorFormat.HSL, 275, 86, 7)));
}, 'new Color(\'#140221\').equals(new Color(ColorFormat.HSL, 275, 86, 7))');
test(() => {
assert_true(new Color(ColorFormat.RGB, 81, 97, 164).equals(new Color(ColorFormat.HSL, 228, 34, 48)));
}, 'new Color(\'new Color(ColorFormat.RGB, 81, 97, 164).equals(new Color(ColorFormat.HSL, 228, 34, 48)))');
test(() => {
assert_true(new Color('rgb(142, 197, 32)').equals(new Color('hsl(80,72%,45%)')));
}, 'new Color(\'rgb(142, 197, 32)\').equals(new Color(\'hsl(80,72%,45%)\'))');
} }
function testHexToRGB() { function testHexToRGB() {
...@@ -118,6 +144,90 @@ function testRGBToHex() { ...@@ -118,6 +144,90 @@ function testRGBToHex() {
}, 'Color.rgbToHex(169, 245, 192)'); }, 'Color.rgbToHex(169, 245, 192)');
} }
function testRGBToHSL() {
test(() => {
assert_equals(JSON.stringify([0, 0, 0]), JSON.stringify(Color.rgbToHSL(0, 0, 0).map(Math.round)));
}, 'Color.rgbToHSL(0, 0, 0).map(Math.round)');
test(() => {
assert_equals(JSON.stringify([0, 0, 100]), JSON.stringify(Color.rgbToHSL(255, 255, 255).map(Math.round)));
}, 'Color.rgbToHSL(255, 255, 255).map(Math.round)');
test(() => {
assert_equals(JSON.stringify([98, 49, 31]), JSON.stringify(Color.rgbToHSL(70, 119, 41).map(Math.round)));
}, 'Color.rgbToHSL(70, 119, 41).map(Math.round)');
test(() => {
assert_equals(JSON.stringify([299, 91, 44]), JSON.stringify(Color.rgbToHSL(212, 10, 214).map(Math.round)));
}, 'Color.rgbToHSL(212, 10, 214).map(Math.round)');
test(() => {
assert_equals(JSON.stringify([80, 72, 45]), JSON.stringify(Color.rgbToHSL(142, 197, 32).map(Math.round)));
}, 'Color.rgbToHSL(142, 197, 32).map(Math.round)');
}
function testHSLToRGB() {
test(() => {
assert_equals(JSON.stringify([0, 0, 0]), JSON.stringify(Color.hslToRGB(0, 0, 0).map(Math.round)));
}, 'Color.hslToRGB(0, 0, 0).map(Math.round)');
test(() => {
assert_equals(JSON.stringify([255, 255, 255]), JSON.stringify(Color.hslToRGB(0, 0, 100).map(Math.round)));
}, 'Color.hslToRGB(0, 0, 100).map(Math.round)');
test(() => {
assert_equals(JSON.stringify([63, 75, 65]), JSON.stringify(Color.hslToRGB(133, 9, 27).map(Math.round)));
}, 'Color.hslToRGB(133, 9, 27).map(Math.round)');
test(() => {
assert_equals(JSON.stringify([37, 250, 254]), JSON.stringify(Color.hslToRGB(181, 99, 57).map(Math.round)));
}, 'Color.hslToRGB(181, 99, 57).map(Math.round)');
test(() => {
assert_equals(JSON.stringify([142, 197, 32]), JSON.stringify(Color.hslToRGB(80, 72, 45).map(Math.round)));
}, 'Color.hslToRGB(80, 72, 45).map(Math.round)');
}
function testHexToHSL() {
test(() => {
assert_equals(JSON.stringify([0, 0, 0]), JSON.stringify(Color.hexToHSL('000000').map(Math.round)));
}, 'Color.hexToHSL(\'000000\').map(Math.round)');
test(() => {
assert_equals(JSON.stringify([0, 0, 100]), JSON.stringify(Color.hexToHSL('ffffff').map(Math.round)));
}, 'Color.hexToHSL(\'ffffff\').map(Math.round)');
test(() => {
assert_equals(JSON.stringify([162, 43, 66]), JSON.stringify(Color.hexToHSL('83ceb7').map(Math.round)));
}, 'Color.hexToHSL(\'83ceb7\').map(Math.round)');
test(() => {
assert_equals(JSON.stringify([80, 72, 45]), JSON.stringify(Color.hexToHSL('8ec520').map(Math.round)));
}, 'Color.hexToHSL(\'8ec520\').map(Math.round)');
}
function testHSLToHex() {
test(() => {
assert_equals('000000', Color.hslToHex(0, 0, 0));
}, 'Color.hslToHex(0, 0, 0)');
test(() => {
assert_equals('ffffff', Color.hslToHex(0, 0, 100));
}, 'Color.hslToHex(0, 0, 100)');
test(() => {
assert_equals('672caf', Color.hslToHex(267, 60, 43));
}, 'Color.hslToHex(267, 60, 43)');
test(() => {
assert_equals('dddecf', Color.hslToHex(63, 18, 84));
}, 'Color.hslToHex(63, 18, 84)');
test(() => {
assert_equals('8ec520', Color.hslToHex(80, 72, 45));
}, 'Color.hslToHex(80, 72, 45)');
}
function testHexValueGetter() { function testHexValueGetter() {
test(() => { test(() => {
assert_equals('1f8069', new Color('#1f8069').hexValue); assert_equals('1f8069', new Color('#1f8069').hexValue);
...@@ -134,6 +244,14 @@ function testHexValueGetter() { ...@@ -134,6 +244,14 @@ function testHexValueGetter() {
test(() => { test(() => {
assert_equals('17679c', new Color(ColorFormat.RGB, 23, 103, 156).hexValue); assert_equals('17679c', new Color(ColorFormat.RGB, 23, 103, 156).hexValue);
}, 'new Color(ColorFormat.RGB, 23, 103, 156).hexValue'); }, 'new Color(ColorFormat.RGB, 23, 103, 156).hexValue');
test(() => {
assert_equals('c505f5', new Color('hsl(288,96%,49%)').hexValue);
}, 'new Color(\'hsl(288,96%,49%)\').hexValue');
test(() => {
assert_equals('388f50', new Color(ColorFormat.HSL, 137, 44, 39).hexValue);
}, 'new Color(ColorFormat.HSL, 137, 44, 39).hexValue');
} }
function testRGBValueGetters() { function testRGBValueGetters() {
...@@ -184,6 +302,104 @@ function testRGBValueGetters() { ...@@ -184,6 +302,104 @@ function testRGBValueGetters() {
test(() => { test(() => {
assert_equals(72, new Color(ColorFormat.RGB, 65, 84, 72).bValue); assert_equals(72, new Color(ColorFormat.RGB, 65, 84, 72).bValue);
}, 'new Color(ColorFormat.RGB, 65, 84, 72).bValue'); }, 'new Color(ColorFormat.RGB, 65, 84, 72).bValue');
test(() => {
assert_equals(20, new Color('hsl(116,79%,25%)').rValue);
}, 'new Color(\'hsl(116,79%,25%)\').rValue');
test(() => {
assert_equals(114, new Color('hsl(116,79%,25%)').gValue);
}, 'new Color(\'hsl(116,79%,25%)\').gValue');
test(() => {
assert_equals(13, new Color('hsl(116,79%,25%)').bValue);
}, 'new Color(\'hsl(116,79%,25%)\').bValue');
test(() => {
assert_equals(236, new Color(ColorFormat.HSL, 301, 64, 79).rValue);
}, 'new Color(ColorFormat.HSL, 301, 64, 79).rValue');
test(() => {
assert_equals(167, new Color(ColorFormat.HSL, 301, 64, 79).gValue);
}, 'new Color(ColorFormat.HSL, 301, 64, 79).gValue');
test(() => {
assert_equals(235, new Color(ColorFormat.HSL, 301, 64, 79).bValue);
}, 'new Color(ColorFormat.HSL, 301, 64, 79).bValue');
}
function testHSLValueGetters() {
test(() => {
assert_equals(61, new Color('#e5e73d').hValue);
}, 'new Color(\'#e5e73d\').hValue');
test(() => {
assert_equals(78, new Color('#e5e73d').sValue);
}, 'new Color(\'#e5e73d\').sValue');
test(() => {
assert_equals(57, new Color('#e5e73d').lValue);
}, 'new Color(\'#e5e73d\').lValue');
test(() => {
assert_equals(111, new Color(ColorFormat.HEX, '61a755').hValue);
}, 'new Color(ColorFormat.HEX, \'61a755\').hValue');
test(() => {
assert_equals(33, new Color(ColorFormat.HEX, '61a755').sValue);
}, 'new Color(ColorFormat.HEX, \'61a755\').sValue');
test(() => {
assert_equals(49, new Color(ColorFormat.HEX, '61a755').lValue);
}, 'new Color(ColorFormat.HEX, \'61a755\').lValue');
test(() => {
assert_equals(210, new Color('rgb(156,172,188)').hValue);
}, 'new Color(\'rgb(156,172,188)\').hValue');
test(() => {
assert_equals(19, new Color('rgb(156,172,188)').sValue);
}, 'new Color(\'rgb(156,172,188)\').sValue');
test(() => {
assert_equals(67, new Color('rgb(156,172,188)').lValue);
}, 'new Color(\'rgb(156,172,188)\').lValue');
test(() => {
assert_equals(3, new Color(ColorFormat.RGB, 212, 34, 24).hValue);
}, 'new Color(ColorFormat.RGB, 212, 34, 24).hValue');
test(() => {
assert_equals(80, new Color(ColorFormat.RGB, 212, 34, 24).sValue);
}, 'new Color(ColorFormat.RGB, 212, 34, 24).sValue');
test(() => {
assert_equals(46, new Color(ColorFormat.RGB, 212, 34, 24).lValue);
}, 'new Color(ColorFormat.RGB, 212, 34, 24).lValue');
test(() => {
assert_equals(178, new Color('hsl(178,70%,63%)').hValue);
}, 'new Color(\'hsl(178,70%,63%)\').hValue');
test(() => {
assert_equals(70, new Color('hsl(178,70%,63%)').sValue);
}, 'new Color(\'hsl(178,70%,63%)\').sValue');
test(() => {
assert_equals(63, new Color('hsl(178,70%,63%)').lValue);
}, 'new Color(\'hsl(178,70%,63%)\').lValue');
test(() => {
assert_equals(104, new Color(ColorFormat.HSL, 104, 88, 63).hValue);
}, 'new Color(ColorFormat.HSL, 104, 88, 63).hValue');
test(() => {
assert_equals(88, new Color(ColorFormat.HSL, 104, 88, 63).sValue);
}, 'new Color(ColorFormat.HSL, 104, 88, 63).sValue');
test(() => {
assert_equals(63, new Color(ColorFormat.HSL, 104, 88, 63).lValue);
}, 'new Color(ColorFormat.HSL, 104, 88, 63).lValue');
} }
function testAsHex() { function testAsHex() {
...@@ -202,6 +418,14 @@ function testAsHex() { ...@@ -202,6 +418,14 @@ function testAsHex() {
test(() => { test(() => {
assert_equals('#6e1026', new Color(ColorFormat.RGB, 110, 16, 38).asHex()); assert_equals('#6e1026', new Color(ColorFormat.RGB, 110, 16, 38).asHex());
}, 'new Color(ColorFormat.RGB, 110, 16, 38).asHex()'); }, 'new Color(ColorFormat.RGB, 110, 16, 38).asHex()');
test(() => {
assert_equals('#ffe6e8', new Color('hsl(355,99,95)').asHex());
}, 'new Color(\'hsl(355,99,95)\').asHex()');
test(() => {
assert_equals('#2d0b06', new Color(ColorFormat.HSL, 7, 75, 10).asHex());
}, 'new Color(ColorFormat.HSL, 7, 75, 10).asHex()');
} }
function testAsRGB() { function testAsRGB() {
...@@ -220,8 +444,41 @@ function testAsRGB() { ...@@ -220,8 +444,41 @@ function testAsRGB() {
test(() => { test(() => {
assert_equals('rgb(15,117,15)', new Color(ColorFormat.RGB, 15, 117, 15).asRGB()); assert_equals('rgb(15,117,15)', new Color(ColorFormat.RGB, 15, 117, 15).asRGB());
}, 'new Color(ColorFormat.RGB, 15, 117, 15).asRGB()'); }, 'new Color(ColorFormat.RGB, 15, 117, 15).asRGB()');
test(() => {
assert_equals('rgb(168,209,168)', new Color('hsl(120,31,74)').asRGB());
}, 'new Color(\'hsl(120,31,74)\').asRGB()');
test(() => {
assert_equals('rgb(251,231,9)', new Color(ColorFormat.HSL, 55, 97, 51).asRGB());
}, 'new Color(ColorFormat.HSL, 55, 97, 51).asRGB()');
} }
function testAsHSL() {
test(() => {
assert_equals('hsl(132,2%,48%)', new Color('#787d79').asHSL());
}, 'new Color(\'#00fff2\').asHSL()');
test(() => {
assert_equals('hsl(305,24%,68%)', new Color(ColorFormat.HEX, 'c099bd').asHSL());
}, 'new Color(ColorFormat.HEX, \'c099bd\').asHSL()');
test(() => {
assert_equals('hsl(259,70%,44%)', new Color('rgb(85,34,192)').asHSL());
}, 'new Color(\'rgb(85,34,192)\').asHSL()');
test(() => {
assert_equals('hsl(86,87%,48%)', new Color(ColorFormat.RGB, 139, 230, 16).asHSL());
}, 'new Color(ColorFormat.RGB, 139, 230, 16).asHSL()');
test(() => {
assert_equals('hsl(225,41%,44%)', new Color('hsl(225,41,44)').asHSL());
}, 'new Color(\'hsl(225,41,44)\').asHSL()');
test(() => {
assert_equals('hsl(307,64%,54%)', new Color(ColorFormat.HSL, 307, 64, 54).asHSL());
}, 'new Color(ColorFormat.HSL, 307, 64, 54).asHSL()');
}
</script> </script>
</body> </body>
</html> </html>
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment