5

INSTRUCTIONS

Write a function that takes 2 colors as arguments and returns the average color.

  • The parameters will be two 6-digit hexadecimal strings. This does not need to be validated.
  • The return value should be a 6-digit hexadecimal string.
  • The hexadecimal strings represent colors in RGB, much like in CSS.
  • The average color is to be determined by taking the arithmetic mean for each component: red, green and blue.

CODE

 const avgColor = (str1, str2) => {
    return (str1 + str2) / 2
 }

QUESTION

Hexadecimal is something like this 0000ff right?

I'm not sure what it means when I need to take the arithmetic mean for each component and lists 3 colors. How do you take an average of strings?

Dave Newton
  • 158,873
  • 26
  • 254
  • 302
mph85
  • 1,276
  • 4
  • 19
  • 39
  • You don't take "an average of strings". You interpret each pair of digits has a number and then do a simple numeric average. – Pointy Jul 16 '19 at 20:43
  • A hexidecimal value isn't a string, it's a [base-16 numeric value](https://en.wikipedia.org/wiki/Hexadecimal). – esqew Jul 16 '19 at 20:43
  • @Pointy sorry, im not understanding. `You interpret each pair of digits has a number`? – mph85 Jul 16 '19 at 20:53
  • 2
    (1) Use substring to get each pair of digits. (2) Use `parseInt(v, 16)` to convert each pair of hex digits to a number. (3) Average your numbers. (4) Convert each R, G, and B number back to hex using `.toString(16)` –  Jul 16 '19 at 20:53
  • `The parameters will be two 6-digit hexadecimal strings`. So this means not 2 strings but 2 numbers? – mph85 Jul 16 '19 at 20:53
  • @Amy thanks, I think I understand it now with the explanation below, the `strings` part confused me and didn't know about `ff` as a value and such – mph85 Jul 16 '19 at 20:57
  • this sounds like homework – ian.pvd Aug 05 '21 at 23:25

5 Answers5

2

Here's a plain JS function:

You have to split the hex string into it's three color components before converting them to calculate the mean:

function calcAvg(hex1,hex2) {

  //parsed into decimal from hex
  //for each color pair
let hexC11 = parseInt(hex1.slice(0,2), 16);  
let hexC12 = parseInt(hex1.slice(2,4), 16);
let hexC13 = parseInt(hex1.slice(4,6), 16);
let hexC21 = parseInt(hex2.slice(0,2), 16);
let hexC22 = parseInt(hex2.slice(2,4), 16);
let hexC23 = parseInt(hex2.slice(4,6), 16);

  //calculate mean for each color pair
let colorMean1 = (hexC11 + hexC21) / 2;
let colorMean2 = (hexC12 + hexC22) / 2;
let colorMean3 = (hexC13 + hexC23) / 2;

  //convert back to hex
let colorMean1Hex = colorMean1.toString(16);
let colorMean2Hex = colorMean2.toString(16);
let colorMean3Hex = colorMean3.toString(16);

  //pad hex if needed
if (colorMean1Hex.length == 1)
  colorMean1Hex = "0" + colorMean1Hex;
if (colorMean2Hex.length == 1)
  colorMean2Hex = "0" + colorMean2Hex;
if (colorMean3Hex.length == 1)
  colorMean3Hex = "0" + colorMean3Hex;

  //merge color pairs back into one hex color
let avgColor = colorMean1Hex +
    colorMean2Hex +
    colorMean3Hex;

  return avgColor;
}

let avg = calcAvg("999999","777777");
console.log(avg);
HBlackorby
  • 1,308
  • 1
  • 11
  • 18
2

You can do it with this snippet:

function avg(a,b){
  const regex=/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ //regular expression to parse string
  a=regex.exec(a).slice(1)  //create array from string 'a' using regex
  b=regex.exec(b).slice(1)  //create array from string 'b' using regex
  let output=''
  for(let i=0;i<3;i++){
    const value=Math.floor(
       (
         parseInt(a[i],16) + //parse decimal from hexadecimal
         parseInt(b[i],16)   //parse decimal from hexadecimal
       )/2                   //perform averaging
     ).toString(16)          //convert back to hexadecimal
     output += (value.length<2?'0':'') + value //add leading zero if needed
  }
  return output
}
FZs
  • 16,581
  • 13
  • 41
  • 50
1

In order to calculate the average of a hexadecimal string value, you need to:

  • Convert the hexadecimal string to integer (something similar to parseInt('0000ff', 16))
  • Split the color components
  • Calculate the average value for each color component
  • Reconstruct the final value from the color components
  • Convert the result back to hexadecimal string (with padding), you can refer to this question How to convert decimal to hexadecimal in JavaScript .

An example of full code snippet will be something similar to

const avgColor = (str1, str2) => {
    // Convert the hexadecimal string to integer
    const color1 = parseInt(str1, 16);
    const color2 = parseInt(str2, 16);

    let avgColor = 0;
    for (let i = 0; i < 3; i++) {
        // Split the color components
        comp1 = (color1 >> (8 * i)) & 0xff;
        comp2 = (color2 >> (8 * i)) & 0xff;
        // Calculate the average value for each color component
        let v = parseInt((comp1 + comp2) / 2) << 8 * i;

        // Reconstruct the final value from the color components
        avgColor += parseInt((comp1 + comp2) / 2) << 8 * i;
    }

    return decimalToHex(avgColor, 6);
}

// Reference from https://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hexadecimal-in-javascript
function decimalToHex(d, padding) {
    var hex = Number(d).toString(16);
    padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding;

    while (hex.length < padding) {
        hex = "0" + hex;
    }

    return hex;
}

console.log(avgColor("0000ff", "ff0000"))

Xiangyu.Wu
  • 459
  • 1
  • 5
  • 18
  • This won't work for it exactly, as they need to split the hex string into its three color components before calculating the average. "The average color is to be determined by taking the arithmetic mean for each component." – HBlackorby Jul 16 '19 at 20:49
  • @HBlackorby Thanks for pointing it out! I have fixed it in my answer. – Xiangyu.Wu Jul 16 '19 at 21:08
1

Hexadecimal is something like this 0000ff right?

Yes.

To elaborate, each two characters of the "hexadecimal string" represents a color in hexadecimal (16 numbers per digit), rather than decimal (10 numbers per digit). So the first two characters represent the Red value of the color, the second two characters represent the Green value of the color, and the last two characters represent the Blue value of the color. Combining these values results in the final color.

To further elaborate, the "ff" hexadecimal value equals 256 as a decimal value. Hexadecimal digits go from 0-9, then continue to a, b, c, d, e, and f, before wrapping around to 0 again, so a hexadecimal "0f" number, would equal 16 in decimal. A hexadecimal "10" number would equal 17 as a decimal value. Counting from 0 to 17 in hexadecimal would look like this:

"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0f", "10".

dqhendricks
  • 19,030
  • 11
  • 50
  • 83
  • brain fried for a second, I'll reboot and see if I understand this fully – mph85 Jul 16 '19 at 20:56
  • 1
    @mph85 so like, if you were to take your example "0000ff". in decimal values, it would mean a red value of 0, a green value of 0, and a blue value of 256. This way of representing colors is referred to as RGB (red, green, blue). With 0-256 values for each component of an RGB value, you can create any color (essentially). using hexadecimal numbers instead of decimal numbers, means you can use 6 characters to represent any RGB color, instead of needing 9 characters to represent any RGB color (as you would using decimals). – dqhendricks Jul 16 '19 at 21:01
  • gotcha, so what does it mean to take the arithmetic mean for each component? would blue just be `128`? – mph85 Jul 16 '19 at 21:06
  • or do i need to convert to number and then average? – mph85 Jul 16 '19 at 21:07
  • 1
    @mph85 yes, but teacher would likely be wanting you to turn it back into a hexidecimal string for your final answer. vanilla javascript has a way of converting hex to dec and vice versa: https://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hexadecimal-in-javascript – dqhendricks Jul 16 '19 at 21:08
  • 1
    @mph85 so likely, break the string into three parts, convert each part to decimal, average the decimal values, then convert back to hex parts, then combine into final string. there may be a way to create averages using hex numbers, but I am unsure. if so, you would be able to skip the conversion to decimal and back. – dqhendricks Jul 16 '19 at 21:10
  • Got it, appreciate the explanation, I'll see what I can come up with with everyone's input. – mph85 Jul 16 '19 at 21:13
-1

There is a jQuery plugin for this if you can use jQuery -

$.xcolor.average(color, color)
Monika Mangal
  • 1,665
  • 7
  • 17
  • Hi, thank you for that. I believe the hw just wanted a function written in vanilla JS, but I upvote for showing me a different way. – mph85 Jul 16 '19 at 20:58