【问题标题】:How to get color value from gradient by percentage with javascript?如何使用javascript按百分比从渐变中获取颜色值?
【发布时间】:2015-07-20 12:08:46
【问题描述】:

我有一个使用 css 应用渐变的固定宽度 div。我想基于这个渐变构建基于滑块的颜色选择器。

当我拖动滑块时,我会计算百分比位置,并且我想根据该值获取十六进制或 rgb 颜色代码。

我的想法是创建一个定义了开始/停止位置和颜色的数组,然后根据滑块位置从该数组中找到两个值,然后以某种方式找到两者之间的颜色:这是我无法前进的地方。

演示:http://jsfiddle.net/pdu8rpfv/

var gradient = [
    [
        0,
        'ff0000'
    ],
    [
        28,
        '008000'
    ],
    [
        72,
        '0000ff'
    ],
    [
        100,
        'ff0000'
    ]
];
$( "#slider" ).slider({
    min: 1,
    slide: function( event, ui ) {

        var colorRange = []
        $.each(gradient, function( index, value ) {
            if(ui.value<=value[0]) {
                colorRange = [index-1,index]
                return false;
            }
        });

        $('#result').css("background-color", 'red');

    }
});

【问题讨论】:

    标签: javascript jquery css colors linear-gradients


    【解决方案1】:

    我能够使用这个基于less.js函数的函数解决这个问题:http://lesscss.org/functions/#color-operations-mix

    function pickHex(color1, color2, weight) {
        var w1 = weight;
        var w2 = 1 - w1;
        var rgb = [Math.round(color1[0] * w1 + color2[0] * w2),
            Math.round(color1[1] * w1 + color2[1] * w2),
            Math.round(color1[2] * w1 + color2[2] * w2)];
        return rgb;
    }
    

    我只需要传递渐变数组中最接近的两个颜色代码和滑块手柄所在的比率(可以借助滑块宽度轻松计算)。这是一个活生生的例子:

    http://jsfiddle.net/vksn3yLL/

    【讨论】:

      【解决方案2】:

      有一个很好的库可以处理各种颜色操作chroma.js

      yarn add chroma-js
      

      然后

      import chroma from 'chroma-js';
      
      const f = chroma.scale(['yellow', 'red', 'black']);
      
      console.log( f(0.25).toString() );                    // #ff8000
      console.log( f(0.5).css('rgba') );                    // rgba(255,0,0,1)
      console.log( f(0.75).css() );                         // rgb(128,0,0)
      console.log( f(1).css() );                            // rgb(0,0,0)
      

      【讨论】:

        【解决方案3】:

        这是另一种将百分比转换为颜色的方法

        此示例根据其值将显示的值从红色变为绿色(例如在 excel 条件格式中):

        function(percentValue) {
          $(`#output`)
            // print the value
            .html(percentValue)
            // colorize the text, more red if it's close to 0
            // and more green as it approach 100
            .css({color: `rgb(${(100 - percent) *2.56}, ${percent *2.56},0)`})
        }
        

        请看下面的演示:

        $('button').click( e => {
          const percent = Math.floor(Math.random()*100);
          const newElm = $(`<b>${percent}</b><br>`)
          .css({color: `rgb(${(100 - percent) *2.56},${percent *2.56},0)`})
          $('body').append(newElm);
        })
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <button>Click to make new percentage</button><br>

        【讨论】:

          【解决方案4】:

          无限数量的颜色渐变(两种或更多)

          如果您有 2、3、4 或 20 种颜色,您可以使用此解决方案。生成一个HTML 元素并使用CSS 渐变背景对其进行样式设置。然后查看单个像素的颜色值。

          1. 创建一个&lt;canvas&gt; 元素。宽度为 101px(0 到 100%),高度为 1px(我们不关心高度)。然后将背景颜色设置为渐变。见方法initCanvas(colorsArray)

          2. 查看画布的单个像素,并返回它的颜色。见方法getColor(percent)

          3. 最后,您可以找到由 5 种颜色(红色、橙色、绿色、石灰、蓝色)组成的渐变示例。

          const WIDTH = 101; // 0 to 100
          const HEIGHT = 1;
            
          let context;
          
          function initCanvas(gradientColors) // gradientColors [colorA, colorB, ..]
          {
            // Canvas
            const canvasElement = document.createElement("CANVAS");
            canvasElement.width = WIDTH;
            canvasElement.height = HEIGHT;
          
            context = canvasElement.getContext("2d");
            
            // Gradient
            const gradient = context.createLinearGradient(0, 0, WIDTH, 0); // x0, y0, x1, y1
            
            const step = 1 / (gradientColors.length - 1); // need to validate at least two colors in gradientColors
            let val = 0;
            gradientColors.forEach(color => {
              gradient.addColorStop(val, color);
              val += step;
            });
          
            // Fill with gradient
            context.fillStyle = gradient;
            context.fillRect(0, 0, WIDTH, HEIGHT); // x, y, width, height
          }
          
          function getColor(percent) // percent [0..100]
          {
            const color = context.getImageData(percent, 0, 1, 1); // x, y, width, height
            const rgba = color.data;
            
            return `rgb(${ rgba[0] }, ${ rgba[1] }, ${ rgba[2] })`;
          }
          
          // Test:
          initCanvas(['red', 'orange', 'green', 'lime', 'blue']);
          
          document.getElementById("color0"  ).style.backgroundColor = getColor(0);
          document.getElementById("color10" ).style.backgroundColor = getColor(10);
          document.getElementById("color20" ).style.backgroundColor = getColor(20);
          document.getElementById("color30" ).style.backgroundColor = getColor(30);
          document.getElementById("color40" ).style.backgroundColor = getColor(40);
          document.getElementById("color50" ).style.backgroundColor = getColor(50);
          document.getElementById("color60" ).style.backgroundColor = getColor(60);
          document.getElementById("color70" ).style.backgroundColor = getColor(70);
          document.getElementById("color80" ).style.backgroundColor = getColor(80);
          document.getElementById("color90" ).style.backgroundColor = getColor(90);
          document.getElementById("color100").style.backgroundColor = getColor(100);
          .example {
            width: 100px;
            height: 25px;
          }
          <h3>Gradient colors: red, orange, green, lime, blue</h3>
          <div id="color0"   class="example">0%  </div>
          <div id="color10"  class="example">10% </div>
          <div id="color20"  class="example">20% </div>
          <div id="color30"  class="example">30% </div>
          <div id="color40"  class="example">40% </div>
          <div id="color50"  class="example">50% </div>
          <div id="color60"  class="example">60% </div>
          <div id="color70"  class="example">70% </div>
          <div id="color80"  class="example">80% </div>
          <div id="color90"  class="example">90% </div>
          <div id="color100" class="example">100%</div>

          P.S - 我使用initCanvs()getColors() 两种方法进行编码,因此您不会为每种颜色选择生成新的画布。但是如果你每次都有新的渐变,你可以合并它们。

          【讨论】:

            【解决方案5】:

            使用与 Felipe Ribeiro 的最佳答案类似的逻辑,

            我创建了一个 Javascript color-scales 来为您处理它。您还可以输入多个色标以及设置透明度级别。

            现场演示在这里:https://codepen.io/dalisc/pen/yLVXoeR

            包链接在这里:https://www.npmjs.com/package/color-scales

            示例用法:

            const ColorScale = require("color-scales");
            let colorScale = new ColorScale(0, 100, ["#ffffff", "#000000"], 0.5);
            let rgbaStr = colorScale.getColor(50).toRGBAString(); // returns "rgba(127,127,127, 0.5)"
            

            该软件包能够根据您的需要输出十六进制、rgb 或 rgba 字符串。它还可以输出自定义颜色对象 ({r,g,b,a}),以防您需要挑选单个颜色分量。

            我在尝试在基于 Javascript 的应用程序上模仿 Tableau 仪表板时遇到了类似的问题。我意识到这是 Tableau 和 Microsoft Excel 等数据可视化工具的常见功能,所以我创建了一个 npm 包来在 Javascript 应用程序上处理它。如果你想减少你的代码,你可以使用这个包。

            【讨论】:

              【解决方案6】:

              三色渐变

              以防万一有人想要 3 色渐变,这里有一个使用红色、黄色和绿色的示例:

              colorGradient 函数的 github JS 代码在 here 可用。

              function colorGradient(fadeFraction, rgbColor1, rgbColor2, rgbColor3) {
                  var color1 = rgbColor1;
                  var color2 = rgbColor2;
                  var fade = fadeFraction;
              
                  // Do we have 3 colors for the gradient? Need to adjust the params.
                  if (rgbColor3) {
                    fade = fade * 2;
              
                    // Find which interval to use and adjust the fade percentage
                    if (fade >= 1) {
                      fade -= 1;
                      color1 = rgbColor2;
                      color2 = rgbColor3;
                    }
                  }
              
                  var diffRed = color2.red - color1.red;
                  var diffGreen = color2.green - color1.green;
                  var diffBlue = color2.blue - color1.blue;
              
                  var gradient = {
                    red: parseInt(Math.floor(color1.red + (diffRed * fade)), 10),
                    green: parseInt(Math.floor(color1.green + (diffGreen * fade)), 10),
                    blue: parseInt(Math.floor(color1.blue + (diffBlue * fade)), 10),
                  };
              
                  return 'rgb(' + gradient.red + ',' + gradient.green + ',' + gradient.blue + ')';
              }
              

              演示:

              // Gradient Function
              function colorGradient(fadeFraction, rgbColor1, rgbColor2, rgbColor3) {
                  console.log('>> fade: ', fadeFraction)
                  var color1 = rgbColor1;
                  var color2 = rgbColor2;
                  var fade = fadeFraction;
              
                  // Do we have 3 colors for the gradient? Need to adjust the params.
                  if (rgbColor3) {
                    fade = fade * 2;
              
                    // Find which interval to use and adjust the fade percentage
                    if (fade >= 1) {
                      fade -= 1;
                      color1 = rgbColor2;
                      color2 = rgbColor3;
                    }
                  }
              
                  var diffRed = color2.red - color1.red;
                  var diffGreen = color2.green - color1.green;
                  var diffBlue = color2.blue - color1.blue;
              
                  var gradient = {
                    red: parseInt(Math.floor(color1.red + (diffRed * fade)), 10),
                    green: parseInt(Math.floor(color1.green + (diffGreen * fade)), 10),
                    blue: parseInt(Math.floor(color1.blue + (diffBlue * fade)), 10),
                  };
                  return 'rgb(' + gradient.red + ',' + gradient.green + ',' + gradient.blue + ')';
              }
                
              // IMPLEMENTATION EXAMPLE:
              var spans = $('.gradient-test');
              var count = spans.length, color;
              var color1 = {
                red: 19, green: 233, blue: 19
              };
              var color3 = {
                red: 255, green: 0, blue: 0
              };
              var color2 = {
                red: 255, green: 255, blue: 0
              };
              $('.gradient-test').each(function(i, span) {
                var g = Math.round(((i+1) * 100) / count);
                if (g < 10){
                  g = '0' + g;
                } 
                g = +g === 100 ? 1 : +('0.' + g)
                color = colorGradient(g, color1, color2, color3);
                $(span).css('background-color', color);
              });
              .gradient-test {
                width: 1rem;
                height: 1rem;
                display: inline-block;
              }
              <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>
              <span class="gradient-test"></span>

              【讨论】:

              • 最后一个颜色是开头的那个,应该是这样吗?
              • 不,不是@htmlcoderexe,是实现代码错误(不在colorGradient函数中)(100%被解析为0.1而不是1.0)。我刚刚修好了。谢谢
              【解决方案7】:

              根据上面的 Gils 回答,我创建了一个使用渐变的类,颜色设置为沿线性渐变的特定百分比。因此,它可以轻松地处理从 CSS 复制粘贴的更复杂的渐变。

              // background: linear-gradient(90deg, #386657 0%, #85B87A 24.48%, #FFE600 51.56%, #BA4F1A 80.21%, #940023 100%);
              const grad = new LinearGradientHelper([
                ['#386657', 0],
                ['#85B87A', .2448],
                ['#FFE600', .5156],
                ['#BA4F1A', .8021],
                ['#940023', 1]
              ])
              
              console.log(grad.getColor(0))
              console.log(grad.getColor(.1))
              console.log(grad.getColor(.4))
              console.log(grad.getColor(.95))
              console.log(grad.getColor(1))
              

              https://jsfiddle.net/ctk916xa/2/

              【讨论】:

                【解决方案8】:

                这是我对多色渐变集 RGB 的实现。 (没有 Alpha 通道)。先前答案的扩展变体。

                r1.addEventListener('change',(ev)=>{
                  let res = test(ev.target.value)
                  d2.innerText=ev.target.value +' color: '+res
                  d2.style.backgroundColor = res
                })
                function test(value){
                  let colorPicked = pickRgbRange(value,
                       {color:[255,0,228,1], position:0},
                       {color:[0,194,255,1,1], position:15},
                       {color:[35,200,0,1], position:35},
                       {color:[255, 250, 164], position:50},
                       {color:[255,0,0,1], position:75},
                       {color:[0,0,0,1], position:100}
                       );
                  let resultRgba = `rgba(${colorPicked[0]},${colorPicked[1]},${colorPicked[2]},${colorPicked[3]})`;
                     return resultRgba
                }
                
                //(ildarin cc0) Start copy from here: ----------------------------------
                /** @description usage
                   let colorPickedRgba = pickRgbRange(value,
                     {color:[255,0,228,1], position:0},
                     {color:[0,194,255,1,0.5], position:.15},
                     {color:[35,200,0,1], position:.35},
                     {color:[255, 250, 164], position:.50},
                     {color:[255,0,0,1], position:.75},
                     {color:[0,0,0,1], position:.100}
                     )
                     let resultRgba = `rgba(${colorPicked[0]},${colorPicked[1]},${colorPicked[2]},${colorPicked[3]})`
                */
                function pickRgbRange(position, ...elements) {
                    var [left, right, weight] = pickClosest(position, ...elements);
                    return pickRgba(left.color, right.color, weight);
                }
                
                function pickRgba(color1, color2, weight) {
                    var w1 = weight;
                    var w2 = 1 - w1;
                    var rgba = [
                        Math.round(color1[0] * w2 + color2[0] * w1),
                        Math.round(color1[1] * w2 + color2[1] * w1),
                        Math.round(color1[2] * w2 + color2[2] * w1),
                        1
                    ];
                    return rgba;
                }
                
                function pickClosest(position, ...elements) {
                    var left = elements[0], 
                    right = { color: [0, 0, 0], position: Number.MAX_VALUE };
                    var leftIndex = 0;
                    for (var i = 0; i < elements.length; i++) {
                        if (position >= elements[i].position && position > left.position){
                            left = elements[i];
                            leftIndex = i;
                        }
                    }
                    if (elements.length - 1 === leftIndex) {
                        right = elements[leftIndex];
                    }
                    else {
                        right = elements[leftIndex + 1];
                    }
                    if(left == right){
                      return [right, right, 0];
                    }
                    var dleft = position - left.position;
                    var sum = dleft + right.position - position;
                    var weight = dleft / sum;
                    return [left, right, weight];
                }
                #r1{
                width:100%;
                }
                #d1,
                #d2 {
                  width: 100%;
                  height: 50px;
                }
                
                #d1 {
                  background: linear-gradient(90deg,
                      rgb(255, 0, 228) 0%,
                      rgb(0, 194, 255) 15%,
                      rgb(35, 200, 0) 35%,
                      rgb(255, 250, 164) 50%,
                      rgb(255, 0, 0) 75%,
                      rgb(0, 0, 0) 100%);
                }
                
                #d2 {
                  text-shadow:0 0 4px #fff;
                  background-color: #ccc;
                }
                <div id='d1'></div>
                <input id='r1' type='range' />
                <div id='d2'></div>

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2018-12-05
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-03-17
                  • 2014-08-12
                  • 2023-01-10
                  相关资源
                  最近更新 更多