【问题标题】:Generating random color deviations生成随机颜色偏差
【发布时间】:2012-02-19 02:40:23
【问题描述】:

我想获取一种颜色并使用 JavaScript 生成与该颜色的随机偏差。例如,假设我有一个颜色#33CCFF,我想将该数字输入到脚本中并获得像#8AE2FF#00AAE2#7BDEFF 这样的数字。基本上,色调应该保持不变,但饱和度/亮度应该会有所波动。

生成这些数字最快、最简单的方法是什么?

【问题讨论】:

  • 如果您使用的是现代浏览器,您实际上可以使用 HSL 指定颜色,而不是使用十六进制。这应该使您的任务非常简单。 css3.info/preview/hsl
  • @BrianGlaz:这是一个巧妙的小技巧,但不幸的是,我正在努力保持浏览器的兼容性,即使是 IE。

标签: javascript random colors generator


【解决方案1】:

将您的 RGB 颜色转换为 HSL,保留色相,例如用一个小的随机数导出饱和度和亮度(亮度),然后再转换回 RGB。

用于转换:http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSL

奖励,兑换码:http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript

【讨论】:

    【解决方案2】:

    老实说,我不知道十六进制代码如何计算饱和度/亮度,所以我会转换为 HSL:

    http://serennu.com/colour/rgbtohsl.php

    改变你想要的,然后再改回来。我看到的唯一主要缺点是 HSL 在您更改后可能不存在于 Hex 字段中。

    如,

    HSL 颜色空间只有 360 x 100 x 100 = 3,600,000 其中的颜色,而 RGB 颜色空间有 256 x 256 x 256 = 16,77,216 种颜色,是原来的四倍。

    【讨论】:

      【解决方案3】:

      我知道这个问题已经存在一年了,但我一直在寻找解决方案,但找不到。

      但是根据这里和那里的建议(主要是 SO),我创建了即用型脚本。

      注意 1:colorToRGB 函数不可靠。我在 SO(附上来源)中找到了它。我更改了某些颜色的十六进制值,但我不想检查所有颜色。为获得最佳效果,请始终使用十六进制值。

      注意 2:generateSimilarColor 函数中的 deviation 仅用于我的目的。您可以更改它以获得更好的结果。

      注意 3:在 SO 上可以找到许多功能。我刚刚将它们收集在一起,并提供了相应问题的链接。

      JavaScript 代码如下(测试环境在文章底部):

      /**
      * Generates similar color based on passed one
      * 
      * @param color accepts few formats, e.g. white, #ffffff or [255, 255, 255]
      * @return hex value, e.g. #ffffff
      * 
      * @author Carlos (*)
      */
      function generateSimilarColor(color) {
      
         var rand = generateRandomInt(-5, 5);
         if(rand < 0) rand -= 5;
         else rand += 5;
         var deviation = rand / 100;
      
         if(!isArray(color) || color.length != 3) { // this is not [r, g, b] array
      
             var hexNotation = colorToRGB(color);
      
             if(!hexNotation) { // we couldn't find HEX value of this string based on color name
                 if(!isString(color) || color.length != 7 || color[0] != '#') { // this is not string in this format: #ffffff
                     return false;
                 }
                 else {
                     hexNotation = color;
                 }
             }
      
             color = hexToRgb(hexNotation);
      
             if(!color) {
                 return false;
             }
         }
      
         var hsl = rgbToHsl(color[0], color[1], color[2]);
      
         // saturation
         hsl[1] += deviation;
         if(hsl[1] > 1) hsl[1] = 1 - Math.abs(deviation);
         else if(hsl[1] < 0) hsl[1] = Math.abs(deviation);
      
         // lightness
         hsl[2] += deviation;
         if(hsl[2] > 1) hsl[2] = 1 - Math.abs(deviation);
         else if(hsl[2] < 0) hsl[2] = Math.abs(deviation);
      
         color = hslToRgb(hsl[0], hsl[1], hsl[2]);
         var hex = rgbToHex(color[0], color[1], color[2]);
      
         return hex;
      }
      
      /**
      * Returns a random integer between min and max
      * Using Math.round() will give you a non-uniform distribution!
      * 
      * @source http://*.com/questions/1527803/generating-random-numbers-in-javascript-in-a-specific-range
      */
      function generateRandomInt(min, max) {
          return Math.floor(Math.random() * (max - min + 1)) + min;
      }
      
      /**
       * @source: [slightly changed] http://*.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
       */
      function componentToHex(c) {
          var hex = c.toString(16);
          return hex.length == 1 ? "0" + hex : hex;
      }
      
      /**
       * @source: [slightly changed] http://*.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
       */
      function rgbToHex(r, g, b) {
          r = parseInt(r);
          g = parseInt(g);
          b = parseInt(b);
          return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
      }
      
      /**
      * @source http://*.com/questions/1058427/how-to-detect-if-a-variable-is-an-array
      */
      function isArray(obj) {
          return Object.prototype.toString.call(obj) === '[object Array]';
      }
      
      /**
      * @source http://*.com/questions/4059147/check-if-a-variable-is-a-string
      */
      function isString(str) {
          return (typeof str == 'string' || str instanceof String);
      }
      
      /**
      * @source: http://*.com/questions/5623838/rgb-to-hex-and-hex-to-rgb slightly change
      */
      function hexToRgb(hex) {
      
         // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
         var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
         hex = hex.replace(shorthandRegex, function(m, r, g, b) {
             return r + r + g + g + b + b;
         });
      
         var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
         return result ? [
             parseInt(result[1], 16),
             parseInt(result[2], 16),
             parseInt(result[3], 16)
         ] : false;
      }
      
      /**
      * Converts an RGB color value to HSL. Conversion formula
      * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
      * Assumes r, g, and b are contained in the set [0, 255] and
      * returns h, s, and l in the set [0, 1].
      *
      * @param   Number  r       The red color value
      * @param   Number  g       The green color value
      * @param   Number  b       The blue color value
      * @return  Array           The HSL representation
      * 
      * @source http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
      */
      function rgbToHsl(r, g, b) {
         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;
      
         if(max == min){
             h = s = 0; // achromatic
         }else{
             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 /= 6;
         }
      
         return [h, s, l];
      }
      
      /**
      * Converts an HSL color value to RGB. Conversion formula
      * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
      * Assumes h, s, and l are contained in the set [0, 1] and
      * returns r, g, and b in the set [0, 255].
      *
      * @param   Number  h       The hue
      * @param   Number  s       The saturation
      * @param   Number  l       The lightness
      * @return  Array           The RGB representation
      */
      function hslToRgb(h, s, l) {
         var r, g, b;
      
         if(s == 0){
             r = g = b = l; // achromatic
         }else{
             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 [r * 255, g * 255, b * 255];
      }
      
      /**
      * @source [slightly changed] http://*.com/questions/1573053/javascript-function-to-convert-color-names-to-hex-codes
      */
      function colorToRGB(color) {
      
          var colors = {"aliceblue":"#f0f8ff","antiquewhite":"#faebd7","aqua":"#00ffff","aquamarine":"#7fffd4","azure":"#f0ffff",
          "beige":"#f5f5dc","bisque":"#ffe4c4","black":"#000000","blanchedalmond":"#ffebcd","blue":"#0000ff","blueviolet":"#8a2be2","brown":"#603311","burlywood":"#deb887",
          "cadetblue":"#5f9ea0","chartreuse":"#7fff00","chocolate":"#d2691e","coral":"#ff7f50","cornflowerblue":"#6495ed","cornsilk":"#fff8dc","crimson":"#dc143c","cyan":"#00ffff",
          "darkblue":"#00008b","darkcyan":"#008b8b","darkgoldenrod":"#b8860b","darkgray":"#a9a9a9","darkgreen":"#006400","darkkhaki":"#bdb76b","darkmagenta":"#8b008b","darkolivegreen":"#556b2f",
          "darkorange":"#ff8c00","darkorchid":"#9932cc","darkred":"#8b0000","darksalmon":"#e9967a","darkseagreen":"#8fbc8f","darkslateblue":"#483d8b","darkslategray":"#2f4f4f","darkturquoise":"#00ced1",
          "darkviolet":"#9400d3","deeppink":"#ff1493","deepskyblue":"#00bfff","dimgray":"#696969","dodgerblue":"#1e90ff",
          "firebrick":"#b22222","floralwhite":"#fffaf0","forestgreen":"#228b22","fuchsia":"#ff00ff",
          "gainsboro":"#dcdcdc","ghostwhite":"#f8f8ff","gold":"#ffd700","goldenrod":"#daa520","gray":"#808080","green":"#008000","greenyellow":"#adff2f",
          "honeydew":"#f0fff0","hotpink":"#ff69b4",
          "indianred ":"#cd5c5c","indigo ":"#4b0082","ivory":"#fffff0","khaki":"#f0e68c",
          "lavender":"#e6e6fa","lavenderblush":"#fff0f5","lawngreen":"#7cfc00","lemonchiffon":"#fffacd","lightblue":"#add8e6","lightcoral":"#f08080","lightcyan":"#e0ffff","lightgoldenrodyellow":"#fafad2",
          "lightgrey":"#d3d3d3","lightgreen":"#90ee90","lightpink":"#ffb6c1","lightsalmon":"#ffa07a","lightseagreen":"#20b2aa","lightskyblue":"#87cefa","lightslategray":"#778899","lightsteelblue":"#b0c4de",
          "lightyellow":"#ffffe0","lime":"#00ff00","limegreen":"#32cd32","linen":"#faf0e6",
          "magenta":"#ff00ff","maroon":"#800000","mediumaquamarine":"#66cdaa","mediumblue":"#0000cd","mediumorchid":"#ba55d3","mediumpurple":"#9370d8","mediumseagreen":"#3cb371","mediumslateblue":"#7b68ee",
          "mediumspringgreen":"#00fa9a","mediumturquoise":"#48d1cc","mediumvioletred":"#c71585","midnightblue":"#191970","mintcream":"#f5fffa","mistyrose":"#ffe4e1","moccasin":"#ffe4b5",
          "navajowhite":"#ffdead","navy":"#000080",
          "oldlace":"#fdf5e6","olive":"#808000","olivedrab":"#6b8e23","orange":"#ffa500","orangered":"#ff4500","orchid":"#da70d6",
          "palegoldenrod":"#eee8aa","palegreen":"#98fb98","paleturquoise":"#afeeee","palevioletred":"#d87093","papayawhip":"#ffefd5","peachpuff":"#ffdab9","peru":"#cd853f","pink":"#ffc0cb","plum":"#dda0dd","powderblue":"#b0e0e6","purple":"#800080",
          "red":"#ff0000","rosybrown":"#bc8f8f","royalblue":"#4169e1",
          "saddlebrown":"#8b4513","salmon":"#fa8072","sandybrown":"#f4a460","seagreen":"#2e8b57","seashell":"#fff5ee","sienna":"#a0522d","silver":"#c0c0c0","skyblue":"#87ceeb","slateblue":"#6a5acd","slategray":"#708090","snow":"#fffafa","springgreen":"#00ff7f","steelblue":"#4682b4",
          "tan":"#d2b48c","teal":"#008080","thistle":"#d8bfd8","tomato":"#ff6347","turquoise":"#40e0d0",
          "violet":"#8F00FF",
          "wheat":"#f5deb3","white":"#ffffff","whitesmoke":"#f5f5f5",
          "yellow":"#ffff00","yellowgreen":"#9acd32"};
      
          if (typeof colors[color.toLowerCase()] != 'undefined')
              return colors[color.toLowerCase()];
      
          return false;
      }
      

      测试环境(需要jQuery):

      <!DOCTYPE html>
      <html lang="en">
          <head>
              <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
              <meta charset="utf-8">
              <title>Color Test</title>
              <script type="text/javascript" src="js/libs/jquery.js"></script>
              <script type="text/javascript" src="js/color.js"></script>
              <script type="text/javascript">
                  $(document).ready(function() {
                      var i, j, colors = ['blue', 'orange', 'green', 'red', 'yellow', 'brown', 'violet'];
                      for(i = 0; i < colors.length; i++) {
                          for(j = 0; j < 3; j++) {
                              $("body").append('<div style="height: 20px; background-color: ' + generateSimilarColor(colors[i]) + ';"></div>');
                          }
                          $("body").append('<div style="height: 20px;"></div>');
                      }
                  });
              </script>
          </head>
          <body></body>
      </html>
      

      任何错误或建议 - 请写。

      【讨论】: