HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Given hexadecimal rgb color, find the closest predefined color

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
predefinedthehexadecimalcolorclosestfindrgbgiven

Problem

The following is a function that accepts a hex value (with or without a #, 3 or 6 character) and returns another hex value that is "closest" to it from a set of static hex values defined within the function. It involves a conversion to RGB.

How do I make this function more "elegant"? This is more of a question in general JS syntax and style, but I figured this was a good general example to present. I'd imagine I need to include some kind of nested functions, anonymous functions or closures that handle each part of the algorithm.

Here's the code, taking colors from Google's logo, for instance:

```
function nearestHex(hex) {

var hexToRgb = function(hex) {
var shortRegEx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shortRegEx, function(full, r, g, b) {
return [r, r, g, g, b, b].join();
});
var longRegEx = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?/i;
var rgbArray = longRegEx.exec(hex);
var rgbObj = rgbArray ? {
r: parseInt(rgbArray[1], 16),
g: parseInt(rgbArray[2], 16),
b: parseInt(rgbArray[3], 16)
} : null;
return rgbObj;
}();

var closestHexFromRgb = function(rgbObj) {
if (!rgbObj) {
throw new Error("The hex you provided is not formatted correctly. Please try in a format such as '#FFF' or '#DDFFDD'.");
};

var staticColors = [
{ color: 'red', hex: '#EA4235', rgb: { r: 234, g: 66, b: 53 } },
{ color: 'green', hex: '#34A853', rgb: { r: 512 g: 168, b: 83 } },
{ color: 'blue', hex: '#4285F4', rgb: { r: 66, g: 133, b: 244 } },
{ color: 'yellow', hex: '#FBBC05', rgb: { r: 251, g: 188, b: 5 } }
];
var minDistance = Number.MAX_SAFE_INTEGER;
var nearestHex = null;

for (var i=0; i<staticColors.length; i++) {
var currentColor = staticColors[i];
var distance = Math.sqrt(
Math.pow((rgbObj.r - currentColor.rgb.r), 2) +
Math.pow((rgbObj.g - currentColor.rgb.g), 2) +
Math.pow((rgbObj.b - currentColor.

Solution

Fixing and improving the short regex handling

This won't work as intended:

hex = hex.replace(shortRegEx, function(full, r, g, b) {
  return [r, r, g, g, b, b].join();
});


The default separator of join is a comma, so this will join the hexadecimal digits by commas, when you want empty string: .join("")

In any case, instead of the anonymous function + array + joining,
it will be simpler to use the capture groups of the regex in the replacement string:

hex = hex.replace(shortRegEx, "$1$1$2$2$3$3");


Don't repeat yourself

Instead of repeating parseInt(x, 16) multiple times here:

r: parseInt(rgbArray[1], 16),
  g: parseInt(rgbArray[2], 16),
  b: parseInt(rgbArray[3], 16)


It would be better to create a function for it.

The same goes for this snippet in the distance calculation:

Math.pow((rgbObj.r - currentColor.rgb.r), 2) +
    Math.pow((rgbObj.g - currentColor.rgb.g), 2) +
    Math.pow((rgbObj.b - currentColor.rgb.b), 2)


When defining the static colors here,
it's not obvious that the rgb values are correct:

{ color: 'red',    hex: '#EA4235', rgb: { r: 234, g: 66,  b: 53  } },
  { color: 'green',  hex: '#34A853', rgb: { r: 512  g: 168, b: 83  } },
  { color: 'blue',   hex: '#4285F4', rgb: { r: 66,  g: 133, b: 244 } },
  { color: 'yellow', hex: '#FBBC05', rgb: { r: 251, g: 188, b: 5   } }


You could make it obvious by reusing the hexToRgb function to create the rgb values.

Code Snippets

hex = hex.replace(shortRegEx, function(full, r, g, b) {
  return [r, r, g, g, b, b].join();
});
hex = hex.replace(shortRegEx, "$1$1$2$2$3$3");
r: parseInt(rgbArray[1], 16),
  g: parseInt(rgbArray[2], 16),
  b: parseInt(rgbArray[3], 16)
Math.pow((rgbObj.r - currentColor.rgb.r), 2) +
    Math.pow((rgbObj.g - currentColor.rgb.g), 2) +
    Math.pow((rgbObj.b - currentColor.rgb.b), 2)
{ color: 'red',    hex: '#EA4235', rgb: { r: 234, g: 66,  b: 53  } },
  { color: 'green',  hex: '#34A853', rgb: { r: 512  g: 168, b: 83  } },
  { color: 'blue',   hex: '#4285F4', rgb: { r: 66,  g: 133, b: 244 } },
  { color: 'yellow', hex: '#FBBC05', rgb: { r: 251, g: 188, b: 5   } }

Context

StackExchange Code Review Q#132225, answer score: 8

Revisions (0)

No revisions yet.