user1815934
user1815934

Reputation: 229

Javascript Calculate darker colour

how can i change this calculation to a darker and not brighter color?

function increase_brightness(hex, percent){
    // strip the leading # if it's there
    hex = hex.replace(/^\s*#|\s*$/g, '');

    // convert 3 char codes --> 6, e.g. `E0F` --> `EE00FF`
    if(hex.length == 3){
        hex = hex.replace(/(.)/g, '$1$1');
    }

    var r = parseInt(hex.substr(0, 2), 16),
        g = parseInt(hex.substr(2, 2), 16),
        b = parseInt(hex.substr(4, 2), 16);

    return '#' +
       ((0|(1<<8) + r + (256 - r) * percent / 100).toString(16)).substr(1) +
       ((0|(1<<8) + g + (256 - g) * percent / 100).toString(16)).substr(1) +
       ((0|(1<<8) + b + (256 - b) * percent / 100).toString(16)).substr(1);
}

src = JavaScript Calculate brighter colour

demo http://jsbin.com/utavax/3/edit

Upvotes: 4

Views: 5881

Answers (4)

Jeremy
Jeremy

Reputation: 3748

I updated your original function to do a cheap version of lightening/darkening by basically multiplying a percentage (up or down) off the original RGB values.

function adjust(hexInput: string, percent: number) {
    let hex = hexInput;

    // strip the leading # if it's there
    hex = hex.replace(/^\s*#|\s*$/g, "");

    // convert 3 char codes --> 6, e.g. `E0F` --> `EE00FF`
    if (hex.length === 3) {
        hex = hex.replace(/(.)/g, "$1$1");
    }

    let r = parseInt(hex.substr(0, 2), 16);
    let g = parseInt(hex.substr(2, 2), 16);
    let b = parseInt(hex.substr(4, 2), 16);

    const calculatedPercent = (100 + percent) / 100;

    r = Math.round(Math.min(255, Math.max(0, r * calculatedPercent)));
    g = Math.round(Math.min(255, Math.max(0, g * calculatedPercent)));
    b = Math.round(Math.min(255, Math.max(0, b * calculatedPercent)));

    return `#${r.toString(16).toUpperCase()}${g.toString(16).toUpperCase()}${b
        .toString(16)
        .toUpperCase()}`;
}

console.log(adjust("#49D174", -14)) // Darken by 14% = #3FB464 
console.log(adjust("#49D174", -27)) // Darken by 27% = #359955

The function takes the percent as an integer, but could easily be modified for a decimal. Negative to darken, positive to lighten.

Upvotes: 4

shybovycha
shybovycha

Reputation: 12275

I've taken the main idea from Stylus (1, 2) and a few code parts from Stack Overflow answers and produced a library, darken_color.js.

Here are a few usage examples:

darken('lightgreen', '0.1'); // -> #63e763 
darken('lightgreen', '10'); // -> #63e763
darken('#90EE90', '10'); // -> #63e763
darken('#9e9', '10%'); // ->  #98ed98

Upvotes: 0

xiaoyi
xiaoyi

Reputation: 6751

You can change

return '#' +
   ((0|(1<<8) + r + (256 - r) * percent / 100).toString(16)).substr(1) +
   ((0|(1<<8) + g + (256 - g) * percent / 100).toString(16)).substr(1) +
   ((0|(1<<8) + b + (256 - b) * percent / 100).toString(16)).substr(1);

to

return '#' +
   ((0|(1<<8) + r * (1 - percent / 100)).toString(16)).substr(1) +
   ((0|(1<<8) + g * (1 - percent / 100)).toString(16)).substr(1) +
   ((0|(1<<8) + b * (1 - percent / 100).toString(16)).substr(1);

will fix your problem. demo.

But darker color is not a good definition. Darker can be interpreted as less brightness or less saturation. So the better approach is to convert the RGB color space to HSB color space, and tweak the S/B channels, then convert them back.


A little explanation on why negative value to original code is not OK.

Give -100 as percent, and some channel, say r, less than 128. Then

r + (256 - r) * percent / 100

is less than 0, after plus 1 << 8 = 256

((0|(1<<8) + r + (256 - r) * percent / 100)

is less than 256.

Take a number less than 256 will generate at most two hex digits by calling toString(16), so .substr(1) will contain 0 or 1 digit only. By combining all these wrong digits together will not generate a proper color in hex representation.

Upvotes: 6

Pulkit Goyal
Pulkit Goyal

Reputation: 5664

return '#' +
   ((0|(1<<8) + r + (256 - r) * percent / 100).toString(16)).substr(1) +
   ((0|(1<<8) + g + (256 - g) * percent / 100).toString(16)).substr(1) +
   ((0|(1<<8) + b + (256 - b) * percent / 100).toString(16)).substr(1);

Here you are adding some percentage of r, g and b to current values which makes the color lighter. If you use a negative value for percentage, it will decrease from current values and make the color darker.

Upvotes: -1

Related Questions