1/** 2 * Map functionality using Leaflet and OpenStreetMap 3 * No API key required - completely free! 4 */ 5 6class DomicMaps { 7 constructor() { 8 this.maps = new Map(); 9 this.init(); 10 } 11 12 init() { 13 // Wait for DOM to be ready 14 if (document.readyState === 'loading') { 15 document.addEventListener('DOMContentLoaded', () => this.initializeMaps()); 16 } else { 17 this.initializeMaps(); 18 } 19 } 20 21 initializeMaps() { 22 // Find all map containers 23 const mapContainers = document.querySelectorAll('.form-map'); 24 25 mapContainers.forEach(container => { 26 this.initializeMap(container); 27 }); 28 } 29 30 async initializeMap(container) { 31 const address = container.getAttribute('data-address'); 32 const zoom = parseInt(container.getAttribute('data-zoom')) || 13; 33 const mapId = container.id; 34 35 if (!address) { 36 console.warn('No address provided for map:', mapId); 37 return; 38 } 39 40 try { 41 // Try to geocode the address 42 const coordinates = await this.geocodeAddress(address); 43 44 if (coordinates) { 45 this.createMap(container, coordinates, zoom); 46 } else { 47 this.showError(container, 'Could not find location for: ' + address); 48 } 49 } catch (error) { 50 console.error('Error initializing map:', error); 51 this.showError(container, 'Error loading map'); 52 } 53 } 54 55 async geocodeAddress(address) { 56 // Check if address is already coordinates (lat,lng format) 57 const coordMatch = address.match(/^(-?\d+\.?\d*),\s*(-?\d+\.?\d*)$/); 58 if (coordMatch) { 59 return { 60 lat: parseFloat(coordMatch[1]), 61 lng: parseFloat(coordMatch[2]) 62 }; 63 } 64 65 // Use Nominatim geocoding service (free, no API key required) 66 const encodedAddress = encodeURIComponent(address); 67 const url = `https://nominatim.openstreetmap.org/search?format=json&q=${encodedAddress}&limit=1`; 68 69 try { 70 const response = await fetch(url, { 71 headers: { 72 'User-Agent': 'Domic WordPress Theme ([email protected])' // Be polite to Nominatim 73 } 74 }); 75 76 if (!response.ok) { 77 throw new Error(`HTTP error! status: ${response.status}`); 78 } 79 80 const data = await response.json(); 81 82 if (data && data.length > 0) { 83 return { 84 lat: parseFloat(data[0].lat), 85 lng: parseFloat(data[0].lon) 86 }; 87 } 88 89 return null; 90 } catch (error) { 91 console.error('Geocoding error:', error); 92 return null; 93 } 94 } 95 96 createMap(container, coordinates, zoom) { 97 // Create the map 98 const map = L.map(container).setView([coordinates.lat, coordinates.lng], zoom); 99 100 // Add OpenStreetMap tile layer 101 // You can easily switch to different tile providers here for different styles: 102 103 // Option 1: Standard OpenStreetMap (current) 104 // L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { 105 // attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', 106 // maxZoom: 19 107 // }).addTo(map); 108 109 // Option 2: CartoDB Positron (minimal, light) 110 L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', { 111 attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>', 112 maxZoom: 19 113 }).addTo(map); 114 115 // Option 3: CartoDB Voyager (minimal, balanced) 116 // L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png', { 117 // attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>', 118 // maxZoom: 19 119 // }).addTo(map); 120 121 // Add a marker at the location 122 const marker = L.marker([coordinates.lat, coordinates.lng]).addTo(map); 123 124 // Store the map instance 125 this.maps.set(container.id, { 126 map: map, 127 marker: marker, 128 coordinates: coordinates 129 }); 130 131 // Add resize observer to handle container size changes 132 if (window.ResizeObserver) { 133 const resizeObserver = new ResizeObserver(() => { 134 map.invalidateSize(); 135 }); 136 resizeObserver.observe(container); 137 } 138 } 139 140 showError(container, message) { 141 container.innerHTML = ` 142 <div class="map-error"> 143 <p><strong>Map Error:</strong> ${message}</p> 144 <p>Please check the address and try again.</p> 145 </div> 146 `; 147 } 148 149 // Public method to get map instance 150 getMap(containerId) { 151 return this.maps.get(containerId); 152 } 153 154 // Public method to update map location 155 async updateMapLocation(containerId, newAddress) { 156 const mapData = this.maps.get(containerId); 157 if (!mapData) return false; 158 159 try { 160 const coordinates = await this.geocodeAddress(newAddress); 161 if (coordinates) {
162 mapData.map.setView([coordinates.lat, coordinates.lng]); 163 mapData.marker.setLatLng([coordinates.lat, coordinates.lng]); 164 mapData.coordinates = coordinates; 165 return true; 166 } 167 } catch (error) { 168 console.error('Error updating map location:', error); 169 } 170 171 return false; 172 } 173} 174 175// Initialize when script loads 176document.addEventListener('DOMContentLoaded', () => { 177 window.domicMaps = new DomicMaps(); 178}); 179 180// Also make it available globally for potential external use 181window.DomicMaps = DomicMaps;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.