From 9826f3fd7046292b242ead77d3c8e334d0361915 Mon Sep 17 00:00:00 2001 From: Eli Ribble Date: Tue, 3 Mar 2026 23:42:24 +0000 Subject: [PATCH] Show map marker for property location --- html/static/js/map-locator-ro.js | 125 +++++++++++++++++++++++++++++ html/template/rmo/mailer/root.html | 7 +- rmo/mailer.go | 2 + 3 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 html/static/js/map-locator-ro.js diff --git a/html/static/js/map-locator-ro.js b/html/static/js/map-locator-ro.js new file mode 100644 index 00000000..6ad4278c --- /dev/null +++ b/html/static/js/map-locator-ro.js @@ -0,0 +1,125 @@ +// A map that can be used to locate a single point by setting its location explicitly +// or by allowing the user to move a marker. +class MapLocatorReadOnly extends HTMLElement { + constructor() { + super(); + + // Create a shadow DOM + this.attachShadow({ mode: "open" }); + + // Initial render + this.render(); + + // markers shown on the map. Should be none or 1, generally. + this._markers = []; + } + + // 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() { + console.log("Setting up the locator read-only..."); + const marker_str = this.getAttribute("marker"); + const marker = JSON.parse(marker_str); + + const mapElement = this.shadowRoot.querySelector("#map"); + this._map = new maplibregl.Map({ + container: mapElement, + center: marker.coordinates, + style: "https://tiles.stadiamaps.com/styles/alidade_smooth.json", + zoom: 16, + }); + this._map.on("load", () => { + console.log("map locator read-only loaded"); + const m = new maplibregl.Marker({ + color: "#FF0000", + draggable: true, + }) + .setLngLat(marker.coordinates) + .addTo(this._map); + this.dispatchEvent(markerDraggedEvent); + this.dispatchEvent( + new CustomEvent("load", { + bubbles: true, + composed: true, // Allows event to cross shadow DOM boundary + detail: { + map: this, + }, + }), + ); + }); + this._map.on("zoomend", (e) => { + this.dispatchEvent( + new CustomEvent("zoomend", { + bubbles: true, + composed: true, + detail: e, + }), + ); + }); + } + + // Initial render of component + render() { + this.shadowRoot.innerHTML = ` + + +
+ `; + } + + GetZoom() { + return this._map.getZoom(); + } + + JumpTo(args) { + this._map.jumpTo(args); + } + + PanTo(coords, options) { + this._map.panTo(coords, options); + } + + SetMarker(coords) { + console.log("Setting map marker", coords); + this._markers.forEach((marker) => marker.remove()); + + const marker = new maplibregl.Marker({ + color: "#FF0000", + draggable: true, + }) + .setLngLat(coords) + .addTo(this._map); + marker.on("dragend", (e) => { + const markerDraggedEvent = new CustomEvent("markerdragend", { + detail: { + marker: marker, + }, + }); + this.dispatchEvent(markerDraggedEvent); + }); + this._markers = [marker]; + } +} + +customElements.define("map-locator-ro", MapLocatorReadOnly); diff --git a/html/template/rmo/mailer/root.html b/html/template/rmo/mailer/root.html index 62ed146b..e9951070 100644 --- a/html/template/rmo/mailer/root.html +++ b/html/template/rmo/mailer/root.html @@ -6,7 +6,7 @@ type="text/javascript" src="//unpkg.com/maplibre-gl@5.0.1/dist/maplibre-gl.js" > - +