Работа с растровыми изображениями в Vega и Vega-Lite позволяет интегрировать графику непосредственно в визуализации: отображать фотографии, иконки, миниатюры, логотипы, тепловые карты, схемы и любые bitmap-ресурсы. Изображения могут использоваться как самостоятельные элементы сцены, как декоративные маркеры данных или как полноценные слои сложной визуализации.
В Vega изображения реализуются через графический примитив
image. Он относится к низкоуровневым marks и предоставляет
полный контроль над отображением.
Базовый пример:
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 400,
"height": 200,
"data": [
{
"name": "images",
"values": [
{
"x": 50,
"y": 40,
"url": "https://example.com/image.png"
}
]
}
],
"marks": [
{
"type": "image",
"from": {
"data": "images"
},
"encode": {
"enter": {
"x": { "field": "x" },
"y": { "field": "y" },
"width": { "value": 120 },
"height": { "value": 120 },
"url": { "field": "url" }
}
}
}
]
}
Источник изображения.
"url": { "field": "url" }
или:
"url": { "value": "https://example.com/logo.png" }
Поддерживаются:
Координаты размещения.
"x": { "value": 100 },
"y": { "value": 50 }
Координаты определяют верхний левый угол изображения.
Размеры изображения.
"width": { "value": 200 },
"height": { "value": 150 }
Если размеры не указаны, браузер использует реальные размеры bitmap-файла.
Сохранение пропорций изображения.
"aspect": { "value": true }
При включённом aspect изображение масштабируется без
искажений.
Горизонтальное выравнивание внутри области.
"align": { "value": "center" }
Возможные значения:
"left""center""right"Вертикальное выравнивание.
"baseline": { "value": "middle" }
Поддерживаются:
"top""middle""bottom"Изображения часто используются как визуальные представления объектов набора данных.
Пример: фотографии сотрудников.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 600,
"height": 200,
"data": [
{
"name": "employees",
"values": [
{
"name": "Anna",
"photo": "anna.jpg",
"x": 50
},
{
"name": "John",
"photo": "john.jpg",
"x": 200
},
{
"name": "Mike",
"photo": "mike.jpg",
"x": 350
}
]
}
],
"marks": [
{
"type": "image",
"from": {
"data": "employees"
},
"encode": {
"enter": {
"x": { "field": "x" },
"y": { "value": 40 },
"width": { "value": 100 },
"height": { "value": 100 },
"url": { "field": "photo" }
}
}
}
]
}
Image marks позволяют заменить стандартные символы
(circle, square) произвольными картинками.
Например, иконки животных:
{
"type": "image",
"encode": {
"enter": {
"x": { "scale": "xscale", "field": "x" },
"y": { "scale": "yscale", "field": "y" },
"width": { "value": 48 },
"height": { "value": 48 },
"url": { "field": "icon" }
}
}
}
Такой подход применяется для:
URL может вычисляться программно.
"url": {
"signal": "'/images/' + datum.id + '.png'"
}
Здесь путь формируется на основе значения datum.id.
Vega поддерживает data URI.
"url": {
"value": "data:image/png;base64,iVBORw0KGgoAAA..."
}
Преимущества:
Недостатки:
SVG-файлы можно использовать как bitmap-ресурсы.
"url": {
"value": "icon.svg"
}
Преимущества SVG:
Свойство opacity регулирует прозрачность.
"opacity": { "value": 0.5 }
Значения:
0 — полностью прозрачное;1 — полностью непрозрачное.Изображения поддерживают rotation.
"angle": { "value": 45 }
Угол задаётся в градусах.
Для корректного вращения можно указать центр.
"xc": { "signal": "datum.x + 50" },
"yc": { "signal": "datum.y + 50" }
Свойство clip ограничивает видимую область.
"clip": { "value": true }
Используется:
Часто требуется масштабировать изображения относительно размеров контейнера.
"width": {
"signal": "width / 5"
}
Сигналы позволяют изменять изображения интерактивно.
Пример изменения размера:
"signals": [
{
"name": "imgSize",
"value": 80
}
]
"width": { "signal": "imgSize" },
"height": { "signal": "imgSize" }
Можно менять URL в зависимости от событий.
"url": {
"signal": "hover ? 'active.png' : 'default.png'"
}
Пример интерактивного эффекта:
"encode": {
"enter": {
"opacity": { "value": 0.7 }
},
"hover": {
"opacity": { "value": 1.0 }
}
}
Распространённый паттерн — карточки с изображением и подписью.
{
"type": "group",
"marks": [
{
"type": "image"
},
{
"type": "text"
}
]
}
Группы позволяют создавать сложные UI-композиции.
Пример структуры:
{
"type": "group",
"from": {
"data": "products"
},
"marks": [
{
"type": "rect"
},
{
"type": "image"
},
{
"type": "text"
}
]
}
Изображение может выступать фоном визуализации.
{
"type": "image",
"encode": {
"enter": {
"x": { "value": 0 },
"y": { "value": 0 },
"width": { "signal": "width" },
"height": { "signal": "height" },
"url": {
"value": "background.jpg"
}
}
}
}
Типичный сценарий:
Сначала рисуется image mark, затем поверх — другие marks.
"marks": [
{
"type": "image"
},
{
"type": "symbol"
}
]
Для интерактивных карт используются scale.
"x": {
"scale": "xscale",
"field": "longitude"
}
Изображение может быть предварительно вычисленной heatmap.
"url": {
"value": "heatmap.png"
}
Поверх неё добавляются аналитические слои.
Большое количество изображений может существенно замедлить рендеринг.
Основные причины:
Рекомендуется:
WebP значительно уменьшает размер.
Не использовать изображения 4000×4000 для миниатюр 50×50.
Одинаковые URL переиспользуются браузером.
Тысячи image marks приводят к просадке FPS.
Vega поддерживает два режима:
Преимущества:
Недостатки:
Преимущества:
Недостатки:
Vega-Lite поддерживает изображения через mark type
"image".
Пример:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"values": [
{
"x": 10,
"y": 20,
"img": "cat.png"
}
]
},
"mark": "image",
"encoding": {
"x": {
"field": "x",
"type": "quantitative"
},
"y": {
"field": "y",
"type": "quantitative"
},
"url": {
"field": "img",
"type": "nominal"
}
}
}
Vega-Lite предоставляет меньше контроля, чем Vega.
Ограничены:
Для сложных image-сцен чаще используется чистый Vega.
Размер задаётся через свойства mark.
"mark": {
"type": "image",
"width": 60,
"height": 60
}
Поддерживаются tooltip-подсказки.
"encoding": {
"tooltip": [
{ "field": "name" },
{ "field": "price" }
]
}
Image marks активно применяются в cartography.
Примеры:
Для оптимизации используются sprite sheets.
Вместо сотен файлов:
icon1.png
icon2.png
icon3.png
используется:
spritesheet.png
Это уменьшает:
В Vega порядок marks определяет слой.
"marks": [
{
"type": "image"
},
{
"type": "text"
}
]
Text будет отображаться поверх image.
Анимации реализуются через:
Пример изменения координат:
"x": {
"signal": "time * 20"
}
При загрузке внешних изображений возможны ограничения браузера.
Типичные проблемы:
Используются:
Если изображения загружены с нарушением CORS, экспорт может завершиться ошибкой.
Особенно это касается:
toCanvas();toImageURL();Для HiDPI рекомендуется:
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 800,
"height": 300,
"data": [
{
"name": "products",
"values": [
{
"name": "Laptop",
"price": 1200,
"img": "laptop.png",
"x": 20
},
{
"name": "Phone",
"price": 700,
"img": "phone.png",
"x": 220
}
]
}
],
"marks": [
{
"type": "group",
"from": {
"data": "products"
},
"encode": {
"enter": {
"x": { "field": "x" },
"y": { "value": 20 },
"width": { "value": 180 },
"height": { "value": 240 }
}
},
"marks": [
{
"type": "rect",
"encode": {
"enter": {
"width": { "value": 180 },
"height": { "value": 240 },
"fill": { "value": "#ffffff" },
"stroke": { "value": "#cccccc" }
}
}
},
{
"type": "image",
"encode": {
"enter": {
"x": { "value": 20 },
"y": { "value": 20 },
"width": { "value": 140 },
"height": { "value": 140 },
"url": { "field": "img" }
}
}
},
{
"type": "text",
"encode": {
"enter": {
"x": { "value": 20 },
"y": { "value": 190 },
"text": { "field": "name" },
"fontSize": { "value": 18 }
}
}
},
{
"type": "text",
"encode": {
"enter": {
"x": { "value": 20 },
"y": { "value": 220 },
"text": {
"signal": "'$' + datum.price"
},
"fontSize": { "value": 16 }
}
}
}
]
}
]
}
| Возможность | image | symbol |
|---|---|---|
| Произвольная графика | Да | Нет |
| Высокая производительность | Ниже | Выше |
| Поддержка bitmap | Да | Нет |
| SVG-иконки | Да | Частично |
| Простота стилизации | Ниже | Выше |
| Использование в инфографике | Отлично | Ограниченно |
При рендеринге Vega:
"url": {
"value": "missing.png"
}
Результат — пустой элемент.
Canvas становится «tainted».
Приводят к:
Изображение может отображаться некорректно.
Упрощает layout.
Особенно в realtime-сценариях.
SVG лучше масштабируется.
Canvas эффективнее для тысяч объектов.
Большие PNG резко увеличивают потребление памяти.