// The API Key provided is restricted to JSFiddle website // Get your own API Key on https://myprojects.geoapify.com const myAPIKey = "6dc7fb95a3b246cfa0f3bcef5ce9ed9a"; // Create a Leaflet map const map = L.map('address-map').setView([50, 10], 5); // Retina displays require different mat tiles quality const isRetina = L.Browser.retina; const baseUrl = "https://maps.geoapify.com/v1/tile/osm-bright/{z}/{x}/{y}.png?apiKey={apiKey}"; const retinaUrl = "https://maps.geoapify.com/v1/tile/osm-bright/{z}/{x}/{y}@2x.png?apiKey={apiKey}"; // add Geoapify attribution map.attributionControl.setPrefix('Powered by <a href="https://www.geoapify.com/" target="_blank">Geoapify</a>') // Add map tiles layer. Set 20 as the maximal zoom and provide map data attribution. L.tileLayer(isRetina ? retinaUrl : baseUrl, { attribution: '<a href="https://openmaptiles.org/" target="_blank">© OpenMapTiles</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a> contributors', apiKey: myAPIKey, maxZoom: 20, id: 'osm-bright', }).addTo(map); // move zoom controls to bottom right map.zoomControl.remove(); L.control.zoom({ position: 'bottomright' }).addTo(map); const autocompleteInput = new autocomplete.GeocoderAutocomplete( document.getElementById("autocomplete"), myAPIKey, { lang: 'en', allowNonVerifiedHouseNumber: true, allowNonVerifiedStreet: true, skipDetails: true }); let selectedLocation; let locationNeedToBeClarified; let suggestedLocation; let locationMarker; autocompleteInput.on('select', (location) => { selectLocation(location); }); map.on('click', (event) => { if (!selectedLocation || locationNeedToBeClarified) { getAddressByLatLon(event.latlng.lat, event.latlng.lng).then(location => { if (selectedLocation) { if (locationMarker) { locationMarker.setLatLng(event.latlng); } suggestedLocation = location; updateAddressInfo(); } else { if (location) { autocompleteInput.setValue(location.properties.formatted); selectLocation(location); } } }); } }); function selectLocation(location) { cleanUp(); // check selected location here selectedLocation = location; if (location) { locationNeedToBeClarified = (location.properties.nonVerifiedParts && location.properties.nonVerifiedParts.length) || !location.properties.housenumber; } zoomMap(); showLocationMarker(); updateAddressInfo(); } function cleanUp() { if (locationMarker) { locationMarker.remove(); locationMarker = null; } locationNeedToBeClarified = false; suggestedLocation = false; } function zoomMap(location) { if (selectedLocation) { let zoom = selectedLocation.properties.street ? 17 : 12; zoom = Math.max(map.getZoom(), zoom); map.flyTo([selectedLocation.properties.lat, selectedLocation.properties.lon], zoom, { duration: 0.1 }) } } // add a marker with icon generated by Geoapify Marker Icon API // https://apidocs.geoapify.com/playground/icon/ const markerWarningIcon = L.icon({ iconUrl: `https://api.geoapify.com/v1/icon/?type=awesome&color=%23ffd14e&size=large&icon=question&noWhiteCircle&scaleFactor=2&apiKey=${myAPIKey}`, iconSize: [38, 56], // size of the icon iconAnchor: [18, 51], // point of the icon which will correspond to marker's location popupAnchor: [0, -57] // point from which the popup should open relative to the iconAnchor }); const markerOkIcon = L.icon({ iconUrl: `https://api.geoapify.com/v1/icon/?type=awesome&color=%2330e970&size=large&icon=check&noWhiteCircle&scaleFactor=2&apiKey=${myAPIKey}`, iconSize: [38, 56], // size of the icon iconAnchor: [18, 51], // point of the icon which will correspond to marker's location popupAnchor: [0, -57] // point from which the popup should open relative to the iconAnchor }); function showLocationMarker() { if (!selectedLocation) return; locationMarker = L.marker([selectedLocation.properties.lat, selectedLocation.properties.lon], { icon: locationNeedToBeClarified ? markerWarningIcon : markerOkIcon, draggable: locationNeedToBeClarified }).addTo(map); if (locationNeedToBeClarified) { // You can also use a tap event with a timeout for touch devices - https://stackoverflow.com/a/56427428 locationMarker.on('dragend', (event) => { getAddressByLatLon(locationMarker.getLatLng().lat, locationMarker.getLatLng().lng).then(address => { suggestedLocation = address; updateAddressInfo(); }); }) } } function updateAddressInfo() { const infoRow = document.getElementById("info"); const warningInfoRow = document.getElementById("warning-info"); const acceptLocationRow = document.getElementById("accept-location"); const acceptAddressRow = document.getElementById("accept-address"); const newAddress = document.getElementById("new-address"); let toHide = [infoRow, warningInfoRow, acceptLocationRow, acceptAddressRow]; let toShow = []; if (!location) { toHide = [warningInfoRow, acceptLocationRow, acceptAddressRow]; toShow = [infoRow]; } else if (location && !locationNeedToBeClarified) { toHide = [infoRow, warningInfoRow, acceptLocationRow, acceptAddressRow]; } else if (location && locationNeedToBeClarified && !suggestedLocation) { toHide = [infoRow, acceptLocationRow, acceptAddressRow]; toShow = [warningInfoRow]; } else if (location && locationNeedToBeClarified && suggestedLocation && suggestedLocation.properties.distance === 0) { toHide = [infoRow, acceptLocationRow]; toShow = [warningInfoRow, acceptAddressRow]; newAddress.textContent = suggestedLocation.properties.formatted; } else if (location && locationNeedToBeClarified && suggestedLocation && suggestedLocation.properties.distance > 0) { toHide = [infoRow, acceptAddressRow]; toShow = [warningInfoRow, acceptLocationRow]; } toHide.forEach(element => element.classList.add("hidden")); toShow.forEach(element => element.classList.remove("hidden")); } function getAddressByLatLon(lat, lon) { return fetch(`https://api.geoapify.com/v1/geocode/reverse?lat=${lat}&lon=${lon}&apiKey=${myAPIKey}`).then(result => result.json()).then(result => { if (result && result.features && result.features.length) { return result.features[0]; } return null; }); } function acceptLocation() { selectedLocation.properties.original_lon = selectedLocation.properties.lon; selectedLocation.properties.lon = locationMarker.getLatLng().lng; selectedLocation.properties.original_lat = selectedLocation.properties.lat; selectedLocation.properties.lat = locationMarker.getLatLng().lng; locationNeedToBeClarified = false; suggestedLocation = null; locationMarker.setIcon(markerOkIcon); locationMarker.dragging.disable(); updateAddressInfo(); } function acceptAddress() { autocompleteInput.setValue(suggestedLocation.properties.formatted); selectedLocation = suggestedLocation; locationNeedToBeClarified = false; suggestedLocation = null; locationMarker.setIcon(markerOkIcon); locationMarker.dragging.disable(); updateAddressInfo(); }
<div id="autocomplete" class="autocomplete-container"></div> <div id="address-map" class="map-container"></div> <div id="messages" class="messages-container"> <div id="info" class="message-row">Please enter your address in the input field below or click on the map to get the address.</div> <div id="warning-info" class="message-row warning hidden">The house number or street is missing. Drag the marker to the correct location to clarify.</div> <div id="accept-location" class="message-row hidden">Would you like to accept the address's new location? <button onclick="acceptLocation()">Yes</button></div> <div id="accept-address" class="message-row hidden">You are located at the following address: <span id="new-address"></span> <br/> Do you want to accept this address? <button onclick="acceptAddress()">Yes</button></div> </div>