Поле zindex: наслоение

В визуализации на основе декларативной модели порядок отображения объектов определяется не только их координатами, но и системой слоёв. При совпадении или пересечении геометрий решающим становится правило painter’s algorithm: элементы, отрисованные позже, перекрывают предыдущие.

В Vega и Vega-Lite управление этим поведением осуществляется через параметр zindex, который задаёт приоритет слоя среди других графических примитивов внутри одного визуального представления.

Ключевая особенность механизма заключается в том, что zindex не влияет на данные и не изменяет геометрию. Он воздействует исключительно на порядок компоновки графических объектов перед финальной отрисовкой.


zindex в Vega: базовый уровень управления слоями

В Vega каждая графическая сущность (mark) может иметь свойство zindex, определяющее порядок её отрисовки относительно других marks в одном и том же наборе.

Основной принцип

  • меньший zindex → элемент рисуется раньше
  • больший zindex → элемент рисуется позже и оказывается поверх

Пример структуры Vega

{
  "marks": [
    {
      "type": "rect",
      "from": {"data": "table"},
      "encode": {
        "enter": {
          "x": {"scale": "x", "field": "x"},
          "x2": {"scale": "x", "field": "x2"},
          "y": {"scale": "y", "field": "y"},
          "y2": {"scale": "y", "field": "y2"},
          "fill": {"value": "steelblue"},
          "zindex": {"value": 0}
        }
      }
    },
    {
      "type": "text",
      "from": {"data": "table"},
      "encode": {
        "enter": {
          "x": {"scale": "x", "field": "x"},
          "y": {"scale": "y", "field": "y"},
          "text": {"field": "label"},
          "fill": {"value": "black"},
          "zindex": {"value": 1}
        }
      }
    }
  ]
}

В этом примере текст всегда оказывается поверх прямоугольников, поскольку имеет более высокий zindex.


Поведение zindex внутри одного слоя

В Vega порядок отрисовки определяется не только значением zindex, но и структурой данных:

  1. marks группируются по родительскому уровню (group mark)
  2. внутри группы применяется сортировка по zindex
  3. при равных значениях сохраняется порядок объявления

Это означает, что стабильность результата зависит от комбинации двух факторов:

  • декларативный порядок в JSON
  • явное значение zindex

zindex в Vega-Lite: абстракция над слоями

Vega-Lite предоставляет более высокий уровень абстракции и чаще скрывает детали рендеринга. Однако zindex остаётся доступным через encoding и используется для управления перекрытием визуальных элементов внутри одного слоя.

Основные сценарии применения

  • линии поверх областей (area + line)
  • подписи поверх маркеров
  • выделение активного элемента в интерактивных графиках
  • управление перекрытием при наложении нескольких геометрий

zindex как encoding channel

В Vega-Lite zindex задаётся как канал encoding:

{
  "data": {"values": [
    {"x": 1, "y": 3, "type": "A"},
    {"x": 2, "y": 5, "type": "B"}
  ]},
  "mark": "point",
  "encoding": {
    "x": {"field": "x", "type": "quantitative"},
    "y": {"field": "y", "type": "quantitative"},
    "color": {"field": "type", "type": "nominal"},
    "zindex": {"field": "type", "type": "ordinal"}
  }
}

Здесь порядок определяется значением категории type, преобразованной в порядок отрисовки.


Фиксированные и вычисляемые значения zindex

Фиксированное значение

Используется для статического управления слоями:

"zindex": {"value": 1}

Применение:

  • гарантированное наложение подписей
  • выделение контрольных линий
  • фиксация фоновых элементов

Вычисляемое значение

Значение может зависеть от данных:

"zindex": {"field": "importance"}

или через трансформацию:

"zindex": {"expr": "datum.value > 10 ? 2 : 0"}

Такой подход позволяет динамически изменять порядок визуальных элементов в зависимости от состояния данных.


Взаимодействие zindex с mark layers

