2009-11-02 29 views
46

¿Alguien sabe, por encima de sus cabezas, una solución de Javascript para calcular el color complementario de un valor hexadecimal?Función JS para calcular el color complementario?

Hay un número de conjuntos de selección de colores y generadores de paleta en la web, pero no he visto ninguno que calcule el color en vivo usando JS.

Una sugerencia detallada o un fragmento sería muy apreciado.

Respuesta

51

Analizada través http://design.geckotribe.com/colorwheel/

// complement 
temprgb=thisrgb; 
temphsv=RGB2HSV(temprgb); 
temphsv.hue=HueShift(temphsv.hue,180.0); 
temprgb=HSV2RGB(temphsv); 

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); 
} 
+0

que lo hizo, gracias! –

+6

La función mágica HueShift (...) es esta: función HueShift (h, s) { \t h + = s; \t while (h> = 360.0) h- = 360.0; \t while (h <0.0) h + = 360.0; \t return h; } – Jacob

+0

También necesitará las funciones max3 y min3: –

21

encuentro que tomando el complemento bit a bit funciona bien y rápidamente.

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

no estoy seguro de si es un complemento perfecto en el sentido de "mezclas entre sí para formar un gris del 70%", sin embargo, un gris del 70% es "blanco puro" en términos de tiempo de color en la película. Se me ocurrió que XORing el RGB hexadecimal en blanco puro podría ser una buena primera aproximación. También puedes probar un gris más oscuro para ver cómo te funciona.

De nuevo, esta es una aproximación rápida y no garantizo que sea perfectamente precisa.

Consulte https://github.com/alfl/textful/blob/master/app.js#L38 para mi implementación.

+9

Esto funciona bien, excepto si desea que el resultado siempre tenga 6 caracteres. Sugiero '('000000' + (('0xffffff'^'0x320ae3'). ToString (16))). Slice (-6);' – professormeowingtons

+0

Buzzzz: (incorrecto) ¿Cuál sería el color opuesto de 0x7F7F7F? 0x808080! Eso no es muy "opuesto". XOR con 0x808080 sería mejor (la distancia de color es siempre la mitad) pero aún no es "mejor". Los métodos HSL dan mejores resultados. – geowar

17

Ninguna de las otras funciones aquí resolvió la situación, así que hice esta.

Se necesita un valor hexadecimal, lo convierte a HSL, cambia la tonalidad 180 grados y se convierte de nuevo a Hex

/* 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); 
} 
+0

Esto funciona genial. ¿Cuánto tiempo tardaste en escribir esto? He estado buscando algo que hace esto por un tiempo y también encontré varias soluciones "listas para usar" que no funcionaron. – AlexanderGriffin

+1

Tardó una hora más o menos - Acabo de parchar algunas respuestas stackoverflow (acreditadas en el código). – Edd

Cuestiones relacionadas