Хотя этот ответ запоздал, принятый неверно, утверждая, что оттенок должен быть в пределах [0, 255]; также можно добиться большей справедливости с помощью более четкого объяснения и кода.
Оттенок - угловое значение в интервале [0, 360); полный круг, где 0 = 360. Цветовое пространство HSV легче визуализировать и является более интуитивным для человека, чем RGB. HSV образует цилиндр, из которого срез отображается во многих средствах выбора цвета, в то время как RGB - это действительно куб и не очень хороший выбор для средства выбора цвета; большинство из тех, кто его использует, должны использовать больше ползунков, чем требуется для сборщика HSV.
При интерполяции оттенка требуется, чтобы меньшая дуга выбиралась для перехода от одного оттенка к другому. Таким образом, учитывая два значения оттенка, есть четыре возможности, с примерами углов ниже:
Δ | ≤ 180 | > 180
--|---------|---------
+ | 40, 60 | 310, 10
− | 60, 40 | 10, 310
if Δ = 180 then both +/− rotation are valid options
Давайте возьмем +
против часовой стрелки и −
как по часовой стрелке. Если разница в абсолютном значении превышает 180, то нормализуйте ее на ± 360, чтобы убедиться, что величина находится в пределах 180; это также меняет направление, правильно.
var d = h2 - h1;
var delta = d + ((Math.abs(d) > 180) ? ((d < 0) ? 360 : -360) : 0);
Теперь просто разделите delta
на необходимое количество шагов, чтобы получить вес каждой итерации цикла для добавления к начальному углу во время интерполяции.
var new_angle = start + (i * delta);
Соответствующая функция извлечена из следующего кода:
function interpolate(h1, h2, steps) {
var d = h2 - h1;
var delta = (d + ((Math.abs(d) > 180) ? ((d < 0) ? 360 : -360) : 0)) / (steps + 1.0);
var turns = [];
for (var i = 1; d && i <= steps; ++i)
turns.push(((h1 + (delta * i)) + 360) % 360);
return turns;
}
"use strict";
function interpolate(h1, h2, steps) {
var d = h2 - h1;
var delta = (d + ((Math.abs(d) > 180) ? ((d < 0) ? 360 : -360) : 0)) / (steps + 1.0);
var turns = [];
for (var i = 1; d && i <= steps; ++i)
turns.push(((h1 + (delta * i)) + 360) % 360);
return turns;
}
function get_results(h1, h2, steps) {
h1 = norm_angle(h1);
h2 = norm_angle(h2);
var r = "Start: " + h1 + "<br />";
var turns = interpolate(h1, h2, steps);
r += turns.length ? "Turn: " : "";
r += turns.join("<br />Turn: ");
r += (turns.length ? "<br />" : "") + "Stop: " + h2;
return r;
}
function run() {
var h1 = get_angle(document.getElementById('h1').value);
var h2 = get_angle(document.getElementById('h2').value);
var steps = get_num(document.getElementById('steps').value);
var result = get_results(h1, h2, steps);
document.getElementById('res').innerHTML = result;
}
function get_num(s) {
var n = parseFloat(s);
return (isNaN(n) || !isFinite(n)) ? 0 : n;
}
function get_angle(s) {
return get_num(s) % 360;
}
function norm_angle(a) {
a %= 360;
a += (a < 0) ? 360 : 0;
return a;
}
<h1 id="title">Hue Interpolation</h1>
Angle 1
<input type="text" id="h1" />
<br />Angle 2
<input type="text" id="h2" />
<br />
<br />Intermediate steps
<input type="text" id="steps" value="5" />
<br />
<br/>
<input type="submit" value="Run" onclick="run()" />
<p id="res"></p>