将0-1值转换为十六进制颜色?

时间:2015-06-10 13:55:28

标签: javascript colors hex rgb rgba

我正在创建一个使用NASA API可视化星标的应用。星的颜色以0到1的值返回,0表示纯蓝色,1表示纯红色。基本上我需要设置一种方法将javascript中的0-1值转换为滑动HEX(或rgb)比例,如下所示:

0: blue (9aafff)
.165: blue white (cad8ff)
.33: white (f7f7ff)
.495: yellow white (fcffd4)
.66: yellow (fff3a1)
.825: orange (ffa350)
1: red (fb6252)

这可能吗?我不知道如何开始接近这个。干杯!

3 个答案:

答案 0 :(得分:2)

最好的工作是在另一个颜色空间而不是RGB颜色空间。例如HSL

示例:

var stones = [ // Your Data
  {v:0, hex:'#9aafff'},
  {v:.165, hex:'#cad8ff'},
  {v:.33, hex:'#f7f7ff'},
  {v:.495, hex:'#fcffd4'},
  {v:.66, hex:'#fff3a1'},
  {v:.825, hex:'#ffa350'},
  {v:1, hex:'#fb6252'},
]
stones.forEach(function(s){
  s.rgb = hexToRgb(s.hex);
  s.hsl = rgbToHsl.apply(0, s.rgb);
});

function valueToRgbColor(val){
  for (var i=1; i<stones.length; i++) {
    if (val<=stones[i].v) {
      var k = (val-stones[i-1].v)/(stones[i].v-stones[i-1].v),
          hsl = interpolArrays(stones[i-1].hsl, stones[i].hsl, k);
      return 'rgb('+hslToRgb.apply(0,hsl).map(function(v){ return v|0})+')';
    }
  }
  throw "bad value";
}

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


function hexToRgb(hex) {
    return /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
    .slice(1).map(function(v){ return parseInt(v,16) });
}

function interpolArrays(a,b,k){
  var c = a.slice();
  for (var i=0;i<a.length;i++) c[i]+=(b[i]-a[i])*k;
  return c;
}

var stones = [ // Your Data
  {v:0, hex:'#9aafff'},
  {v:.165, hex:'#cad8ff'},
  {v:.33, hex:'#f7f7ff'},
  {v:.495, hex:'#fcffd4'},
  {v:.66, hex:'#fff3a1'},
  {v:.825, hex:'#ffa350'},
  {v:1, hex:'#fb6252'},
]
stones.forEach(function(s){
  s.rgb = hexToRgb(s.hex);
  s.hsl = rgbToHsl.apply(0, s.rgb);
});

function valueToRgbColor(val){
  for (var i=1; i<stones.length; i++) {
    if (val<=stones[i].v) {
      var k = (val-stones[i-1].v)/(stones[i].v-stones[i-1].v),
          hsl = interpolArrays(stones[i-1].hsl, stones[i].hsl, k);
      return 'rgb('+hslToRgb.apply(0,hsl).map(function(v){ return v|0})+')';
    }
  }
  throw "bad value";
}

