Mapbox — это мощная картографическая платформа, которая позволяет разработчикам интегрировать интерактивные и настраиваемые карты в свои веб-приложения. В этой статье мы рассмотрим, как использовать Mapbox в приложении React для отображения карт, добавления маркеров, расчета направлений и многого другого. Мы предоставим пошаговые инструкции и фрагменты кода, которые помогут вам начать работу с Mapbox в React.
Начиная
Для начала убедитесь, что у вас настроено приложение React. Если у вас его еще нет, вы можете создать новый проект React, используя create vite@latest или любой другой предпочтительный метод.
Установка зависимостей
Чтобы использовать Mapbox в React, нам нужно установить несколько зависимостей. Откройте терминал и перейдите в каталог проекта React. Затем выполните следующую команду:
npm install mapbox-gl axios @mapbox/mapbox-sdk react-icons bootstrap sass
При этом будут установлены необходимые пакеты: mapbox-gl
для библиотеки Mapbox, axios
для выполнения HTTP-запросов и @mapbox/mapbox-sdk
для служб геокодирования.
Настройка токена доступа Mapbox
Чтобы получить доступ к API Mapbox, вам необходимо иметь токен доступа. Если у вас его нет, вы можете зарегистрировать учетную запись Mapbox на mapbox.com. Получив учетную запись, перейдите к настройкам учетной записи и создайте новый токен доступа.
Скопируйте свой токен доступа, так как он понадобится нам позже в нашем коде. Для производственных приложений рекомендуется безопасно хранить токен доступа, например, в переменной среды. В этой статье мы предполагаем, что токен доступа хранится в безопасном месте.
Импорт зависимостей:
import React, { useRef, useEffect, useState, useContext } from "react"; import "./Map.scss"; import mapboxgl from "mapbox-gl"; import "mapbox-gl/dist/mapbox-gl.css"; import axios from "axios"; import MapboxGeocoding from "@mapbox/mapbox-sdk/services/geocoding"; import { FaArrowsAltV } from "react-icons/fa"; import { MdLocationOn } from "react-icons/md"; import { AiFillHome } from "react-icons/ai";
Здесь импортируются необходимые зависимости для создания карты и реализации функций геокодирования.
Инициализация состояния и ссылок:
const mapContainerRef = useRef(null); const [mapStyle, setMapStyle] = useState("mapbox://styles/mapbox/streets-v11"); const [isFocused, setIsFocused] = useState(false); const [origin, setOrigin] = useState(""); const destination = [88.3639, 22.5726]; const [routeGeometry, setRouteGeometry] = useState(null); const [originCord, setOriginCord] = useState([]); let originCoordinates = []; const [routeInfo, setRouteInfo] = useState([]); const [suggestions, setSuggestions] = useState([]); const [expand, setExpand] = useState(false); const initialItemCount = 4; const geocodingClient = MapboxGeocoding({ accessToken: import.meta.env.VITE_MAP_BOX_ACCESS_TOKEN, });
Здесь объявлены переменные состояния для отслеживания различных данных, таких как стиль карты, состояние фокуса, исходный адрес, координаты пункта назначения, геометрия маршрута, исходные координаты, информация о маршруте, предложения для автозаполнения и состояние расширения для направлений. Ссылки используются для ссылки на контейнер карты.
Инициализация карты и стиль:
Этот раздел инициализирует карту Mapbox, создавая новый экземпляр mapboxgl.Map
и устанавливая его начальные свойства, такие как контейнер, стиль, центральные координаты и уровень масштабирования.
Он также добавляет на карту элемент управления компасом и пользовательский маркер.
useEffect(() => { mapboxgl.accessToken = import.meta.env.VITE_MAP_BOX_ACCESS_TOKEN; const map = new mapboxgl.Map({ container: mapContainerRef.current, style: mapStyle, center: [88.3639, 22.5726], // longitude and latitude zoom: 12, attributionControl: false, }); map.on("style.load", () => { // Add the compass control const compassControl = new mapboxgl.NavigationControl({ showCompass: true, }); map.addControl(compassControl, "top-right"); // Create a marker with a custom icon const marker = new mapboxgl.Marker({ element: document.getElementById("custom-marker"), }) .setLngLat([88.3639, 22.5726]) // longitude and latitude .addTo(map) .setPopup( new mapboxgl.Popup({ closeButton: true }).setHTML( ` <div class="location-details"> <span><strong>City:</strong> Kolkata</span><br> <span><strong>State:</strong> West Bengal</span><br> <span><strong>Country:</strong> INDIA</span></div> </div> ` ) ); // Create a marker at the starting position const startMarker = new mapboxgl.Marker() .setLngLat(originCord) .addTo(map); if (routeGeometry) { map.addSource("route", { type: "geojson", data: { type: "Feature", geometry: routeGeometry, }, }); map.addLayer({ id: "route", type: "line", source: "route", layout: { "line-join": "round", "line-cap": "round", }, paint: { "line-color": "#3b9ddd", "line-width": 6, }, }); } // Get the route bounds const bounds = routeGeometry.coordinates.reduce( (bounds, coord) => bounds.extend(coord), new mapboxgl.LngLatBounds() ); // Zoom out to fit the route within the map view map.fitBounds(bounds, { padding: 50, }); }); // return () => { // map.remove(); // }; }, [mapStyle, routeGeometry]);
Автозаполнение поиска:
В этом разделе обрабатывается пользовательский ввод в поле ввода поиска (<input id="fromAddress" />
) и извлекаются предложения автозаполнения с использованием Mapbox Geocoding API.
const handleInputChange = (event) => { const { value } = event.target; setOrigin(value); axios .get(`https://api.mapbox.com/geocoding/v5/mapbox.places/${value}.json`, { params: { access_token: mapboxgl.accessToken, autocomplete: true, types: ["place"], limit: 5, }, }) .then((response) => { const { features } = response.data; setSuggestions(features); }) .catch((error) => { console.error("Error fetching autocomplete suggestions:", error); }); };
Обработка предложений автозаполнения:
В этом разделе отображаются предложения автозаполнения на основе пользовательского ввода и обрабатывается выбор предложения.
const handleSelectSuggestion = (suggestion) => { setOrigin(suggestion.place_name); setOriginCord(suggestion.center); setSuggestions([]); };
Расчет и отображение направлений:
В этом разделе маршруты маршрута рассчитываются с помощью Mapbox Directions API на основе координат исходной и конечной точек.
Он делает HTTP-запрос к API и получает информацию о маршруте, включая расстояние, продолжительность и пошаговые инструкции.
const calcRouteDirection = async () => { if (origin.length > 2) { try { const origin = document.getElementById("fromAddress").value; if (origin.length > 2) { try { const response = await geocodingClient .forwardGeocode({ query: origin, types: ["place"], limit: 1, }) .send(); const destinationCoordinates = response.body.features[0].center; originCoordinates = destinationCoordinates; setOriginCord(destinationCoordinates); } catch (error) { console.error("Error calculating directions:", error); throw error; } } const response = await axios.get( `https://api.mapbox.com/directions/v5/mapbox/${localStorage.getItem( "mode" )}/${originCoordinates[0]},${originCoordinates[1]};${ destination[0] },${destination[1]}?steps=true&geometries=geojson&access_token=${ import.meta.env.VITE_MAP_BOX_ACCESS_TOKEN }` ); const routes = response.data.routes; console.log("routes=>", routes); setRouteInfo(routes); // Check if any routes are returned if (routes.length > 0) { const { distance, duration, geometry } = routes[0]; // Valid directions, use the distance and duration for further processing const directions = { distance, duration, }; localStorage.setItem("fromLocation", origin); setRouteGeometry(geometry); // Set the route geometry return directions; } else { // No routes found throw new Error("Unable to calculate directions"); } } catch (error) { // Handle error console.error("Error calculating directions:", error); throw error; } } };
Переключение режимов движения:
Этот раздел позволяет пользователю переключаться между различными режимами движения (вождение, ходьба, езда на велосипеде) и соответствующим образом пересчитывать направления.
Он обновляет значение localStorage
для выбранного режима движения и запускает функцию calcRouteDirection
.
<a className={`mode-button ${selectedMode === "driving" ? "active" : ""}`} onClick={() => handleModeChange("driving")} > Driving </a> <a className={`mode-button ${selectedMode === "walking" ? "active" : ""}`} onClick={() => handleModeChange("walking")} > Walking </a> <a className={`mode-button ${selectedMode === "cycling" ? "active" : ""}`} onClick={() => handleModeChange("cycling")} > Cycling </a> const handleModeChange = (mode) => { localStorage.setItem("selectedMode", mode); setSelectedMode(mode); calcRouteDirection(); };
Отображение инструкций по маршруту:
В этом разделе отображаются пошаговые инструкции для выбранного маршрута. Он перебирает массив routeInfo
и отображает каждую инструкцию как элемент списка.
<ul> {routeInfo[0].legs[0].steps.map((step, index) => ( <li key={index}>{step.maneuver.instruction}</li> ))} </ul>
Обновление карты и визуализации маршрута:
Этот раздел обновляет карту и визуализирует маршрут на карте всякий раз, когда изменяется пункт отправления, пункт назначения или выбранный режим движения.
Он обновляет центр карты и уровень масштабирования в зависимости от границ маршрута и отображает маршрут с помощью Mapbox LineString
и Layer
.
useEffect(() => { if (map && routeGeometry) { map.fitBounds(routeGeometry.bounds, { padding: 20 }); map.addLayer({ id: "route", type: "line", source: { type: "geojson", data: { type: "Feature", properties: {}, geometry: routeGeometry, }, }, layout: { "line-join": "round", "line-cap": "round", }, paint: { "line-color": "#00f", "line-width": 4, }, }); } }, [map, routeGeometry]);
В заключение представленный код демонстрирует потенциал React, Mapbox и API в создании динамической и функциональной карты и компонента направлений. Он демонстрирует такие функции, как предложения автозаполнения, переключение режима движения, расчет маршрута, визуализация маршрута и пошаговые инструкции. Используя эти технологии, разработчики могут создавать мощные и удобные картографические приложения, которые расширяют возможности пользователей и предоставляют ценные навигационные функции.
Исходный код: https://github.com/Priyammondal/map-box-react
Живая демонстрация: https://map-box-react.netlify.app/