Интерполяция цветов в D3.js используется для плавного перехода между двумя или несколькими цветовыми значениями. Механизм интерполяции лежит в основе анимаций, градиентов, тепловых карт, цветовых шкал и визуализации данных, где цвет отражает изменение состояния или числового диапазона.
В библиотеке D3.js интерполяция реализована через набор функций
семейства d3.interpolate*, каждая из которых работает с
определённой цветовой моделью.
Базовый принцип работы интерполятора:
const interpolate = d3.interpolateRgb("red", "blue");
console.log(interpolate(0)); // red
console.log(interpolate(0.5)); // промежуточный цвет
console.log(interpolate(1)); // blue
Аргумент функции интерполятора принимает значение от 0
до 1:
0 — начальный цвет1 — конечный цветd3.interpolateRgbНаиболее распространённый способ интерполяции цветов.
const color = d3.interpolateRgb("#ff0000", "#0000ff");
console.log(color(0.25));
console.log(color(0.5));
console.log(color(0.75));
D3 выполняет линейную интерполяцию отдельно для каждого канала:
Например:
rgb(255, 0, 0) → rgb(0, 0, 255)
Промежуточные значения вычисляются математически.
const svg = d3.select("svg");
for (let i = 0; i <= 10; i++) {
svg.append("rect")
.attr("x", i * 40)
.attr("y", 0)
.attr("width", 40)
.attr("height", 40)
.attr("fill", d3.interpolateRgb("orange", "purple")(i / 10));
}
Результатом станет плавный цветовой переход.
d3.interpolateHslRGB-интерполяция не всегда создаёт визуально естественные переходы. Цвет может становиться грязным или тусклым. Для более плавных переходов используется модель HSL.
const color = d3.interpolateHsl("yellow", "blue");
console.log(color(0.5));
HSL состоит из:
RGB:
d3.interpolateRgb("red", "green")(0.5)
HSL:
d3.interpolateHsl("red", "green")(0.5)
Результаты будут визуально различаться:
d3.interpolateLabЦветовая модель LAB разработана для более точного соответствия восприятию человека.
const color = d3.interpolateLab("white", "steelblue");
console.log(color(0.5));
Преимущества LAB:
LAB особенно полезен:
d3.interpolateHclHCL является модификацией LAB.
const color = d3.interpolateHcl("purple", "orange");
Особенности:
HCL часто считается лучшим вариантом для визуализации данных.
d3.interpolateCubehelixАлгоритм Cubehelix создаёт цветовые схемы с равномерным изменением яркости.
const color = d3.interpolateCubehelix("purple", "orange");
Преимущества:
Используется в:
| Модель | Особенность | Применение |
|---|---|---|
| RGB | Простая математическая интерполяция | Базовые анимации |
| HSL | Более плавные оттенки | UI, декоративные эффекты |
| LAB | Перцептивная равномерность | Аналитика |
| HCL | Улучшенная визуализация | Data Visualization |
| Cubehelix | Равномерная яркость | Научные графики |
Интерполяция тесно связана со шкалами (scales).
const scale = d3.scaleLinear()
.domain([0, 100])
.range(["white", "darkblue"]);
D3 автоматически создаёт интерполятор.
console.log(scale(50));
Метод .interpolate() позволяет выбрать модель
интерполяции.
const scale = d3.scaleLinear()
.domain([0, 100])
.range(["red", "blue"])
.interpolate(d3.interpolateHcl);
Теперь шкала использует HCL.
const color = d3.scaleSequential(d3.interpolateViridis)
.domain([0, 100]);
Использование:
rect.attr("fill", d => color(d.value));
D3 содержит встроенные цветовые схемы.
d3.interpolateViridis(0.5)
d3.interpolateInferno(0.5)
d3.interpolatePlasma(0.5)
d3.interpolateMagma(0.5)
d3.interpolateCividis(0.5)
const schemes = [
d3.interpolateViridis,
d3.interpolateInferno,
d3.interpolatePlasma
];
schemes.forEach((scheme, row) => {
for (let i = 0; i < 100; i++) {
svg.append("rect")
.attr("x", i * 5)
.attr("y", row * 30)
.attr("width", 5)
.attr("height", 30)
.attr("fill", scheme(i / 99));
}
});
D3 активно использует интерполяцию при переходах
(transitions).
d3.select("rect")
.transition()
.duration(2000)
.attr("fill", "green");
Во время transition D3 автоматически создаёт интерполятор.
function customInterpolator(t) {
return `rgb(${255 * t}, 0, ${255 * (1 - t)})`;
}
Использование:
svg.append("rect")
.attr("fill", customInterpolator(0.3));
const scale = d3.scaleLinear()
.domain([0, 50, 100])
.range(["green", "yellow", "red"]);
D3 автоматически создаёт сегментированную интерполяцию.
const color = d3.scaleSequential()
.domain([0, 1])
.interpolator(d3.interpolateInferno);
Применение:
cells.attr("fill", d => color(d.temperature));
Используется для данных с центральной точкой.
const color = d3.scaleDiverging(d3.interpolateRdYlBu)
.domain([-1, 0, 1]);
Типичные сценарии:
d3.scaleSequential()
Предназначены для:
d3.scaleOrdinal()
Используются для:
D3 поддерживает палитры ColorBrewer.
d3.schemeBlues[9]
Пример:
const scale = d3.scaleQuantize()
.domain([0, 100])
.range(d3.schemeBlues[9]);
D3 интерполирует и alpha-канал.
d3.interpolateRgb(
"rgba(255,0,0,0.1)",
"rgba(255,0,0,1)"
)(0.5);
d3.colorconst c1 = d3.color("red");
const c2 = d3.color("blue");
const interpolate = d3.interpolate(c1, c2);
d3.interpolateD3 умеет автоматически определять тип данных.
d3.interpolate("red", "blue");
Также поддерживаются:
const interpolate = d3.interpolateArray(
["red", "green"],
["blue", "yellow"]
);
const interpolate = d3.interpolateObject(
{ color: "red", value: 10 },
{ color: "blue", value: 100 }
);
При работе с большими наборами данных важно учитывать:
const context = canvas.getContext("2d");
Canvas эффективнее SVG при десятках тысяч элементов.
Плохо:
.attr("fill", d => d3.interpolateViridis(d))
Лучше:
const viridis = d3.interpolateViridis;
.attr("fill", d => viridis(d))
Наиболее качественными считаются:
Причины:
scaleSequentialconst color = d3.scaleSequential()
.domain([0, 100])
.interpolator(d3.interpolateViridis);
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("r", 5)
.attr("fill", d => color(d.value));
const color = d3.scaleSequential(t =>
d3.interpolateViridis(1 - t)
);
const scale = d3.scaleQuantize()
.domain([0, 1])
.range(d3.schemeGreens[5]);
Цветовые легенды обычно строятся через непрерывные шкалы.
for (let i = 0; i < 100; i++) {
legend.append("rect")
.attr("x", i)
.attr("width", 1)
.attr("height", 20)
.attr("fill", d3.interpolateViridis(i / 99));
}
const gradient = defs.append("radialGradient")
.attr("id", "grad");
gradient.append("stop")
.attr("offset", "0%")
.attr("stop-color", "white");
gradient.append("stop")
.attr("offset", "100%")
.attr("stop-color", "blue");
attrTweenselection.transition()
.attrTween("fill", function() {
const interpolate = d3.interpolateRgb(
"red",
"blue"
);
return function(t) {
return interpolate(t);
};
});
RGB может давать:
Для аналитики предпочтительнее:
Ошибка:
color(200)
при ожидаемом диапазоне 0–1.
const temperature = d3.scaleSequential()
.domain([-30, 50])
.interpolator(d3.interpolateTurbo);
const density = d3.scaleSequential()
.interpolator(d3.interpolateMagma);
const profit = d3.scaleDiverging()
.interpolator(d3.interpolateRdBu)
.domain([-100, 0, 100]);
Интерполяторы D3 возвращают CSS-совместимые строки.
element.style.background =
d3.interpolateRainbow(0.4);
d3.interpolateRainbow(t)
Особенности:
d3.interpolateTurbo(t)
Turbo отличается:
Используется:
Неправильно выбранная палитра может:
Корректная интерполяция обеспечивает: