React-Leaflet v3: Создание картографического приложения
Вот код созданного нами компонента Leaflet:
Это прекрасно работает, но наш код не очень похож на React, поскольку мы манипулируем DOM с помощью vanilla Leaflet и рендерим все в один div «map». Давайте рассмотрим, как создать правильное приложение сопоставления React с открытым исходным кодом с помощью React-Leaflet.
Некоторые вещи, которые следует помнить
Важно помнить, что React-Leaflet не заменяет Leaflet. Он просто предоставляет способ создания слоев Leaflet в качестве компонентов React, вместо использования настройки useRef
/ useEffect
, как мы использовали в нашем приложении vanilla-Leaflet / React. Это означает, что наши компоненты React-Leaflet могут вести себя иначе, чем стандартный компонент React. Из документации React-Leaflet:
Рендеринг DOM
React не отображает слои Leaflet в DOM, этот рендеринг выполняется самим Leaflet. React визуализирует элемент <div>
только при визуализации компонента MapContainer
, содержимого компонентов слоев пользовательского интерфейса.
Помните, как мы отрендерили все в один div на карте vanilla Leaflet? React-Leaflet делает то же самое за кулисами!
Свойства компонента
Свойства, переданные компонентам, используются для создания соответствующего экземпляра Leaflet при первом рендеринге компонента и по умолчанию должны рассматриваться как неизменяемые.
Во время первого рендеринга все эти свойства должны поддерживаться, как и Leaflet, однако они не будут обновляться в пользовательском интерфейсе при изменении, если они явно не задокументированы как изменяемые.
Изменения изменяемых свойств сравниваются по ссылке (если не указано иное) и применяются, вызывая соответствующий метод для экземпляра элемента Leaflet.
Опять же, это очень похоже на нашу карту vanilla Leaflet. Элементы-листовки создаются только при первом монтировании компонента, точно так же, как мы использовали хук useEffect
, а затем модифицировали его с помощью refs.
Реагирование на контекст
React Leaflet использует контекстный API React, чтобы сделать некоторые экземпляры элементов Leaflet доступными для дочерних элементов, которые в этом нуждаются.
Каждый экземпляр карты Leaflet имеет свой собственный контекст React, созданный компонентом MapContainer
. Другие компоненты и хуки, предоставляемые React Leaflet, могут использоваться только как потомки MapContainer
.
React-Leaflet использует контекстный API, чтобы сделать свои экземпляры и состояние доступными для всех своих дочерних элементов. Вы увидите пример этого, как только мы перейдем к тому, как мы обрабатываем события карты.
Начинаем
Чтобы упростить настройку, у меня есть стартер, который вы можете использовать на Stack Blitz. Если вы предпочитаете следовать инструкциям на своем локальном компьютере, ознакомьтесь с разделом документации по установке. Не забудьте установить Leaflet, а также React-Leaflet! Также обратите внимание, что в этой демонстрации мы будем использовать некоторые стили и компоненты из Material-UI.
В public/index.html
, мы можем вставить ссылку CDN для файлов CSS и Javascript Leaflet:
index.html
<!-- CSS -->
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin=""
/>
<!-- JS -->
<script
src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin=""
></script>
Теперь мы можем настроить наш MapContainer
и наш слой листов карты. MapContainer - это то, что создает экземпляр карты Leaflet и совместно использует этот экземпляр со всеми его дочерними элементами через контекстный API. Для наших целей мы только передадим center
, zoom
, style
и zoomControl
в MapContainer
на данный момент, но ознакомьтесь с этим списком реквизитов, которые вы можете передать для последующего использования. Мы будем центрировать нашу карту по Соединенным Штатам ( [37.0902, -95.7129]
), установив zoom
для 3
, и установив zoomControl
для false
,так как мы добавим его немного позже. У опоры style
также должны быть установлены высота и ширина.
В src/map
мы можем создать новый файл с именем Map.jsx
, а затем импортировать его в наш файл App.js
:
Map.jsx
import React from 'react'
import { MapContainer, TileLayer } from 'react-leaflet'
const Map = () => {
return (
<>
<MapContainer
center={[37.0902, -95.7129]}
zoom={3}
zoomControl={false}
style={{ height: '100vh', width: '100%' }}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</MapContainer>
</>
)
}
export default Map
App.jsx
import React from "react";
import "./assets/css/style.css";
import { Container } from "@material-ui/core";
import Map from "./map/Map";
export default function App() {
return (
<Container disableGutters>
<Map />
</Container>
);
}
Теперь у вас на экране должна быть пустая карта, которая выглядит примерно так:
Добавление элементов управления
Теперь, когда у нас есть наша карта, давайте добавим ZoomControl
и LayersControl
.
ZoomControl
добавить очень просто. Нам нужно импортировать компонент ZoomControl
и разместить его прямо под компонентом TileLayer
. Мы также хотим передать ему опору position
со значением 'topright'
:
Map.jsx
import React from 'react'
import { MapContainer, TileLayer, ZoomControl } from 'react-leaflet'
const Map = () => {
return (
<>
<MapContainer
center={[37.0902, -95.7129]}
zoom={3}
zoomControl={false}
style={{ height: '100vh', width: '100%' }}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<ZoomControl position='topright'/>
</MapContainer>
</>
)
}
export default Map
LayersControl
немного по-другому. Мы можем импортировать этот компонент и поместить его прямо над только что установленным ZoomControl
. Затем мы используем LayersControl.BaseLayers
и LayersControl.Overlay
чтобы добавить наши слои к элементу управления. Мы будем использовать компонент LayersControl.Overlay
для включения и выключения таких слоев, как маркеры и круги, на карте позже, а пока мы поместим компонент TileLayer
внутрь компонента LayersControl.BaseLayers
. Давайте также добавим вторую опцию плитки карты, чтобы мы действительно могли использовать наш элемент управления слоем. Перейдите к демонстрации Leaflet-Providers и выберите вторую плитку для использования, а затем настройте свой код следующим образом:
Map.jsx
import React from 'react'
import { MapContainer, TileLayer, ZoomControl, LayersControl } from 'react-leaflet'
const Map = () => {
return (
<>
<MapContainer
center={[37.0902, -95.7129]}
zoom={3}
zoomControl={false}
style={{ height: '100vh', width: '100%' }}
>
<LayersControl position="topright">
{/*
Give the layer a name that will be displayed inside of the layers control.
We also want to pass the checked prop to whichever map tile we want
displayed as the default:
*/}
<LayersControl.BaseLayer checked name="Basic Map">
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</LayersControl.BaseLayer>
{/*
Add the second maptile:
*/}
<LayersControl.BaseLayer name="Topo Map">
<TileLayer
attribution='Map data: © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="http://viewfinderpanoramas.org">SRTM</a> | Map style: © <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)'
url="https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png"
/>
</LayersControl.BaseLayer>
</LayersControl>
<ZoomControl position='topright'/>
</MapContainer>
</>
)
}
export default Map
Доступ к экземпляру карты и обработчикам событий
Вспомните раздел "Что нужно помнить" в этой статье. Мы узнали, что MapContainer
делает экземпляр карты Leaflet доступным для своих потомков и что хуки для доступа к этому состоянию доступны только его потомкам. Из-за этого нам выгодно отделить логику MapContainer
от логики слоя. В src/map
, давайте создадим новый файл с именем Layers.jsx
и копипастнем наш компонент LayersControl
здесь:
Layers.jsx
import React from 'react'
import { TileLayer, LayersControl } from 'react-leaflet'
const Layers = () => {
return (
<>
<LayersControl position="topright">
<LayersControl.BaseLayer checked name="Basic Map">
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</LayersControl.BaseLayer>
<LayersControl.BaseLayer name="Topo Map">
<TileLayer
attribution='Map data: © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="http://viewfinderpanoramas.org">SRTM</a> | Map style: © <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)'
url="https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png"
/>
</LayersControl.BaseLayer>
</LayersControl>
</>
)
}
export default Layers
Map.jsx
import React from 'react'
import { MapContainer, ZoomControl } from 'react-leaflet'
import Layers from './Layers'
const Map = () => {
return (
<>
<MapContainer
center={[37.0902, -95.7129]}
zoom={3}
zoomControl={false}
style={{ height: '100vh', width: '100%' }}
>
<Layers />
<ZoomControl position='topright'/>
</MapContainer>
</>
)
}
export default Map
Экземпляр карты Leaflet имеет множество методов, доступных для получения и установки его состояния. Чтобы использовать эти методы, React-Leaflet предоставляет нам хук useMap
. Скажем, мы хотим получить начальные границы и уровень масштабирования нашей карты. Мы могли бы вызвать useMap
в верхней части нашего компонента и присвоить его переменной, скажем map
, а затем ссылаться на эту переменную всякий раз, когда мы хотим использовать метод карты Leaflet:
Layers.jsx
import React from 'react'
// Import the useMap hook:
import { useMap, TileLayer, LayersControl } from 'react-leaflet'
const Layers = () => {
// Call useMap:
const map = useMap()
// Use the map methods:
console.log("Map Bounds:", map.getBounds())
console.log("Zoom Level:", map.getZoom())
return (
// ..LayersControl...
)
}
export default Layers
Однако, если бы мы хотели получать границы и уровень масштабирования каждый раз, когда они меняются, мы бы использовали хук useMapEvents
. Мы импортируем его так же, как и хук useMap
, но мы прикрепим обработчики событий карты Leaflet к экземпляру карты следующим образом:
Layers.jsx
import React from 'react'
// Import useMapEvents:
import { useMapEvents, TileLayer, LayersControl } from 'react-leaflet'
const Layers = () => {
// Call useMapEvents:
const map = useMapEvents({
// Use leaflet map event as the key and a call back with the
// map method as the value:
zoomend: () => {
// Get the zoom level once zoom ended:
console.log(map.getZoom())
},
moveend: () => {
// Get bounds once move has ended:
console.log(map.getBounds())
}
})
return (
// ...LayersControl...
)
}
export default Layers
Отображение данных с помощью GeoJSON
Очень высока вероятность, что в какой-то момент в процессе создания вашего картографического приложения вы будете получать и отображать данные в формате geoJSON. Наша карта в настоящее время сосредоточена на США, поэтому мы будем использовать геоданные для штатов Вайоминг, Монтана, а также Северная и Южная Дакота. Я уже настроил файлы, содержащие geoJSON для каждого состояния в src/data
.
Чтобы отобразить geoJSON, мы собираемся использовать компонент слоя React-Leaflet GeoJSON
. Мы собираемся импортировать данные Layers.jsx
, поместить данные в массив в состоянии, затем использовать .map()
для итерации этого массива и возврата слоев GeoJSON
. При итерации данных нам необходимо передать свойство geometry
, найденное в массиве features
каждого набора geoJSON, которое дает слою GeoJSON
тип и координаты создаваемого слоя. Нам также нужно будет предоставить уникальный ключ для каждого слоя GeoJSON, поэтому мы будем использовать display_name
найденный в properties
для каждого массива features
. Если вы хотите изменить стиль слоя GeoJSON
, вы можете передать объект опций в опору pathOptions
. Вот как все это будет выглядеть:
Layers.jsx
import React, { useState } from 'react'
import { useMapEvents, TileLayer, LayersControl, GeoJSON } from 'react-leaflet'
import WY from '../data/Wyoming.json'
import MT from '../data/Montana.json'
import ND from '../data/NorthDakota.json'
import SD from '../data/SouthDakota.json'
const Layers = () => {
// Set all the border data to state array:
const [borderData, setBorderData] = useState([ND, MT, SD, WY])
const map = useMapEvents({
// ... Map Events ...
})
return (
<>
<LayersControl position="topright">
<LayersControl.BaseLayer checked name="Basic Map">
// ... LayersContol.BaseLayer ...
</LayersControl.BaseLayer>
{
// Iterate the borderData with .map():
borderData.map((data) => {
// Get the layer data from geojson:
const geojson = data.features[0].geometry
// Get the name of the state from geojson:
const state_name = data.features[0].properties.display_name
return (
// Pass data to layer via props:
<>
<GeoJSON key={state_name} data={geojson} pathOptions={{ color: 'blue' }} />
</>
)
})
}
</LayersControl>
</>
)
}
export default Layers
Добавление наложений в LayersControl
Чтобы добавить базовые слои к нашему LayersControl
, мы использовали LayersControl.BaseLayer
для каждого базового слоя, который мы хотели добавить на карту. Это очень похожий процесс добавления желаемых наложений. Вместо LayersControl.BaseLayer
мы обернем наши слои в LayersControl.Overlay
указав name
и установив checked
равным true
чтобы слои отображались на карте по умолчанию:
Layers.jsx
import { useMapEvents, TileLayer, LayersControl, GeoJSON } from 'react-leaflet'
// ... Data Imports ...
const Layers = () => {
const [borderData, setBorderData] = useState([ND, MT, SD, WY])
const map = useMapEvents({
// ... Map Events ...
})
return (
<>
<LayersControl position="topright">
<LayersControl.BaseLayer checked name="Basic Map">
{// ... Layers Control: Base Layers ...}
</LayersControl.BaseLayer>
{borderData.map((data) => {
const geojson = data.features[0].geometry
const state_name = data.features[0].properties.display_name.split(',')[0]
// Wrap the geojson in LayersControl.Overlay. We'll use state_name
// as the name for the layer in the control and set checked to true:
return (
<>
<LayersControl.Overlay checked name={state_name}>
<GeoJSON key={state_name} data={geojson} pathOptions={{ color: 'blue' }} />
</LayersControl.Overlay>
</>
)
})}
</LayersControl>
</>
)
}
export default Layers
Добавление маркеров и всплывающих окон с LayerGroup
Допустим, мы хотим добавить больше в пользовательский интерфейс нашей карты, отображая некоторые маркеры, которые будут соответствовать geoJSON. Создать точки-маркеры невероятно просто. Мы просто импортируем компонент слоя React-Leaflet Marker
, оборачиваем его компонентом слой Geojson
и передаем объект latLng, который мы создадим с помощью метода Leaflet LatLng
для его опоры position
. Мы также импортируем компонент слоя Popup
, добавим текст и обернем его компонентом Marker
. Мы также можем использовать библиотеки, такие как Material UI, чтобы добавить дополнительный стиль к нашим всплывающим окнам. На данный момент мы просто будем использовать UI материала Typography
и компоненты Divider
:
Layers.jsx
import {
useMapEvents,
TileLayer,
LayersControl,
GeoJSON,
Marker, // Import the Marker and Popup layer components
Popup
} from 'react-leaflet'
// Import L from leaflet to create LatLng objects:
import L from 'leaflet'
// Import Material UI Components for styling:
import { Typography, Divider } from '@material-ui/core'
// ... Data Imports ...
const Layers = () => {
const [borderData, setBorderData] = useState([ND, MT, SD, WY])
const map = useMapEvents({
// ... Map Events ...
})
// Function to provide each state's latLng:
const getMarkerPosition = (state_name) => {
switch (state_name) {
case 'Montana':
// Use L.latLng to create latLng object.
// { "lat": LATITUDE, "lng": LONGITUDE }
return L.latLng(46.8797, -110.3626)
case 'Wyoming':
return L.latLng(43.0760, -107.2903)
case 'North Dakota':
return L.latLng(47.5515, -101.0020)
case 'South Dakota':
return L.latLng(43.9695, -99.9018)
default: return
}
}
return (
<>
<LayersControl position="topright">
<LayersControl.BaseLayer checked name="Basic Map">
{ // ... Base Layers ... }
</LayersControl.BaseLayer>
{borderData.map((data) => {
const geojson = data.features[0].geometry
const state_name = data.features[0].properties.display_name.split(',')[0]
// Wrap the Marker/Popup with the GeoJSON layer.
// Pass the getMarkerPosition to the position prop with the state_name param.
// Give the popup some Material UI styling with Typography and Divider:
return (
<>
<LayersControl.Overlay checked name={state_name}>
<GeoJSON key={state_name} data={geojson} pathOptions={{ color: 'blue' }}>
<Marker position={getMarkerPosition(state_name)}>
<Popup>
<Typography variant='subtitle2'>
{state_name}
</Typography>
<Divider />
<Typography variant='body2' style={{ margin: 3 }}>
Lat: {JSON.stringify(getMarkerPosition(state_name).lat)}
</Typography>
<Typography variant='body2' style={{ margin: 3 }}>
Lng: {JSON.stringify(getMarkerPosition(state_name).lng)}
</Typography>
</Popup>
</Marker>
</GeoJSON>
</LayersControl.Overlay>
</>
)
})}
</LayersControl>
</>
)
}
export default Layers
Обратите внимание на что-нибудь странное, особенно с LayersControl
? Каждое имя отображается дважды. Это связано с тем, что LayersControl
добавляет переключатель как для границы, так и для маркера точки с одним и тем же именем, чего мы не хотим. Чтобы исправить это, мы просто должны сказать, LayersControl
что компоненты GeoJson
и Marker
являются частью LayerGroup
. Просто импортируйте компонент React-LeafletLayerGroup
и используйте его как оболочку GeoJSON
и Marker
:
Layers.jsx
import {
useMapEvents,
TileLayer,
LayersControl,
LayerGroup, // Import LayerGroup
GeoJSON,
Marker,
Popup
} from 'react-leaflet'
// ... Imports ...
const Layers = () => {
const [borderData, setBorderData] = useState([ND, MT, SD, WY])
const map = useMapEvents({
// ... Map Events
})
const getMarkerPosition = (state_name) => {
// ... Marker Position ...
}
return (
<>
<LayersControl position="topright">
<LayersControl.BaseLayer checked name="Basic Map">
{ // ... Base Layers ... }
</LayersControl.BaseLayer>
{borderData.map((data) => {
console.log(data)
const geojson = data.features[0].geometry
const state_name = data.features[0].properties.display_name.split(',')[0]
// Wrap the GeoJSON component and its children with the LayerGroup component:
return (
<>
<LayersControl.Overlay checked name={state_name}>
<LayerGroup>
<GeoJSON key={state_name} data={geojson} pathOptions={{ color: 'blue' }}>
<Marker position={getMarkerPosition(state_name)}>
<Popup>
{ // ... Popup Content ... }
</Popup>
</Marker>
</GeoJSON>
</LayerGroup>
</LayersControl.Overlay>
</>
)
})}
</LayersControl>
</>
)
}
export default Layers
Обработчики событий слоя
Бывают случаи, когда мы захотим изменить элементы на нашей карте, например, изменить fillOpacity
для GeoJSON
с событием onmouseover
и снова onmouseout
. Чтобы добавить эту функциональность, мы будем использовать опору eventHandlers
для GeoJSON
. Многие компоненты React-Leaflet имеют опору eventHandlers
, но некоторые нет, поэтому обязательно обратитесь к документации. Для обработки событий наведения и вывода мыши мы настроим функцию с оператором switch, которая обрабатывает оба случая:
Layers.jsx
// ... Imports ...
const Layers = () => {
const [borderData, setBorderData] = useState([ND, MT, SD, WY])
const map = useMapEvents({
// ... Map Events ...
})
const getMarkerPosition = (state_name) => {
// ... Marker Position ...
}
// Our mouse event handler:
const onMouseEvent = (event, type) => {
switch (type) {
case 'over':
// Set the style of the Leaflet DOM element:
event.target.setStyle({ fillOpacity: 0.5 })
break
case 'out':
event.target.setStyle({ fillOpacity: 0.0 })
break
default:
break
}
}
return (
<>
<LayersControl position="topright">
<LayersControl.BaseLayer checked name="Basic Map">
{// ... Base Layers ... }
</LayersControl.BaseLayer>
{borderData.map((data) => {
const geojson = data.features[0].geometry
const state_name = data.features[0].properties.display_name.split(',')[0]
// We use the eventHandlers prop to tell the GeoJSON layer to listen for mouse events:
return (
<>
<LayersControl.Overlay checked name={state_name}>
<LayerGroup>
<GeoJSON
key={state_name}
data={geojson}
pathOptions={{ color: 'blue' }}
eventHandlers={{
mouseover: (event, type) => onMouseEvent(event, 'over'),
mouseout: (event, type) => onMouseEvent(event, 'out'),
}}
>
<Marker position={getMarkerPosition(state_name)}>
<Popup>
{// ... Popup Content ... }
</Popup>
</Marker>
</GeoJSON>
</LayerGroup>
</LayersControl.Overlay>
</>
)
})}
</LayersControl>
</>
)
}
export default Layers
В завершение
Хорошо, теперь у нас есть работающее картографическое приложение, созданное с помощью React-Leaflet версии 3! Вот финальная версия нашего кода:
Layers.jsx
import React, { useState } from 'react'
import {
useMapEvents,
TileLayer,
LayersControl,
LayerGroup,
GeoJSON,
Marker,
Popup,
} from 'react-leaflet'
import L from 'leaflet'
import { Typography, Divider } from '@material-ui/core'
import WY from '../data/Wyoming.json'
import MT from '../data/Montana.json'
import ND from '../data/NorthDakota.json'
import SD from '../data/SouthDakota.json'
const Layers = () => {
const [borderData, setBorderData] = useState([ND, MT, SD, WY])
const map = useMapEvents({
zoomend: () => {
console.log(map.getZoom())
},
moveend: () => {
console.log(map.getBounds())
},
})
const getMarkerPosition = (state_name) => {
switch (state_name) {
case 'Montana':
return L.latLng(46.8797, -110.3626)
case 'Wyoming':
return L.latLng(43.076, -107.2903)
case 'North Dakota':
return L.latLng(47.5515, -101.002)
case 'South Dakota':
return L.latLng(43.9695, -99.9018)
default:
return
}
}
const onMouseEvent = (event, type) => {
switch (type) {
case 'over':
event.target.setStyle({ fillOpacity: 0.5 })
break
case 'out':
event.target.setStyle({ fillOpacity: 0.0 })
break
default:
break
}
}
return (
<>
<LayersControl position='topright'>
<LayersControl.BaseLayer checked name='Basic Map'>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
/>
</LayersControl.BaseLayer>
<LayersControl.BaseLayer name='Topo Map'>
<TileLayer
attribution='Map data: © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="http://viewfinderpanoramas.org">SRTM</a> | Map style: © <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)'
url='https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png'
/>
</LayersControl.BaseLayer>
{borderData.map((data) => {
const geojson = data.features[0].geometry
const state_name = data.features[0].properties.display_name.split(
','
)[0]
return (
<>
<LayersControl.Overlay checked name={state_name}>
<LayerGroup>
<GeoJSON
key={state_name}
data={geojson}
pathOptions={{ color: 'blue', fillOpacity: 0 }}
eventHandlers={{
mouseover: (event, type) => onMouseEvent(event, 'over'),
mouseout: (event, type) => onMouseEvent(event, 'out'),
}}
>
<Marker position={getMarkerPosition(state_name)}>
<Popup>
<Typography variant='subtitle2'>
{state_name}
</Typography>
<Divider />
<Typography variant='body2' style={{ margin: 3 }}>
Lat:{' '}
{JSON.stringify(getMarkerPosition(state_name).lat)}
</Typography>
<Typography variant='body2' style={{ margin: 3 }}>
Lng:{' '}
{JSON.stringify(getMarkerPosition(state_name).lng)}
</Typography>
</Popup>
</Marker>
</GeoJSON>
</LayerGroup>
</LayersControl.Overlay>
</>
)
})}
</LayersControl>
</>
)
}
export default Layers
Map.jsx
import React from 'react'
import { MapContainer, ZoomControl } from 'react-leaflet'
import Layers from './Layers'
const Map = () => {
return (
<>
<MapContainer
center={[37.0902, -95.7129]}
zoom={3}
zoomControl={false}
style={{ height: '100vh', width: '100%' }}
>
<Layers />
<ZoomControl position='topright' />
</MapContainer>
</>
)
}
export default Map
Я рекомендую вам прочитать документацию, так как с этим пакетом вы можете сделать множество интересных вещей.
После того, как вы попрактикуетесь в использовании всех хуков и компонентов, которые может предложить общедоступный API React-Leaflet, перейдите в раздел документации Core API. Core API позволяет создавать настраиваемые компоненты Leaflet и расширять сторонние плагины Leaflet для работы с React-Leaflet.