В Vega модель исполнения визуализации построена вокруг объекта View, который инкапсулирует состояние сцены, данные, масштабы и рендеринг. Любое динамическое изменение набора данных в уже созданной визуализации выполняется через механизм изменений (changeset), который применяется к конкретному источнику данных.
Экземпляр View представляет запущенную визуализацию,
созданную после компиляции спецификации:
После инициализации визуализации через view.runAsync()
или view.initialize() дальнейшие изменения данных
выполняются без пересоздания графа сцены.
view.change()Метод используется для применения изменений к одному из наборов данных:
view.change(dataName, changeset)
Параметры:
dataName — строка, имя набора данных, определённого в
спецификации Vegachangeset — объект типа changeset,
описывающий операции вставки, удаления или обновленияМетод не изменяет данные напрямую, а формирует декларативное описание трансформации.
Changeset — это структура, описывающая атомарные операции над данными. Создаётся через фабрику:
const cs = vega.changeset();
Основные операции:
Добавление новых элементов в поток данных:
cs.insert([
{ category: "A", value: 10 },
{ category: "B", value: 20 }
]);
Удаление по предикату или набору значений:
cs.remove(d => d.category === "A");
или точечное удаление:
cs.remove([{ category: "A", value: 10 }]);
Комбинация ins ert + update:
cs.upsert(
{ category: "A", val ue: 15 },
d => d.category === "A"
);
cs.remove(() => true);
Полезно при полной перезагрузке набора данных.
После формирования changeset он применяется к конкретному источнику:
view.change("table", cs).runAsync();
Где "table" — имя data-источника в Vega-spec:
{
"data": [
{
"name": "table",
"values": []
}
]
}
После вызова view.change() происходят следующие
этапы:
Важно, что сам view.change() не запускает рендер
автоматически в синхронном режиме — он лишь фиксирует изменения.
view.runAsync()Для гарантированной отрисовки используется:
view.change("table", cs).runAsync();
runAsync():
Пример батчинга:
const cs = vega.changeset()
.insert([{ category: "C", value: 30 }])
.remove(d => d.category === "B");
view.change("table", cs);
view.change("otherTable", vega.changeset().insert([{ x: 1 }]));
view.runAsync();
Оба изменения будут применены в одном проходе.
В более старых сценариях используется:
view.change("table", cs).run();
Особенности:
Механизм changeset специально разработан для минимизации пересчётов:
Это делает возможным:
Типичный сценарий взаимодействия:
function updateData(newPoint) {
const cs = vega.changeset().insert([newPoint]);
view.change("table", cs).runAsync();
}
Удаление устаревших значений:
function pruneOld() {
const cs = vega.changeset()
.remove(d => d.timestamp < Date.now() - 60000);
view.change("table", cs).runAsync();
}
В Vega-Lite прямого аналога view.change() нет на уровне
спецификации, но после компиляции Vega-Lite → Vega:
dataName соответствует внутренним именам,
сгенерированным компиляторомПример:
const runtime = vl.compile(spec).spec;
const view = new vega.View(vega.parse(runtime));
Далее:
view.change("source_0", vega.changeset().insert(data)).runAsync();
view.data()
возвращает копию)Несовпадение имени источника данных приводит к отсутствию обновления без ошибок выполнения.
view.change("table", cs); // изменения не отрисуются
cs.upsert(item, d => d.id); // ошибка: предикат должен возвращать boolean
Правильно:
cs.upsert(item, d => d.id === item.id);
view.change() фактически реализует потоковую модель:
Это позволяет строить архитектуры визуализации, близкие к event-driven системам обработки данных.