2009-11-02 10 views
46

Qualcuno sa, in cima alle vostre teste, una soluzione Javascript per calcolare il colore complementare di un valore esadecimale?Funzione JS per calcolare il colore complementare?

C'è un numero di suite di selezione del colore e generatori di palette sul web ma non ho visto nessuno che calcoli il colore live usando JS.

Un suggerimento dettagliato o uno snippet sarebbe molto apprezzato.

risposta

51

analizzati attraverso 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

Che lo ha fatto, grazie! –

+6

La funzione magica di HueShift (...) è questa: funzione HueShift (h, s) { \t h + = s; \t while (h> = 360.0) h- = 360,0; \t mentre (h <0,0) h + = 360,0; \t ritorno h; } – Jacob

+0

Avrete anche bisogno delle funzioni max3 e min3: –

21

trovo che prendendo il complemento a bit funziona bene, e rapidamente.

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

non sono sicuro se è un complemento perfetto, nel senso di "mescola insieme per formare un grigio al 70%", ma un grigio 70% è "bianco puro" in termini di tempi di colore nel cinema. Mi è venuto in mente che XORare l'esagono RGB dal bianco puro potrebbe essere una buona prima approssimazione. Puoi anche provare un grigio più scuro per vedere come funziona per te.

Ancora una volta, questa è un'approssimazione veloce e non mi garantisce che sia perfettamente accurata.

Vedere https://github.com/alfl/textful/blob/master/app.js#L38 per la mia implementazione.

+9

Funziona bene, tranne se si desidera che il risultato sia sempre lungo 6 caratteri. Suggerisco '('000000' + (('0xffffff'^'0x320ae3'). ToString (16))). Slice (-6);' – professormeowingtons

+0

Buzzzz: (errato) Quale sarebbe il colore opposto di 0x7F7F7F? 0x808080! Non è molto "contrario". XOR con 0x808080 sarebbe migliore (la distanza dei colori è sempre metà), ma non ancora "migliore". I metodi HSL danno i migliori risultati. – geowar

17

Nessuna delle altre funzioni ha risolto il problema, quindi l'ho creato.

ci vuole un valore esadecimale, lo converte in HSL, sposta la tonalità di 180 gradi e converte di nuovo 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

Funziona alla grande. Quanto tempo ti ci è voluto per scrivere questo? Ho cercato qualcosa che funzioni per un po 'e ho anche incontrato diverse soluzioni "out of the box" che non funzionavano. – AlexanderGriffin

+1

Ci sono voluti circa un'ora - ho appena messo insieme alcune risposte StackOverflow (accreditate nel codice). – Edd

Problemi correlati