Loading map...
Map failed to load.
// Configuration for Saudi Arabia
const SAUDI_CENTER = { lat: 24.7136, lng: 46.6753 }; // Riyadh coordinates
const SAUDI_BOUNDS = {
north: 32.154, south: 16.347,
east: 55.666, west: 34.632
};
// Global variables
let map, pickupMarker, dropMarker;
let directionsService, directionsRenderer;
let pickupAutocomplete, dropAutocomplete;
// Initialize the map
function initMap() {
try {
// Create map instance
map = new google.maps.Map(document.getElementById('route-map'), {
center: SAUDI_CENTER,
zoom: 12,
restriction: {
latLngBounds: SAUDI_BOUNDS,
strictBounds: false
},
gestureHandling: 'cooperative',
mapTypeControl: false,
streetViewControl: false,
fullscreenControl: true
});
// Initialize services
directionsService = new google.maps.DirectionsService();
directionsRenderer = new google.maps.DirectionsRenderer({
suppressMarkers: true,
polylineOptions: {
strokeColor: '#3750FF',
strokeOpacity: 1,
strokeWeight: 5
}
});
directionsRenderer.setMap(map);
// Create custom markers with new icons
pickupMarker = new google.maps.Marker({
position: SAUDI_CENTER,
map: map,
draggable: true,
icon: {
url: 'https://ahiluxurytravels.com/wp-content/uploads/2025/04/—Pngtree—car-top-view-image_8931232.png', // Google's default taxi icon
scaledSize: new google.maps.Size(40, 40), // Adjust size as needed
anchor: new google.maps.Point(20, 20) // Center of the image
},
zIndex: 100
});
dropMarker = createMarker(
{ lat: SAUDI_CENTER.lat + 0.01, lng: SAUDI_CENTER.lng + 0.01 },
'#3750FF', // Purple color
'drop',
'M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4z', // Smaller circle path
{
filled: true,
scale: 1.0, // Smaller scale for the dot
strokeWeight: 0 // No border
}
);
// Initialize autocomplete
initAutocomplete();
// Set current date as minimum for date picker
document.getElementById('pickup-date').min = new Date().toISOString().split('T')[0];
// Hide loading indicator
document.getElementById('map-loading').style.display = 'none';
// Initial route update
updateRoute();
} catch (error) {
console.error('Map initialization error:', error);
showMapError();
}
}
// Create custom marker with SVG icon
function createMarker(position, color, type, path) {
return new google.maps.Marker({
position: position,
map: map,
draggable: true,
icon: {
path: path,
fillColor: color,
fillOpacity: 1,
strokeColor: '#fff',
strokeWeight: 1,
scale: 1.5,
anchor: new google.maps.Point(12, 12)
},
zIndex: type === 'pickup' ? 100 : 99
});
}
// Initialize address autocomplete
function initAutocomplete() {
// Pickup location
const pickupInput = document.getElementById('pickup-location');
const pickupSuggestions = document.getElementById('pickup-suggestions');
pickupAutocomplete = new google.maps.places.Autocomplete(pickupInput, {
bounds: new google.maps.LatLngBounds(
new google.maps.LatLng(SAUDI_BOUNDS.south, SAUDI_BOUNDS.west),
new google.maps.LatLng(SAUDI_BOUNDS.north, SAUDI_BOUNDS.east)
),
componentRestrictions: { country: 'sa' },
fields: ['address_components', 'geometry', 'formatted_address']
});
pickupInput.addEventListener('input', function() {
if (this.value.length > 2) {
showPlaceSuggestions(this.value, pickupSuggestions, 'pickup');
} else {
pickupSuggestions.innerHTML = '';
}
});
pickupAutocomplete.addListener('place_changed', function() {
const place = pickupAutocomplete.getPlace();
if (place.geometry) {
pickupMarker.setPosition(place.geometry.location);
updateRoute();
map.panTo(place.geometry.location);
}
});
// Drop location
const dropInput = document.getElementById('drop-location');
const dropSuggestions = document.getElementById('drop-suggestions');
dropAutocomplete = new google.maps.places.Autocomplete(dropInput, {
bounds: new google.maps.LatLngBounds(
new google.maps.LatLng(SAUDI_BOUNDS.south, SAUDI_BOUNDS.west),
new google.maps.LatLng(SAUDI_BOUNDS.north, SAUDI_BOUNDS.east)
),
componentRestrictions: { country: 'sa' },
fields: ['address_components', 'geometry', 'formatted_address']
});
dropInput.addEventListener('input', function() {
if (this.value.length > 2) {
showPlaceSuggestions(this.value, dropSuggestions, 'drop');
} else {
dropSuggestions.innerHTML = '';
}
});
dropAutocomplete.addListener('place_changed', function() {
const place = dropAutocomplete.getPlace();
if (place.geometry) {
dropMarker.setPosition(place.geometry.location);
updateRoute();
map.panTo(place.geometry.location);
}
});
// Marker drag events
pickupMarker.addListener('dragend', function() {
updateAddressFromMarker(pickupMarker, 'pickup-location');
updateRoute();
});
dropMarker.addListener('dragend', function() {
updateAddressFromMarker(dropMarker, 'drop-location');
updateRoute();
});
}
// Show place suggestions
function showPlaceSuggestions(query, container, type) {
const service = new google.maps.places.AutocompleteService();
service.getPlacePredictions({
input: query,
componentRestrictions: { country: 'sa' },
bounds: new google.maps.LatLngBounds(
new google.maps.LatLng(SAUDI_BOUNDS.south, SAUDI_BOUNDS.west),
new google.maps.LatLng(SAUDI_BOUNDS.north, SAUDI_BOUNDS.east)
)
}, (predictions, status) => {
container.innerHTML = '';
if (status !== google.maps.places.PlacesServiceStatus.OK || !predictions) {
return;
}
predictions.slice(0, 5).forEach(prediction => {
const suggestion = document.createElement('div');
suggestion.className = 'suggestion-item';
suggestion.textContent = prediction.description;
suggestion.onclick = () => {
selectSuggestion(prediction.place_id, type);
container.innerHTML = '';
};
container.appendChild(suggestion);
});
});
}
// Select a suggestion
function selectSuggestion(placeId, type) {
const service = new google.maps.places.PlacesService(map);
const inputId = type + '-location';
service.getDetails({ placeId }, (place, status) => {
if (status === google.maps.places.PlacesServiceStatus.OK && place.geometry) {
document.getElementById(inputId).value = place.formatted_address;
if (type === 'pickup') {
pickupMarker.setPosition(place.geometry.location);
} else {
dropMarker.setPosition(place.geometry.location);
}
updateRoute();
map.panTo(place.geometry.location);
}
});
}
// Update address from marker position
function updateAddressFromMarker(marker, fieldId) {
const geocoder = new google.maps.Geocoder();
geocoder.geocode({
location: marker.getPosition(),
componentRestrictions: { country: 'sa' }
}, (results, status) => {
if (status === 'OK' && results[0]) {
document.getElementById(fieldId).value = results[0].formatted_address;
}
});
}
// Update the route between markers
function updateRoute() {
directionsService.route({
origin: pickupMarker.getPosition(),
destination: dropMarker.getPosition(),
travelMode: google.maps.TravelMode.DRIVING,
provideRouteAlternatives: false,
optimizeWaypoints: true
}, (response, status) => {
if (status === 'OK') {
directionsRenderer.setDirections(response);
// Adjust viewport to show the entire route
const bounds = new google.maps.LatLngBounds();
response.routes[0].legs.forEach(leg => {
bounds.union(leg.start_location);
bounds.union(leg.end_location);
});
map.fitBounds(bounds);
// Ensure zoom level isn't too close
if (map.getZoom() > 14) {
map.setZoom(14);
}
}
});
}
// Show map error
function showMapError() {
document.getElementById('map-loading').style.display = 'none';
document.getElementById('map-error').style.display = 'block';
document.getElementById('route-map').style.display = 'none';
}
// Retry loading map
function retryMapLoad() {
document.getElementById('map-error').style.display = 'none';
document.getElementById('map-loading').style.display = 'block';
document.getElementById('route-map').style.display = 'block';
loadGoogleMaps();
}
// Load Google Maps API
function loadGoogleMaps() {
const script = document.createElement('script');
script.src = `https://maps.googleapis.com/maps/api/js?key=AIzaSyDWT9zv0PDKFl2gQVEAOBa0DALrO9UvO1A&libraries=places&callback=initMap®ion=SA&language=en`;
script.async = true;
script.defer = true;
script.onerror = showMapError;
document.head.appendChild(script);
}
// Initialize when ready
if (document.readyState === 'complete') {
loadGoogleMaps();
} else {
window.addEventListener('load', loadGoogleMaps);
}
// Handle window resize
window.addEventListener('resize', function() {
if (map) {
google.maps.event.trigger(map, 'resize');
updateRoute();
}
});
// IMPROVED ADDRESS RESOLUTION FUNCTION
function updateAddressFromMarker(marker, fieldId) {
const geocoder = new google.maps.Geocoder();
geocoder.geocode({
location: marker.getPosition(),
componentRestrictions: { country: 'sa' }
}, (results, status) => {
if (status === 'OK' && results[0]) {
let address = results[0].formatted_address;
// 1. Check if address is just "Saudi Arabia"
if (address.trim() === "Saudi Arabia") {
// 2. Try to find a more detailed result
const detailedResult = results.find(r =>
r.formatted_address &&
!r.formatted_address.match(/^Saudi Arabia$/i)
);
// 3. If found, use that instead
if (detailedResult) {
address = detailedResult.formatted_address;
}
// 4. Otherwise build from components
else {
address = buildAddressFromComponents(results[0]);
}
}
// 5. Final fallback to coordinates if still vague
if (address.match(/^Saudi Arabia(,|$)/i)) {
const lat = marker.getPosition().lat().toFixed(4);
const lng = marker.getPosition().lng().toFixed(4);
address = ` ${lat}, ${lng}`;
}
document.getElementById(fieldId).value = address;
}
});
}
// HELPER FUNCTION TO BUILD ADDRESS FROM COMPONENTS
function buildAddressFromComponents(result) {
const components = result.address_components || [];
const parts = [];
// Street address components
const streetNum = components.find(c => c.types.includes('street_number'))?.long_name;
const route = components.find(c => c.types.includes('route'))?.long_name;
if (streetNum && route) parts.push(`${streetNum} ${route}`);
else if (route) parts.push(route);
// Area components
const neighborhood = components.find(c =>
c.types.includes('neighborhood') ||
c.types.includes('sublocality')
)?.long_name;
if (neighborhood) parts.push(neighborhood);
// City components
const city = components.find(c =>
c.types.includes('locality') ||
c.types.includes('administrative_area_level_2')
)?.long_name;
if (city) parts.push(city);
return parts.length > 0
? `${parts.join(', ')}, Saudi Arabia`
: 'Saudi Arabia';
}
document.addEventListener('DOMContentLoaded', function() {
// Handle form submission
const form = document.querySelector('.taxi-booking-form');
const submitBtn = document.querySelector('.submit-btn');
const preloader = document.getElementById('form-preloader');
if (form) {
form.addEventListener('submit', function(e) {
// Show loading state
submitBtn.classList.add('loading');
submitBtn.disabled = true;
preloader.style.display = 'flex';
// Optional: Hide after 5 seconds timeout (safety measure)
setTimeout(() => {
preloader.style.display = 'none';
submitBtn.classList.remove('loading');
submitBtn.disabled = false;
}, 5000);
});
}
// For CF7 forms specifically
document.addEventListener('wpcf7mailsent', function(event) {
// Hide preloader when mail is sent
preloader.style.display = 'none';
submitBtn.classList.remove('loading');
submitBtn.disabled = false;
});
document.addEventListener('wpcf7mailfailed', function(event) {
// Hide preloader if mail fails
preloader.style.display = 'none';
submitBtn.classList.remove('loading');
submitBtn.disabled = false;
});
});
// Update your existing submit button HTML to include a text span:
//