Tile-серверы

Tile-сервер (сервер тайлов) — это сервер, предоставляющий картографические изображения небольшими квадратными фрагментами фиксированного размера. Вместо загрузки всей карты целиком браузер получает только те части, которые необходимы для отображения текущей области просмотра.

В экосистеме Leaflet тайлы являются основным источником визуального представления карты. После создания объекта карты обычно подключается слой тайлов, который становится базовой подложкой:

const map = L.map('map').setView([55.751244, 37.618423], 10);

L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '© OpenStreetMap contributors'
}).addTo(map);

В результате карта начинает запрашивать изображения у tile-сервера и отображать их в соответствующих местах.


Что такое тайл

Тайл представляет собой квадратное изображение, обычно размером:

  • 256×256 пикселей;
  • 512×512 пикселей (Retina и современные стили карт).

Каждый тайл имеет собственные координаты:

  • x — положение по горизонтали;
  • y — положение по вертикали;
  • z — уровень масштабирования (zoom).

Типичный URL тайла выглядит следующим образом:

https://tile.openstreetmap.org/10/618/320.png

Где:

10  → zoom
618 → x
320 → y

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


Принцип разбиения карты

В основе большинства современных веб-карт лежит схема разбиения мира на сетку тайлов.

На нулевом масштабе весь мир представлен одним тайлом:

Zoom 0

+-----+
|     |
|     |
+-----+

На первом масштабе карта разбивается на четыре части:

Zoom 1

+---+---+
|   |   |
+---+---+
|   |   |
+---+---+

На втором масштабе количество тайлов увеличивается до шестнадцати:

Zoom 2

4 × 4 = 16 тайлов

Общее количество тайлов вычисляется по формуле:

2^z × 2^z

Например:

Zoom Тайлов по оси Всего тайлов
0 1 1
1 2 4
2 4 16
3 8 64
10 1024 1 048 576
18 262 144 68 719 476 736

Поэтому хранение карты в виде отдельных фрагментов значительно эффективнее загрузки огромных изображений.


Подключение tile-сервера

В Leaflet за работу с тайлами отвечает класс L.TileLayer.

Базовый синтаксис:

L.tileLayer(urlTemplate, options)

Пример:

L.tileLayer(
    'https://tile.openstreetmap.org/{z}/{x}/{y}.png'
);

Плейсхолдеры:

Переменная Назначение
{z} Масштаб
{x} Координата X
{y} Координата Y

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


OpenStreetMap как источник тайлов

Самый распространённый источник картографических тайлов:

L.tileLayer(
    'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
    {
        attribution:
            '© OpenStreetMap contributors'
    }
).addTo(map);

Особенности:

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

Атрибуция обязательна, поскольку данные предоставляются сообществом OpenStreetMap.


Параметр attribution

Большинство поставщиков карт требуют отображения информации об авторстве.

Пример:

L.tileLayer(url, {
    attribution:
        '© OpenStreetMap contributors'
});

Несколько источников:

L.tileLayer(url, {
    attribution:
        '© OpenStreetMap contributors | Tiles by ExampleMaps'
});

Атрибуция автоматически отображается в правом нижнем углу карты.


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

Современные браузеры блокируют смешанный контент.

Неправильно:

http://tile.server.com/{z}/{x}/{y}.png

Если сайт открыт через HTTPS, карта может не загрузиться.

Правильно:

https://tile.server.com/{z}/{x}/{y}.png

Использование защищённого соединения стало стандартом для всех современных tile-серверов.


Основные параметры TileLayer

minZoom

Минимальный масштаб:

L.tileLayer(url, {
    minZoom: 5
});

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


maxZoom

Максимальный масштаб:

L.tileLayer(url, {
    maxZoom: 19
});

При достижении максимального уровня увеличение прекращается.


tileSize

Размер одного тайла:

L.tileLayer(url, {
    tileSize: 256
});

или

L.tileLayer(url, {
    tileSize: 512
});

Значение должно соответствовать настройкам сервера.


opacity

Прозрачность слоя:

L.tileLayer(url, {
    opacity: 0.6
});

Диапазон:

0.0 — полностью прозрачный
1.0 — полностью непрозрачный

zIndex

Порядок наложения:

L.tileLayer(url, {
    zIndex: 100
});

Чем больше значение, тем выше слой располагается относительно других слоёв.


bounds

Ограничение области действия тайлов:

L.tileLayer(url, {
    bounds: [
        [40, -20],
        [70, 40]
    ]
});

Тайлы будут отображаться только внутри указанных координат.


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

Многие tile-серверы используют несколько поддоменов:

a.tile.server.com
b.tile.server.com
c.tile.server.com

