From 5b33b7ffcf2105d91d026b4903b577e61dbdd20f Mon Sep 17 00:00:00 2001 From: Eli Ribble Date: Mon, 16 Feb 2026 18:49:07 +0000 Subject: [PATCH] Switch cell detail page to libremap rendering --- html/static/js/map-cell.js | 167 ++++++++++++++++++++++++++ html/template/sync/cell.html | 31 ++--- html/template/sync/component/map.html | 87 -------------- html/template/sync/dashboard.html | 2 - scss/custom.scss | 1 + scss/sync/cell.scss | 12 ++ sync/cell.go | 102 ++++++++++++++++ sync/dash.go | 93 -------------- 8 files changed, 295 insertions(+), 200 deletions(-) create mode 100644 html/static/js/map-cell.js delete mode 100644 html/template/sync/component/map.html create mode 100644 scss/sync/cell.scss create mode 100644 sync/cell.go diff --git a/html/static/js/map-cell.js b/html/static/js/map-cell.js new file mode 100644 index 00000000..8e4dcea2 --- /dev/null +++ b/html/static/js/map-cell.js @@ -0,0 +1,167 @@ +var map = null; +// A map for showing a single h3 cell +class MapCell extends HTMLElement { + constructor() { + super(); + + // Create a shadow DOM + this.attachShadow({ mode: "open" }); + + this._markers = []; + // Initial render + this.render(); + } + + // 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(); + } + } + + // Lifecycle: watch these attributes for changes + static get observedAttributes() { + return [ + "api-key", + "latitude", + "longitude", + "organization-id", + "tegola", + "zoom", + ]; + } + + // Lifecycle: respond to attribute changes + attributeChangedCallback(name, oldValue, newValue) { + // Only handle if map exists and values actually changed + if (!this._map || oldValue === newValue) return; + + if (name === "api-key") { + this._apiKey = newValue; + } + + if (name === "latitude" || name === "longitude") { + if (this.hasAttribute("latitude") && this.hasAttribute("longitude")) { + const lat = Number(this.getAttribute("latitude")); + const lng = Number(this.getAttribute("longitude")); + this._map.setCenter([lat, lng]); + } + } + + if (name === "organization-id") { + this._organizationID = newValue; + } + + if (name === "tegola") { + this._tegola = newValue; + } + + if (name === "zoom") { + this._map.setZoom(Number(newValue)); + } + } + + _initializeMap() { + const geojson = JSON.parse(this.getAttribute("geojson")); + const lat = Number(this.getAttribute("latitude") || 36.2); + const lng = Number(this.getAttribute("longitude") || -119.2); + const organization_id = Number(this.getAttribute("organization-id") || 0); + const tegola = this.getAttribute("tegola"); + const zoom = Number(this.getAttribute("zoom") || 15); + + const mapElement = this.shadowRoot.querySelector("#map"); + this._map = new maplibregl.Map({ + container: mapElement, + center: { + lat: lat, + lng: lng, + }, + style: "https://tiles.stadiamaps.com/styles/alidade_smooth.json", + zoom: zoom, + }); + const layer_id = "geojson-layer"; + const source_id = "geojson-source"; + this._map.on("load", () => { + this._map.addSource(source_id, { + data: geojson, + type: "geojson", + }); + this._map.addLayer({ + id: layer_id, + interactive: false, + paint: { + "fill-opacity": 0.3, + "fill-color": "#dc3545", + }, + source: source_id, + type: "fill", + }); + }); + } + + // Initial render of component + render() { + this.shadowRoot.innerHTML = ` + + +
+
+
+ `; + } + + jumpTo(args) { + this._map.jumpTo(args); + } + + setMarker(coords) { + console.log("Setting map marker", coords); + this._map.jumpTo({ + center: coords, + zoom: 14, + }); + this._markers.forEach((marker) => marker.remove()); + + const marker = new maplibregl.Marker({ + color: "#FF0000", + draggable: true, + }) + .setLngLat(coords) + .addTo(this._map); + marker.on("dragend", function (e) { + const markerDraggedEvent = new CustomEvent("markerdragend", { + detail: { + marker: marker, + }, + }); + mapContainer.dispatchEvent(markerDraggedEvent); + }); + this._markers = [marker]; + } +} + +customElements.define("map-cell", MapCell); diff --git a/html/template/sync/cell.html b/html/template/sync/cell.html index a450448f..734870c1 100644 --- a/html/template/sync/cell.html +++ b/html/template/sync/cell.html @@ -2,21 +2,11 @@ {{ define "title" }}Dash{{ end }} {{ define "extraheader" }} - {{ template "map" .MapData }} - + + {{ end }} {{ define "content" }}
@@ -30,9 +20,14 @@
-
-
-
+
diff --git a/html/template/sync/component/map.html b/html/template/sync/component/map.html deleted file mode 100644 index 7f486c8c..00000000 --- a/html/template/sync/component/map.html +++ /dev/null @@ -1,87 +0,0 @@ -{{ define "sync/component/map.html" }} - - - - -{{ end }} diff --git a/html/template/sync/dashboard.html b/html/template/sync/dashboard.html index 7b841523..6fdcfb2d 100644 --- a/html/template/sync/dashboard.html +++ b/html/template/sync/dashboard.html @@ -7,7 +7,6 @@ src="//unpkg.com/maplibre-gl@5.0.1/dist/maplibre-gl.js" > -