70 votes

Fonction JS pour calculer la couleur complémentaire ?

Quelqu'un connaît-il, de mémoire, une solution Javascript pour calculer la couleur complémentaire d'une valeur hexagonale ?

Il existe un certain nombre de suites de sélection de couleurs et de générateurs de palettes sur le web, mais je n'en ai vu aucun qui calcule réellement la couleur de manière dynamique en utilisant JS.

Un conseil détaillé ou un extrait serait très apprécié.

68voto

Stefan Kendall Points 28274

Analysé par http://design.geckotribe.com/colorwheel/

    // Complement
    temprgb={ r: 0, g: 0xff, b: 0xff }; // Cyan
    temphsv=RGB2HSV(temprgb);
    temphsv.hue=HueShift(temphsv.hue,180.0);
    temprgb=HSV2RGB(temphsv);
    console.log(temprgb); // Complement is red (0xff, 0, 0)

    function RGB2HSV(rgb) {
        hsv = new Object();
        max=max3(rgb.r,rgb.g,rgb.b);
        dif=max-min3(rgb.r,rgb.g,rgb.b);
        hsv.saturation=(max==0.0)?0:(100*dif/max);
        if (hsv.saturation==0) hsv.hue=0;
        else if (rgb.r==max) hsv.hue=60.0*(rgb.g-rgb.b)/dif;
        else if (rgb.g==max) hsv.hue=120.0+60.0*(rgb.b-rgb.r)/dif;
        else if (rgb.b==max) hsv.hue=240.0+60.0*(rgb.r-rgb.g)/dif;
        if (hsv.hue<0.0) hsv.hue+=360.0;
        hsv.value=Math.round(max*100/255);
        hsv.hue=Math.round(hsv.hue);
        hsv.saturation=Math.round(hsv.saturation);
        return hsv;
    }

    // RGB2HSV and HSV2RGB are based on Color Match Remix [http://color.twysted.net/]
    // which is based on or copied from ColorMatch 5K [http://colormatch.dk/]
    function HSV2RGB(hsv) {
        var rgb=new Object();
        if (hsv.saturation==0) {
            rgb.r=rgb.g=rgb.b=Math.round(hsv.value*2.55);
        } else {
            hsv.hue/=60;
            hsv.saturation/=100;
            hsv.value/=100;
            i=Math.floor(hsv.hue);
            f=hsv.hue-i;
            p=hsv.value*(1-hsv.saturation);
            q=hsv.value*(1-hsv.saturation*f);
            t=hsv.value*(1-hsv.saturation*(1-f));
            switch(i) {
            case 0: rgb.r=hsv.value; rgb.g=t; rgb.b=p; break;
            case 1: rgb.r=q; rgb.g=hsv.value; rgb.b=p; break;
            case 2: rgb.r=p; rgb.g=hsv.value; rgb.b=t; break;
            case 3: rgb.r=p; rgb.g=q; rgb.b=hsv.value; break;
            case 4: rgb.r=t; rgb.g=p; rgb.b=hsv.value; break;
            default: rgb.r=hsv.value; rgb.g=p; rgb.b=q;
            }
            rgb.r=Math.round(rgb.r*255);
            rgb.g=Math.round(rgb.g*255);
            rgb.b=Math.round(rgb.b*255);
        }
        return rgb;
    }

    //Adding HueShift via Jacob (see comments)
    function HueShift(h,s) { 
        h+=s; while (h>=360.0) h-=360.0; while (h<0.0) h+=360.0; return h; 
    }

    //min max via Hairgami_Master (see comments)
    function min3(a,b,c) { 
        return (a<b)?((a<c)?a:c):((b<c)?b:c); 
    } 
    function max3(a,b,c) { 
        return (a>b)?((a>c)?a:c):((b>c)?b:c); 
    }

7 votes

La fonction magique HueShift(...) est la suivante : function HueShift(h,s) { h+=s ; while (h>=360.0) h-=360.0 ; while (h<0.0) h+=360.0 ; return h ; }

0 votes

Vous aurez également besoin des fonctions max3 et min3 :

4 votes

Function min3(a,b,c) { return (a<b) ?((a<c)?a:c) :((b<c)?b:c) ; } function max3(a,b,c) { return (a>b) ?((a>c)?a:c) :((b>c)?b:c) ; }

37voto

Alex Flanagan Points 59

Je trouve que le fait d'utiliser le complément de l'offre fonctionne bien, et rapidement.

var color = 0x320ae3;
var complement = 0xffffff ^ color;

Je ne suis pas sûr qu'il s'agisse d'un complément parfait dans le sens de "se mélange pour former un gris à 70%", mais un gris à 70% est un "blanc pur" en termes de synchronisation des couleurs dans les films. Il m'est venu à l'esprit qu'un XOR de l'hexagone RVB du blanc pur pourrait être une bonne première approximation. Vous pouvez également essayer un gris plus foncé pour voir comment cela fonctionne pour vous.

Encore une fois, il s'agit d'une approximation rapide et je ne garantis pas qu'elle sera parfaitement exacte.

Ver https://github.com/alfl/textful/blob/master/app.js#L38 pour ma mise en œuvre.

10 votes

Cela fonctionne bien, sauf si vous souhaitez que le résultat soit toujours composé de 6 caractères. Je suggère ('000000' + (('0xffffff' ^ '0x320ae3').toString(16))).slice(-6);

0 votes

Buzzzz : (faux) Quelle serait la couleur opposée de 0x7F7F7F ? 0x808080 ! Ce n'est pas très "opposé". XOR avec 0x808080 serait meilleur (la distance de couleur est alors toujours de moitié) mais toujours pas "meilleur". Les méthodes HSL donnent les meilleurs résultats.

0 votes

