Архитектура расширения строится вокруг взаимодействия между страницей браузера, встроенным редактором спецификаций и движком рендеринга, основанным на Vega и Vega-Lite. Основная задача заключается в том, чтобы предоставить интерактивную среду для мгновенного прототипирования визуализаций без необходимости разворачивания отдельного приложения или сервера.
Расширение работает как изолированный клиентский модуль, внедряемый в контекст веб-страницы через content scripts. Оно перехватывает пользовательские действия, связанные с редактированием JSON-спецификаций, и передаёт их в sandbox-окружение, где происходит компиляция Vega/Vega-Lite описаний в SVG или Canvas.
Внутренняя структура расширения обычно разделяется на несколько слоёв:
UI-слой чаще всего реализован на базе CodeMirror или Monaco Editor, обеспечивая подсветку синтаксиса JSON и автодополнение. При изменении текста редактор генерирует событие, которое поступает в валидатор.
Валидатор проверяет соответствие спецификации формату Vega или Vega-Lite. Ошибки фиксируются до этапа рендеринга, что предотвращает падение графического движка. Далее данные передаются в трансляционный слой.
Расширение Vega Voyager реализует концепцию интерактивного исследовательского пространства для визуализаций. Его ключевая особенность заключается в автоматической генерации вариантов графиков на основе набора данных или частичной спецификации.
В отличие от статического рендеринга, Voyager строит пространство возможных визуальных представлений. Это достигается за счёт комбинации:
Внутри расширения этот процесс реализован как pipeline:
Профилирование данных включает вычисление статистик: min/max, уникальные значения, распределение категорий, выявление временных рядов. Эти метаданные становятся основой для генерации визуальных кодировок.
На этапе synthesis расширение формирует набор возможных Vega-Lite спецификаций. Каждая спецификация представляет собой JSON-объект следующей структуры:
{
"data": {"values": [...]},
"mark": "bar",
"encoding": {
"x": {"field": "category", "type": "nominal"},
"y": {"field": "value", "type": "quantitative"}
}
}
Voyager расширяет этот базовый механизм, перебирая комбинации:
Каждая комбинация оценивается функцией полезности, основанной на информационной плотности и читаемости.
После генерации спецификация передаётся в runtime Vega, который выполняет компиляцию в низкоуровневую сценографическую модель. Vega строит dataflow-граф, где каждый узел представляет трансформацию данных или визуальный элемент.
Процесс включает:
Scenegraph является ключевой абстракцией: он описывает визуализацию как иерархию графических объектов, где каждый объект реагирует на изменения данных.
Расширение поддерживает двустороннюю интерактивность. Пользовательские действия — hover, click, brush selection — обрабатываются через event system Vega runtime.
События пробрасываются обратно в расширение, где могут:
Это создаёт цикл обратной связи между визуализацией и генерацией новых графиков.
Vega-Lite используется как декларативный слой высокого уровня. Он служит промежуточным языком между пользовательским описанием и полной Vega-спецификацией.
Преобразование Vega-Lite → Vega выполняется автоматически компилятором. Это позволяет:
В расширении Voyager Vega-Lite часто используется как входной формат, который затем расширяется до множества Vega-вариантов.
Состояние расширения включает:
Синхронизация состояния между UI и runtime осуществляется через message passing API браузера. В Chrome это chrome.runtime.sendMessage и chrome.tabs.sendMessage.
Каждое изменение спецификации триггерит пересборку только затронутых частей dataflow-графа, что снижает вычислительную нагрузку.
Поскольку Voyager генерирует большое количество визуализаций, критически важна оптимизация:
Особое внимание уделяется throttling обновлений редактора: при вводе JSON изменения агрегируются с задержкой, чтобы избежать избыточных пересборок.
Каждая визуализация получает score, вычисляемый по набору критериев:
Результаты сортируются и отображаются в виде сетки (gallery view), где пользователь может быстро сравнивать варианты.
Архитектура Vega Voyager допускает подключение пользовательских модулей:
Плагины интегрируются через registration API и могут расширять как этап генерации, так и этап рендеринга.
Пример расширения transform:
vega.transformationRegistry.register("normalizeZScore", (data, field) => {
const mean = computeMean(data, field);
const std = computeStd(data, field);
return data.map(d => ({
...d,
[field]: (d[field] - mean) / std
}));
});
Поскольку расширение работает с произвольными JSON-спецификациями, вводятся ограничения:
Это предотвращает инъекции кода и перегрузку браузерного контекста.
Vega Voyager встраивается в аналитические рабочие процессы:
Комбинация декларативного описания и автоматической генерации делает его инструментом exploratory analysis, где основной акцент смещён с построения графика на анализ пространства возможных представлений данных.