Текстовые альтернативы карты

Интерактивные веб-карты в Mapbox GL JS опираются на WebGL-рендеринг, где визуальная сцена формируется динамически: слои, стили, маркеры и подписи отрисовываются на canvas. Такая модель обеспечивает высокую производительность и гибкость, но одновременно создаёт фундаментальную проблему доступности: содержимое карты не представлено в виде семантического HTML и не интерпретируется напрямую вспомогательными технологиями.

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

Ключевые цели текстовых альтернатив:

  • представление географического содержимого в линейной текстовой форме
  • обеспечение доступности для экранных читалок
  • поддержка режимов без графики или с отключённым WebGL
  • сохранение смысла интерактивных элементов (точек, маршрутов, слоёв)

Семантическое описание карты как базовый слой доступности

Mapbox GL JS не предоставляет полноценного DOM-представления карты, однако позволяет обогащать контейнер карты семантическими атрибутами.

Основной контейнер карты (map.getContainer()) и canvas (map.getCanvas()) требуют явного описания роли:

map.getCanvas().setAttribute('role', 'img');
map.getCanvas().setAttribute('aria-label', 'Интерактивная карта с объектами инфраструктуры и дорогами');

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


Текстовое описание текущего состояния карты

Любая карта в Mapbox GL JS имеет изменяемое состояние:

  • центр (center)
  • масштаб (zoom)
  • наклон (pitch)
  • поворот (bearing)
  • видимые слои

Эти параметры могут быть преобразованы в текстовое описание.

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

  • координаты центра: широта и долгота
  • уровень масштабирования
  • список активных слоёв
  • количество отображаемых объектов
function describeMapState(map) {
  const center = map.getCenter();
  const zoom = map.getZoom();

  return `
Координаты центра: ${center.lng.toFixed(4)}, ${center.lat.toFixed(4)}.
Масштаб: ${zoom.toFixed(2)}.
Поворот: ${map.getBearing()} градусов.
Наклон: ${map.getPitch()} градусов.
  `;
}

Такой текст используется для обновления aria-live региона.


ARIA-live регион как механизм динамической передачи информации

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

<div id="map-description" aria-live="polite"></div>

Обновление содержимого:

function updateDescription(map) {
  const description = describeMapState(map);
  document.getElementById('map-description').textContent = description;
}

События синхронизации:

  • moveend
  • zoomend
  • rotate
  • pitchend
map.on('moveend', () => updateDescription(map));
map.on('zoomend', () => updateDescription(map));
map.on('rotate', () => updateDescription(map));

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


Альтернативное представление объектов через список

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

Каждый объект слоя Symbol Layer или GeoJSON источника может быть преобразован в строку:

  • название
  • тип объекта
  • координаты
  • дополнительные свойства

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

function extractFeatures(map) {
  const features = map.queryRenderedFeatures();

  return features.map(f => {
    const name = f.properties?.name || 'Без названия';
    const type = f.layer?.type || 'объект';
    const coords = f.geometry?.coordinates;

    return `${name}, тип: ${type}, координаты: ${coords}`;
  });
}

Результат может быть размещён в отдельном DOM-контейнере:

<ul id="map-feature-list"></ul>

Текстовые альтернативы слоёв (layers)

В Mapbox GL JS стилизация слоёв определяет визуальное представление, но не их семантику. Для доступности требуется отдельное описание каждого слоя.

Примеры текстового описания слоёв:

  • дороги: классификация (motorway, primary, secondary)
  • здания: тип и высота
  • вода: природные объекты
  • POI: точки интереса
function describeLayers(map) {
  const layers = map.getStyle().layers;

  return layers.map(layer => {
    return `Слой: ${layer.id}, тип: ${layer.type}`;
  });
}

При необходимости более детализированного описания учитываются фильтры и источники данных:

  • source
  • source-layer
  • filter

Альтернативы для маркеров и точек интереса

