Поле bind: связывание с элементами управления

Поле 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"]
}

Применяются при выборе единственного режима.


Пример фильтрации через bind

Динамическая фильтрация по значению

const 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"}
  }
};

Ползунок определяет минимальное отображаемое значение.


Связывание выбора категорий

Использование select

params: [
  {
    name: "selectedCategory",
    value: "A",

    bind: {
      input: "select",
      options: ["A", "B", "C"]
    }
  }
]

Фильтрация:

transform: [
  {
    filter: "datum.category === selectedCategory"
  }
]

Настройка подписей элементов управления

Поле name

bind: {
  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.


Базовый пример Vega

{
  "$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, median

params: [
  {
    name: "aggregation",

    value: "sum",

    bind: {
      input: "radio",

      options: [
        "sum",
        "mean",
        "median"
      ]
    }
  }
]

Связь с выражениями Vega

Во многих случаях bind используется вместе с expr.

Пример

{
  expr: "pow(sizeControl, 2)"
}

Ползунок задаёт коэффициент, а выражение вычисляет итоговый размер.


Автоматическая генерация DOM

Vega самостоятельно создаёт HTML-элементы управления рядом с визуализацией.

Это означает:

  • не требуется писать HTML вручную;
  • не нужен addEventListener;
  • не требуется синхронизация состояния;
  • отсутствует прямое управление DOM.

Кастомизация элементов управления

CSS-оформление

Поскольку Vega создаёт стандартные HTML-элементы, они стилизуются обычным CSS.

Пример:

input[type="range"] {
  width: 300px;
}

Привязка к существующему DOM

В Vega возможно связывание с заранее созданным HTML-элементом.

Пример

bind: {
  element: "#slider"
}

HTML:

<input id="slider" type="range">

Отличия Vega-Lite и Vega

Возможность Vega-Lite Vega
Простые параметры Да Да
Полный контроль сигналов Нет Да
Произвольные события Ограничено Полностью
Гибкая реактивность Частично Полностью
Низкоуровневый контроль Нет Да

Ограничения bind

Только поддерживаемые HTML-элементы

Поддерживаются:

  • range
  • checkbox
  • radio
  • select
  • text

Нестандартные компоненты напрямую не подключаются.


Ограничения Vega-Lite

В Vega-Lite система параметров упрощена.

Для сложной логики часто требуется:

  • чистая Vega;
  • пользовательские сигналы;
  • внешняя JavaScript-логика.

Использование вместе с событиями

В 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.

Перерисовываются только изменённые части сцены.

Однако большое количество связанных параметров может приводить к:

  • частым перерасчётам;
  • нагрузке на layout;
  • избыточным обновлениям DOM.

Оптимизация

Использование разумного step

Плохой вариант:

step: 0.0001

Хороший вариант:

step: 1

Ограничение диапазонов

Слишком большие диапазоны могут вызывать чрезмерные перерасчёты.


Интерактивное масштабирование

Управление коэффициентом zoom

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()

Интеграция с внешним JavaScript

Хотя bind автоматизирует интерфейс, параметры можно менять вручную.

Пример

view.signal("opacity", 0.3).run();

Реактивная модель Vega

Главная особенность bind заключается не в создании HTML-контролов, а в интеграции с реактивной системой Vega.

Каждое изменение:

  1. обновляет сигнал;
  2. пересчитывает зависимости;
  3. обновляет сцены;
  4. синхронизирует интерфейс;
  5. минимизирует лишние операции.

Благодаря этому Vega и Vega-Lite позволяют создавать сложные интерактивные визуализации без ручного управления состоянием интерфейса.