map/load-app.js

212 lines
5 KiB
JavaScript
Raw Normal View History

2025-02-09 19:55:34 +00:00
import show_error from './show-error.mjs';
import * as marked from './marked.js';
console.clear();
window.marked = marked;
class MarkdownElement extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
const shadowRoot = this.attachShadow({mode:'open'});
const markdown_changed = () => {
const html = marked.parse(this.textContent);
shadowRoot.innerHTML = html;
for(let a of shadowRoot.querySelectorAll('a')) {
a.setAttribute('target','_blank');
}
}
const observer = new MutationObserver(markdown_changed);
observer.observe(this, {characterData: true, subtree: true});
markdown_changed();
}
}
customElements.define('mark-down', MarkdownElement);
class LeafletElement extends HTMLElement {
constructor() {
super();
}
addStylesheet(url) {
const linkElem = document.createElement("link");
linkElem.setAttribute("rel", "stylesheet");
linkElem.setAttribute("href", url);
this.shadowRoot.append(linkElem);
}
connectedCallback() {
const shadowRoot = this.attachShadow({mode:'open'});
this.addStylesheet("https://unpkg.com/leaflet@1.9.4/dist/leaflet.css");
this.addStylesheet('map.css');
const div = this.div = document.createElement('div');
div.style.height = '100%';
shadowRoot.append(div);
const map = this.map = L.map(div);
this.markers = [];
this.update_view();
this.update_markers();
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
map.on('move', () => {
const {lat,lng} = map.getCenter();
})
map.on('click', e => {
const ce = new CustomEvent('mapclick', {detail: {latlng: e.latlng}});
this.dispatchEvent(ce);
})
map.on('move', e => {
this.dispatchEvent(new CustomEvent('mapmove'));
})
}
static get observedAttributes() { return ['lat', 'lon', 'markers'] };
update_view() {
const centre = this.getAttribute('centre') == 'true';
const home = ['lat','lon'].map(a => parseFloat(this.getAttribute(a)) || 0);
if(centre) {
this.map.setView(home, this.map.getZoom() || 13);
}
}
update_markers() {
this.markers.forEach(m => {
m.marker.remove();
})
const data = JSON.parse(this.getAttribute('markers'));
this.markers = data.map(({id,pos,icon}) => {
const marker = L.marker(
pos,
{
icon: L.divIcon({html: `<span id="${id}">${icon}</span>`}),
iconSize: [20,20]
}
);
marker.addTo(this.map);
marker.on('click', e => {
this.dispatchEvent(new CustomEvent('markerclick', {detail: {id}}));
})
return {pos, marker};
});
}
attributeChangedCallback(name, oldValue, newValue) {
if(!this.map) {
return;
}
switch(name) {
case 'lat':
case 'lon':
case 'centre':
this.update_view();
break;
case 'markers':
this.update_markers();
break;
}
}
set html(value) {
this.shadowRoot.innerHTML = value;
}
}
customElements.define('leaflet-map', LeafletElement);
let opfs;
try {
opfs = await navigator.storage.getDirectory();
} catch(e) {
}
2025-02-09 19:55:34 +00:00
async function init_app() {
const compilation_error = await show_error;
if(compilation_error) {
return;
}
const params = (new URL(window.location)).searchParams;
console.log(params);
let map_id = params.get('map') || '';
if(!map_id) {
map_id = Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16).padStart(8,'0').slice(0,8);
}
2025-02-09 19:55:34 +00:00
let markers = [];
try {
markers = await (await fetch(`data/markers-${map_id}.json`)).json();
2025-02-09 19:55:34 +00:00
} catch(e) {
try {
const fh = await opfs.getFileHandle(`markers-${map_id}.json`);
2025-02-09 19:55:34 +00:00
const f = await fh.getFile();
markers = JSON.parse(await f.text())
} catch(e) {
}
}
const emoji = await (await fetch('emoji_metadata.json')).json();
const app = Elm.App.init({
node: document.body,
flags: {emoji, markers, map_id}
});
2025-02-09 19:55:34 +00:00
navigator.geolocation.watchPosition(
(r) => {
app.ports.receive_position.send(r.coords);
},
(e) => console.error(e),
{enableHighAccuracy: true}
);
const send_value_handlers = {
save: async ({markers}) => {
try {
const f = await opfs.getFileHandle(`markers-${map_id}.json`, {create:true});
const w = await f.createWritable();
await w.write(JSON.stringify(markers));
await w.close();
} catch(e) {
}
2025-02-09 19:55:34 +00:00
const fd = new FormData();
fd.set('content', JSON.stringify(markers));
fd.set('map_id', map_id);
2025-02-09 19:55:34 +00:00
fetch('cgi-bin/save_data.py', {
method: 'POST',
body: fd
})
}
}
app.ports.send_value.subscribe(msg => {
send_value_handlers[msg.type](msg);
});
}
init_app();