Система визуализации Vega построена вокруг декларативного описания
интерактивности через поток событий. В отличие от императивных подходов
(где обработчики навешиваются через addEventListener),
здесь взаимодействие описывается как часть спецификации. Центральный
механизм — сигналы (signals), а поле on определяет, какие
события из DOM или графических примитивов преобразуются в изменения
состояния.
Событийная модель Vega основана на потоках событий (event streams),
которые можно фильтровать, комбинировать и преобразовывать. Поле
on задаёт набор правил:
on в сигналах
VegaСигнал в Vega описывает реактивное значение, которое может изменяться
под воздействием событий. Поле on является массивом
обработчиков событий.
Структура:
{
"signals": [
{
"name": "exampleSignal",
"value": 0,
"on": [
{
"events": "...",
"update": "..."
}
]
}
]
}
Каждый объект внутри on содержит:
events — описание источника событийupdate — выражение, вычисляющее новое значение
сигналаforce — принудительное обновление даже
без изменения значенияbetween, consume —
управление распространением событийeventsПоле events задаёт поток событий. Оно может быть:
{
"events": "mousedown"
}
{
"events": "rect:mouseover"
}
Здесь событие ограничено графическими примитивами Vega
(rect, symbol, text и т.д.).
{
"events": "mousedown[event.shiftKey]"
}
Используется JavaScript-подобная фильтрация через выражения.
{
"events": "mousedown, mousemove, mouseup"
}
Или более сложные конструкции:
{
"events": "mousedown > mousemove > mouseup"
}
Здесь > означает последовательность во времени.
updateupdate — это выражение Vega Expression Language, которое
вычисляет новое значение сигнала при каждом событии.
Пример:
{
"name": "mouseX",
"value": 0,
"on": [
{
"events": "mousemove",
"update": "event.x"
}
]
}
updateВ выражениях доступны:
event — объект DOM событияdatum — данные, если событие связано с визуальным
элементом{
"signals": [
{
"name": "x",
"value": 0,
"on": [
{
"events": "mousemove",
"update": "event.x"
}
]
},
{
"name": "y",
"value": 0,
"on": [
{
"events": "mousemove",
"update": "event.y"
}
]
}
]
}
Система обновляет сигналы при каждом движении мыши, формируя реактивное состояние.
Обработчики могут включать условия:
{
"events": "mousedown",
"update": "event.shiftKey ? x + 10 : x - 10"
}
Также возможно использование фильтрации прямо в
events:
{
"events": "mousedown[event.button === 0]"
}
Это позволяет разделять поведение без дополнительного кода.
Поле on — массив, а значит несколько обработчиков могут
реагировать на один и тот же поток событий.
{
"on": [
{
"events": "mousedown",
"update": "1"
},
{
"events": "mousedown",
"update": "2"
}
]
}
Порядок важен: при совпадении условий обработчики выполняются последовательно.
Vega позволяет слушать события не только глобально, но и на уровне элементов сцены.
{
"events": "symbol:click",
"update": "datum.value"
}
Здесь:
symbol — тип графического элементаclick — тип событияdatum.value — значение из связанного набора данныхon для перетаскиванияКлассический сценарий — drag-and-drop:
{
"signals": [
{
"name": "dragX",
"value": 0,
"on": [
{
"events": "symbol:mousedown",
"update": "x"
},
{
"events": "window:mousemove",
"update": "dragX + event.dx"
},
{
"events": "window:mouseup",
"update": "dragX"
}
]
}
]
}
Здесь используются:
window:mousemove — глобальные событияevent.dx — изменение координатыon в Vega-LiteВ Vega-Lite напрямую поле on встречается в нескольких
контекстах, главным образом:
{
"selection": {
"brush": {
"type": "interval",
"on": "[mousedown[event.shiftKey], mouseup] > mousemove"
}
}
}
Здесь on управляет тем, как формируется интервал
выбора:
Хотя Vega-Lite абстрагирует сигналы, on может
использоваться для описания событий, которые управляют фильтрацией или
выделением данных.
Одно из ключевых преимуществ on — возможность
композиции:
"events": "mousedown > mousemove > mouseup"
"events": "touchstart, mousedown"
"events": "mousemove[event.altKey && event.shiftKey]"
В выражениях update доступны математические и логические
операции:
Пример:
{
"events": "mousemove",
"update": "clamp(event.x, 0, width)"
}
onПриводит к чрезмерному обновлению сигналов:
"events": "mousemove"
без ограничения по элементу или состоянию.
Несколько on могут перезаписывать значения сигналов,
если логика не разделена.
datumИспользование datum вне событий, связанных с
mark-элементами, приводит к undefined.
onПоле on является ключевым элементом реактивной модели
Vega:
Система событий через on фактически заменяет
классические обработчики событий JavaScript в рамках визуализации,
перенося их в декларативное описание графа состояний.