Загрузка пользовательских стилей

Стиль (Style) в MapLibre GL JS представляет собой JSON-документ, описывающий внешний вид карты. В нём определяются:

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

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

При создании экземпляра карты стиль указывается через свойство style:

const map = new maplibregl.Map({
    container: 'map',
    style: 'style.json',
    center: [37.6176, 55.7558],
    zoom: 10
});

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


Способы загрузки пользовательских стилей

MapLibre GL JS поддерживает несколько вариантов загрузки:

  1. Из локального JSON-файла.
  2. С удалённого HTTP-сервера.
  3. Из JavaScript-объекта.
  4. Динамическая загрузка во время работы приложения.
  5. Генерация стиля на стороне клиента.

Каждый подход имеет собственные особенности и сценарии применения.


Загрузка стиля из локального файла

Самый распространённый вариант — хранение файла стиля рядом с приложением.

Структура проекта:

project/
│
├── index.html
├── styles/
│   └── map-style.json
└── js/
    └── app.js

Создание карты:

const map = new maplibregl.Map({
    container: 'map',
    style: './styles/map-style.json'
});

Во время инициализации браузер отправляет запрос к файлу стиля, получает JSON и передаёт его в MapLibre.

Фрагмент такого файла:

{
  "version": 8,
  "sources": {},
  "layers": [
    {
      "id": "background",
      "type": "background",
      "paint": {
        "background-color": "#f0f0f0"
      }
    }
  ]
}

Минимально допустимый стиль обязан содержать:

  • поле version;
  • объект sources;
  • массив layers.

Загрузка стиля с удалённого сервера

Во многих проектах стили располагаются на отдельном сервере или CDN.

Пример:

const map = new maplibregl.Map({
    container: 'map',
    style: 'https://example.com/styles/city-style.json'
});

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

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

Важно учитывать настройки CORS.

Сервер должен возвращать заголовки:

Access-Control-Allow-Origin: *

или

Access-Control-Allow-Origin: https://my-site.com

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


Загрузка стиля из JavaScript-объекта

Файл JSON не является обязательным. Стиль можно описать непосредственно в коде.

Пример:

const style = {
    version: 8,
    sources: {},
    layers: [
        {
            id: 'background',
            type: 'background',
            paint: {
                'background-color': '#dbeafe'
            }
        }
    ]
};

const map = new maplibregl.Map({
    container: 'map',
    style: style
});

Такой способ удобен для:

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

Структура файла стиля

Полноценный стиль обычно состоит из нескольких разделов.

Пример упрощённой структуры:

{
  "version": 8,

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

  "sprite": "https://example.com/sprites/sprite",

  "sources": {},

  "layers": []
}

Основные элементы:

Поле Назначение
version Версия спецификации
glyphs URL шрифтов
sprite URL набора иконок
sources Источники данных
layers Слои карты
light Настройки освещения
terrain Рельеф
sky Небо

Загрузка стилей с подключёнными векторными тайлами

На практике стиль почти всегда содержит источники данных.

Пример:

{
  "version": 8,

  "sources": {
    "osm": {
      "type": "vector",
      "tiles": [
        "https://tiles.example.com/{z}/{x}/{y}.pbf"
      ]
    }
  },

  "layers": [
    {
      "id": "roads",
      "type": "line",
      "source": "osm",
      "source-layer": "transportation"
    }
  ]
}

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

  1. Загружается стиль.
  2. Анализируются источники данных.
  3. Загружаются тайлы.
  4. Загружаются шрифты и спрайты.
  5. Выполняется отрисовка слоёв.

Если один из ресурсов недоступен, соответствующие слои могут не отображаться.


Отслеживание завершения загрузки стиля

После загрузки стиля возникает событие load.

map.on('load', () => {
    console.log('Карта полностью загружена');
});

Это событие срабатывает после завершения первичной инициализации.

Для проверки состояния можно использовать:

if (map.isStyleLoaded()) {
    console.log('Стиль загружен');
}

Метод возвращает:

true

если все элементы стиля успешно загружены.


Событие styledata

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

map.on('styledata', () => {
    console.log('Стиль обновлён');
});

Сценарии срабатывания:

  • первоначальная загрузка;
  • вызов setStyle();
  • изменение некоторых параметров стиля;
  • перезагрузка ресурсов.

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


Динамическая смена стиля

MapLibre позволяет полностью заменить стиль карты во время работы приложения.

map.setStyle('dark-style.json');

После выполнения:

  1. старый стиль удаляется;
  2. загружается новый;
  3. выполняется повторная инициализация карты.

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

document
    .getElementById('dark-theme')
    .addEventListener('click', () => {

        map.setStyle('styles/dark.json');

    });

