javascript - hsl 到 rgb 的转换。值(value)观太差了。与解决方案进行比较。我做了什么不同的事情?

标签 javascript rgb hsl

解决了!查看编辑

我构建了一个颜色选择器应用程序。很简单;您单击 RGB 调色板,它会创建一个包含 RGB 值、HSL 值和 HEX 值的样本。
我用过this formula用于转换。

基本上,我根据 x 和 y 鼠标位置构建了静态 99% 饱和度的 HSL 值。

从那里,我通过将 HSL 转换为 RGB 创建了可供选择的调色板。

调色板上的单击事件将创建 RGB、HSL 和 HEX 样本以及每个样本的值。

由于我无法获得匹配的 RGB 和 HSL 值,因此我尚未合并 HEX 值。

我终于找到了一个可行的解决方案。有人能告诉我我的计算在哪里偏离了工作解决方案吗?我不想只是接受可行的解决方案并继续前进;我想知道我的逻辑从哪里开始崩溃。

非常感谢您的帮助!

编辑:所以 Bob__ 建议我使用更好的方法来标准化 RGB 值,而不是仅仅根据它们的值加或减 1。我添加了这个函数来根据色调值(-0.333 - 360.333)制作RGB channel

      function normalizeRGB(color){
         var newVal = (360.333 - (-0.333))/(360.333 - (-0.333)) *   
                      (color- (-0.333) + (-0.333));
        return newVal;
      }

index.html:

            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>Color Picker, Bro</title>
                <link href='http://fonts.googleapis.com/css?  family=Raleway:700,300' rel='stylesheet' type='text/css'>
                <link rel="stylesheet" href="style.css">
                <script src='https://code.jquery.com/jquery-2.1.3.min.js'></script>
                <script type="text/javascript" src='myColorPickerSol.js'></script>
                <!-- <script type="text/javascript" src='actualWorkingColorPickerSol.js'></script> -->
            </head>
            <body>

                <div id='container'>
                    <h1>Color Picker, bro</h1>
                    <section id='canvas'></section>
                        <section id='readout'>
                            <p>HSL: <span id='hsl'></span></p>
                            <section id='swatchhsl'></section>
                            <p>RGB: <span id='rgb'></span></p>
                            <section id='swatchrgb'></section>
                            <p>HEX: <span id='hex'></span></p>
                        </section>
                    </section>
                </div>

            </body>
            </html>

样式.css:

             body {
                      background:   url(http://subtlepatterns.com/patterns/subtle_white_mini_waves.png);
             }

             #container {
                margin: 0 auto;
                width: 800px;
                height: inherit;
                text-align: center;
                font-family: Raleway;
                font-weight: 300;
            }
            #canvas {
                margin: 0 auto;
                border: 5px solid black;
                box-sizing: border-box;
                height: 360px;
                width: 360px;
            }
            #readout {
                background: rgba(117,117,117, .2);
                margin: 20px auto;
                height: 400px;
                width: 360px;
                border: 1px #333 solid;
                box-sizing: border-box;
                border-radius: 20px;
            }
            #swatchhsl,#swatchrgb {
                margin: 0 auto;
                height: 75px;
                width: 95%;
                border-radius: 20px;
            }
            p, span {
                letter-spacing: 1px;
            }
            p {
                font-weight: 700;
            }

            span {
                font-weight: 300;
            }