for (var i=0; i<=1; i+=.03) {
  var color = valueToRgbColor(i);
  $('<div>').css({background:color}).text(i.toFixed(2)+" -> "+color).appendTo('body');
}
body {
  background: #222;
}
div {
  width:200px;
  margin:auto;
  color: #333;
  padding: 2px;
  text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

在这个例子中,我使用了颜色空间转换函数here但是一旦你知道要查找什么就很容易找到。

请注意,现代浏览器了解HSL颜色(例如:background: hsl(120,100%, 50%);),因此,如果您只是构建HTML,则不必在页面中嵌入所有这些代码,只需预先计算颜色停止和插值直接关于HSL值。

答案 1 :(得分:0)

这是我刚才做的纯Javascript解决方案之一。它处理两种颜色之间的线性插值。

/* 
NASA color to RGB function
by Alexis Paques

It process a linear interpolation between two colors, here is the scheme:
0: blue
.165: blue white
.33: white
.495: yellow white
.66: yellow
.825: orange
1: red
*/

var blue = [0,0,255];
var bluewhite = [127,127,255];
var white = [255,255,255];
var yellowwhite = [255,255,127];
var yellow = [255,255,0];
var orange = [255,127,0];
var red = [255,0,0];
function color01toRGB(color01){
  var RGB = [0,0,0];
  var fromRGB = [0,0,0];
  var toRGB = [0,0,0];
  if(!color01)
    return '#000000';
  if(color01 > 1 || color01 < 0)
    return '#000000';
  if(color01 >= 0 && color01 <= 0.165 ){
    fromRGB = blue;
    toRGB = bluewhite;
  }
  else if(color01 > 0.165 && color01 <= 0.33 ){
    fromRGB = bluewhite;
    toRGB = white;
  }
  else if(color01 > 0.33 && color01 <= 0.495 ){
    fromRGB = white;
    toRGB = yellowwhite;
  }
  else if(color01 > 0.495 && color01 <= 0.66 ){
    fromRGB = yellowwhite;
    toRGB = yellow;
  }
  else if(color01 > 0.66 && color01 <= 0.825 ){
    fromRGB = yellow;
    toRGB = orange;
  }
  else if(color01 > 0.825 && color01 <= 1 ){
    fromRGB = orange;
    toRGB = red;
  }

  // 0.165
  for (var i = RGB.length - 1; i >= 0; i--) {
    RGB[i] = Math.round(fromRGB[i]*color01/0.165 + toRGB[i]*(1-color01/0.165)).toString(16);
  };

  return '#' + RGB.join('');
}

答案 2 :(得分:0)

由于您有一个值列表,所有值都非常饱和且明亮,因此您可以在当前(RGB)空间中进行插值。它不会像你转换为HSL一样漂亮,但是对于你拥有的颜色会很好。

由于您在数据中没有任何加权或曲线,因此使用简单的线性插值应该可以正常工作。类似的东西:

&#13;
&#13;
var stops = [
  [0, 154, 175, 255],
  [0.165, 202, 216, 255],
  [0.33, 247, 247, 255],
  [0.495, 252, 255, 212],
  [0.66, 255, 243, 161],
  [0.825, 255, 163, 80],
  [1, 251, 98, 82]
];

function convertColor(color) {
  var c = Math.min(Math.max(color, 0), 1); // Clamp between 0 and 1

  // Find the first stop below c
  var startIndex = 0;
  for (; stops[startIndex][0] < c && startIndex < stops.length; ++startIndex) {
    // nop
  }
  var start = stops[startIndex];
  console.log('using stop', startIndex, 'as start');

  // Find the next stop (above c)
  var stopIndex = startIndex + 1;
  if (stopIndex >= stops.length) {
    stopIndex = stops.length - 1;
  }
  var stop = stops[stopIndex];
  console.log('using stop', stopIndex, 'as stop');

  // Find the distance from start to c and start to stop
  var range = stop[0] - start[0];
  var diff = c - start[0];

  // Convert diff into a ratio from start to stop
  if (range > 0) {
    diff /= range;
  }

  console.log('interpolating', c, 'between', stop[0], 'and', start[0], 'by', diff);

  // Convert from RGB to HSL
  var a = rgbToHsl(start[1], start[2], start[3]);
  var b = rgbToHsl(stop[1], stop[2], stop[3]);
  console.log('hsl stops', a, b);

  // Interpolate between the two colors (start * diff + (stop * (1 - diff)))
  var out = [0, 0, 0];
  out[0] = a[0] * diff + (b[0] * (1 - diff));
  out[1] = a[1] * diff + (b[1] * (1 - diff));
  out[2] = a[2] * diff + (b[2] * (1 - diff));
  console.log('interpolated', out);

  // Convert back from HSL to RGB  
  var r = hslToRgb(out[0], out[1], out[2]);
  r = r.map(function(rv) {
    // Round each component of the output
    return Math.round(rv);
  });

  return r;
}

// Set the divs
var divs = document.querySelectorAll('.star');
Array.prototype.forEach.call(divs, function(star) {
  var color = convertColor(star.dataset.color);
  var colorStr = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';
  console.log('setting', star, 'to', colorStr);
  star.style.backgroundColor = colorStr;
});

// HSL to RGB conversion from http://stackoverflow.com/a/30758827/129032
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];
}

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];
}
&#13;
.star {
  width: 24px;
  height: 24px;
  display: inline-block;
  box-shadow: 0px 0px 16px -2px rgba(0, 0, 0, 0.66);
}
&#13;
<div class="star" data-color="0.0"></div>
<div class="star" data-color="0.05"></div>
<div class="star" data-color="0.1"></div>
<div class="star" data-color="0.15"></div>
<div class="star" data-color="0.2"></div>
<div class="star" data-color="0.25"></div>
<div class="star" data-color="0.3"></div>
<div class="star" data-color="0.35"></div>
<div class="star" data-color="0.4"></div>
<div class="star" data-color="0.45"></div>
<div class="star" data-color="0.5"></div>
<div class="star" data-color="0.55"></div>
<div class="star" data-color="0.6"></div>
<div class="star" data-color="0.65"></div>
<div class="star" data-color="0.7"></div>
<div class="star" data-color="0.75"></div>
<div class="star" data-color="0.8"></div>
<div class="star" data-color="0.85"></div>
<div class="star" data-color="0.9"></div>
<div class="star" data-color="0.95"></div>
<div class="star" data-color="1.0"></div>
&#13;
&#13;
&#13;