Генерация glyphs

Система отображения текста в MapLibre GL JS основана на использовании glyphs — специальных наборов глифов (символьных изображений), которые используются для рендеринга подписей на карте. Каждый символ текста не хранится внутри стиля карты напрямую. Вместо этого движок загружает необходимые глифы с сервера по мере необходимости и собирает из них текстовые надписи.

Такой подход обеспечивает несколько важных преимуществ:

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

При работе с текстовыми слоями (symbol) система glyphs является обязательным компонентом практически любого картографического стиля.


Как устроены glyphs

Внутри MapLibre GL JS текст отображается следующим образом:

  1. В стиле карты указывается путь к glyphs.
  2. При обнаружении текстовой подписи движок определяет необходимые символы.
  3. Запрашиваются соответствующие наборы глифов.
  4. Загруженные данные помещаются в кэш.
  5. Из отдельных глифов формируется надпись.

Схема выглядит следующим образом:

Текст объекта
       ↓
Определение символов
       ↓
Загрузка glyphs
       ↓
Кэширование
       ↓
Отрисовка текста

Например, если карта содержит подпись:

Москва

движок загружает глифы для символов:

М
о
с
к
в
а

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


Поле glyphs в стиле карты

Путь к серверу глифов задаётся через свойство:

{
  "glyphs": "https://example.com/fonts/{fontstack}/{range}.pbf"
}

Данное свойство находится в корне JSON-описания стиля.

Полный пример:

{
  "version": 8,
  "glyphs": "https://example.com/fonts/{fontstack}/{range}.pbf",
  "sources": {},
  "layers": []
}

Плейсхолдеры fontstack и range

В URL используются специальные переменные.

fontstack

Содержит название шрифта или набора шрифтов.

Пример:

Open Sans Regular

или

Noto Sans Regular

В результате запрос может выглядеть так:

https://example.com/fonts/Open Sans Regular/0-255.pbf

range

Содержит диапазон Unicode-символов.

Пример:

0-255
256-511
512-767

Если на карте используются кириллические символы, MapLibre автоматически запрашивает соответствующий диапазон Unicode.

Например:

https://example.com/fonts/Open Sans Regular/1024-1279.pbf

Формат PBF

Файлы glyphs используют расширение:

.pbf

Это бинарный формат Protocol Buffers.

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

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

Обычный TTF-файл может занимать несколько мегабайт, тогда как набор glyphs для одного диапазона символов зачастую занимает всего несколько килобайт.


Использование шрифтов в слоях

После настройки glyphs текстовые слои могут ссылаться на конкретные шрифты.

Пример:

map.addLayer({
    id: 'cities',
    type: 'symbol',
    source: 'cities',
    layout: {
        'text-field': ['get', 'name'],
        'text-font': ['Open Sans Regular'],
        'text-size': 14
    }
});

Здесь MapLibre будет искать глифы для шрифта:

Open Sans Regular

через URL, указанный в свойстве glyphs.


Несколько шрифтов

Разрешается указывать несколько шрифтов одновременно.

Пример:

layout: {
    'text-font': [
        'Open Sans Regular',
        'Arial Unicode MS Regular'
    ]
}

В этом случае используется механизм резервного отображения.

Если символ отсутствует в первом шрифте:

Open Sans Regular

то будет выполнена попытка найти его во втором:

Arial Unicode MS Regular

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


Почему glyphs загружаются диапазонами

Unicode содержит более миллиона возможных кодовых точек.

Загрузка полного шрифта для каждой карты привела бы к серьёзным проблемам:

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

Поэтому используется разбиение на диапазоны.

Например:

0–255
256–511
512–767
...

Если карта содержит только латиницу:

Berlin
Paris
London

будет загружен лишь небольшой набор диапазонов.

Если появляются китайские подписи:

北京
上海
广州

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


Генерация glyphs

MapLibre GL JS не создаёт glyphs самостоятельно в браузере.

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

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

fontnik

Этот инструмент преобразует обычные шрифты:

.ttf
.otf

в наборы:

.pbf

разбитые по диапазонам Unicode.


Fontnik

Fontnik был разработан компанией Mapbox и долгое время являлся стандартным инструментом генерации glyphs.

Типичная схема работы:

TTF
 ↓
Fontnik
 ↓
PBF glyphs
 ↓
MapLibre GL JS

После обработки создаётся структура каталогов:

fonts/
 ├─ Open Sans Regular/
 │   ├─ 0-255.pbf
 │   ├─ 256-511.pbf
 │   ├─ 512-767.pbf
 │   └─ ...
 └─ Noto Sans Regular/
     ├─ 0-255.pbf
     ├─ 256-511.pbf
     └─ ...

Локальный сервер glyphs