myColorPickerSol.js

     $(document).ready(function(){
    var canvas = $('#canvas');
  //swatch matches closest when either pure blue, green or red; loses all accuracy when colors mix.
  // dark blue gets really close. Purple gets really close, which makes me suspect the Green channel value is where the problem lies.

    // y-axis as Luminace(0-100%)
    // x-axis as Hue(0-360)


    var yPos;
    var lum;
    var hue;// aka xPos;

    var temp1;//for hslToRGB
    var temp2;//for hslToRGB
    var tempR;
    var tempG;
    var tempB;

    var red;
    var blue;
    var green;
    var realColVal;

    $('#canvas').mousemove(function(event){
      hue = Math.abs(event.offsetX);

      hueForRGB = (hue/360);

      yPos = Math.abs(event.offsetY);

      lum = (yPos/360);
      // console.log(lum + ' lum');

      $(canvas).css({'background-color':'hsl('+ event.offsetX + ',99%,'+ Math.round(lum *100) + '%)'});





    });
  // swatch listener
    $(canvas).click(function(event){

      hsl2RGB(lum);

      $('#rgb').text(red + ','+ green + ',' + blue);
      $('#hsl').text(hue + ',99%,' + Math.round(lum * 100) + '%');
      $(canvas).css({'background-color':'rgb('+ red + ','+ green + ','+ blue + ')'});
    });


  //red channel must be in upper third; green in middle third; blue in lower third.
    function hsl2RGB(lum){

      tempR = (hueForRGB + 0.333);
      tempG = hueForRGB;
      tempB = (hueForRGB - 0.333);
    // set temporary lum based on whether it is above/below 50%
      temp1 = lumMorOrLess50(lum);

  // set secondary temporary lum value
      temp2 = ((2.0 * (lum)) - temp1);

 //-----------EDIT ----------------------------- 
 // used the formula to make the tempR|G|B values between 0 and 1
 // tempR = makeRGB01(tempR);
//  tempG = makeRGB01(tempG);
//  tempB = makeRGB01(tempB);  
 //-----------------------------------------------

      red   = Math.round(convert2RGB(tempR,temp1,temp2));
      green = Math.round(convert2RGB(tempG,temp1,temp2));
      blue  = Math.round(convert2RGB(tempB,temp1,temp2));

  //swatch appears on click for hsl and rgb
      $('#swatchhsl').css({'background-color':'hsl('+ hue + ',99%,'+ Math.round(lum * 100 )+ '%)'});
      $('#swatchrgb').css({'background-color':'rgb('+ red + ','+ green + ','+ blue + ')'});

    };

    //force tempR|G|B to be between 0-1
    function makeRGB01(input) {
      if(input > 1){
        input -= 1.0;
      } else if(input < 0){
        input += 1.0;
      };
      return input;
    };

    //get value for each rgb channel
    function convert2RGB(tempColVal, val1, val2){
       //first convert tempColVal to between 0 and 1 then make it an RGB value
       tempColVal = makeRGB01(tempColVal);

      //next run 3 test;
        if(6.0 * tempColVal < 1){
          realColVal = (val2 + (val1 - val2) * 6 * tempColVal);
          console.log(realColVal + 'test 1; val1: '+ val1 + 'val2: ' + val2  );
       //-------EDIT ------------------------------------------
       // test2 will set realColVal to val1 instead of tempColVal
       //-------------------------------------------------------
        } else if(2.0 * tempColVal < 1){
          realColVal = val1;
          console.log(realColVal + 'test 2');
        } else if(3.0 * tempColVal < 2){
          realColVal = (val2 + (val1 - val2)*(0.666 - tempColVal) * 6.0);
          console.log(realColVal + 'test 3');
        } else {
          realColVal = val2;
          console.log(realColVal + 'realColVal = default (temp 2)');
        };

       //-------EDIT ------------------------------------------
       // normalize value before multiplying by 255

       realColVal = normalizeRGB(realColVal); 
       //-------------------------------------------------------
      // force value between 0 and 1 then set it to RGB scale and    
      // return
      return  (Math.abs(realColVal) * 255.0));

    };


    //configure temporary luminance value, temp1,  based on luminance
    function lumMorOrLess50(val){
      if(val < 0.50){
        return ((1.0 + 0.99) * val);
      } else {
        return ((.99 + val) - (val * .99));
      };
    };



  });

