nidus-sync/static/js/map-proxied-arcgis-tile.js
Eli Ribble 31947c848a
Move static outside HTML. Start work on TypeScript bundle
It's not strictly HTML, so that's just correct.

This is just worth doing while building the new TypeScript bundle
2026-03-21 03:06:59 +00:00

167 lines
4 KiB
JavaScript

// A map that shows multiple single point locations.
// Points have additional detail popups.
// The background layer is proxied from Arcgis
class MapProxiedArcgisTile extends HTMLElement {
static observedAttributes = ["latitude", "longitude"];
constructor() {
super();
// Create a shadow DOM
this.attachShadow({ mode: "open" });
// Initial render
this.render();
// Keep track of any 'on' calls to add to the map as soon as we create it.
this._preOns = [];
this._map = null;
this._markers = [];
}
attributeChangedCallback(name, old_value, new_value) {
//console.log("map-arcgis-tile: attribute changed", name, old_value, new_value);
if ((name == "latitude" || name == "longitude") && this._map != null) {
const latitude = parseFloat(this.getAttribute("latitude"));
const longitude = parseFloat(this.getAttribute("longitude"));
this._map.jumpTo({
center: [longitude, latitude],
zoom: 19,
});
}
}
// Lifecycle: when element is added to the DOM
connectedCallback() {
// Initialize the map when the element is added to the DOM
setTimeout(() => this._initializeMap(), 0);
}
disconnectedCallback() {
if (this._map) {
this._map.remove();
}
}
_initializeMap() {
const latitude = parseFloat(this.getAttribute("latitude"));
const longitude = parseFloat(this.getAttribute("longitude"));
const organization_id = Number(this.getAttribute("organization-id") || 0);
const tegola = this.getAttribute("tegola");
const url_tiles = this.getAttribute("url-tiles");
const mapElement = this.shadowRoot.querySelector("#map");
this._map = new maplibregl.Map({
center: [longitude, latitude],
container: mapElement,
style: "https://tiles.stadiamaps.com/styles/osm_bright.json",
zoom: 19,
});
this._map.on("load", () => {
if (organization_id != 0) {
this._map.addSource("tegola", {
type: "vector",
tiles: [
`${tegola}maps/nidus/{z}/{x}/{y}?id=${organization_id}&organization_id=${organization_id}`,
],
});
this._map.addLayer({
id: "service-area",
source: "tegola",
"source-layer": "service-area-bounds",
type: "line",
paint: {
"line-color": "#f00",
},
});
}
this._map.addSource("flyover", {
type: "raster",
tiles: [url_tiles],
});
this._map.addLayer({
id: "flyover-layer",
source: "flyover",
type: "raster",
});
this.dispatchEvent(new CustomEvent("load"), {
bubbles: true,
composed: true, // Allows event to cross shadow DOM boundary
detail: {
map: this,
},
});
this._map.on("click", (e) => {
this.dispatchEvent(
new CustomEvent("map-click", {
bubbles: true,
composed: true,
detail: {
lng: e.lngLat.lng,
lat: e.lngLat.lat,
map: this,
point: e.point,
},
}),
);
});
});
for (const on of this._preOns) {
this._map.on(...on);
}
}
// Initial render of component
render() {
this.shadowRoot.innerHTML = `
<style>
@import url("//unpkg.com/maplibre-gl@5.0.1/dist/maplibre-gl.css");
#map {
height: 100%;
width: 100%;
}
</style>
<div id="map"></div>
`;
}
addLayer(a) {
return this._map.addLayer(a);
}
addSource(a, b) {
return this._map.addSource(a, b);
}
jumpTo(args) {
return this._map.jumpTo(args);
}
on(...args) {
if (this._map != null) {
return this._map.on(...args);
} else {
this._preOns.push(args);
}
}
once(a, b) {
return this._map.once(a, b);
}
queryRenderedFeatures(a) {
return this._map.queryRenderedFeatures(a);
}
FitBounds(bounds, options) {
return this._map.fitBounds(bounds, options);
}
SetLayoutProperty(layout, property, value) {
return this._map.setLayoutProperty(layout, property, value);
}
SetMarkers(markers) {
console.log("Setting map markers", markers);
this._markers.forEach((marker) => marker.remove());
this._markers = markers;
for (let m of markers) {
m.addTo(this._map);
}
}
}
customElements.define("map-proxied-arcgis-tile", MapProxiedArcgisTile);