Vega-Lite активно использует layered marks:

  • area
  • line
  • point
  • text

При использовании составных графиков порядок слоёв часто определяется структурой specification, но zindex позволяет переопределить этот порядок внутри слоя.

Пример конфликтного наложения:

  • area задаёт фон
  • line накладывается поверх
  • points должны быть выше линии
  • labels должны быть выше всех

Практика: комбинированный график

{
  "layer": [
    {
      "mark": {"type": "area", "opacity": 0.3},
      "encoding": {
        "x": {"field": "x", "type": "quantitative"},
        "y": {"field": "y", "type": "quantitative"}
      }
    },
    {
      "mark": "line",
      "encoding": {
        "x": {"field": "x"},
        "y": {"field": "y"},
        "zindex": {"value": 1}
      }
    },
    {
      "mark": "point",
      "encoding": {
        "x": {"field": "x"},
        "y": {"field": "y"},
        "size": {"value": 80},
        "zindex": {"value": 2}
      }
    }
  ]
}

Здесь zindex используется для тонкой настройки поверхностного порядка внутри одного слоя, несмотря на наличие layer-конструкции.


zindex и интерактивность

При использовании событий (hover, click, selection) zindex становится инструментом визуальной приоритизации активных элементов.

Типичный сценарий:

  • базовые точки имеют zindex = 0
  • выделенная точка получает zindex = 10
"zindex": {
  "condition": {
    "selection": "hover",
    "value": 10
  },
  "value": 0
}

Это обеспечивает мгновенное визуальное выделение без изменения геометрии или данных.


Сортировка и ограничения модели

Несмотря на гибкость, zindex имеет ряд ограничений:

1. Локальность

zindex работает внутри одного визуального контекста (mark group). Он не гарантирует порядок между независимыми view.

2. Не заменяет layer-архитектуру

Layer задаёт архитектурный порядок, zindex — локальную корректировку.

3. Не влияет на оси и сетки

Элементы декора (grid, axis) управляются системой компоновки Vega-Lite и не всегда подчиняются zindex.


Типичные ошибки при использовании

Конфликт layer и zindex

Когда слой уже определяет порядок, попытка управлять им через zindex может давать неожиданный результат.

Смешивание ordinal и quantitative значений

Использование числового поля как ordinal без явной шкалы приводит к нестабильной сортировке.

Переоценка влияния zindex

zindex не решает проблемы визуальной композиции, связанные с масштабом или прозрачностью.


Поведение при равных значениях

Если несколько элементов имеют одинаковый zindex:

  • применяется порядок объявления в спецификации
  • или порядок данных после трансформаций

Это делает результат потенциально недетерминированным при сложных преобразованиях данных.


Производительность и рендеринг

zindex не оказывает значительного влияния на вычислительную сложность, поскольку сортировка выполняется на этапе подготовки сцены. Однако при больших наборах данных с вычисляемым zindex:

  • возрастает стоимость трансформаций
  • усложняется этап сортировки перед отрисовкой

Особенно это заметно при использовании выражений expr, зависящих от вычисляемых полей.


Сочетание zindex с прозрачностью и смешением

При использовании opacity и blend режимов zindex остаётся верхнеуровневым механизмом порядка, но визуальное восприятие может изменяться:

  • элемент с меньшим zindex, но высокой прозрачностью может визуально уступать
  • пересечение слоёв создаёт эффект «полупрозрачной глубины»

Это часто используется в плотных scatterplot визуализациях для уменьшения визуального шума.


Роль zindex в сложных дашбордах

В многослойных дашбордах Vega-Lite zindex становится инструментом локального контроля:

  • выделение KPI-элементов
  • приоритет всплывающих аннотаций
  • управление конфликтами перекрытия в интерактивных графиках

При этом архитектурный порядок остаётся за layer и resolve-логикой, а zindex выполняет роль тонкой корректировки визуальной иерархии.