简体   繁体   English

JS函数来计算补色?

[英]JS function to calculate complementary colour?

Does anybody know, off the top of your heads, a Javascript solution for calculating the complementary colour of a hex value?有没有人知道,一个用于计算十六进制值互补色的 Javascript 解决方案?

There are a number of colour picking suites and palette generators on the web but I haven't seen any that actually calculate the colour dynamically using JS.网络上有许多颜色选择套件和调色板生成器,但我还没有看到任何使用 JS 动态计算颜色的实际。

A detailed hint or a snippet would be very much appreciated.非常感谢详细的提示或片段。

Parsed through http://design.geckotribe.com/colorwheel/通过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); }

I find that taking the bit-wise complement works well, and quickly.我发现采用按位补码效果很好,而且很快。

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

I'm not sure if it's a perfect complement in the sense of "mixes together to form a 70% grey", however a 70% grey is "pure white" in terms of color timing in film.我不确定它是否是“混合在一起形成 70% 灰色”的完美补充,但是就电影中的色彩时间而言,70% 灰色是“纯白色”。 It occurred to me that XORing the RGB hex out of pure white might be a good first approximation.我突然想到,从纯白色中对 RGB 十六进制进行异或可能是一个很好的初步近似。 You could also try a darker grey to see how that works for you.您也可以尝试更深的灰色,看看它对您有什么作用。

Again, this is a fast approximation and I make no guarantees that it'll be perfectly accurate.同样,这是一个快速的近似值,我不保证它会完全准确。

See https://github.com/alfl/textful/blob/master/app.js#L38 for my implementation.有关我的实现,请参阅https://github.com/alfl/textful/blob/master/app.js#L38

None of the other functions here worked out the box, so I made this one.这里的其他功能都没有解决这个问题,所以我做了这个。

It takes a hex value, converts it to HSL, shifts the hue 180 degrees and converts back to Hex它需要一个十六进制值,将其转换为 HSL,将色调移动 180 度并转换回十六进制

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

Rather than reinventing the wheel, I found a library to work with colors.我没有重新发明轮子,而是找到了一个可以处理颜色的库。

Tiny Color微小的颜色

This is how you would implement some of the other answers using it.这就是您使用它实现其他一些答案的方式。

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

RGB Complimentary RGB 免费

 function componentToHex(c) { var hex = c.toString(16); return hex.length == 1 ? "0" + hex : hex; } function hexToRgb(hex) { var result = /^#?([af\\d]{2})([af\\d]{2})([af\\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; } function rgbComplimentary(r,g,b){ var hex = "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); 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]/255.0, g = rgb[1]/255.0, b = rgb[2]/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 hs and l values into rg 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 rb and g values to hex rgb = b | (g << 8) | (r << 16); return hexToRgb("#" + (0x1000000 | rgb).toString(16).substring(1)); } console.log(rgbComplimentary(242, 211, 215));

HEX Complimentary十六进制免费

 function hexComplimentary(hex){ 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]/255.0, g = rgb[1]/255.0, b = rgb[2]/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; 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 rb and g values to hex rgb = b | (g << 8) | (r << 16); return "#" + (0x1000000 | rgb).toString(16).substring(1); } console.log(hexComplimentary("#ff5a5a"));

Source: Updated https://stackoverflow.com/a/37657940/6569224 answer来源:更新https://stackoverflow.com/a/37657940/6569224答案

Hex and RGB complementry This is most correct and efficient way to get complementary hex color value十六进制和 RGB 互补这是获得互补十六进制颜色值的最正确和最有效的方法

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)];
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM