# Given hexadecimal rgb color, find the closest predefined color

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.rgb.b), 2) ); if (distance < minDistance) { minDistance = distance; nearestHex = currentColor.hex; } }; return nearestHex; }(); closestHexFromRgb(hexToRgb(hex)); };  ## 1 Answer ### 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.