image: растровые изображения

Работа с растровыми изображениями в Vega и Vega-Lite позволяет интегрировать графику непосредственно в визуализации: отображать фотографии, иконки, миниатюры, логотипы, тепловые карты, схемы и любые bitmap-ресурсы. Изображения могут использоваться как самостоятельные элементы сцены, как декоративные маркеры данных или как полноценные слои сложной визуализации.


Тип mark: image в Vega

В 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" }
        }
      }
    }
  ]
}

Основные свойства image

url

Источник изображения.

"url": { "field": "url" }

или:

"url": { "value": "https://example.com/logo.png" }

Поддерживаются:

  • PNG
  • JPEG
  • GIF
  • WebP
  • SVG (как изображение)
  • base64 data URI

x и y

Координаты размещения.

"x": { "value": 100 },
"y": { "value": 50 }

Координаты определяют верхний левый угол изображения.


width и height

Размеры изображения.

"width": { "value": 200 },
"height": { "value": 150 }

Если размеры не указаны, браузер использует реальные размеры bitmap-файла.


aspect

Сохранение пропорций изображения.

"aspect": { "value": true }

При включённом aspect изображение масштабируется без искажений.


align

Горизонтальное выравнивание внутри области.

"align": { "value": "center" }

Возможные значения:

  • "left"
  • "center"
  • "right"

baseline

Вертикальное выравнивание.

"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.


Использование base64 изображений

Vega поддерживает data URI.

"url": {
  "value": "data:image/png;base64,iVBORw0KGgoAAA..."
}

Преимущества:

  • отсутствие дополнительных HTTP-запросов;
  • переносимость спецификации;
  • удобство автономных приложений.

Недостатки:

  • увеличение размера JSON;
  • ухудшение читаемости;
  • рост потребления памяти.

SVG как источник изображения

SVG-файлы можно использовать как bitmap-ресурсы.

"url": {
  "value": "icon.svg"
}

Преимущества SVG:

  • масштабируемость;
  • малый размер;
  • чёткость на Retina-дисплеях.

Прозрачность изображений

Свойство 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'"
}

Обработка hover-состояний

Пример интерактивного эффекта:

"encode": {
  "enter": {
    "opacity": { "value": 0.7 }
  },

  "hover": {
    "opacity": { "value": 1.0 }
  }
}

Комбинирование image и text

Распространённый паттерн — карточки с изображением и подписью.

{
  "type": "group",

  "marks": [
    {
      "type": "image"
    },
    {
      "type": "text"
    }
  ]
}

Использование group для карточек

Группы позволяют создавать сложные 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"
}

Поверх неё добавляются аналитические слои.


Lazy loading и производительность

Большое количество изображений может существенно замедлить рендеринг.

Основные причины:

  • декодирование bitmap;
  • сетевые запросы;
  • расход GPU-памяти;
  • перерасчёт layout.

Оптимизация изображений

Рекомендуется:

Использовать WebP

WebP значительно уменьшает размер.

Уменьшать разрешение

Не использовать изображения 4000×4000 для миниатюр 50×50.

Кэшировать ресурсы

Одинаковые URL переиспользуются браузером.

Ограничивать число изображений

Тысячи image marks приводят к просадке FPS.


Canvas и SVG рендереры

Vega поддерживает два режима:

  • SVG renderer
  • Canvas renderer

SVG renderer

Преимущества:

  • DOM-доступ;
  • простота отладки;
  • CSS-стилизация.

Недостатки:

  • плохая производительность при большом количестве изображений.

Canvas renderer

Преимущества:

  • высокая производительность;
  • эффективный рендеринг bitmap.

Недостатки:

  • отсутствие DOM-элементов;
  • сложнее интерактивность.

Image в Vega-Lite

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-Lite предоставляет меньше контроля, чем Vega.

Ограничены:

  • сложные трансформации;
  • кастомные вычисления;
  • низкоуровневые encode-блоки;
  • динамические сигналы.

