AB
Size: a a a
AB
MD
AB
MD
AB
import React, { useEffect, useRef, useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSearchPlus, faSearchMinus } from '@fortawesome/free-solid-svg-icons';
import nanoid from 'nanoid';
import { useScript } from './use-script';
export const Mapbox = ({
mapboxAPIToken,
defaultCenter,
defaultZoom,
onMapZoomChange,
onMapPositionChange,
viewport,
}) => {
const [map, setMap] = useState(null);
const [key, setKey] = useState(nanoid());
const [ready, setReady] = useState(false);
const [zoom, setZoom] = useState(defaultZoom);
const [center, setCenter] = useState(defaultCenter);
const [loaded, error] = useScript(
'https://api.mapbox.com/mapbox-gl-js/v1.4.1/mapbox-gl.js',
);
const mapContainer = useRef(null);
const handleZoomIn = () => map.zoomIn();
const handleZoomOut = () => map.zoomOut();
const handlePositionChange = ({ target }) => {
const changedCenter = {
...center,
[target.name]: parseFloat(target.value),
};
setCenter(changedCenter);
};
const handlePositionSubmit = event => {
event.preventDefault();
map.setCenter(center);
};
useEffect(() => {
if (loaded && !error && !map) {
const instance = new window.mapboxgl.Map({
accessToken: mapboxAPIToken,
style: 'mapbox://styles/mapbox/streets-v11',
container: mapContainer.current,
center: [center.lon, center.lat],
zoom,
});
setMap(instance);
}
}, [loaded, error, map, center, zoom, mapboxAPIToken]);
useEffect(() => {
if (map) {
function handle() {
setReady(true);
}
map.on('load', handle);
return () => map.off('load');
}
}, [map]);
useEffect(() => {
setReady(false);
setMap(null); // reset map instance
setKey(nanoid()); // reset key = force map rerender
}, [mapboxAPIToken, viewport]);
useEffect(() => {
if (map) {
function handle() {
setZoom(map.getZoom());
if (onMapZoomChange) {
onMapZoomChange(map.getZoom());
}
}
map.on('zoomend', handle);
return () => map.off('zoomend', handle);
}
}, [map, onMapZoomChange]);
useEffect(() => {
if (map) {
function handle() {
const normalizedCenter = {
lon: map.getCenter().lng,
lat: map.getCenter().lat,
};
setCenter(normalizedCenter);
if (onMapPositionChange) {
onMapPositionChange({ center: normalizedCenter });
}
}
map.on('moveend', handle);
return () => map.off('moveend', handle);
}
}, [map, onMapPositionChange]);
useEffect(() => {
if (map) {
map.setCenter(defaultCenter);
setCenter(defaultCenter);
}
}, [map, defaultCenter]);
useEffect(() => {
if (map) {
map.setZoom(defaultZoom);
setZoom(defaultZoom);
}
}, [map, defaultZoom]);
return (
<>
<div
className="Mapbox"
style={{
width: `${viewport.width}px`,
height: `${viewport.height}px`,
}}>
{loaded && <div ref={mapContainer} key={key} />}
{!ready && <div className="Mapbox-loader" />}
<div className="Mapbox-zoom">
<button type="button" onClick={handleZoomIn}>
<FontAwesomeIcon icon={faSearchPlus} size="lg" />
</button>
<button type="button" onClick={handleZoomOut}>
<FontAwesomeIcon icon={faSearchMinus} size="lg" />
</button>
</div>
<form onSubmit={handlePositionSubmit} className="Mapbox-position">
<label htmlFor="lat">
<span>Latitude:</span>
<input
type="number"
id="lat"
name="lat"
value={center.lat}
onChange={handlePositionChange}
/>
</label>AB
<label htmlFor="lon">
<span>Longtitude:</span>
<input
type="number"
id="lon"
name="lon"
value={center.lon}
onChange={handlePositionChange}
/>
</label>
<button type="submit">Submit</button>
</form>
</div>
</>
);
};
AB
AB
MD
DD
AB
DD
AB
AB
DD
DD
AB
DD
AB
AB