Поле bind: связывание с DOM

Система связывания bind в спецификациях Vega и Vega-Lite реализует прямую интеграцию параметров визуализации с DOM-элементами управления. Она позволяет сигналам (signals) и параметрам (params) изменяться через стандартные HTML-инпуты без ручного написания обработчиков событий, обеспечивая декларативную модель интерактивности.

В Vega интерактивность строится вокруг системы сигналов. Сигнал представляет собой реактивную переменную, значение которой может изменяться в ответ на внешние события или пользовательский ввод.

Базовая структура сигнала:

{
  "signals": [
    {
      "name": "threshold",
      "value": 10
    }
  ]
}

Сигнал сам по себе не связан с DOM. Связь появляется через поле bind, которое описывает источник значения.

Поле bind: концептуальная модель

Поле bind определяет, каким образом сигнал отображается в пользовательском интерфейсе и каким HTML-элементом управляется его значение. Это декларативная замена ручной работы с addEventListener.

Обобщённая структура:

{
  "signals": [
    {
      "name": "threshold",
      "value": 10,
      "bind": {
        "input": "range",
        "min": 0,
        "max": 100,
        "step": 1
      }
    }
  ]
}

В момент рендеринга Vega создаёт соответствующий DOM-элемент и синхронизирует его значение с сигналом.

Типы DOM-привязок

Text input

Используется для строковых значений или чисел в свободном вводе.

{
  "name": "label",
  "value": "A",
  "bind": {
    "input": "text"
  }
}

Особенности:

  • значение всегда строка
  • отсутствие ограничений на формат
  • применяется для динамических подписей, фильтров

Range slider

Один из наиболее распространённых типов управления числовыми параметрами.

{
  "name": "opacity",
  "value": 0.5,
  "bind": {
    "input": "range",
    "min": 0,
    "max": 1,
    "step": 0.01
  }
}

Семантика:

  • непрерывное или дискретное изменение
  • мгновенная реакция визуализации
  • используется для фильтров, прозрачности, масштабирования

Select (выпадающий список)

Используется для выбора из конечного множества значений.

{
  "name": "colorScheme",
  "value": "category10",
  "bind": {
    "input": "select",
    "options": ["category10", "set1", "accent"]
  }
}

Свойства:

  • строго ограниченный набор значений
  • удобен для переключения режимов отображения
  • применяется для тем, палитр, агрегирующих функций

Checkbox

Булевы переключатели для бинарных состояний.

{
  "name": "showPoints",
  "value": true,
  "bind": {
    "input": "checkbox"
  }
}

Используется для:

  • включения/выключения слоёв
  • управления вспомогательной графикой
  • переключения режимов детализации

Двусторонняя реактивность

Связывание bind реализует двунаправленную модель:

  1. DOM изменяет значение сигнала
  2. сигнал изменяет состояние визуализации
  3. визуализация перерисовывается

Изменение сигнала программно также обновляет UI:

{
  "signals": [
    {
      "name": "zoom",
      "value": 1,
      "bind": {
        "input": "range",
        "min": 1,
        "max": 10
      }
    }
  ]
}

Если zoom обновляется через трансформации или другие сигналы, ползунок синхронизируется автоматически.

Привязка к фильтрам данных

Наиболее частый сценарий применения bind — интерактивная фильтрация данных.

{
  "signals": [
    {
      "name": "minValue",
      "value": 0,
      "bind": {
        "input": "range",
        "min": 0,
        "max": 100
      }
    }
  ],
  "data": [
    {
      "name": "table",
      "transform": [
        {
          "type": "filter",
          "expr": "datum.value >= minValue"
        }
      ]
    }
  ]
}

Механизм работы:

  • DOM изменяет minValue
  • пересчитывается выражение фильтра
  • данные обновляются в графике

Связь bind и Vega-Lite params

В Vega-Lite концепция bind реализуется через params. Vega-Lite абстрагирует сигналы, но сохраняет ту же модель реактивности.

Пример:

{
  "params": [
    {
      "name": "cutoff",
      "value": 50,
      "bind": {
        "input": "range",
        "min": 0,
        "max": 100
      }
    }
  ],
  "transform": [
    {
      "filter": "datum.x > cutoff"
    }
  ]
}

Отличие от Vega:

  • отсутствуют явные signals
  • bind интегрирован в уровень параметров
  • упрощён синтаксис

Динамическая генерация options

Для select возможно вычисление списка значений через данные:

{
  "name": "category",
  "value": "A",
  "bind": {
    "input": "select",
    "options": {"signal": "data('table').map(d => d.type)"}
  }
}

Это связывает DOM не только с сигналами, но и с вычисляемыми данными.

Синхронизация нескольких сигналов

Несколько bind могут управляться одновременно, формируя связанную систему параметров:

{
  "signals": [
    {
      "name": "xMin",
      "value": 0,
      "bind": {"input": "range", "min": 0, "max": 50}
    },
    {
      "name": "xMax",
      "value": 100,
      "bind": {"input": "range", "min": 50, "max": 200}
    }
  ]
}

Такая конфигурация часто используется для управления диапазонами осей.

Ограничения модели bind

Механизм привязки имеет ряд структурных ограничений:

  • отсутствует сложная кастомизация DOM-структуры
  • нет встроенной системы компоновки контролов
  • ограниченный набор input-типов
  • невозможность произвольных React/Vue компонентов без расширения Vega runtime

Несмотря на это, декларативность обеспечивает воспроизводимость и переносимость визуализаций.

Взаимодействие bind и выражений

Сигналы, управляемые через bind, могут использоваться в выражениях Vega Expression Language:

{
  "signals": [
    {
      "name": "scale",
      "value": 1,
      "bind": {"input": "range", "min": 0.5, "max": 5}
    },
    {
      "name": "computedSize",
      "update": "scale * 20"
    }
  ]
}

Здесь:

  • scale управляется DOM
  • computedSize зависит от scale
  • изменения распространяются реактивно

Архитектурная роль bind

bind выступает мостом между декларативной графической моделью и императивной пользовательской средой браузера. В рамках Vega он интегрирует систему сигналов с DOM без нарушения принципа декларативности спецификации.

Ключевая роль:

  • устранение ручного event handling
  • унификация управления параметрами
  • обеспечение реактивной синхронизации состояния визуализации и интерфейса