From 749f8aaec79154e279583e7d2d9f5562bc3b4527 Mon Sep 17 00:00:00 2001 From: Eli Ribble Date: Wed, 14 Jan 2026 20:14:58 +0000 Subject: [PATCH] Initial work on creating custom map component This isn't done, I'm just shifting gears. --- htmlpage/static/js/address-suggestion.js | 27 --- htmlpage/static/js/map-locator.js | 215 +++++++++++++++++++++++ htmlpage/static/js/map.js | 62 ------- public-report/template/pool.html | 50 ++---- 4 files changed, 227 insertions(+), 127 deletions(-) create mode 100644 htmlpage/static/js/map-locator.js delete mode 100644 htmlpage/static/js/map.js diff --git a/htmlpage/static/js/address-suggestion.js b/htmlpage/static/js/address-suggestion.js index 8b63b3df..29a1ce91 100644 --- a/htmlpage/static/js/address-suggestion.js +++ b/htmlpage/static/js/address-suggestion.js @@ -197,30 +197,3 @@ class AddressInput extends HTMLElement { } customElements.define('address-input', AddressInput); - -function setLocationInputs(suggestion) { - let address = document.getElementById('address'); - let country = document.getElementById('address-country'); - let latitude = document.getElementById('latitude'); - let longitude = document.getElementById('longitude'); - let latlngAccuracyType = document.getElementById('latlng-accuracy-type'); - let postcode = document.getElementById('address-postcode'); - let place = document.getElementById('address-place'); - let region = document.getElementById('address-region'); - let street = document.getElementById('address-street'); - - // Extract context data from properties - const props = suggestion.properties; - const context = props.context || {}; - - // Populate structured fields - address.value = props.full_address; - country.value = context.country.name; - latitude.value = props.coordinates.latitude; - longitude.value = props.coordinates.longitude; - latlngAccuracyType.value = props.coordinates.accuracy; - postcode.value = context.postcode.name; - place.value = context.place.name; - region.value = context.region.name; - street.value = context.country.name; -} diff --git a/htmlpage/static/js/map-locator.js b/htmlpage/static/js/map-locator.js new file mode 100644 index 00000000..d9c362b2 --- /dev/null +++ b/htmlpage/static/js/map-locator.js @@ -0,0 +1,215 @@ +var map = null; +// 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 MapLocator 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 = null; + } + + // 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', '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 === 'zoom') { + this._map.setZoom(Number(newValue)); + } + } + + _initializeMap() { + console.log("Setting up the map..."); + const lat = Number(this.getAttribute('latitude') || 36.2); + const lng = Number(this.getAttribute('longitude') || -119.2); + const zoom = Number(this.getAttribute('zoom') || 15); + + mapboxgl.accessToken = this._apiKey; + map = new mapboxgl.Map({ + container: "map", + center: { + lat: lat, + lng: lng, + }, + style: 'mapbox://styles/mapbox/streets-v12', // style URL + zoom: zoom, + }); + map.addControl(new mapboxgl.GeolocateControl({ + positionOptions: { + enableHighAccuracy: true + }, + trackUserLocation: true, + showUserHeading: true + })); + map.addControl(new mapboxgl.NavigationControl()); + map.on("load", function() { + this.dispatchEvent(new CustomEvent('load') { + bubbles: true, + composed: true, // Allows event to cross shadow DOM boundary + detail: { + map: this + } + }); + }); + } + + async _fetchAddressSuggestions(text) { + try { + const url = `https://api.mapbox.com/search/geocode/v6/forward?q=${encodeURIComponent(text)}&access_token=${this._apiKey}`; + + const response = await fetch(url); + const data = await response.json(); + return data; + } catch (error) { + console.error('Error fetching geocoding suggestions:', error); + } + } + + _renderSuggestions(suggestions) { + console.log("Rendering suggestions", suggestions); + this._suggestions.innerHTML = suggestions.map((item, index) => { + if (item.properties.place_formatted != "") { + return ` +
+
${item.properties.name || item.properties.full_address}
+
${item.properties.place_formatted}
+
` + } else { + return ` +
+
${item.properties.name || item.properties.full_address}
+
${item.properties.place_formatted}
+
` + } + }).join(''); + + // Add click listeners to suggestions + this.shadowRoot.querySelectorAll('.suggestion-item').forEach(el => { + el.addEventListener('click', e => { + const index = parseInt(el.dataset.index); + const suggestion = suggestions[index]; + this.value = suggestion.properties.full_address; + this._suggestions.innerHTML = ''; + + // Dispatch custom event + this.dispatchEvent(new CustomEvent('address-selected', { + bubbles: true, + composed: true, // Allows event to cross shadow DOM boundary + detail: { + location: suggestion + } + })); + }); + }); + } + + // 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 mapboxgl.Marker({ + color: "#FF0000", + draggable: true + }).setLngLat(coords).addTo(map); + marker.on('dragend', function(e) { + const markerDraggedEvent = new CustomEvent("markerdragend", { + detail: { + marker: marker + } + }); + mapContainer.dispatchEvent(markerDraggedEvent); + }); + this._markers = [marker]; + } +} + +customElements.define('map-locator', MapLocator); + + + +function mapLoad(MAPBOX_ACCESS_TOKEN) { + return new Promise((resolve, reject) => { + }); +} diff --git a/htmlpage/static/js/map.js b/htmlpage/static/js/map.js deleted file mode 100644 index 3bdf7ace..00000000 --- a/htmlpage/static/js/map.js +++ /dev/null @@ -1,62 +0,0 @@ -var map = null; -var markers = []; - -function mapAddMarker(coords) { - const mapContainer = document.getElementById("map-container"); - const marker = new mapboxgl.Marker({ - color: "#FF0000", - draggable: true - }).setLngLat(coords).addTo(map); - marker.on('dragend', function(e) { - const markerDraggedEvent = new CustomEvent("markerdragend", { - detail: { - marker: marker - } - }); - mapContainer.dispatchEvent(markerDraggedEvent); - }); - markers.push(marker); -} - -function mapLoad(MAPBOX_ACCESS_TOKEN) { - return new Promise((resolve, reject) => { - console.log("Setting up the map..."); - mapboxgl.accessToken = MAPBOX_ACCESS_TOKEN; - map = new mapboxgl.Map({ - container: "map", - center: { - lat: 36.2, - lng: -119.2 - }, - style: 'mapbox://styles/mapbox/streets-v12', // style URL - zoom: 15, - }); - map.addControl(new mapboxgl.GeolocateControl({ - positionOptions: { - enableHighAccuracy: true - }, - trackUserLocation: true, - showUserHeading: true - })); - map.addControl(new mapboxgl.NavigationControl()); - map.on("load", function() { - console.log("Map loaded."); - resolve(map); - }); - }); -} - -function mapJumpTo(args) { - map.jumpTo(args); -} - -function mapSetMarker(coords) { - console.log("Setting map marker", coords); - map.jumpTo({ - center: coords, - zoom: 14, - }); - markers.forEach((marker) => marker.remove()); - mapAddMarker(coords); -} - diff --git a/public-report/template/pool.html b/public-report/template/pool.html index 70390fdf..d97f2423 100644 --- a/public-report/template/pool.html +++ b/public-report/template/pool.html @@ -8,7 +8,7 @@ - + {{template "photo-upload-header"}}