C'est juste, si vous xoriez du gris à partir du gris, vous obtenez un gris différent. Appelez cela une limite de l'approche :D

34voto

Edd Points 2387

Aucune des autres fonctions ici n'a fonctionné hors de la boîte, alors j'ai fait celle-ci.

Il prend une valeur hexadécimale, la convertit en HSL, décale la teinte de 180 degrés et la reconvertit en hexadécimal.

/* hexToComplimentary : Converts hex value to HSL, shifts
 * hue by 180 degrees and then converts hex, giving complimentary color
 * as a hex value
 * @param  [String] hex : hex value  
 * @return [String] : complimentary color as hex value
 */
function hexToComplimentary(hex){

    // Convert hex to rgb
    // Credit to Denis http://stackoverflow.com/a/36253499/4939630
    var rgb = 'rgb(' + (hex = hex.replace('#', '')).match(new RegExp('(.{' + hex.length/3 + '})', 'g')).map(function(l) { return parseInt(hex.length%2 ? l+l : l, 16); }).join(',') + ')';

    // Get array of RGB values
    rgb = rgb.replace(/[^\d,]/g, '').split(',');

    var r = rgb[0], g = rgb[1], b = rgb[2];

    // Convert RGB to HSL
    // Adapted from answer by 0x000f http://stackoverflow.com/a/34946092/4939630
    r /= 255.0;
    g /= 255.0;
    b /= 255.0;
    var max = Math.max(r, g, b);
    var min = Math.min(r, g, b);
    var h, s, l = (max + min) / 2.0;

    if(max == min) {
        h = s = 0;  //achromatic
    } else {
        var d = max - min;
        s = (l > 0.5 ? d / (2.0 - max - min) : d / (max + min));

        if(max == r && g >= b) {
            h = 1.0472 * (g - b) / d ;
        } else if(max == r && g < b) {
            h = 1.0472 * (g - b) / d + 6.2832;
        } else if(max == g) {
            h = 1.0472 * (b - r) / d + 2.0944;
        } else if(max == b) {
            h = 1.0472 * (r - g) / d + 4.1888;
        }
    }

    h = h / 6.2832 * 360.0 + 0;

    // Shift hue to opposite side of wheel and convert to [0-1] value
    h+= 180;
    if (h > 360) { h -= 360; }
    h /= 360;

    // Convert h s and l values into r g and b values
    // Adapted from answer by Mohsen http://stackoverflow.com/a/9493060/4939630
    if(s === 0){
        r = g = b = l; // achromatic
    } else {
        var hue2rgb = function hue2rgb(p, q, t){
            if(t < 0) t += 1;
            if(t > 1) t -= 1;
            if(t < 1/6) return p + (q - p) * 6 * t;
            if(t < 1/2) return q;
            if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
            return p;
        };

        var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
        var p = 2 * l - q;

        r = hue2rgb(p, q, h + 1/3);
        g = hue2rgb(p, q, h);
        b = hue2rgb(p, q, h - 1/3);
    }

    r = Math.round(r * 255);
    g = Math.round(g * 255); 
    b = Math.round(b * 255);

    // Convert r b and g values to hex
    rgb = b | (g << 8) | (r << 16); 
    return "#" + (0x1000000 | rgb).toString(16).substring(1);
}

9voto

webturner Points 2668

Plutôt que de réinventer la roue, j'ai trouvé une bibliothèque pour travailler avec les couleurs.

Couleur minuscule

Voici comment mettre en œuvre certaines des autres réponses en l'utilisant.

color1 = tinycolor2('#f00').spin(180).toHexString(); // Hue Shift
color2 = tinycolor2("#f00").complement().toHexString(); // bitwise

3voto

Complémentarité Hex et RGB C'est la façon la plus correcte et la plus efficace d'obtenir la valeur hexadécimale de la couleur complémentaire.

function complementryHexColor(hex){
    let r = hex.length == 4 ? parseInt(hex[1] + hex[1], 16) : parseInt(hex.slice(1, 3), 16);
    let g = hex.length == 4 ? parseInt(hex[2] + hex[2], 16) : parseInt(hex.slice(3, 5), 16);
    let b = hex.length == 4 ? parseInt(hex[3] + hex[3], 16) : parseInt(hex.slice(5), 16);

    [r, g, b] = complementryRGBColor(r, g, b);
    return '#' + (r < 16 ? '0' + r.toString(16) : r.toString(16)) + (g < 16 ? '0' + g.toString(16) : g.toString(16)) + (b < 16 ? '0' + b.toString(16) : b.toString(16));
}

function complementryRGBColor(r, g, b) {
    if (Math.max(r, g, b) == Math.min(r, g, b)) {
        return [255 - r, 255 - g, 255 - b];

    } else {
        r /= 255, g /= 255, b /= 255;
        var max = Math.max(r, g, b), min = Math.min(r, g, b);
        var h, s, l = (max + min) / 2;
        var d = max - min;
        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);

        switch (max) {
            case r: h = (g - b) / d + (g < b ? 6 : 0); break;
            case g: h = (b - r) / d + 2; break;
            case b: h = (r - g) / d + 4; break;
        }

        h = Math.round((h*60) + 180) % 360;
        h /= 360;

        function hue2rgb(p, q, t) {
            if (t < 0) t += 1;
            if (t > 1) t -= 1;
            if (t < 1/6) return p + (q - p) * 6 * t;
            if (t < 1/2) return q;
            if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
            return p;
        }

        var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
        var p = 2 * l - q;

        r = hue2rgb(p, q, h + 1/3);
        g = hue2rgb(p, q, h);
        b = hue2rgb(p, q, h - 1/3);

        return [Math.round(r*255), Math.round(g*255), Math.round(b*255)];
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X