In location-centric applications, implementing robust features for geolocation, routing, and fare estimation is crucial. Here's a breakdown of the key utilities that can be implemented:
import axios from "axios"; import { useUserStore } from "@/store/userStore"; /** * Fetch latitude, longitude, and address details for a given place ID. * @param {string} placeId - The unique identifier for a place (e.g., "ChIJN1t_tDeuEmsRUsoyG83frY4"). * @returns {Promise<{latitude: number, longitude: number, address: string}>} Location data. * Example response: * { * latitude: -33.8670522, * longitude: 151.1957362, * address: "Sydney NSW, Australia" * } */ export const getLatLong = async (placeId: string) => { try { const response = await axios.get("https://maps.googleapis.com/maps/api/place/details/json", { params: { placeid: placeId, // Place ID for the location key: process.env.EXPO_PUBLIC_MAP_API_KEY, // API key for authentication }, }); const data = response.data; // Validate response status and extract required fields if (data.status === "OK" && data.result) { const location = data.result.geometry.location; // Get latitude and longitude const address = data.result.formatted_address; // Get formatted address return { latitude: location.lat, longitude: location.lng, address: address, }; } else { // Handle API response errors throw new Error("Unable to fetch location details"); } } catch (error) { // Catch and throw any request or processing errors throw new Error("Unable to fetch location details"); } }; /** * Reverse geocode latitude and longitude to fetch the address. * @param {number} latitude - Latitude of the location (e.g., -33.8670522). * @param {number} longitude - Longitude of the location (e.g., 151.1957362). * @returns {Promise<string>} Address of the location. * Example response: "Sydney NSW, Australia" */ export const reverseGeocode = async (latitude: number, longitude: number) => { try { const response = await axios.get( `https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}&key=${process.env.EXPO_PUBLIC_MAP_API_KEY}` ); // Check if the response status is OK and extract the address if (response.data.status === "OK") { const address = response.data.results[0].formatted_address; return address; // Return the formatted address } else { // Log failure details and return an empty string console.log("Geocoding failed: ", response.data.status); return ""; } } catch (error) { // Handle any request or processing errors console.log("Error during reverse geocoding: ", error); return ""; } }; /** * Extract relevant place data from API response. * @param {Array} data - Array of place predictions from the API. * @returns {Array<{place_id: string, title: string, description: string}>} Processed place data. * Example response: * [ * { place_id: "xyz123", title: "Sydney Opera House", description: "Iconic performing arts venue in Sydney" } * ] */ function extractPlaceData(data: any) { return data.map((item: any) => ({ place_id: item.place_id, // Unique identifier for the place title: item.structured_formatting.main_text, // Main title of the place description: item.description, // Detailed description })); } /** * Fetch autocomplete suggestions for places based on a query. * @param {string} query - User's input for place suggestions (e.g., "Sydney"). * @returns {Promise<Array>} List of place suggestions. * Example response: * [ * { place_id: "xyz123", title: "Sydney Opera House", description: "Iconic performing arts venue in Sydney" } * ] */ export const getPlacesSuggestions = async (query: string) => { const { location } = useUserStore.getState(); // Get user's current location from the store try { const response = await axios.get( `https://maps.googleapis.com/maps/api/place/autocomplete/json`, { params: { input: query, // Query string for suggestions location: `${location?.latitude},${location?.longitude}`, // Use current location for proximity radius: 50000, // Search within a 50km radius components: "country:IN", // Restrict results to India key: process.env.EXPO_PUBLIC_MAP_API_KEY, // API key for authentication } } ); // Process and return extracted place data return extractPlaceData(response.data.predictions); } catch (error) { // Log errors and return an empty array console.error("Error fetching autocomplete suggestions:", error); return []; } }; /** * Calculate the distance between two geographic coordinates using the Haversine formula. * @param {number} lat1 - Latitude of the first point (e.g., 28.7041). * @param {number} lon1 - Longitude of the first point (e.g., 77.1025). * @param {number} lat2 - Latitude of the second point (e.g., 28.5355). * @param {number} lon2 - Longitude of the second point (e.g., 77.3910). * @returns {number} Distance in kilometers. * Example response: 20.56 */ export const calculateDistance = (lat1: number, lon1: number, lat2: number, lon2: number) => { const R = 6371; // Earth's radius in kilometers const dLat = (lat2 - lat1) * (Math.PI / 180); // Latitude difference in radians const dLon = (lon2 - lon1) * (Math.PI / 180); // Longitude difference in radians const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); // Haversine formula const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); // Angular distance return R * c; // Distance in kilometers }; /** * Calculate fare for different vehicle types based on the distance traveled. * @param {number} distance - Distance traveled in kilometers (e.g., 15). * @returns {Object} Fare breakdown for each vehicle type. * Example response: * { * bike: 50, * auto: 60, * cabEconomy: 100, * cabPremium: 150 * } */ export const calculateFare = (distance: number) => { // Fare rates for different vehicle types const rateStructure = { bike: { baseFare: 10, perKmRate: 5, minimumFare: 25 }, auto: { baseFare: 15, perKmRate: 7, minimumFare: 30 }, cabEconomy: { baseFare: 20, perKmRate: 10, minimumFare: 50 }, cabPremium: { baseFare: 30, perKmRate: 15, minimumFare: 70 }, }; // Helper function to calculate fare const fareCalculation = (baseFare: number, perKmRate: number, minimumFare: number) => { const calculatedFare = baseFare + (distance * perKmRate); // Calculate fare based on distance return Math.max(calculatedFare, minimumFare); // Ensure the fare meets the minimum }; // Return fare details for each vehicle type return { bike: fareCalculation(rateStructure.bike.baseFare, rateStructure.bike.perKmRate, rateStructure.bike.minimumFare), auto: fareCalculation(rateStructure.auto.baseFare, rateStructure.auto.perKmRate, rateStructure.auto.minimumFare), cabEconomy: fareCalculation(rateStructure.cabEconomy.baseFare, rateStructure.cabEconomy.perKmRate, rateStructure.cabEconomy.minimumFare), cabPremium: fareCalculation(rateStructure.cabPremium.baseFare, rateStructure.cabPremium.perKmRate, rateStructure.cabPremium.minimumFare), }; }; /** * Generate points along a quadratic Bezier curve between two points with a control point. * @param {Array<number>} p1 - The starting point of the curve [latitude, longitude] (e.g., [28.7041, 77.1025]). * @param {Array<number>} p2 - The ending point of the curve [latitude, longitude] (e.g., [28.5355, 77.3910]). * @param {Array<number>} controlPoint - The control point for the curve [latitude, longitude] (e.g., [28.6, 77.25]). * @param {number} numPoints - The number of points to generate along the curve. * @returns {Array<{latitude: number, longitude: number}>} Array of coordinates forming the curve. * Example response: * [ * { latitude: 28.7041, longitude: 77.1025 }, * { latitude: 28.635, longitude: 77.175 }, * { latitude: 28.5355, longitude: 77.3910 } * ] */ function quadraticBezierCurve(p1: any, p2: any, controlPoint: any, numPoints: any) { const points = []; const step = 1 / (numPoints - 1); // Step size for dividing the curve for (let t = 0; t <= 1; t += step) { const x = (1 - t) ** 2 * p1[0] + // Contribution of starting point 2 * (1 - t) * t * controlPoint[0] + // Contribution of control point t ** 2 * p2[0]; // Contribution of ending point const y = (1 - t) ** 2 * p1[1] + 2 * (1 - t) * t * controlPoint[1] + t ** 2 * p2[1]; const coord = { latitude: x, longitude: y }; // Store as coordinate object points.push(coord); // Add to the points array } return points; // Return array of points forming the curve } /** * Calculate the control point for a quadratic Bezier curve between two points. * @param {Array<number>} p1 - The starting point [latitude, longitude]. * @param {Array<number>} p2 - The ending point [latitude, longitude]. * @returns {Array<number>} The control point [latitude, longitude]. * Example response: [28.6, 77.25] */ const calculateControlPoint = (p1: any, p2: any) => { const d = Math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2); // Distance between p1 and p2 const scale = 1; // Scale factor for bending the curve const h = d * scale; // Adjusted distance from midpoint const w = d / 2; // Halfway between points const x_m = (p1[0] + p2[0]) / 2; // Midpoint x const y_m = (p1[1] + p2[1]) / 2; // Midpoint y const x_c = x_m + ((h * (p2[1] - p1[1])) / (2 * Math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2))) * (w / d); const y_c = y_m - ((h * (p2[0] - p1[0])) / (2 * Math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2))) * (w / d); return [x_c, y_c]; // Return calculated control point }; /** * Generate Bezier curve points for given locations. * @param {Array<{latitude: number, longitude: number}>} places - Array containing at least two points. * @returns {Array<{latitude: number, longitude: number}>} Array of coordinates forming the curve. * Example response: * [ * { latitude: 28.7041, longitude: 77.1025 }, * { latitude: 28.635, longitude: 77.175 }, * { latitude: 28.5355, longitude: 77.3910 } * ] */ export const getPoints = (places: any) => { const p1 = [places[0].latitude, places[0].longitude]; // Starting point const p2 = [places[1].latitude, places[1].longitude]; // Ending point const controlPoint = calculateControlPoint(p1, p2); // Calculate the control point return quadraticBezierCurve(p1, p2, controlPoint, 100); // Generate 100 points along the curve }; /** * Map of vehicle types to their respective icons. * @type {Record<'bike' | 'auto' | 'cabEconomy' | 'cabPremium', { icon: any }>} * Example usage: * vehicleIcons.bike.icon -> Path to bike icon */ export const vehicleIcons: Record<'bike' | 'auto' | 'cabEconomy' | 'cabPremium', { icon: any }> = { bike: { icon: require('@/assets/icons/bike.png') }, // Icon for bike auto: { icon: require('@/assets/icons/auto.png') }, // Icon for auto cabEconomy: { icon: require('@/assets/icons/cab.png') }, // Icon for economy cab cabPremium: { icon: require('@/assets/icons/cab_premium.png') }, // Icon for premium cab };
These utilities empower developers to:
By combining geolocation, route visualization, and fare estimation, you can significantly elevate your app's functionality and deliver more value to your users.
The above is the detailed content of Essential Functions for Location-Based Apps in React Native Using Google Maps APIs. For more information, please follow other related articles on the PHP Chinese website!