css 如何用javascript从渐变中按百分比获取颜色值?

i86rm4rw  于 2023-03-05  发布在  Java
关注(0)|答案(9)|浏览(343)

我有一个固定宽度的div渐变应用使用css。我想建立基于滑块的颜色选择器的基础上,这个梯度。
当我拖动滑块我计算的百分比位置,我想得到十六进制或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');

    }
});
hgtggwj0

hgtggwj01#

我可以使用这个函数来解决这个问题,这个函数基于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/

6ioyuze2

6ioyuze22#

有一个很好的库可以处理各种颜色操作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)
qmb5sa22

qmb5sa223#

这是将百分比转换为颜色的另一种方法
这个例子使一个显示的值从红色变为绿色取决于它的值(像例如在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)`})
}

请参见以下演示:
x一个一个一个一个x一个一个二个x

jexiocij

jexiocij4#

三色渐变

以防万一有人想要一个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 + ')';
}

演示:

x一个一个一个一个x一个一个二个一个x一个一个三个一个

06odsfpq

06odsfpq5#

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

如果你有2,3,4或20种颜色,你可以使用这个解决方案。生成一个HTML元素和风格的CSS渐变背景。然后看看一个单一的像素颜色值。
1.创建一个<canvas>元素。宽度为101px(0到100%),高度为1px(我们不关心高度)。然后将背景色设置为渐变。参见initCanvas(colorsArray)方法。
1.查看画布上的一个像素,并返回它的颜色。参见方法getColor(percent)
1.最后你可以找到一个由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>

我的代码有两个方法initCanvs()getColors(),所以你不会为每个颜色选择生成新的画布。但是如果你每次都有新的渐变,你可以合并它们。

9rygscc1

9rygscc16#

这是我实现的多颜色渐变集RGB。(没有阿尔法通道)。扩展变种以前的答案。

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>
wfauudbj

wfauudbj7#

用和费利佩·里贝罗的答案相似的逻辑,
我已经创建了一个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字符串,还可以输出自定义Color对象({r,g,b,a}),以备您选择单个颜色分量。
当我尝试在基于Javascript的应用程序上模拟Tableau Jmeter 板时,遇到了类似的问题。我意识到这是Tableau和Microsoft Excel等数据可视化工具的常见功能,因此我创建了一个npm包来在Javascript应用程序上处理它。如果您想减少代码,可以使用该包。

zlhcx6iw

zlhcx6iw8#

基于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/

icnyk63a

icnyk63a9#

我的两分钱,计算一个线性的任意向量列表,一个任意的维度,与任意停止(可能是有用的CYMK梯度,但实际上我写这个,因为我不喜欢重复代码的红色,绿色和蓝色):

function binarySearch(arr, el, cmp) {
    // thanks to https://stackoverflow.com/questions/22697936
    let m = 0;
    const n = arr.length - 1;
    while (m <= n) {
        let k = (n + m) >> 1;
        let z = cmp(el, arr[k]);
        if (z > 0) {
            m = k + 1;
        } else if (z < 0) {
            n = k - 1;
        } else {
            return k;
        }
    }
    return ~m;
}
function LinearGradient(colors, stops) {
    if (colors.length !== stops.length) {
        throw new Error('Number of stops must equad to number of colors')
    }
    if (colors.length < 2) {
        throw new Error('Must specify at least two colors')
    }
    if (stops[0] !== 0) {
        // add explicit zero stop if not specified
        stops = [0, ...stops];
        colors = [colors[0], ...colors];
    }
    if (stops[1] !== 1) {
        // add explicit final stop if not specified
        stops = [...stops, 1];
        colors = [...colors, colors.slice(-1)[0]];
    }
    if (stops.some(stop => stop < 0 || stop > 1)) {
        throw new Error('All stops must be in the range 0..1')
    }
    if (stops.some((stop, i) => i > 0 && stop < stops[i-1])) {
        throw new Error('Stops must be sorted')
    }
    return (pos) => {
        let i = binarySearch(stops, pos, (a, b) => a - b);
        if (i < 0) i = ~i;
        const i1 = i == 0? 0 : i-1;
        const i2 = i == 0? 1 : i;
        const s1 = stops[i1], s2 = stops[i2];
        const c1 = colors[i1], c2 = colors[i2];
        const rel = ((pos - s1) / (s2 - s1));
        const pt = c1.map((c, i) => Math.round(c * (1-rel) + c2[i] * rel));
        return pt;
    }
}
const rgb = (c) => `rgb(${c[0]}, ${c[1]}, ${c[2]})`;

然后是一些测试代码:

[0,0.01,0.25,0.5,0.75,0.99,1].map(LinearGradient([[255,0,0],[255,255,0],[0,255,0]],[0,0.5,1])).map(rgb)
// ['rgb(255, 0, 0)', 'rgb(255, 5, 0)', 'rgb(255, 128, 0)', 'rgb(255, 255, 0)', 'rgb(128, 255, 0)', 'rgb(5, 255, 0)', 'rgb(0, 255, 0)']

这并不包括很多注解,但简而言之,LinearGradient()接受一个颜色列表(作为向量或3元素数组)和停止(每种颜色在其峰值处),并返回一个函数,该函数计算范围0..1内不同点的渐变。实用函数rgb用于生成rgb()颜色表达式,以供CSS使用。

相关问题