Для сложных image-сцен чаще используется чистый Vega.


Width и height в Vega-Lite

Размер задаётся через свойства mark.

"mark": {
  "type": "image",
  "width": 60,
  "height": 60
}

Tooltip для изображений

Поддерживаются tooltip-подсказки.

"encoding": {
  "tooltip": [
    { "field": "name" },
    { "field": "price" }
  ]
}

Изображения в географических визуализациях

Image marks активно применяются в cartography.

Примеры:

  • маркеры городов;
  • иконки транспорта;
  • погодные символы;
  • военные обозначения;
  • игровые объекты.

Спрайты и atlas-текстуры

Для оптимизации используются sprite sheets.

Вместо сотен файлов:

icon1.png
icon2.png
icon3.png

используется:

spritesheet.png

Это уменьшает:

  • количество HTTP-запросов;
  • latency;
  • нагрузку на GPU.

Z-index и порядок слоёв

В Vega порядок marks определяет слой.

"marks": [
  {
    "type": "image"
  },
  {
    "type": "text"
  }
]

Text будет отображаться поверх image.


Анимация изображений

Анимации реализуются через:

  • signals;
  • transitions;
  • изменение encode-состояний.

Пример изменения координат:

"x": {
  "signal": "time * 20"
}

Безопасность и CORS

При загрузке внешних изображений возможны ограничения браузера.

Типичные проблемы:

  • blocked by CORS;
  • tainted canvas;
  • невозможность экспорта canvas.

Решение проблем CORS

Используются:

  • Access-Control-Allow-Origin;
  • локальные proxy;
  • same-origin ресурсы;
  • CDN с корректными заголовками.

Экспорт визуализаций с изображениями

Если изображения загружены с нарушением CORS, экспорт может завершиться ошибкой.

Особенно это касается:

  • toCanvas();
  • toImageURL();
  • PNG export.

Image marks и Retina-дисплеи

Для HiDPI рекомендуется:

  • SVG;
  • изображения 2x;
  • WebP высокого качества.

Типичные сценарии использования

Дашборды товаров

  • фотография;
  • цена;
  • рейтинг;
  • описание.

Карты помещений

  • фоновая схема;
  • интерактивные метки.

Геоаналитика

  • спутниковые снимки;
  • тепловые карты;
  • погодные слои.

Медиааналитика

  • thumbnails видео;
  • preview-изображения.

Игровые интерфейсы

  • спрайты;
  • иконки;
  • карты уровней.

Практический пример: карточки товаров

{
  "$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

Возможность image symbol
Произвольная графика Да Нет
Высокая производительность Ниже Выше
Поддержка bitmap Да Нет
SVG-иконки Да Частично
Простота стилизации Ниже Выше
Использование в инфографике Отлично Ограниченно

Архитектурные особенности image marks

При рендеринге Vega:

  1. Загружает ресурс.
  2. Декодирует bitmap.
  3. Кэширует изображение.
  4. Размещает объект в scenegraph.
  5. Выполняет отрисовку через Canvas/SVG backend.

Частые ошибки

Неверный URL

"url": {
  "value": "missing.png"
}

Результат — пустой элемент.


Проблемы CORS

Canvas становится «tainted».


Слишком большие изображения

Приводят к:

  • утечкам памяти;
  • долгому рендерингу;
  • зависаниям интерфейса.

Отсутствие width/height

Изображение может отображаться некорректно.


Рекомендации по проектированию

Использовать единые размеры миниатюр

Упрощает layout.

Минимизировать число bitmap

Особенно в realtime-сценариях.

Предпочитать SVG для иконок

SVG лучше масштабируется.

Использовать Canvas renderer для больших сцен

Canvas эффективнее для тысяч объектов.

Контролировать размеры ресурсов

Большие PNG резко увеличивают потребление памяти.