В Vega сигналы представляют собой базовый механизм реактивного состояния, который используется для управления динамическими значениями внутри визуализации. Каждый сигнал — это именованная переменная, которая может хранить значение, вычисляться на основе выражений и изменяться в ответ на события пользовательского взаимодействия или внутренние изменения системы рендеринга.
Сигналы задаются в массиве signals в спецификации Vega и
имеют три ключевых свойства, определяющих их поведение:
name, value и on.
Базовая форма определения сигнала выглядит следующим образом:
{
"signals": [
{
"name": "example",
"value": 0,
"on": []
}
]
}
Каждое из полей выполняет строго определённую роль в системе реактивного обновления.
namename определяет уникальный идентификатор сигнала в
рамках всей спецификации Vega.
name:signalsПример:
{
"name": "mouseX",
"value": 0
}
После объявления такого сигнала его можно использовать в выражениях:
{
"encode": {
"update": {
"x": { "signal": "mouseX" }
}
}
}
Таким образом name формирует основу адресации состояния
внутри графа визуализации.
valuevalue задаёт начальное значение сигнала. Это значение
используется при инициализации сцены до того, как начнут обрабатываться
события и вычисляться реактивные зависимости.
value:onПример с числом:
{
"name": "threshold",
"value": 10
}
Пример с выражением:
{
"name": "centerX",
"value": "width / 2"
}
В этом случае centerX вычисляется при инициализации
сцены на основе текущих параметров layout.
value не является статическим значением в классическом
смысле. Оно может быть пересчитано при пересборке сцены или изменении
внешних параметров, если используется выражение.
onon определяет набор правил, которые описывают, как
сигнал изменяется в ответ на события. Это ключевой механизм реактивного
программирования в Vega.
Каждый элемент массива on представляет собой правило
обновления сигнала.
{
"name": "dragX",
"value": 0,
"on": [
{
"events": "mousedown",
"update": "x()"
}
]
}
eventsevents определяет, на какие события подписывается
сигнал.
События могут быть:
mousedown, mouseup,
mousemove)window:resize)@mark:mouseover)Пример:
{
"events": "mousemove",
"update": "x()"
}
Также поддерживаются сложные выражения:
{
"events": "mousedown, touchstart"
}
или последовательности:
{
"events": "mousedown[!event.shiftKey] > mousemove"
}
updateupdate определяет выражение, вычисляющее новое значение
сигнала при срабатывании события.
update:x(),
y())eventПример простого обновления:
{
"name": "mouseX",
"value": 0,
"on": [
{
"events": "mousemove",
"update": "x()"
}
]
}
В этом случае сигнал mouseX постоянно синхронизируется с
координатой мыши по оси X.
Сигналы в Vega образуют направленный граф зависимостей. При изменении одного сигнала автоматически пересчитываются все выражения, которые его используют.
onupdateon для интерактивности{
"name": "dragging",
"value": false,
"on": [
{
"events": "mousedown",
"update": "true"
},
{
"events": "mouseup",
"update": "false"
}
]
}
{
"name": "offsetX",
"value": 0,
"on": [
{
"events": "mousedown",
"update": "x() - datum.x"
}
]
}
Сигналы выполняют роль глобального реактивного состояния внутри спецификации Vega. Они заменяют необходимость внешнего state-менеджмента, характерного для классических JavaScript-приложений.
Основные сценарии использования:
name, value и onЭти три поля образуют единую модель:
name задаёт идентичность сигналаvalue определяет начальное состояниеon обеспечивает изменение состояния во времениПример комплексного сигнала:
{
"name": "zoom",
"value": 1,
"on": [
{
"events": "wheel",
"update": "clamp(zoom * pow(1.001, -event.deltaY), 0.5, 10)"
}
]
}
Здесь:
name задаёт параметр масштабированияvalue устанавливает стартовый zoomon обеспечивает интерактивное изменение через колесо
мыши