Интерактивные свойства: hover-блок

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

Селекторы hover как разновидность single selection

В Vega-Lite основным механизмом для реализации hover является selection с типом single, где активное состояние привязывается к событиям мыши.

Ключевые особенности hover-selection:

  • активация по событию mouseover
  • деактивация по mouseout
  • хранение состояния только одного элемента одновременно
  • отсутствие необходимости в клике
  • мгновенная реакция без подтверждения действия

Базовая структура hover-селекции:

{
  "selection": {
    "hover": {
      "type": "single",
      "on": "mouseover",
      "empty": "none",
      "clear": "mouseout"
    }
  }
}

Такая конфигурация формирует временное состояние, которое может быть использовано в любом канале encoding.

Привязка hover к визуальным каналам

Hover-состояние в Vega-Lite чаще всего применяется для динамического изменения следующих параметров:

  • opacity (подсветка элемента)
  • stroke width (акцентирование контуров)
  • color (перекраска элемента)
  • size (увеличение маркера)
  • tooltip (отображение дополнительных данных)

Пример условного изменения прозрачности:

{
  "mark": "circle",
  "encoding": {
    "x": {"field": "x", "type": "quantitative"},
    "y": {"field": "y", "type": "quantitative"},
    "opacity": {
      "condition": {
        "selection": "hover",
        "value": 1
      },
      "value": 0.3
    }
  },
  "selection": {
    "hover": {
      "type": "single",
      "on": "mouseover",
      "clear": "mouseout"
    }
  }
}

Логика условного кодирования опирается на проверку принадлежности текущего элемента состоянию selection.

Hover и tooltip как связанная система

Tooltip в Vega-Lite может работать независимо, однако в сочетании с hover-selection формируется более контролируемая модель взаимодействия.

Базовый вариант tooltip:

{
  "mark": "point",
  "encoding": {
    "x": {"field": "time", "type": "temporal"},
    "y": {"field": "value", "type": "quantitative"},
    "tooltip": [
      {"field": "time", "type": "temporal"},
      {"field": "value", "type": "quantitative"}
    ]
  }
}

При добавлении hover-selection tooltip может быть условно усилен или расширен логикой отображения только активного элемента через selection-driven фильтрацию.

Использование nearest для улучшения hover-поведения

Параметр nearest: true позволяет привязывать hover не строго к геометрии маркера, а к ближайшей точке данных. Это особенно важно для линий и сложных графиков, где попадание курсором в точный пиксель точки затруднено.

{
  "selection": {
    "hover": {
      "type": "single",
      "nearest": true,
      "on": "mouseover",
      "clear": "mouseout"
    }
  }
}

Поведение изменяется следующим образом:

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

Hover в layered-структурах

В многослойных визуализациях hover может применяться к отдельным слоям или ко всей композиции.

Пример слоя с подсветкой:

{
  "layer": [
    {
      "mark": "line",
      "encoding": {
        "x": {"field": "x"},
        "y": {"field": "y"}
      }
    },
    {
      "mark": "point",
      "encoding": {
        "x": {"field": "x"},
        "y": {"field": "y"},
        "opacity": {
          "condition": {
            "selection": "hover",
            "value": 1
          },
          "value": 0.2
        }
      }
    }
  ],
  "selection": {
    "hover": {
      "type": "single",
      "on": "mouseover",
      "clear": "mouseout"
    }
  }
}

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

Hover на уровне Vega: signals и event streams

В Vega hover реализуется через систему signals и событийную модель.

Принцип построения:

  • signal хранит состояние наведения
  • event stream отслеживает mouseover/mouseout
  • update expression изменяет состояние

Пример сигнала:

{
  "signals": [
    {
      "name": "hovered",
      "value": null,
      "on": [
        {"events": "symbol:mouseover", "update": "datum"},
        {"events": "symbol:mouseout", "update": "null"}
      ]
    }
  ]
}

Далее сигнал используется в encoding:

{
  "marks": [
    {
      "type": "symbol",
      "encode": {
        "update": {
          "opacity": {
            "signal": "hovered ? (datum === hovered ? 1 : 0.3) : 1"
          }
        }
      }
    }
  ]
}

Такой уровень управления позволяет строить сложные интерактивные состояния, выходящие за рамки стандартного Vega-Lite API.

Комбинация hover и multi-selection

Hover может сосуществовать с другими типами selection, например multi (click-based выделение). В этом случае формируется двухуровневая модель состояния:

  • hover: временное, transient состояние
  • select: фиксированное, persistent состояние

Пример комбинирования:

"selection": {
  "hover": {
    "type": "single",
    "on": "mouseover",
    "clear": "mouseout"
  },
  "select": {
    "type": "multi",
    "on": "click"
  }
}

При таком подходе encoding может учитывать оба состояния:

  • hover усиливает визуальный акцент
  • select фиксирует выделение
  • приоритет определяется через условные выражения

Сложные правила визуального приоритета

При сочетании нескольких состояний применяется логика приоритетов:

  1. hover имеет временный приоритет
  2. select имеет постоянный приоритет
  3. базовое состояние используется при отсутствии активных selections

Пример условного выражения:

"opacity": {
  "condition": {
    "test": "datum === hover || datum === select",
    "value": 1
  },
  "value": 0.2
}

В более сложных случаях используется вложенная логика с проверкой наличия активного hover.

Производительность hover-интеракций

Hover-события являются высокочастотными, поэтому при больших наборах данных важно учитывать:

  • минимизацию вычислений в update выражениях
  • использование nearest вместо точного hit-testing
  • снижение количества reactive encodings
  • избегание сложных трансформаций внутри hover-сигналов

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

Типовые паттерны использования hover

На практике hover-блок применяется в нескольких устойчивых шаблонах:

  • подсветка точек на scatter plot
  • выделение линии и соответствующих значений
  • синхронное выделение в нескольких осях
  • временное отображение подробной информации
  • динамическое сравнение элементов

Каждый из этих паттернов строится на одном принципе: временное изменение визуального состояния без изменения данных и без фиксации выбора.

Ошибки проектирования hover-интеракций

Наиболее распространённые проблемы:

  • отсутствие clear приводит к «залипанию» состояния
  • слишком агрессивный hover мешает просмотру данных
  • одновременное использование hover и click без приоритизации
  • перегрузка encoding условными выражениями
  • отсутствие визуального различия между hover и selection

Корректная реализация требует строгого разделения временных и постоянных состояний и минимизации визуального шума при активном взаимодействии.