В Leaflet:

L.tileLayer(
    'https://{s}.tile.server.com/{z}/{x}/{y}.png',
    {
        subdomains: ['a', 'b', 'c']
    }
);

Или сокращённая запись:

subdomains: 'abc'

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


Retina-тайлы

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

Leaflet позволяет автоматически использовать Retina-тайлы:

L.tileLayer(url, {
    detectRetina: true
});

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

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

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

Переключение между несколькими tile-серверами

Часто требуется выбор различных картографических стилей.

Создание нескольких слоёв:

const osm = L.tileLayer(
    'https://tile.openstreetmap.org/{z}/{x}/{y}.png'
);

const satellite = L.tileLayer(
    'https://server.com/satellite/{z}/{x}/{y}.jpg'
);

osm.addTo(map);

Добавление переключателя:

L.control.layers({
    "OpenStreetMap": osm,
    "Satellite": satellite
}).addTo(map);

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


Светлые и тёмные стили карт

Различные tile-серверы могут предоставлять разные визуальные оформления:

  • светлая карта;
  • тёмная карта;
  • спутниковая карта;
  • транспортная карта;
  • туристическая карта;
  • карта рельефа.

Пример подключения тёмного стиля:

L.tileLayer(
    'https://tiles.example.com/dark/{z}/{x}/{y}.png'
);

С точки зрения Leaflet работа с любым стилем происходит одинаково — меняется только URL.


Ограничение запросов к серверу

Tile-серверы обычно имеют ограничения:

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

Плохая практика:

for(let i = 0; i < 100; i++) {
    L.map(`map${i}`);
}

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

Хорошая практика:

  • использовать одну карту на странице;
  • включать браузерное кэширование;
  • соблюдать условия использования поставщика тайлов;
  • использовать собственный сервер при высокой нагрузке.

Кэширование тайлов

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

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

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

При перемещении карты Leaflet повторно использует уже загруженные изображения, если они присутствуют в кэше.


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

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

L.tileLayer(url, {
    errorTileUrl: 'images/error.png'
});

Причины ошибок:

  • сервер недоступен;
  • неверный URL;
  • отсутствие тайла;
  • ограничения доступа;
  • проблемы сети.

События TileLayer

tileloadstart

Начало загрузки тайла:

tileLayer.on('tileloadstart', function(e) {
    console.log('Загрузка');
});

tileload

Тайл успешно загружен:

tileLayer.on('tileload', function(e) {
    console.log('Готово');
});

tileerror

Ошибка загрузки:

tileLayer.on('tileerror', function(e) {
    console.log('Ошибка');
});

load

Загружены все необходимые тайлы:

tileLayer.on('load', function() {
    console.log('Карта готова');
});

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


Собственный tile-сервер

В крупных проектах нередко разворачивается собственная инфраструктура.

Причины:

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

URL собственного сервера выглядит аналогично:

L.tileLayer(
    'https://maps.company.com/{z}/{x}/{y}.png'
);

Для Leaflet источник тайлов не имеет значения, если сервер поддерживает стандартную схему координат.


TMS и XYZ

Существует два популярных формата адресации тайлов.

XYZ

Используется большинством современных сервисов:

/{z}/{x}/{y}.png

Координата y увеличивается сверху вниз.


TMS

Использует обратную нумерацию по оси Y:

/{z}/{x}/{y}.png

Визуально URL одинаков, но система координат отличается.

Для TMS в Leaflet:

L.tileLayer(url, {
    tms: true
});

Leaflet автоматически преобразует координаты.


Непрерывная прокрутка мира

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

Это достигается за счёт циклического отображения тайлов.

Отключение:

L.tileLayer(url, {
    noWrap: true
});

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


Ограничение мировых границ

Дополнительно можно запретить перемещение за пределы определённой области:

const bounds = [
    [85, -180],
    [-85, 180]
];

map.setMaxBounds(bounds);

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


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

На быстродействие карты влияют:

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

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

  1. Использовать CDN.
  2. Включать браузерное кэширование.
  3. Применять сжатие изображений.
  4. Не загружать тайлы сверх необходимого масштаба.
  5. Использовать Retina-режим только при необходимости.
  6. Минимизировать количество одновременно активных тайловых слоёв.

Жизненный цикл тайла

Процесс отображения карты состоит из нескольких этапов:

1. Изменение масштаба или положения карты
            ↓
2. Вычисление координат x/y/z
            ↓
3. Формирование URL
            ↓
4. Запрос к tile-серверу
            ↓
5. Получение изображения
            ↓
6. Кэширование
            ↓
7. Отображение на карте

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