When setting the value for the color picker, round it to the closest available value in the layout

This commit is contained in:
Keegan
2016-03-15 04:53:58 +11:00
parent dad8b2a025
commit 4ee5a7361c
3 changed files with 171 additions and 11 deletions
+100 -4
View File
@@ -10,6 +10,8 @@ module.exports = {
description: ''
},
initialize: function(minified, clay) {
var HTML = minified.HTML;
var self = this;
/**
* @param {string|boolean|number} color
@@ -22,13 +24,23 @@ module.exports = {
return 'transparent';
}
color = padColorString(color);
return '#' + (useSunlight ? sunlightColorMap[color] : color);
}
/**
* @param {string} color
* @return {string}
*/
function padColorString(color) {
color = color.toLowerCase();
while (color.length < 6) {
color = '0' + color;
}
return '#' + (useSunlight ? sunlightColorMap[color] : color);
return color;
}
/**
@@ -37,12 +49,66 @@ module.exports = {
*/
function normalizeColor(value) {
switch (typeof value) {
case 'number': return value.toString(16);
case 'number': return padColorString(value.toString(16));
case 'string': return value.replace(/^#|^0x/, '');
default: return value;
}
}
/**
* @param {Array.<Array>} layout
* @returns {Array}
*/
function flattenLayout(layout) {
return layout.reduce(function(a, b) {
return a.concat(b);
}, []);
}
/**
* Convert HEX color to LAB.
* Adapted from: https://github.com/antimatter15/rgb-lab
* @param {string} hex
* @returns {Array} - [l, a, b]
*/
function hex2lab(hex) {
hex = hex.replace(/^#|^0x/, '');
var r = parseInt(hex.slice(0, 2), 16) / 255;
var g = parseInt(hex.slice(2, 4), 16) / 255;
var b = parseInt(hex.slice(4), 16) / 255;
r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
var x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
var y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000;
var z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
x = (x > 0.008856) ? Math.pow(x, 1 / 3) : (7.787 * x) + 16 / 116;
y = (y > 0.008856) ? Math.pow(y, 1 / 3) : (7.787 * y) + 16 / 116;
z = (z > 0.008856) ? Math.pow(z, 1 / 3) : (7.787 * z) + 16 / 116;
return [(116 * y) - 16, 500 * (x - y), 200 * (y - z)];
}
/**
* Find the perceptual color distance between two LAB colors
* @param {Array} labA
* @param {Array} labB
* @returns {number}
*/
function deltaE(labA, labB) {
var deltaL = labA[0] - labB[0];
var deltaA = labA[1] - labB[1];
var deltaB = labA[2] - labB[2];
return Math.sqrt(Math.pow(deltaL, 2) +
Math.pow(deltaA, 2) +
Math.pow(deltaB, 2));
}
/**
* Returns the layout based on the connected watch
* @returns {Array}
@@ -62,8 +128,32 @@ module.exports = {
return standardLayouts.COLOR;
}
var HTML = minified.HTML;
var self = this;
/**
* @param {number|string} color
* @return {number}
*/
self.roundColorToLayout = function(color) {
var itemValue = normalizeColor(color);
// if the color is not in the layout we will need find the closest match
if (colorList.indexOf(itemValue) === -1) {
var itemValueLAB = hex2lab(itemValue);
var differenceArr = colorList.map(function(color) {
var colorLAB = hex2lab(normalizeColor(color));
return deltaE(itemValueLAB, colorLAB);
});
// Get the lowest number from the differenceArray
var lowest = Math.min.apply(Math, differenceArr);
// Get the index for that lowest number
var index = differenceArr.indexOf(lowest);
itemValue = colorList[index];
}
return parseInt(itemValue, 16);
};
var useSunlight = self.config.sunlight !== false;
var sunlightColorMap = {
'000000': '000000', '000055': '001e41', '0000aa': '004387', '0000ff': '0068ca',
@@ -118,6 +208,12 @@ module.exports = {
layout = [layout];
}
var colorList = flattenLayout(layout).map(function(item) {
return normalizeColor(item);
}).filter(function(item) {
return item;
});
var grid = '';
var rows = layout.length;
var cols = 0;
+3 -7
View File
@@ -145,16 +145,12 @@ module.exports = {
},
color: {
get: function() {
return parseInt(this.$manipulatorTarget.get('value'), 16);
return parseInt(this.$manipulatorTarget.get('value'), 10) || 0;
},
set: function(value) {
switch (typeof value) {
case 'number': value = value.toString(16); break;
case 'string': value = value.replace(/^#|^0x/, ''); break;
}
value = value || '000000';
value = this.roundColorToLayout(value || 0);
if (this.get() === parseInt(value, 16)) { return this; }
if (this.get() === value) { return this; }
this.$manipulatorTarget.set('value', value);
return this.trigger('change');
},
+68
View File
@@ -134,6 +134,39 @@ function testAutoLayout(platform, layout, allowGray, desc, activeWatchInfo) {
});
}
/**
* @param {number|string} input
* @param {number} expected
* @param {array|string} layout
* @return {void}
*/
function testClosestToLayout(input, expected, layout) {
it('rounds ' + input + ' to ' + expected.toString(16) +
' in layout: ' + JSON.stringify(layout),
function() {
var clayConfig;
var colorItem;
clayConfig = fixture.clayConfig([{
type: 'color',
sunlight: false,
layout: layout
}]);
colorItem = clayConfig.getItemsByType('color')[0];
colorItem.set(input);
assert.strictEqual(colorItem.get(), expected);
clayConfig = fixture.clayConfig([{
type: 'color',
sunlight: false,
layout: layout
}]);
colorItem = clayConfig.getItemsByType('color')[0];
colorItem.set(input);
assert.strictEqual(colorItem.get(), expected);
});
}
/**
* @param {boolean} sunlight
* @param {Array|string} [layout=color]
@@ -291,6 +324,41 @@ describe('component - color', function() {
assert.strictEqual($picker.get('classList').contains('show'), false);
});
describe('color rounding', function() {
var layout = 'GRAY';
testClosestToLayout('000000', 0x000000, layout);
testClosestToLayout('005500', 0x000000, layout);
testClosestToLayout('55aa55', 0xaaaaaa, layout);
testClosestToLayout('ffaaff', 0xaaaaaa, layout);
testClosestToLayout('ffffaa', 0xffffff, layout);
testClosestToLayout('ffffff', 0xffffff, layout);
layout = 'BLACK_WHITE';
testClosestToLayout('000000', 0x000000, layout);
testClosestToLayout('005500', 0x000000, layout);
testClosestToLayout('55aa55', 0xffffff, layout);
testClosestToLayout('ffaaff', 0xffffff, layout);
testClosestToLayout('ffffaa', 0xffffff, layout);
testClosestToLayout('ffffff', 0xffffff, layout);
layout = 'COLOR';
testClosestToLayout('000000', 0x000000, layout);
testClosestToLayout('005500', 0x005500, layout);
testClosestToLayout('55bb55', 0x55aa55, layout);
testClosestToLayout('ff99ff', 0xffaaff, layout);
testClosestToLayout('ffffee', 0xffffff, layout);
testClosestToLayout('ffffff', 0xffffff, layout);
layout = ['ff0000', 'ff5500', 'ff00ff', '00ff00', '555555'];
testClosestToLayout('000000', 0x555555, layout);
testClosestToLayout('ff0000', 0xff0000, layout);
testClosestToLayout('ff1111', 0xff0000, layout);
testClosestToLayout('00aa00', 0x00ff00, layout);
testClosestToLayout('ff55ff', 0xff00ff, layout);
testClosestToLayout('aaaaaa', 0x555555, layout);
testClosestToLayout('ffffff', 0x555555, layout);
});
describe('layouts', function() {
// allow gray does nothing for 2.x