Поле bind в Vega и Vega-Lite используется для связывания
параметров, сигналов и интерактивных состояний с HTML-элементами
управления. Благодаря этому график получает полноценный интерфейс
взаимодействия: ползунки, выпадающие списки, чекбоксы, переключатели и
текстовые поля напрямую изменяют визуализацию без ручной обработки DOM и
событий JavaScript.
В Vega-Lite bind чаще всего применяется совместно с
параметрами (params), а в Vega — с сигналами
(signals).
Основная идея механизма:
Связь строится вокруг трёх компонентов:
| Компонент | Назначение |
|---|---|
bind |
описание HTML-элемента управления |
| параметр / сигнал | хранение текущего значения |
| выражения или трансформации | использование значения в визуализации |
bind в Vega-Lite{
params: [
{
name: "size",
value: 100,
bind: {
input: "range",
min: 10,
max: 500,
step: 10
}
}
]
}
Здесь создаётся ползунок (range), изменяющий параметр
size.
const spec = {
$schema: "https://vega.github.io/schema/vega-lite/v5.json",
data: {
values: [
{x: 10, y: 20},
{x: 20, y: 40},
{x: 30, y: 10},
{x: 40, y: 50}
]
},
params: [
{
name: "pointSize",
value: 100,
bind: {
input: "range",
min: 10,
max: 1000,
step: 10
}
}
],
mark: "point",
encoding: {
x: {field: "x", type: "quantitative"},
y: {field: "y", type: "quantitative"},
size: {
value: {
expr: "pointSize"
}
}
}
};
После перемещения ползунка размер всех точек обновляется динамически.
range)Наиболее распространённый вариант.
bind: {
input: "range",
min: 0,
max: 100,
step: 1
}
| Свойство | Назначение |
|---|---|
min |
минимальное значение |
max |
максимальное значение |
step |
шаг изменения |
text)bind: {
input: "text"
}
Применяется для:
select)bind: {
input: "select",
options: ["A", "B", "C"]
}
Позволяет переключать режимы визуализации.
checkbox)bind: {
input: "checkbox"
}
Обычно используется для:
radio)bind: {
input: "radio",
options: ["sum", "mean", "median"]
}
Применяются при выборе единственного режима.
bindconst spec = {
$schema: "https://vega.github.io/schema/vega-lite/v5.json",
data: {
values: [
{category: "A", value: 10},
{category: "B", value: 40},
{category: "C", value: 70},
{category: "D", value: 100}
]
},
params: [
{
name: "threshold",
value: 50,
bind: {
input: "range",
min: 0,
max: 100,
step: 1
}
}
],
transform: [
{
filter: "datum.value >= threshold"
}
],
mark: "bar",
encoding: {
x: {field: "category"},
y: {field: "value"}
}
};
Ползунок определяет минимальное отображаемое значение.
selectparams: [
{
name: "selectedCategory",
value: "A",
bind: {
input: "select",
options: ["A", "B", "C"]
}
}
]
Фильтрация:
transform: [
{
filter: "datum.category === selectedCategory"
}
]
namebind: {
input: "range",
name: "Размер точек: "
}
Результат:
<label>
Размер точек:
<input type="range">
</label>
value{
name: "opacity",
value: 0.5,
bind: {
input: "range",
min: 0,
max: 1,
step: 0.1
}
}
Параметр сразу получает начальное значение 0.5.
params: [
{
name: "size",
value: 100,
bind: {
input: "range",
min: 10,
max: 500
}
},
{
name: "opacity",
value: 0.7,
bind: {
input: "range",
min: 0,
max: 1,
step: 0.1
}
}
]
encoding: {
opacity: {
value: {
expr: "opacity"
}
}
}
params: [
{
name: "pointColor",
value: "steelblue",
bind: {
input: "select",
options: [
"steelblue",
"red",
"green",
"orange"
]
}
}
]
Использование:
mark: {
type: "point",
color: {
expr: "pointColor"
}
}
Параметры, управляемые через bind, могут участвовать в
вычислениях.
transform: [
{
calculate: "datum.value * scaleFactor",
as: "scaled"
}
]
scaleFactor изменяется через ползунок.
bind в
VegaВ Vega применяется аналогичный механизм, но вместо
params используются signals.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"signals": [
{
"name": "radius",
"value": 50,
"bind": {
"input": "range",
"min": 10,
"max": 200
}
}
]
}
Сигналы в Vega — полноценная реактивная система.
Изменение значения сигнала автоматически:
signals: [
{
name: "domainMax",
value: 100,
bind: {
input: "range",
min: 10,
max: 500
}
}
]
Использование:
scales: [
{
name: "xscale",
type: "linear",
domain: [0, {"signal": "domainMax"}],
range: "width"
}
]
bind и
условийparams: [
{
name: "showLabels",
value: true,
bind: {
input: "checkbox"
}
}
]
Использование:
opacity: {
condition: {
test: "showLabels",
value: 1
},
value: 0
}
sum, mean, medianparams: [
{
name: "aggregation",
value: "sum",
bind: {
input: "radio",
options: [
"sum",
"mean",
"median"
]
}
}
]
Во многих случаях bind используется вместе с
expr.
{
expr: "pow(sizeControl, 2)"
}
Ползунок задаёт коэффициент, а выражение вычисляет итоговый размер.
Vega самостоятельно создаёт HTML-элементы управления рядом с визуализацией.
Это означает:
addEventListener;Поскольку Vega создаёт стандартные HTML-элементы, они стилизуются обычным CSS.
Пример:
input[type="range"] {
width: 300px;
}
В Vega возможно связывание с заранее созданным HTML-элементом.
bind: {
element: "#slider"
}
HTML:
<input id="slider" type="range">
| Возможность | Vega-Lite | Vega |
|---|---|---|
| Простые параметры | Да | Да |
| Полный контроль сигналов | Нет | Да |
| Произвольные события | Ограничено | Полностью |
| Гибкая реактивность | Частично | Полностью |
| Низкоуровневый контроль | Нет | Да |
bindПоддерживаются:
rangecheckboxradioselecttextНестандартные компоненты напрямую не подключаются.
В Vega-Lite система параметров упрощена.
Для сложной логики часто требуется:
В Vega сигнал может одновременно:
bind;{
name: "size",
value: 50,
on: [
{
events: "mousemove",
update: "x()"
}
],
bind: {
input: "range",
min: 0,
max: 500
}
}
bind обеспечивает двустороннее связывание:
Это важная особенность реактивной модели Vega.
Типичная структура интерактивной аналитической панели:
| Элемент | Тип bind |
|---|---|
| выбор метрики | select |
| фильтр диапазона | range |
| включение тренда | checkbox |
| режим агрегации | radio |
| текстовый поиск | text |
Все элементы автоматически управляют визуализацией.
bind работает эффективно благодаря реактивному движку
Vega.
Перерисовываются только изменённые части сцены.
Однако большое количество связанных параметров может приводить к:
stepПлохой вариант:
step: 0.0001
Хороший вариант:
step: 1
Слишком большие диапазоны могут вызывать чрезмерные перерасчёты.
params: [
{
name: "zoom",
value: 1,
bind: {
input: "range",
min: 1,
max: 10,
step: 0.1
}
}
]
Использование:
scale: {
domain: [0, {"expr": "100 / zoom"}]
}
params: [
{
name: "query",
value: "",
bind: {
input: "text",
name: "Поиск: "
}
}
]
Фильтр:
filter: "indexof(datum.name, query) >= 0"
filter: "test(regexp(query, 'i'), datum.name)"
В Vega параметры через bind могут менять:
signals: [
{
name: "frequency",
value: 1,
bind: {
input: "range",
min: 1,
max: 20
}
}
]
Использование:
update: "sin(datum.x * frequency)"
Хорошо:
name: "opacityControl"
Плохо:
name: "x1"
Избыточное число контролов ухудшает UX и производительность.
Логически связанные параметры должны располагаться рядом.
Пустые или неопределённые параметры затрудняют работу с графиком.
value{
name: "size",
bind: {
input: "range"
}
}
Некоторые конфигурации работают нестабильно без начального значения.
value: "10"
вместо:
value: 10
filter: "datum.value > slider"
при отсутствии параметра slider.
Для проверки сигналов в Vega:
view.signal("radius")
Для обновления:
view.signal("radius", 100).run()
Хотя bind автоматизирует интерфейс, параметры можно
менять вручную.
view.signal("opacity", 0.3).run();
Главная особенность bind заключается не в создании
HTML-контролов, а в интеграции с реактивной системой Vega.
Каждое изменение:
Благодаря этому Vega и Vega-Lite позволяют создавать сложные интерактивные визуализации без ручного управления состоянием интерфейса.