I want to draw a custom map and perform searches based on longitude and latitude using the Google Maps API. My goal is to design a search functionality similar to Google Maps for my project. I have already applied the code available in the Google Places API documentation. Is it possible to achieve this?
<script src="https://maps.googleapis.com/maps/api/js?key=&callback=initMap&libraries=places&v=weekly" defer></script>
<script>
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
zoom: countries["in"].zoom,
center: countries["in"].center,
mapTypeControl: false,
panControl: false,
zoomControl: false,
streetViewControl: false,
});
infoWindow = new google.maps.InfoWindow({
content: document.getElementById("info-content"),
});
autocomplete = new google.maps.places.Autocomplete(document.getElementById("autocomplete"), {
types: ["establishment"],
componentRestrictions: countryRestrict,
fields: ["geometry", "address_components", "name", "types"],
});
places = new google.maps.places.PlacesService(map);
autocomplete.addListener("place_changed", onPlaceChanged);
document.getElementById("country").addEventListener("change", setAutocompleteCountry);
}
function onPlaceChanged() {
const place = autocomplete.getPlace();
if (place.geometry && place.geometry.location) {
map.panTo(place.geometry.location);
map.setZoom(15);
// Extract the postal code, address, name, and category from the place object
let postalCode = '';
let address = '';
let name = place.name || '';
let category = 'travel_agency'; // Default category
let keywords = ''; // Can be extracted or set based on the place
// Iterate over address components to find postal code and address
if (place.address_components) {
for (const component of place.address_components) {
if (component.types.includes('postal_code')) {
postalCode = component.long_name;
}
if (component.types.includes('route') || component.types.includes('street_address')) {
address += component.long_name + ' ';
}
}
}
// Call the search function with extracted values
search(name, postalCode.trim(), address.trim(), category, keywords);
} else {
document.getElementById("autocomplete").placeholder = "Enter a city or establishment";
}
}
// Search for places based on the extracted details
function search(name, postalCode, address, category, keywords) {
const query = `${name} ${postalCode} ${address} ${keywords} ${category}`;
const search = {
query: query,
bounds: map.getBounds(),
};
places.textSearch(search, (results, status) => {
if (status === google.maps.places.PlacesServiceStatus.OK && results) {
clearResults();
clearMarkers();
// Create a marker for each place found, and assign a letter of the alphabetic to each marker icon.
for (let i = 0; i < results.length; i++) {
const markerLetter = String.fromCharCode("A".charCodeAt(0) + (i % 26));
const markerIcon = MARKER_PATH + markerLetter + ".png";
// Use marker animation to drop the icons incrementally on the map.
markers[i] = new google.maps.Marker({
position: results[i].geometry.location,
animation: google.maps.Animation.DROP,
icon: markerIcon,
});
// If the user clicks a place marker, show the details of that place in an info window.
markers[i].placeResult = results[i];
google.maps.event.addListener(markers[i], "click", showInfoWindow);
setTimeout(dropMarker(i), i * 100);
addResult(results[i], i);
}
}
});
}
function clearMarkers() {
for (let i = 0; i < markers.length; i++) {
if (markers[i]) {
markers[i].setMap(null);
}
}
markers = [];
}
// Set the country restriction based on user input.
// Also center and zoom the map on the given country.
function setAutocompleteCountry() {
const country = document.getElementById("country").value;
if (country == "all") {
autocomplete.setComponentRestrictions({ country: [] });
map.setCenter({ lat: 15, lng: 0 });
map.setZoom(2);
} else {
autocomplete.setComponentRestrictions({ country: country });
map.setCenter(countries[country].center);
map.setZoom(countries[country].zoom);
}
clearResults();
clearMarkers();
}
function dropMarker(i) {
return function () {
markers[i].setMap(map);
};
}
// list data for all results
function addResult(result, i) {
const results = document.getElementById("results");
const markerLetter = String.fromCharCode("A".charCodeAt(0) + (i % 26));
const markerIcon = MARKER_PATH + markerLetter + ".png";
const tr = document.createElement("tr");
tr.style.backgroundColor = i % 2 === 0 ? "#F0F0F0" : "#FFFFFF";
tr.onclick = function () {
google.maps.event.trigger(markers[i], "click");
};
const iconTd = document.createElement("td");
const nameTd = document.createElement("td");
const icon = document.createElement("img");
icon.src = markerIcon;
icon.setAttribute("class", "placeIcon");
icon.setAttribute("className", "placeIcon");
const name = document.createTextNode(result.name);
iconTd.appendChild(icon);
nameTd.appendChild(name);
tr.appendChild(iconTd);
tr.appendChild(nameTd);
results.appendChild(tr);
}
function clearResults() {
const results = document.getElementById("results");
while (results.childNodes[0]) {
results.removeChild(results.childNodes[0]);
}
}
// Get the place details for a hotel. Show the information in an info window,
// anchored on the marker for the hotel that the user selected.
function showInfoWindow() {
// @ts-ignore
const marker = this;
places.getDetails({ placeId: marker.placeResult.place_id }, (place, status) => {
if (status !== google.maps.places.PlacesServiceStatus.OK) {
return;
}
infoWindow.open(map, marker);
buildIWContent(place);
});
}
// Load the place information into the HTML elements used by the info window.
function buildIWContent(place) {
document.getElementById("iw-icon").innerHTML = '<img class="hotelIcon" ' + 'src="' + place.icon + '"/>';
document.getElementById("iw-url").innerHTML = '<b><a href="' + place.url + '">' + place.name + "</a></b>";
document.getElementById("iw-address").textContent = place.vicinity;
if (place.formatted_phone_number) {
document.getElementById("iw-phone-row").style.display = "";
document.getElementById("iw-phone").textContent = place.formatted_phone_number;
} else {
document.getElementById("iw-phone-row").style.display = "none";
}
if (place.rating) {
let ratingHtml = "";
for (let i = 0; i < 5; i++) {
if (place.rating < i + 0.5) {
ratingHtml += "✩";
} else {
ratingHtml += "✭";
}
document.getElementById("iw-rating-row").style.display = "";
document.getElementById("iw-rating").innerHTML = ratingHtml;
}
} else {
document.getElementById("iw-rating-row").style.display = "none";
}
// The regexp isolates the first part of the URL (domain plus subdomain)
// to give a short URL for displaying in the info window.
if (place.website) {
let fullUrl = place.website;
let website = String(hostnameRegexp.exec(place.website));
if (!website) {
website = "http://" + place.website + "/";
fullUrl = website;
}
document.getElementById("iw-website-row").style.display = "";
document.getElementById("iw-website").textContent = website;
} else {
document.getElementById("iw-website-row").style.display = "none";
}
}
window.initMap = initMap;
$(document).ready(function () {
$("#results").on("click", "td", function () {
var agency_name = $(this).closest("tr").find("td:nth-child(2)").text().trim();
if (agency_name) {
$.ajax({
method: "GET",
url: "{{ url('bdm/get-agent-list') }}",
data: {
agencyName: agency_name,
},
success: function (response) {
// Clear previous agency name and update with the new one
$('.agency_name').text(agency_name);
// Show the modal
$('#agentModal').modal('show');
// Clear previous table data
var table = $(".datatable").DataTable();
table.clear().draw();
// Populate the table with new data
addRowToTable(response);
},
error: function (jqXHR, textStatus, errorThrown) {
$(".error").append([textStatus, errorThrown]);
},
});
}
});
// Function to fetch the list of agent draw each row from according to selected location
function addRowToTable(response) {
var table = $(".datatable").DataTable();
$.each(response.agent_list, function (index, value) {
// intializing action btn
var createMeeting = "<a href='{{ url('branch-visit/create') }}/?agent_id=" + value.id + "' class='btn btn-sm btn-success create-meeting-btn' target='_blank'>Create Meeting</a>";
// Add the new row to the table
table.row
.add([
index + 1, // Serial number
value.first_name, // Agent name
createMeeting, // Action buttons
])
.draw(false); // Draw the table without resetting the pagination
});
}
});
</script>