👋
Welcome to offline-map-react
Project make with ReactJS and Leaflet to show specified points and heat points in the map, without active internet connexion.
✨ Demo
Used Libs
- Leaflet JS v1.8.0
- React Leaflet v4.0.0
- Leaflet.LocateControl v0.76.1
- Leaflet.Offline v2
- Leaflet.WebglTemperatureMap v0.2.0
- Leaflet.Heat
Install
npm i offline-map-react
Add following Leaflet CDN in your index.html
<head>
...
<!-- LEAFLET -->
<link href='https://cdn.jsdelivr.net/npm/leaflet.locatecontrol/dist/L.Control.Locate.min.css' rel='stylesheet'/>
<script
charset='utf-8'
src='https://cdn.jsdelivr.net/npm/leaflet.locatecontrol/dist/L.Control.Locate.min.js'
></script>
<link
crossorigin=''
href='https://unpkg.com/leaflet@1.8.0/dist/leaflet.css'
integrity='sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=='
rel='stylesheet'
/>
<script
crossorigin=''
integrity='sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ=='
src='https://unpkg.com/leaflet@1.8.0/dist/leaflet.js'
></script>
...
</head>
Usage
import React, {useEffect, useState} from 'react';
import './App.css';
import {OfflineMap} from 'offline-map-react'
import {ICheckpoint} from "offline-map-react/dist/cjs/types/src/lib/LeafletMap/index.types";
function App() {
const [checkpoints, setCheckpoints] = useState<ICheckpoint[]>([])
const OfflineMapInstance = OfflineMap({
checkpoints,
})
useEffect(() => {
window.navigator.geolocation.getCurrentPosition(position => {
// checkpoints will be renderer in map
setCheckpoints([{
position: {lat: 40.750749, lng: -74.077218},
id: Math.random(),
text: 'Ponto de Controle 1',
alreadyCollected: false, // default false
}])
})
}, [])
useEffect(() => {
// create heat points if map instance exists
// [lat, lng, intensity]
OfflineMapInstance.setHeatPoints([40.750749, -74.077218, 0.5])
// set map view on user location
OfflineMapInstance.setMapViewOnUserLocation()
}, [OfflineMapInstance.map])
return (
<div className="App">
{/* saved tiles number */}
{OfflineMapInstance.progressSaveMap}
{/* number of total tiles to save */}
{OfflineMapInstance.totalLayersToSave}
{/* call te function to render the map */}
{OfflineMapInstance.renderMap(
// can be pass any children if is a valid React Leaflet child
)}
{/* custom buttons to save and delete map from cache */}
<button onClick={
() => mapInstance?.offlineMapControls().saveCurrentMapView()
}>
Salvar Mapa
</button>
<button onClick={
() => mapInstance?.offlineMapControls().deleteCurrentMapView()
}>
Excluir Mapa
</button>
{/* custom button to toggle user location */}
<button onClick={
() => mapInstance?.offlineMapControls().toggleUserLocation()
}>
Alternar Localização
</button>
{/* progress bar when save map */}
{
mapInstance?.progressSaveMap > 0 && (
<progress id="file"
value={Number((mapInstance?.progressSaveMap / mapInstance?.totalLayersToSave) * 100).toFixed(2)}
max="100">
{Number((mapInstance?.progressSaveMap / mapInstance?.totalLayersToSave) * 100).toFixed(2)}%
</progress>
)
}
{/* show gps accuracy */}
<div>
GPS Accuracy: {mapInstance?.accuracy} meters
</div>
{/* show tutorial do calibrate gps */}
<div>
{mapInstance?.calibrateGpsTutorial()}
</div>
{/* reset heatlayer render */}
<div>
{mapInstance?.resetHeatLayerRender()}
</div>
</div>
);
}
export default App;
Style
- Without "height" and "width" property the map will be not render
#map {
height: 400px;
width: 800px;
}
NextJS Support
-
1º Create "Map" component
Map.tsx
import {OfflineMap} from "offline-map-react"; function Map() { const mapInstance = OfflineMap({ checkpoints: [], // pass your checkpoints }) return (mapInstance.renderMap({/* Optional: Pass valid React Leaflet children */})) } export default Map
-
2º Create "DynamicMap" component
DynamicMap.tsx
import dynamic from 'next/dynamic' function DynamicMap() { const DynamicComponentWithNoSSR = dynamic( () => import('./Map'), {ssr: false} ) return ( <DynamicComponentWithNoSSR /> ) } export default DynamicMap
-
3º Use the DynamicMap component in your screen component
Home.tsx
import type {NextPage} from 'next' import Head from 'next/head' import styles from '../styles/Home.module.css' import DynamicMap from "./DynamicMap"; const Home: NextPage = () => { return ( <div className={styles.container}> <Head>{/* your header and Leaflet CDN's */}</Head> <main className={styles.main}> <DynamicMap /> </main> <footer className={styles.footer}> footer </footer> </div> ) } export default Home
Author
- Twitter: @fernandesdotts
- Github: @fernandes-dev
- LinkedIn: @fernandes-dev
🤝 Contributing
Contributions, issues and feature requests are welcome!
Feel free to
check issues page.
Show your support
Give a
This README was generated with