Маркер в Mapbox GL JS часто представлен DOM-элементом или символом в слое symbol. Для экранных читалок требуется явное текстовое представление.

Структура альтернативы:

  • имя объекта
  • категория
  • расстояние от центра карты
  • координаты
function describeMarker(feature) {
  const name = feature.properties.name;
  const category = feature.properties.category;

  return `Объект ${name}, категория ${category}`;
}

Для групп объектов формируется список:

<div aria-label="Список объектов на карте">
  <!-- текстовые элементы -->
</div>

Текстовая альтернатива маршрутов и линий

Линейные геометрии (LineString) требуют последовательного описания узлов и логики движения.

Пример описания маршрута:

  • начальная точка
  • промежуточные узлы
  • конечная точка
  • длина маршрута
function describeRoute(feature) {
  const coords = feature.geometry.coordinates;

  const start = coords[0];
  const end = coords[coords.length - 1];

  return `
Маршрут начинается в ${start}.
Заканчивается в ${end}.
Количество сегментов: ${coords.length}.
  `;
}

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


Fallback-режим при отсутствии WebGL

В средах, где WebGL недоступен, Mapbox GL JS может не отрисовать карту. В таких случаях применяется статическая или текстовая замена.

Стратегии fallback:

  • отображение списка объектов
  • использование GeoJSON без визуализации
  • статическое изображение карты с подписью
  • табличное представление координат

Пример переключения:

if (!mapboxgl.supported()) {
  renderTextualMap();
}

Табличное представление геоданных

Таблицы обеспечивают структурированное отображение информации:

Объект Тип Широта Долгота
A POI 51.5 0.12

Генерация:

function toTable(features) {
  return features.map(f => ({
    name: f.properties.name,
    type: f.geometry.type,
    lat: f.geometry.coordinates[1],
    lng: f.geometry.coordinates[0]
  }));
}

Текстовые альтернативы всплывающих окон (popups)

Popup в Mapbox GL JS содержит HTML-контент, но для доступности требуется параллельная текстовая репрезентация.

Пример:

  • заголовок
  • описание
  • координаты
  • ссылка на объект
function popupToText(properties) {
  return `
Название: ${properties.name}
Описание: ${properties.description}
`;
}

Для синхронизации используется зеркальный DOM-контейнер:

<div id="popup-text-alternative"></div>

Контекстная навигация как текстовая карта

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

  • масштаб
  • текущий регион
  • активный слой
  • выбранный объект

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

Регион: Карагандинская область
Объекты: 42
Активный слой: дороги
Выбранный объект: отсутствует

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

Mapbox GL JS отделяет геоданные от DOM, что создаёт архитектурную особенность: визуальная сцена не является источником семантики. Поэтому текстовые альтернативы строятся не на DOM-инспекции, а на исходных данных GeoJSON и состоянии карты.

Основные источники текстовой информации:

  • GeoJSON source
  • map.querySourceFeatures
  • map.queryRenderedFeatures
  • состояние map.getCenter(), getZoom(), getBearing()

Согласованность визуального и текстового представления

Критически важным аспектом является синхронизация:

  • любое изменение стиля должно отражаться в тексте
  • фильтры слоёв должны обновлять списки
  • перемещение карты должно обновлять координаты
  • выбор объекта должен обновлять описание

Несоответствие между визуальной и текстовой моделью приводит к разрыву доступности, при котором вспомогательные технологии получают устаревшие данные.


Структурирование текстовой модели карты

Полноценная текстовая альтернатива может быть организована как многоуровневая модель:

  • уровень 1: общее состояние карты
  • уровень 2: слои
  • уровень 3: объекты
  • уровень 4: детали объектов

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


Преобразование интерактивной карты в линейный документ

В некоторых сценариях карта может быть полностью представлена как документ:

  • заголовок региона
  • описание границ
  • перечень объектов
  • список маршрутов
  • координатные таблицы

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