插值HSL颜色

5

我正在构建一款星形可视化引擎,需要对接收到的API数据进行插值处理。HSL颜色值如下:

-.63, hsl: 228° 100% 80%,
.165, hsl: 224° 100% 90%,
.33, hsl: 240° 100% 98%,
.495, hsl: 64° 100% 92%,
.66, hsl: 52° 100% 82%,
.825, hsl: 28° 100% 66%,
2.057, hsl: 6° 95% 65%,

每个星星都会返回一个介于-.63和2.057之间的颜色值,我需要一个函数来获取该值并在由上述停止点组成的光谱中获取颜色。
我之前得到了一些帮助,但我无法弄清楚这个问题,并且找不到插值HSL值的简明教程或步骤。我唯一能想到的解决方法是通过外部库来实现,但这对于相对简单的事情似乎是一个荒谬的解决方案。任何帮助将不胜感激!

我没有看到具体的问题。你需要弄清楚的是什么“this”?线性插值吗? - Jongware
@Jongware 是的,我已经更新了问题以便更清晰地表达。 - j_d
好的,谢谢 - 好多了。不过你的HSL数组看起来很奇怪。我们可以假设这些值是固定的,这样我们就可以用更常见的Javascript表示法来写它们了吗? - Jongware
@Jongware 是的,它们是固定的。抱歉,我对 HSL 颜色还很陌生,以前没有使用过。据我所知,它们与十六进制或 RGB 相比,插值时失真较小。 - j_d
这取决于你所谓的“失真”是什么。插值沿着你指定的轴工作,在HSL的情况下,其中之一是色调,与RGB相比,它看起来更自然。 - Jongware
@Jongware 我明白了。所以,考虑到HSL的三个值,我猜想插值需要接收一个值(例如0.5),并为其生成三个值(H、S、L)。 - j_d
2个回答

4
在 HSB 空间中,一个简单的线性插值函数:
function get_color_for(value) {
    var i, h,s,b,stops = [
        [-0.63, [228, 100, 80]],
        [0.165, [224, 100, 90]],
        [0.33, [240, 100, 98]],
        [0.495, [64, 100, 92]],
        [0.66, [52, 100, 82]],
        [0.825, [28, 100, 66]],
        [2.057, [6, 95, 65]]
    ];
    if (value <= stops[0][0]) return stops[0][1];
    if (value >= stops[stops.length - 1][0]) return stops[stops.length - 1][1];
    i = 0;
    while (value > stops[i][0])
       i++;
    value -= stops[i-1][0];
    value /= (stops[i][0]-stops[i-1][0]);
    h = stops[i-1][1][0]+(stops[i][1][0]-stops[i-1][1][0])*value;
    s = stops[i-1][1][1]+(stops[i][1][1]-stops[i-1][1][1])*value;
    b = stops[i-1][1][2]+(stops[i][1][2]-stops[i-1][1][2])*value;
    return [h,s,b];
}

对于小于最小输入值的数,它总是返回第一个颜色集,而对于大于最大值的数,则返回最后一个颜色集。返回的值是一个HSL数组,可立即在CSS中使用。如果您的环境需要RGB颜色,可以使用hsl-to-rgb转换函数,例如this earlier SO question中所述。检查您的输出设备对RGB范围的期望:0.0到1.0、0到100或0到255。请注意,此函数通常不能用于hsb。问题在于hue部分:它在360度处绕回,因此尝试在350和10之间进行插值将使其返回青色(在170左右的值),而不是红色(在0处的值)。这里有一个jsfiddle,显示了一系列数字的输出。

1
RGB插值在您的颜色比例尺中效果更好,HSL在蓝色和黄色之间添加了一种带绿色的颜色:

enter image description here

RGB插值:
function lerp(start, end, t) {
    return (1 - t) * start + t * end;
}

function getColor(t) {
    var colors = [
        [153, 173, 255], [204, 218, 255], [245, 245, 255],
        [252, 255, 214], [255, 243, 163], [255, 163, 82],
        [251, 98,  81]
    ];
    var domain = [-0.63, 0.165, 0.33, 0.495, 0.66, 0.825, 2.057];

    if (t <= domain[0]) {
        return colors[0];
    }

    if (t >= domain[domain.length - 1]) {
        return colors[colors.length - 1];
    }

    for (var i = 0; t > domain[i]; i++);

    var from = colors[i - 1];
    var to = colors[i];
    t = (t - domain[i - 1]) / (domain[i] - domain[i - 1]);
    return [
        lerp(from[0], to[0], t),
        lerp(from[1], to[1], t),
        lerp(from[2], to[2], t)
    ];
}

绘制它:

function rgbToCSS(rgb) {
    return 'rgb(' + Math.round(rgb[0]) + ',' +
                    Math.round(rgb[1]) + ',' +
                    Math.round(rgb[2]) + ')';
}

var canvas = document.createElement('canvas');
canvas.width = 800;
canvas.height = 100;
var context = canvas.getContext('2d');
for (var i = 0; i < canvas.width; i++) {
    context.fillStyle = rgbToCSS(getColor(lerp(-0.63, 2.057, i / canvas.width)));
    context.fillRect(i, 0, 1, canvas.height);
}
document.body.appendChild(canvas);

JSFiddle

的英译中文是:

{{链接1:JSFiddle}}


我也注意到了那种微绿色的色调,但我认为我的天体物理学知识不足以确定恒星是否真的会有那种颜色(杰克·范斯在他的小说中提到了至少一颗星星;我不知道那是否属实)。因为我相当确定它们不会在RGB空间中发光,所以我没有做出评论。尽管如此:对于一个同样好的答案,我还是要点赞! - Jongware
@Jongware 天文学家们迄今为止还没有发现绿色的恒星,它们的颜色从蓝色到白色,然后变成黄色。https://zh.wikipedia.org/wiki/%E6%98%9F%E5%BA%A7%E5%88%86%E7%B1%BB#%E7%8E%B0%E4%BB%A3%E5%88%86%E7%B1%BB - Alexey Lebedev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接