Смена стиля через объект

Метод setStyle() принимает не только URL.

map.setStyle({
    version: 8,
    sources: {},
    layers: [
        {
            id: 'background',
            type: 'background',
            paint: {
                'background-color': '#000000'
            }
        }
    ]
});

Это позволяет генерировать внешний вид карты программно.


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

После вызова setStyle() пользовательские слои обычно исчезают.

Например:

map.addSource('cities', {
    type: 'geojson',
    data: 'cities.geojson'
});

После смены стиля источник будет удалён.

Распространённое решение:

map.on('styledata', () => {

    if (!map.getSource('cities')) {

        map.addSource('cities', {
            type: 'geojson',
            data: 'cities.geojson'
        });

    }

});

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


Асинхронная загрузка стиля через Fetch API

Иногда требуется предварительно обработать стиль.

Для этого используется fetch().

async function loadStyle() {

    const response = await fetch('style.json');

    const style = await response.json();

    map.setStyle(style);

}

Подход позволяет:

  • модифицировать стиль;
  • добавлять параметры;
  • выполнять валидацию;
  • объединять несколько конфигураций.

Изменение стиля перед загрузкой

Полученный JSON можно менять программно.

Пример изменения цвета фона:

const response = await fetch('style.json');

const style = await response.json();

style.layers[0].paint['background-color'] = '#111827';

map.setStyle(style);

Фактически стиль становится обычным объектом JavaScript.


Генерация стиля на лету

Некоторые приложения полностью создают стиль программно.

Пример:

function createStyle(color) {

    return {
        version: 8,
        sources: {},
        layers: [
            {
                id: 'background',
                type: 'background',
                paint: {
                    'background-color': color
                }
            }
        ]
    };

}

map.setStyle(createStyle('#22c55e'));

Подход широко используется в:

  • GIS-системах;
  • административных панелях;
  • конструкторах карт;
  • системах брендирования.

Обработка ошибок загрузки

При недоступности файла или наличии ошибок возникает событие error.

map.on('error', (event) => {
    console.error(event.error);
});

Типичные причины:

  • неверный URL;
  • отсутствие доступа к файлу;
  • ошибки JSON;
  • проблемы CORS;
  • недоступность тайлового сервера.

Пример сообщения:

Failed to load resource

или

Unexpected token

при повреждённом JSON.


Проверка корректности JSON

Даже небольшая синтаксическая ошибка приводит к невозможности загрузки.

Некорректный пример:

{
  "version": 8,
  "sources": {},
  "layers": [],
}

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

Корректный вариант:

{
  "version": 8,
  "sources": {},
  "layers": []
}

Работа со шрифтами

Для отображения подписей стиль содержит параметр glyphs.

Пример:

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

Во время загрузки MapLibre автоматически запрашивает нужные диапазоны символов.

Шаблон:

{fontstack}

заменяется названием шрифта, а

{range}

диапазоном символов.


Подключение спрайтов

Наборы иконок подключаются через свойство sprite.

{
  "sprite": "https://example.com/sprites/sprite"
}

MapLibre автоматически загрузит:

sprite.json
sprite.png

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

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

{
  "type": "symbol"
}

через свойство:

"icon-image"

Использование нескольких вариантов стилей

В крупных проектах часто создаются отдельные конфигурации:

light.json
dark.json
satellite.json
terrain.json

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

const styles = {
    light: 'styles/light.json',
    dark: 'styles/dark.json',
    satellite: 'styles/satellite.json'
};

map.setStyle(styles.dark);

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


Кэширование пользовательских стилей

Браузер обычно кэширует файлы стилей.

При разработке это может приводить к отображению устаревшей версии.

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

style: 'style.json?v=15'

После изменения номера версии браузер загружает новый файл.

Другой вариант — настройка HTTP-заголовков:

Cache-Control: no-cache

или

Cache-Control: max-age=86400

в зависимости от требований проекта.


Организация каталога стилей

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

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

styles/
│
├── light/
│   ├── style.json
│   ├── sprite.png
│   └── sprite.json
│
├── dark/
│   ├── style.json
│   ├── sprite.png
│   └── sprite.json
│
└── terrain/
    ├── style.json
    ├── sprite.png
    └── sprite.json

Такая организация облегчает:

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

Практические рекомендации

Использование абсолютных URL упрощает переносимость стилей между проектами и серверами.

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

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

Проверка доступности ресурсов предотвращает ситуации, при которых карта отображается частично или остаётся пустой.

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

Генерация стилей через JavaScript обеспечивает высокий уровень гибкости и позволяет создавать полностью динамические интерфейсы картографических приложений на базе MapLibre GL JS.