Установка плагинов

Плагины в MapLibre GL JS представляют собой способ расширения функциональности карты без модификации ядра рендеринга. Архитектура библиотеки построена вокруг композиции модулей: карта, источники данных, слои, стили и внешние расширения взаимодействуют через публичные API. Плагины интегрируются в этот слой как независимые JavaScript-модули, подключаемые в рантайме или на этапе сборки приложения.

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

Типичная модель плагина включает:

  • добавление пользовательских контролов (controls)
  • расширение источников данных (sources)
  • внедрение пользовательских слоёв (custom layers)
  • обработку событий карты
  • интеграцию внешних API

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

Установка плагинов через npm и пакетные менеджеры

Наиболее распространённый способ установки плагинов — использование npm или yarn. В экосистеме MapLibre большинство расширений распространяются как отдельные пакеты.

Установка базового набора инструментов:

npm install maplibre-gl

Далее устанавливается конкретный плагин, например контрол масштаба или маршрутизации:

npm install @maplibre/maplibre-gl-geocoder

или альтернативные расширения:

npm install maplibre-gl-compare
npm install maplibre-gl-draw

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

import maplibregl from "maplibre-gl";
import MapboxGeocoder from "@maplibre/maplibre-gl-geocoder";

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

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

Современные сборщики (Vite, Webpack, Rollup) позволяют подключать плагины как ES-модули. Это предпочтительный подход, так как он обеспечивает tree-shaking и контроль зависимостей.

Пример инициализации карты с плагином:

import maplibregl from "maplibre-gl";
import MaplibreGlDirections from "maplibre-gl-directions";

const map = new maplibregl.Map({
    container: "map",
    style: "https://demotiles.maplibre.org/style.json",
    center: [30.5, 50.5],
    zoom: 9
});

map.addControl(new MaplibreGlDirections({
    accessToken: "YOUR_TOKEN"
}));

В данном примере плагин реализует контрол, добавляемый через метод addControl. Это наиболее типичный механизм интеграции расширений UI-уровня.

Подключение через CDN

В проектах без сборки можно подключать плагины через CDN. В этом случае они обычно доступны как глобальные переменные.

Подключение основной библиотеки:

<link href="https://unpkg.com/maplibre-gl/dist/maplibre-gl.css" rel="stylesheet">
<script src="https://unpkg.com/maplibre-gl/dist/maplibre-gl.js"></script>

Подключение плагина:

<script src="https://unpkg.com/maplibre-gl-draw/dist/maplibre-gl-draw.js"></script>

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

const map = new maplibregl.Map({
    container: "map",
    style: "https://demotiles.maplibre.org/style.json"
});

const draw = new MaplibreGlDraw();
map.addControl(draw);

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

Типы плагинов и их установка

Контролы интерфейса

Контролы — самый распространённый тип плагинов. Они добавляют элементы управления на карту: поиск, масштабирование, маршруты, измерения.

Контрол реализуется через интерфейс с методами:

  • onAdd(map)
  • onRemove()

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

class CustomControl {
    onAdd(map) {
        this.map = map;
        this.container = document.createElement("div");
        this.container.className = "custom-control";
        return this.container;
    }

    onRemove() {
        this.container.parentNode.removeChild(this.container);
        this.map = undefined;
    }
}

Установка:

map.addControl(new CustomControl(), "top-right");

Позиционирование контролов важно для UX: доступны области top-left, top-right, bottom-left, bottom-right.

Плагины рисования

Расширения типа draw добавляют возможность интерактивного создания геометрии.

import MaplibreGlDraw from "maplibre-gl-draw";

const draw = new MaplibreGlDraw({
    displayControlsDefault: false,
    controls: {
        polygon: true,
        line_string: true,
        point: true,
        trash: true
    }
});

map.addControl(draw);

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

Плагины поиска и геокодинга

Геокодеры подключаются как контролы, но требуют дополнительной настройки API.

import MaplibreGeocoder from "@maplibre/maplibre-gl-geocoder";

const geocoder = new MaplibreGeocoder({
    forwardGeocode: async (config) => {
        const response = await fetch(`/api/geocode?q=${config.query}`);
        const data = await response.json();
        return {
            features: data.features
        };
    }
});

