Skip to content

Instantly share code, notes, and snippets.

@adactio
Created December 16, 2024 12:11
Show Gist options
  • Save adactio/b4a27fd783bb9381d2ada52767d5bf81 to your computer and use it in GitHub Desktop.
Save adactio/b4a27fd783bb9381d2ada52767d5bf81 to your computer and use it in GitHub Desktop.
embed-map is an HTML web component
class EmbedMap extends HTMLElement {
constructor () {
super();
}
loadScript(src, callback) {
let script = document.createElement('script');
script.src = src;
script.addEventListener('load', callback);
document.querySelector('head').appendChild(script);
}
loadLibrary () {
caches.match('/js/leaflet/maplibre-gl.js')
.then( responseFromCache => {
if (responseFromCache) {
let link = document.createElement('link');
link.rel = 'stylesheet';
link.href = '/js/leaflet/maplibre-gl.css';
document.querySelector('head').appendChild(link);
this.loadScript('/js/leaflet/leaflet.js', () => {
this.loadScript('/js/leaflet/maplibre-gl.js', () => {
this.loadScript('/js/leaflet/leaflet-maplibre-gl.js', () => {
this.init();
});
});
});
} else {
this.loadScript('/js/leaflet/leaflet.js', () => {
this.init();
});
}
});
}
setLocation (lat, lon) {
this.location = L.latLng(lat, lon);
}
addMarker (lat, lon, overlay) {
let marker = L.marker([lat, lon]).addTo(this.map);
if (overlay) {
marker.bindPopup(overlay);
}
this.pins.push(marker);
}
removePins () {
this.pins.forEach( (pin) => {
pin.remove();
});
this.pins = [];
}
dropPins () {
let elements = document.querySelectorAll('[data-latlon]');
if (elements.length < 1) {
return;
}
let boundary = L.latLngBounds();
let coords;
elements.forEach( (element) => {
coords = element.dataset.latlon.split(',');
element.marker = this.addMarker(coords[0], coords[1], element.cloneNode(true));
boundary.extend(L.latLng(coords[0], coords[1]));
});
this.map.setView(boundary.getCenter());
if (elements.length > 1) {
this.map.fitBounds(boundary);
}
}
updatePins () {
this.removePins();
this.dropPins();
}
draw () {
let mapOptions = {
zoom: this.magnification
};
if (!this.map) {
this.map = L.map(this.querySelector('.map'), mapOptions);
if (L.maplibreGL) {
L.maplibreGL({
style: 'https://tiles.openfreemap.org/styles/bright',
attribution: '&copy; <a href="https://www.openmaptiles.org/">OpenMapTiles</a> Data from <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(this.map);
} else {
L.tileLayer('https://{s}.tile.openstreetmap.de/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(this.map);
}
}
if (this.location) {
this.map.setView(this.location);
}
if (this.dataset.updates) {
this.map.on('moveend', (ev) => {
this.broadcastLocation();
});
this.map.on('zoomend', (ev) => {
this.broadcastLocation();
});
}
}
broadcastLocation () {
let detail = {};
let location = this.map.getCenter();
detail.latitude = parseFloat(location.lat).toFixed(6);
detail.longitude = parseFloat(location.lng).toFixed(6);
detail.zoom = this.map.getZoom();
const locationUpdate = new CustomEvent('locationUpdate', { bubbles: true, detail: detail });
document.dispatchEvent(locationUpdate);
}
init () {
if (this.dataset.geolocate) {
this.querySelector('.map').innerHTML = '<div style="text-align: center"><p>Getting location… please wait.<span class="loader loading"></span></p></div>';
navigator.geolocation.getCurrentPosition(
(position) => {
this.magnification = 12;
this.setLocation(position.coords.latitude, position.coords.longitude);
this.draw();
this.broadcastLocation();
},
(error) => {
this.draw();
}
);
}
if (this.dataset.latitude && this.dataset.longitude) {
this.setLocation(this.dataset.latitude, this.dataset.longitude);
}
this.draw();
if (this.dataset.marker) {
this.addMarker(this.dataset.latitude, this.dataset.longitude);
} else {
this.dropPins();
document.addEventListener('updateMarkers', (ev) => {
this.updatePins();
});
}
}
connectedCallback () {
this.innerHTML = '<div class="map"></div>';
this.magnification = 12;
if (this.dataset.zoom) {
this.magnification = this.dataset.zoom;
}
this.map = null;
this.pins = [];
this.location = null;
if (window.L) {
this.init();
} else {
this.loadLibrary();
}
}
}
customElements.define('embed-map', EmbedMap);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment