Система сигналов в Vega построена на реактивной модели вычислений,
где каждое изменение состояния автоматически приводит к пересчёту
зависимых выражений, масштабов, фильтров и визуальных элементов. В этом
контексте view.signal() является центральным API для чтения
и изменения состояния визуализации на уровне экземпляра
View.
Сигналы представляют собой именованные реактивные переменные, определённые в спецификации Vega. Они могут:
View.Реактивность означает, что изменение сигнала автоматически вызывает пересчёт всех зависимых вычислений без ручного управления обновлением каждого элемента сцены.
view.signal(name) как механизм чтения состоянияМетод view.signal(name) без второго аргумента возвращает
текущее значение сигнала из активного экземпляра визуализации.
view.signal(name)
name;View.const currentScale = view.signal("scaleFactor");
Если сигнал отсутствует в спецификации или ещё не инициализирован,
результатом будет undefined.
view.signal(name, value)При передаче второго аргумента метод становится сеттером и изменяет значение сигнала.
view.signal(name, value)
.run() или .runAsync();view.signal("threshold", 42);
view.run();
В этом примере изменение сигнала threshold влияет на все
выражения, где он используется: фильтры, вычисляемые поля, условные
стили.
run() и runAsync()Изменение сигнала само по себе не гарантирует немедленное обновление DOM или canvas. Для применения изменений используется запуск рендер-цикла:
view.signal("opacity", 0.5).run();
или асинхронный вариант:
await view.signal("opacity", 0.5).runAsync();
run() — синхронное выполнение, блокирует до завершения
рендера;runAsync() — возвращает Promise, удобен для цепочек
взаимодействий и анимаций.При изменении сигнала происходит каскадное обновление:
View.Ключевая особенность: пользователь работает не с отдельными объектами, а с графом зависимостей.
Сигналы часто выступают мостом между пользовательскими событиями и графикой.
view.signal("minValue", 10).run();
В Vega-спецификации:
"transform": [
{
"type": "filter",
"expr": "datum.value > minValue"
}
]
Изменение сигнала автоматически перестраивает фильтр.
Сигналы часто обновляются через event listeners:
"signals": [
{
"name": "mouseX",
"on": [
{
"events": "mousemove",
"update": "x()"
}
]
}
]
На стороне Jav * aScript:
view.signal("mouseX");
При движении мыши Vega обновляет сигнал автоматически, а
view.signal() позволяет считывать его текущее значение.
При множественных изменениях сигналов важно учитывать стоимость перерисовки. Vega поддерживает группировку обновлений:
view
.signal("a", 1)
.signal("b", 2)
.signal("c", 3)
.run();
В этом случае:
Сигналы могут быть использованы внутри выражений Vega:
"expr": "width * scaleFactor"
или:
"expr": "datum.value > threshold"
При изменении scaleFactor или threshold
автоматически пересчитываются все зависимые узлы.
Изменение сигнала не приводит к обновлению сцены без
run().
При частых изменениях сигналов без батчинга возможны промежуточные перерисовки.
Чтение несуществующего сигнала возвращает undefined, что
может привести к ошибкам выражений.
Сигналы не строго типизированы, поэтому ответственность за согласованность лежит на разработчике.
Сигналы выступают в роли внутреннего состояния визуализации, аналогичного state в UI-фреймворках.
view.signal("zoom", 1.5).run();
В Vega:
"scale": {
"name": "xscale",
"domain": {"signal": "zoomDomain"}
}
Изменение сигнала меняет отображаемый диапазон без пересборки спецификации.
view.signal() в сложных сценарияхСигналы могут использоваться как параметры анимационных функций:
"expr": "sin(time * speed)"
view.signal("speed", 2).run();
view.signal()Метод view.signal() фактически является:
Он объединяет декларативную модель Vega и императивное управление из JavaScript, сохраняя при этом целостность реактивной системы.