Для небольших проектов файлы glyphs часто размещаются на том же сервере, что и приложение.

Структура может выглядеть так:

public/
 ├─ fonts/
 │   ├─ Open Sans Regular/
 │   └─ Noto Sans Regular/
 ├─ style.json
 └─ index.html

Тогда путь в стиле будет следующим:

{
  "glyphs": "/fonts/{fontstack}/{range}.pbf"
}

Использование CDN

Glyphs могут загружаться и с внешнего сервера.

Пример:

{
  "glyphs": "https://cdn.example.com/fonts/{fontstack}/{range}.pbf"
}

Преимущества такого подхода:

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

Кэширование glyphs

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

Поэтому при повторном появлении тех же символов повторный запрос не выполняется.

Например:

Москва
Мурманск
Минск

Символ:

М

будет загружен только один раз.

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


Поддержка многоязычных карт

Одно из ключевых преимуществ системы glyphs — эффективная работа с различными языками.

Пример данных:

{
  "name_en": "Moscow",
  "name_ru": "Москва",
  "name_zh": "莫斯科",
  "name_ar": "موسكو"
}

Стиль может динамически выбирать поле:

'text-field': ['get', 'name_ru']

или

'text-field': ['get', 'name_en']

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


Unicode и диапазоны

Каждый диапазон обычно охватывает 256 символов.

Примеры:

Диапазон Символы
0–255 Базовая латиница
256–511 Расширенная латиница
1024–1279 Кириллица
1536–1791 Арабский
19968+ Китайские иероглифы

При появлении нового символа движок определяет его Unicode-код и вычисляет требуемый диапазон.


Проверка загрузки glyphs

Открыв инструменты разработчика браузера на вкладке Network, можно увидеть запросы:

0-255.pbf
256-511.pbf
1024-1279.pbf

Например:

GET /fonts/Open Sans Regular/0-255.pbf
GET /fonts/Open Sans Regular/1024-1279.pbf

Если запросы завершаются ошибкой:

404 Not Found

подписи на карте могут не отображаться.


Типичные ошибки

Неверный URL

Ошибка:

{
  "glyphs": "/font/{fontstack}/{range}.pbf"
}

при фактическом расположении:

/fonts/

Результат:

404 Not Found

Отсутствующий шрифт

В слое указан:

'text-font': ['Roboto Regular']

но каталог:

Roboto Regular/

отсутствует.

Результат:

Failed to load glyph range

Несовпадение имени шрифта

Каталог:

OpenSans-Regular

а в стиле:

'text-font': ['Open Sans Regular']

MapLibre рассматривает эти строки как разные значения.


Ошибки CORS

При размещении glyphs на отдельном домене необходимо настроить заголовки:

Access-Control-Allow-Origin: *

или более строгие разрешения для конкретных доменов.

Без корректной настройки браузер заблокирует загрузку.


Генерация собственного набора glyphs

Типичный процесс подготовки:

  1. Выбрать шрифты.
  2. Получить файлы TTF или OTF.
  3. Сгенерировать наборы PBF.
  4. Разместить их на сервере.
  5. Настроить поле glyphs.
  6. Использовать соответствующие значения в text-font.

Схема:

Шрифт
  ↓
Генератор glyphs
  ↓
PBF-файлы
  ↓
Веб-сервер
  ↓
MapLibre GL JS

Влияние на производительность

Корректно организованная система glyphs позволяет:

  • уменьшить размер передаваемых данных;
  • ускорить первоначальную загрузку карты;
  • снизить потребление оперативной памяти;
  • обеспечить плавное масштабирование;
  • поддерживать большие объёмы текстовых подписей.

Особенно заметен эффект при отображении:

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

Связь glyphs и символических слоёв

Glyphs используются только слоями типа:

type: 'symbol'

Пример:

map.addLayer({
    id: 'roads-labels',
    type: 'symbol',
    source: 'roads',
    layout: {
        'text-field': ['get', 'name']
    }
});

Если текстовые подписи отсутствуют, система glyphs практически не участвует в работе карты.

Для слоёв:

fill
line
circle
raster
hillshade
background

загрузка glyphs не требуется.


Взаимодействие glyphs и text-field

Содержимое свойства:

'text-field'

определяет, какие символы будут запрошены.

Пример:

'text-field': ['get', 'name']

При появлении нового объекта:

{
  "name": "Караганда"
}

MapLibre анализирует строку, определяет необходимые Unicode-символы и автоматически загружает отсутствующие диапазоны glyphs.

Таким образом, система генерации glyphs представляет собой фундаментальный механизм текстового рендеринга в MapLibre GL JS, обеспечивающий компактное хранение шрифтов, эффективную загрузку символов по диапазонам Unicode и высокопроизводительное отображение подписей на картах любого масштаба и языкового состава.