这是有效的解决方案,actualColorPickerSol.js我做了什么不同的事情?

            $(function() {
                console.log('Loaded, bro');
                colorPicker();
            });

            function colorPicker() {
                var canvas = $('#canvas');
                canvas.on('mousemove', changeCanvasBackground);
                canvas.on('click', printColorReadout);
            }

            function changeCanvasBackground(event) {
                var xCoord = Math.abs(event.offsetX);
                var yCoord = Math.abs(event.offsetY);
                var rgbValues = 'rgb(' + rgb(hsl(xCoord, yCoord)) + ')';
                $(this).css('background', rgbValues);
            }

            function printColorReadout(event) {
                var xCoord = event.offsetX;
                var yCoord = event.offsetY;
                var hslValues = hsl(xCoord, yCoord);
                var rgbValues = rgb(hslValues);
                var hexValues = hex(rgbValues);

                var hslString = parseHSL(hslValues);
                var rgbString = parseRGB(rgbValues);
                var hexString = parseHEX(hexValues);

                $('#hsl').text(hslString);
                $('#rgb').text(rgbString);
                $('#hex').text(hexString);
                $('#swatchhsl').css('background', hslString);
                $('#swatchrgb').css('background', rgbString);
            }

            function hsl(xCoord, yCoord) {
                // HSL = hsl(hue, saturation, luminance)
                var hsl;
                var hue = xCoord;
                var luminance = Math.round(((yCoord / 360) * 100));

                return [hue, 100, luminance];
            }

            function rgb(hslValues) {
                var hue = hslValues[0];
                var sat = hslValues[1] / 100;
                var lum = hslValues[2] / 100;
                var tempLum1, tempLum2, tempHue, tempR, tempG, tempB;

                if (lum < .50) {
                    tempLum1 = lum * (1 + sat);
                } else {
                    tempLum1 = (lum + sat) - (lum * sat);
                }

                tempLum2 = (2 * lum) - tempLum1;
                tempHue = hue / 360;

                tempR = tempHue + .333;
                tempG = tempHue;
                tempB = tempHue - .333;

             //This is the only part I think I did differently. 
             //The code below makes sure the green and blue values 
             //are between 0 and 1, then it checks all the colors to 
             //make sure they are between 0 and 1.  I tried this, 
            // and there was no change in the effect; 
           // the hsl and rgb values were still different.

                if (tempG < 0) { tempG += 1};
                if (tempG > 1) { tempG -= 1};
                if (tempB < 0) { tempB += 1};
                if (tempB > 1) { tempB -= 1};

                var normalizedRGB = [tempR, tempG, tempB].map(function(color, idx) {
                    if (color < 0) { return color += 1};
                    if (color > 1) { return color -= 1};
                    return color;
                });

                var rgbArray = normalizedRGB.map(function(color) {
                    if (colorCondition1(color)) {
                        return tempLum2 + ( tempLum1 - tempLum2 ) * 6 * color;
                    } else if (colorCondition2(color)) {
                        return tempLum1;
                    } else if (colorCondition3(color)) {
                        return tempLum2 + (tempLum1 - tempLum2) * (.666 - color) * 6;
                    }   else {
                        return tempLum2;
                    }
                });

                var rgbValues = rgbArray.map(function(color, idx) {
                    var convertedVal = color * 255;
                    return Math.round(convertedVal);
                });

                return rgbValues;
            }

            function hex(rgbValues) {
                var r = rgbValues[0];
                var g = rgbValues[1];
                var b = rgbValues[2];

                return [numToHex(r), numToHex(g), numToHex(b)];
            }

            function numToHex(num) {
                var hexCode = num.toString(16);
                if (hexCode.length < 2) { hexCode = "0" + hexCode; }
                return hexCode;
            }

            function colorCondition1(val) {
                return 6 * val < 1;
            }

            function colorCondition2(val) {
                return 2 * val < 1;
            }

            function colorCondition3(val) {
                return 3 * val < 2;
            }

            function parseHSL(hslValues) {
                return [
                    "hsl(",
                    hslValues[0], ", ",
                    hslValues[1], "%, ",
                    hslValues[2], "%)"
                ].join('');
            }

            function parseRGB(rgbValues) {
                return "rgb(" + rgbValues.join(', ') + ")";
            }

            function parseHEX(hexValues) {
                return "#" + hexValues.join('');
            }

最佳答案

将您的函数与您发布的链接中提供的算法进行比较,我认为,正如我在评论中所说,convert2RGB 的更正确实现可能是:

function convert2RGB(tempColVal, val1, val2){
   //first convert tempColVal to between 0 and 1 then make it an RGB value
   tempColVal = makeRGB01(tempColVal);

  //next run 3 test;
    if(6.0 * tempColVal < 1){
      realColVal = (val2 + (val1 - val2) * 6.0 * tempColVal);
  //    console.log(realColVal + 'test 1; val1: '+ val1 + 'val2: ' + val2  );
    } else if(2.0 * tempColVal < 1){
      realColVal = val1;
  //    console.log(realColVal + 'test 2');
    } else if(3.0 * tempColVal < 2){
      realColVal = (val2 + (val1 - val2)*(0.666 - tempColVal) * 6.0);
  //    console.log(realColVal + 'test 3');
    } else {
      realColVal = val2;
  //    console.log(realColVal + 'realColVal = default (temp 2)');
    };
      // Convert them to 8-bit by multiply them with 255 and return
  return  Math.round(realColVal * 255.0);

};

编辑: 不要更改您的 makeRGB01(),因为该算法的使用方式与调用 convert2RGB() 之前的方式相同。您的错误是将其也应用于返回的正确值。

关于javascript - hsl 到 rgb 的转换。值(value)观太差了。与解决方案进行比较。我做了什么不同的事情?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34316927/

相关文章:

python - seaborn husl 或 hsl 调色板不工作 : remains default black and white colors

machine-learning - 机器学习算法中的循环数据

javascript - 当我尝试从 iFrame 内部调用父页面上的函数时出现 IE8 错误

HTML 标签内的 Javascript

javascript - 这个 HTML5 , Javascript slider 代码有什么问题?

colors - 将 RGB/十六进制颜色代码映射到一般颜色类别

javascript - 操作 RGBA Javascript

javascript - Visual Studio 编辑器中的 JS 文件中的箭头是什么意思?

c# - 如何检查 RGB 颜色以及如何知道此范围是绿色还是红色?

javascript - 插入 HSL 颜色