rater/assets/controllers/map_controller.js

91 lines
2.6 KiB
JavaScript

import { Controller } from '@hotwired/stimulus';
import L from 'leaflet';
import 'leaflet/dist/leaflet.min.css';
L.Icon.Default.mergeOptions({
iconUrl: '/leaflet/marker-icon.png',
iconRetinaUrl: '/leaflet/marker-icon-2x.png',
shadowUrl: '/leaflet/marker-shadow.png',
});
export default class extends Controller {
connect() {
this.map = L.map(this.element).setView([51.0543, 3.7174], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
maxZoom: 19,
}).addTo(this.map);
this.pendingLatlng = null;
this.dialog = document.getElementById('add-subject-dialog');
this.nameInput = document.getElementById('subject-name');
this.submitBtn = document.getElementById('subject-submit');
this.cancelBtn = document.getElementById('subject-cancel');
this.loadSubjects();
this.map.on('click', (e) => this.openModal(e.latlng));
this.submitBtn.addEventListener('click', () => this.handleSubmit());
this.cancelBtn.addEventListener('click', () => this.closeModal());
// Esc key / backdrop close — clear pending state
this.dialog.addEventListener('close', () => this.resetModal());
}
loadSubjects() {
fetch('/api/subjects')
.then(r => r.json())
.then(data => {
data.payload.subjects.forEach(s => {
if (s.latitude && s.longitude) {
this.addMarker(s.latitude, s.longitude, s.name);
}
});
});
}
openModal(latlng) {
this.pendingLatlng = latlng;
this.nameInput.value = '';
this.dialog.showModal();
this.nameInput.focus();
}
closeModal() {
this.dialog.close();
}
resetModal() {
this.pendingLatlng = null;
this.nameInput.value = '';
}
handleSubmit() {
const name = this.nameInput.value.trim();
if (!name || !this.pendingLatlng) return;
const latlng = this.pendingLatlng;
fetch('/api/subjects', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: name,
latitude: latlng.lat,
longitude: latlng.lng,
}),
})
.then(r => r.json())
.then(() => {
this.addMarker(latlng.lat, latlng.lng, name);
this.closeModal();
});
}
addMarker(lat, lng, name) {
L.marker([lat, lng]).addTo(this.map).bindPopup(name);
}
}