Stimulus — это легковесный JavaScript-фреймворк, предназначенный для улучшения взаимодействия между HTML и логикой на стороне клиента без необходимости сложной инфраструктуры. В контексте работы с картографическими библиотеками Stimulus обеспечивает структурированный подход к управлению компонентами карты, их инициализации, обновлению данных и взаимодействию с DOM.
Контроллер Stimulus создается как класс, наследующий
Controller из пакета @hotwired/stimulus.
Основной принцип работы — связывание DOM-элементов с методами
контроллера через data-атрибуты.
Пример структуры контроллера для карты:
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static targets = ["map"]
connect() {
this.initializeMap();
}
initializeMap() {
this.map = L.map(this.mapTarget).setView([51.505, -0.09], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(this.map);
}
addMarker(lat, lng, popupText = '') {
const marker = L.marker([lat, lng]).addTo(this.map);
if (popupText) marker.bindPopup(popupText);
}
}
Ключевые моменты:
static targets позволяет явно указать элементы DOM, с
которыми будет взаимодействовать контроллер.connect() вызывается автоматически при привязке
контроллера к элементу DOM.addMarker,
инкапсулируют логику работы с библиотекой (например, Leaflet).HTML-разметка связывается с контроллером с помощью
data-controller и data-target:
<div data-controller="map" data-map-target="map" style="height: 400px;"></div>
<button data-action="click->map#addMarker" data-lat="51.505" data-lng="-0.09" data-popup="Hello!">Добавить маркер</button>
Особенности:
data-action="click->map#addMarker" связывает событие
click с методом addMarker контроллера
map.data-lat, data-lng,
data-popup могут быть прочитаны в методе контроллера через
event.currentTarget.dataset.Пример обработки данных кнопки:
addMarker(event) {
const lat = parseFloat(event.currentTarget.dataset.lat);
const lng = parseFloat(event.currentTarget.dataset.lng);
const popup = event.currentTarget.dataset.popup || '';
this.addMarker(lat, lng, popup);
}
Stimulus обеспечивает удобный способ динамически обновлять карту при
изменении данных. Например, можно использовать методы
addLayer, removeLayer или setView
для управления отображением элементов:
updateMap(center, zoom, markers = []) {
this.map.setView(center, zoom);
this.map.eachLayer(layer => {
if (layer instanceof L.Marker) this.map.removeLayer(layer);
});
markers.forEach(({lat, lng, popup}) => this.addMarker(lat, lng, popup));
}
Этот подход позволяет:
Stimulus легко сочетается с API для картографических сервисов, таких как Mapbox или Google Maps. Основная идея — инкапсулировать API-запросы и инициализацию карты в методы контроллера:
loadMapboxMap() {
mapboxgl.accessToken = 'YOUR_ACCESS_TOKEN';
this.map = new mapboxgl.Map({
container: this.mapTarget,
style: 'mapbox://styles/mapbox/streets-v11',
center: [30.5, 50.5],
zoom: 9
});
}
Преимущества такого подхода:
Контроллер Stimulus позволяет подписываться на события карты и обрабатывать их методами класса:
connect() {
this.initializeMap();
this.map.on('click', this.handleMapClick.bind(this));
}
handleMapClick(event) {
const {lat, lng} = event.latlng;
this.addMarker(lat, lng, 'Новый маркер');
}
Особенности:
.bind(this) гарантирует, что метод
сохраняет контекст контроллера.click,
move, zoom, dragend.Stimulus поддерживает организацию нескольких контроллеров на одной странице. Для карт это полезно при:
Пример HTML с несколькими контроллерами:
<div data-controller="map filter">
<div data-map-target="map" style="height: 400px;"></div>
<select data-action="change->filter#apply">
<option value="all">Все</option>
<option value="parks">Парки</option>
<option value="museums">Музеи</option>
</select>
</div>
В этом случае контроллер filter может вызывать методы
updateMap контроллера map через
this.application.getControllerForElementAndIdentifier(element, "map").
connect(). Повторное создание карты ведет к утечкам
памяти.Stimulus предоставляет ясную и организованную структуру для работы с картографическими библиотеками, позволяя разделять DOM, логику карты и взаимодействие с пользователем. Такой подход упрощает поддержку кода, повышает читаемость и позволяет легко масштабировать функциональность при добавлении новых источников данных или интерактивных элементов.