> 웹 프론트엔드 > JS 튜토리얼 > Google Maps API를 사용하는 React Native의 위치 기반 앱을 위한 필수 기능

Google Maps API를 사용하는 React Native의 위치 기반 앱을 위한 필수 기능

Linda Hamilton
풀어 주다: 2024-12-07 20:15:14
원래의
148명이 탐색했습니다.

Essential Functions for Location-Based Apps in React Native Using Google Maps APIs

위치 중심 애플리케이션에서는 지리적 위치, 경로, 요금 추정을 위한 강력한 기능을 구현하는 것이 중요합니다. 구현할 수 있는 주요 유틸리티는 다음과 같습니다.


? 1. 위도, 경도, 주소 가져오기

  • 함수: getLatLong(placeId)
  • 목적: Google Places API를 사용하여 지정된 placeId에 대한 지리 좌표(위도 및 경도)와 주소를 검색합니다.
  • 사용 사례: 고유한 장소 ID를 기반으로 정확한 위치를 식별하는 데 유용합니다(예: 지도 마커의 경우).
  • : placeId의 경우 함수는 위도, 경도 및 주소를 구조화된 형식으로 반환합니다.

? 2. 역지오코딩

  • 함수: reverseGeocode(위도, 경도)
  • 목적: Google Geocoding API를 사용하여 지리적 좌표를 사람이 읽을 수 있는 주소로 변환합니다.
  • 사용 사례: 사용자가 선택한 위치의 주소 또는 GPS 좌표를 표시합니다.
  • : 주어진 좌표에 "Sydney NSW, Australia"와 같이 사용자에게 친숙한 주소를 제공하세요.

? 3. 장소 자동완성 제안

  • 함수: getPlacesSuggestions(쿼리)
  • 목적: Google Places Autocomplete API를 사용하여 사용자 입력을 기반으로 위치 제안을 가져옵니다.
  • 사용 사례: 위치 제안 드롭다운을 제공하여 검색 기능을 향상합니다.
  • : 사용자가 "Sydney"를 입력하면 "Sydney Opera House" 또는 "Sydney Airport"를 제안합니다.

? 4. 거리 계산

  • 함수: 계산거리(lat1, lon1, lat2, lon2)
  • 목적: Haversine 공식을 사용하여 두 지리적 지점 사이의 거리를 계산합니다.
  • 사용 사례: 사용자의 현재 위치와 목적지 사이의 거리를 추정하는 데 적합합니다.
  • : 두 좌표 세트 사이의 거리를 20.56km로 계산합니다.

? 5. 동적 요금 추정

  • 함수:calculateFare(거리)
  • 목적: 이동 거리를 기준으로 다양한 차량 유형(자전거, 자동차, 이코노미 택시, 프리미엄 택시)에 대한 요금을 계산합니다.
  • 사용 사례: 차량 공유 앱이나 배달 서비스에서 예상 요금을 동적으로 표시하는 데 유용합니다.
  • : 10km 이동 시 자전거 ₹50, 이코노미 택시 ₹100와 같은 요금 세부정보를 제공합니다.

6. 베지어 곡선을 사용하여 부드러운 경로 생성

  • 함수: getPoints(장소)
  • 목적: 2차 베지어 곡선을 사용하여 두 점 사이에 부드럽고 시각적으로 매력적인 경로를 만듭니다.
  • 사용 사례: 내비게이션 앱의 지도에 세련된 경로 시각화를 추가합니다.
  • : 두 위치 사이의 곡선을 따라 100개의 점을 생성하여 부드러운 폴리라인을 만듭니다.

? 7. 차량 아이콘 관리

  • 유틸리티: 차량 아이콘
  • 목적: 일관되고 역동적인 UI를 위해 차량 유형(예: 자전거, 자동차, cabEconomy)을 해당 아이콘에 매핑합니다.
  • 사용 사례: 차량 공유 또는 배달 앱에서 선택한 차량 유형에 따라 적절한 아이콘을 표시합니다.
  • : "자전거" 또는 "cabPremium" 아이콘을 동적으로 가져옵니다.

전체 코드:

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
};
로그인 후 복사

? 결론

이 유틸리티를 사용하면 개발자는 다음을 수행할 수 있습니다.

  1. 원활한 위치 기반 서비스를 통합하세요.
  2. 실시간 데이터와 직관적인 비주얼로 사용자 경험을 향상하세요.
  3. Google Maps API를 사용하여 확장 가능하고 동적인 React Native 애플리케이션을 구축하세요.

위치정보, 경로 시각화, 요금 추정을 결합하면 앱 기능을 크게 향상하고 사용자에게 더 많은 가치를 제공할 수 있습니다.

위 내용은 Google Maps API를 사용하는 React Native의 위치 기반 앱을 위한 필수 기능의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