Leaflet построен вокруг императивного управления картой с использованием тайлов и DOM-слоёв. Основная модель — набор слоёв, каждый из которых рендерится как HTML или Canvas поверх тайловой подложки. Вся логика взаимодействия с картой сводится к добавлению и удалению объектов через API слоёв и маркеров.
Mapbox GL JS использует WebGL-рендеринг и декларативную модель стилей. Карта описывается как набор источников данных (sources) и слоёв (layers), а визуализация управляется через стиль JSON-формата. Это принципиально меняет подход: вместо управления объектами на карте напрямую, происходит управление описанием того, как данные должны быть отрисованы.
Ключевое различие:
В Leaflet геометрия добавляется напрямую:
L.marker([51.5, -0.09]).addTo(map);
L.polyline([[51.5, -0.09], [51.51, -0.1]]).addTo(map);
Каждый объект существует независимо и управляется через API экземпляра.
В Mapbox GL JS данные разделяются на источники:
map.addSource('points', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [-0.09, 51.5]
}
}
]
}
});
И затем отображаются через слой:
map.addLayer({
id: 'points-layer',
type: 'circle',
source: 'points',
paint: {
'circle-radius': 6,
'circle-color': '#ff0000'
}
});
При переходе необходимо:
В Leaflet маркеры являются DOM-элементами:
L.marker([51.5, -0.09])
.bindPopup('Точка')
.addTo(map);
Они легко кастомизируются через HTML и CSS.
В Mapbox GL JS есть два подхода:
const el = document.createElement('div');
el.className = 'marker';
new mapboxgl.Marker(el)
.setLngLat([-0.09, 51.5])
.addTo(map);
map.addLayer({
id: 'points',
type: 'circle',
source: 'points',
paint: {
'circle-radius': 8,
'circle-color': '#3b82f6'
}
});
Leaflet использует событийную модель:
map.on('click', function(e) {
console.log(e.latlng);
});
Mapbox GL JS разделяет события карты и события слоёв:
map.on('click', 'points-layer', (e) => {
console.log(e.features[0]);
});
Особенность:
В Leaflet GeoJSON используется как слой:
L.geoJSON(data).addTo(map);
В Mapbox GL JS GeoJSON становится источником:
map.addSource('data', {
type: 'geojson',
data: data
});
и визуализируется отдельно:
map.addLayer({
id: 'data-fill',
type: 'fill',
source: 'data',
paint: {
'fill-color': '#088',
'fill-opacity': 0.5
}
});
Leaflet использует URL-шаблоны тайлов:
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png')
.addTo(map);
Mapbox GL JS использует стили:
mapboxgl.accessToken = 'TOKEN';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v12'
});
В Leaflet:
map.addLayer(layer);
map.removeLayer(layer);
В Mapbox GL JS:
map.addLayer({
id: 'roads',
type: 'line',
source: 'composite',
'source-layer': 'road'
});
Удаление:
map.removeLayer('roads');
Каждый слой в Mapbox GL JS:
Leaflet:
Mapbox GL JS:
Изменение точки мышления:
| Leaflet | Mapbox GL JS |
|---|---|
| addMarker() | addSource() + addLayer() |
| update marker | setData() |
| remove marker | remove layer/source |
Leaflet:
map.panTo([51.5, -0.09]);
map.setZoom(10);
Mapbox GL JS:
map.flyTo({
center: [-0.09, 51.5],
zoom: 10
});
Дополнительно:
map.easeTo({
center: [-0.09, 51.5],
duration: 2000
});
Leaflet:
Mapbox GL JS:
map.addSource('points', {
type: 'geojson',
data: geojson,
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50
});
Слои:
map.addLayer({
id: 'clusters',
type: 'circle',
source: 'points',
filter: ['has', 'point_count']
});
Основной фактор перехода:
Последствия:
Leaflet:
L.circle([51.5, -0.09], {
color: 'red',
radius: 500
}).addTo(map);
Mapbox GL JS:
paint: {
'circle-color': [
'match',
['get', 'type'],
'A', '#f00',
'B', '#0f0',
'#00f'
]
}
Leaflet:
marker.setLatLng([lat, lng]);
Mapbox GL JS:
map.getSource('points').setData(newGeoJSON);
Leaflet:
Mapbox GL JS:
map.addLayer({
id: 'custom',
type: 'custom',
renderingMode: '2d',
onAdd: function(map, gl) {},
render: function(gl, matrix) {}
});
Leaflet:
marker.on('mouseover', fn);
Mapbox GL JS:
map.on('mouseenter', 'points-layer', fn);
map.on('mouseleave', 'points-layer', fn);
Дополнительно:
map.getCanvas().style.cursor = 'pointer';
L.marker([51.5, -0.09]).addTo(map);
map.addSource('point', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: [{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [-0.09, 51.5]
}
}]
}
});
map.addLayer({
id: 'point-layer',
type: 'circle',
source: 'point',
paint: {
'circle-radius': 6,
'circle-color': '#ff0000'
}
});