map.addControl(geocoder);

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

Установка через интеграцию в сборку проекта

В крупных приложениях плагины интегрируются как часть архитектуры приложения.

Пример структуры проекта:

src/
  map/
    index.js
    plugins/
      draw.js
      geocoder.js
      customControl.js

Файл инициализации карты:

import maplibregl from "maplibre-gl";
import { initDraw } from "./plugins/draw";
import { initGeocoder } from "./plugins/geocoder";

export function createMap() {
    const map = new maplibregl.Map({
        container: "map",
        style: "/style.json"
    });

    initDraw(map);
    initGeocoder(map);

    return map;
}

Такой подход позволяет изолировать плагины от логики UI и бизнес-слоя.

Регистрация плагинов и управление жизненным циклом

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

Пример:

class PluginManager {
    constructor(map) {
        this.map = map;
        this.plugins = [];
    }

    use(plugin) {
        const instance = plugin(this.map);
        this.plugins.push(instance);
        return instance;
    }

    destroy() {
        this.plugins.forEach(p => p.destroy?.());
    }
}

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

const manager = new PluginManager(map);

manager.use(initDrawPlugin);
manager.use(initGeocoderPlugin);

Это упрощает контроль за утечками памяти и порядком инициализации.

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

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

map.on("load", () => {
    map.addLayer({
        id: "custom-layer",
        type: "circle",
        source: "points",
        paint: {
            "circle-radius": 6,
            "circle-color": "#ff0000"
        }
    });
});

Расширенные плагины могут инкапсулировать создание источников:

export function initHeatmapPlugin(map) {
    map.addSource("heat", {
        type: "geojson",
        data: "/data/heat.json"
    });

    map.addLayer({
        id: "heat-layer",
        type: "heatmap",
        source: "heat"
    });
}

Проблемы совместимости и версионирования

Плагины тесно зависят от версии ядра MapLibre GL JS. Несовместимость API может проявляться в:

  • изменении структуры Map объекта
  • обновлении событийной модели
  • изменении формата источников данных
  • модификации WebGL pipeline

Рекомендуется фиксировать версии:

{
  "dependencies": {
    "maplibre-gl": ">=3.0.0 <4.0.0"
  }
}

и проверять peerDependencies у каждого плагина.

Типичные ошибки при установке плагинов

Часто встречающиеся проблемы:

1. Двойная загрузка библиотеки Если MapLibre подключён через CDN и npm одновременно, возникает конфликт глобальных объектов.

2. Отсутствие CSS плагина Многие плагины требуют отдельного CSS:

import "maplibre-gl/dist/maplibre-gl.css";
import "@maplibre/maplibre-gl-geocoder/dist/maplibre-gl-geocoder.css";

3. Несоответствие версий Плагин может использовать устаревшие методы API.

4. Неправильный порядок инициализации Контролы добавляются до события load, что приводит к ошибкам:

map.on("load", () => {
    map.addControl(plugin);
});

Расширение функциональности через композицию плагинов

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

map.addControl(draw);
map.addControl(geocoder);
map.addControl(scaleControl);

или через композицию:

function initPlugins(map) {
    return [
        initDraw(map),
        initGeocoder(map),
        initCustomLayers(map)
    ];
}

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

Интеграция с внешними сервисами через плагины

Плагины часто выступают мостом между картой и внешними API:

  • маршрутизация (OSRM, GraphHopper)
  • геокодинг (Nominatim, Pelias)
  • тайлы (vector/raster tile servers)
  • аналитика и трекинг событий

Пример маршрутизации:

map.addControl(new MaplibreGlDirections({
    api: "https://router.project-osrm.org/route/v1"
}));

Такая архитектура отделяет визуализацию от логики вычислений.

Структура качественного плагина

Хорошо спроектированный плагин обычно включает:

  • отдельный entry point
  • экспорт функции инициализации
  • методы destroy/remove
  • обработку событий карты
  • изоляцию DOM
  • отсутствие глобальных побочных эффектов

Пример шаблона:

export function createPlugin(options = {}) {
    let map;

    return {
        onAdd(m) {
            map = m;
            // init
        },
        onRemove() {
            // cleanup
            map = null;
        }
    };
}

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