首頁 > web前端 > js教程 > 使用 Google 地圖 API 的 React Native 中基於位置的應用程式的基本功能

使用 Google 地圖 API 的 React Native 中基於位置的應用程式的基本功能

Linda Hamilton
發布: 2024-12-07 20:15:14
原創
186 人瀏覽過

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

在以位置為中心的應用程式中,實現強大的地理位置、路線和票價估算功能至關重要。以下是可以實現的關鍵實用程式的細分:


1.取得緯度、經度和地址

  • 函數:getLatLong(placeId)
  • 用途:使用 Google Places API 擷取地理座標(緯度和經度)以及給定 placeId 的位址。
  • 用例:可用於根據唯一的 placeId 識別確切位置(例如,地圖標記)。
  • 範例:對於 placeId,函數以結構化格式傳回緯度、經度和位址。

2.反向地理編碼

  • 函數:reverseGeocode(緯度,經度)
  • 用途:使用 Google Geocoding API 將地理座標轉換為人類可讀的位址。
  • 用例:顯示使用者所選位置的位址或 GPS 座標。
  • 範例:為給定座標提供使用者友善的地址,例如「澳洲新南威爾斯州雪梨」。

3.放置自動完成建議

  • 函數:getPlacesSuggestions(query)
  • 用途:使用 Google Places Autocomplete API 根據使用者輸入取得位置建議。
  • 用例:透過提供位置建議下拉式選單來增強搜尋功能。
  • 範例:當使用者輸入「雪梨」時建議「雪梨歌劇院」或「雪梨機場」。

4.計算距離

  • 函數:計算距離(lat1, lon1, lat2, lon2)
  • 用途:使用半正弦公式計算兩個地理點之間的距離。
  • 用例:非常適合估計使用者目前位置與其目的地之間的距離。
  • 範例:計算兩組座標之間的距離為20.56公里。

5.動態票價估算

  • 函數:計算票價(距離)
  • 用途:根據行駛距離計算不同車輛類型(自行車、汽車、經濟型計程車、高級計程車)的票價。
  • 用例:對於叫車應用程式或送貨服務動態顯示票價估算很有用。
  • 範例:提供票價詳細信息,例如 10 公里行程的自行車 50 盧比或經濟型出租車 100 盧比。

6。使用貝塞爾曲線產生平滑路線

  • 函數:getPoints(地點)
  • 目的:使用二次貝塞爾曲線在兩點之間創建一條平滑、具有視覺吸引力的路線。
  • 用例:在導航應用程式的地圖上添加精美的路線視覺化。
  • 範例:沿著兩個位置之間的曲線產生 100 個點以建立平滑的折線。

7.車輛圖示管理

  • 實用程式:車輛圖標
  • 目的:將車輛類型(例如自行車、汽車、計程車經濟)映射到各自的圖標,以獲得一致且動態的 UI。
  • 用例:根據乘車或送貨應用程式中所選的車輛類型顯示適當的圖示。
  • 範例:動態取得「bike」或「cabPremium」的圖示。

完整程式碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

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 地圖 API 的 React Native 中基於位置的應用程式的基本功能的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板