@chayns-components/maps
Version:
A set of beautiful React components for developing your own applications with chayns.
168 lines • 5.37 kB
JavaScript
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Wrapper } from '@googlemaps/react-wrapper';
import { StyledMapWrapper } from './MapWrapper.styles';
import { Polygon } from '@react-google-maps/api';
import Marker from './map/marker/Marker';
import Map from './map/Map';
const MapWrapper = ({
apiToken,
polygonOptions,
initialZoom,
initialPosition,
markers,
onMarkerAdd,
onMarkerRemove,
onMarkerChange
}) => {
const [polygonPath, setPolygonPath] = useState();
const [canPolyDraw, setCanPolyDraw] = useState(false);
const [zoom, setZoom] = useState(initialZoom);
const [center, setCenter] = useState(initialPosition);
const [internalMarkers, setInternalMarkers] = useState();
const [map, setMap] = useState();
useEffect(() => {
if (markers) {
setInternalMarkers(markers);
}
}, [markers]);
const handleClick = useCallback(e => {
const latLng = e.latLng?.toJSON();
if (!latLng) {
return;
}
setInternalMarkers(prevState => {
if (prevState && prevState.length >= 2) {
return prevState;
}
const newMarker = {
position: {
lat: latLng.lat,
lng: latLng.lng
},
id: prevState ? prevState.length : 0
};
if (typeof onMarkerAdd === 'function') {
onMarkerAdd(newMarker);
}
return prevState ? [...prevState, newMarker] : [newMarker];
});
}, [onMarkerAdd]);
useEffect(() => {
if (!internalMarkers) {
return;
}
if (internalMarkers.length !== 2) {
setCanPolyDraw(false);
return;
}
const path = [{
lat: internalMarkers[0]?.position.lat ?? 0,
lng: internalMarkers[0]?.position.lng ?? 0
}, {
lat: internalMarkers[0]?.position.lat ?? 0,
lng: internalMarkers[1]?.position.lng ?? 0
}, {
lat: internalMarkers[1]?.position.lat ?? 0,
lng: internalMarkers[1]?.position.lng ?? 0
}, {
lat: internalMarkers[1]?.position.lat ?? 0,
lng: internalMarkers[0]?.position.lng ?? 0
}];
const maxLat = path.reduce((prev, current) => prev.lat > current.lat ? prev : current);
const minLat = path.reduce((prev, current) => prev.lat < current.lat ? prev : current);
const maxLng = path.reduce((prev, current) => prev.lng > current.lng ? prev : current);
const minLng = path.reduce((prev, current) => prev.lng < current.lng ? prev : current);
const topLeft = path.find(item => item.lat === maxLat.lat && item.lng === minLng.lng);
const bottomRight = path.find(item => item.lat === minLat.lat && item.lng === maxLng.lng);
if (!topLeft || !bottomRight) {
return;
}
const centerLat = (topLeft.lat + bottomRight.lat) / 2;
const centerLng = (topLeft.lng + bottomRight.lng) / 2;
const polygonCenter = {
lat: centerLat,
lng: centerLng
};
if (!polygonCenter) {
return;
}
setCanPolyDraw(true);
setPolygonPath(path);
}, [internalMarkers]);
const handleIdle = m => {
setMap(m);
setZoom(m.getZoom() ?? 0);
setCenter(m.getCenter()?.toJSON() ?? {
lat: 0,
lng: 0
});
};
const handlePositionChange = position => {
setCenter(position);
};
const handleMarkerChange = useCallback(marker => {
setInternalMarkers(prevState => {
const updatedMarkers = (prevState ?? []).map(prevMarker => {
if (prevMarker.id === marker.id) {
return {
...prevMarker,
position: marker.position
};
}
return prevMarker;
});
if (typeof onMarkerChange === 'function') {
onMarkerChange(updatedMarkers);
}
return updatedMarkers;
});
}, [onMarkerChange]);
const handleMarkerRemove = useCallback(id => {
setInternalMarkers(prevState => {
if (typeof onMarkerRemove === 'function') {
onMarkerRemove(id);
}
return prevState ? prevState.filter(marker => marker.id !== id) : [];
});
}, [onMarkerRemove]);
const markerList = useMemo(() => {
const items = [];
if (!internalMarkers) {
return items;
}
internalMarkers.forEach(({
id,
position
}) => {
items.push(/*#__PURE__*/React.createElement(Marker, {
key: `marker_${id}`,
id: id,
position: position,
isDraggable: true,
map: map,
onChange: handleMarkerChange,
onRemove: handleMarkerRemove
}));
});
return items;
}, [handleMarkerChange, handleMarkerRemove, internalMarkers, map]);
return useMemo(() => /*#__PURE__*/React.createElement(StyledMapWrapper, null, /*#__PURE__*/React.createElement(Wrapper, {
apiKey: apiToken,
libraries: ['places']
}, /*#__PURE__*/React.createElement(Map, {
onClick: handleClick,
onIdle: handleIdle,
onPositionChange: handlePositionChange,
center: center,
zoom: zoom,
fullscreenControl: false,
mapTypeControl: false,
streetViewControl: false
}, /*#__PURE__*/React.createElement(React.Fragment, null, markerList, canPolyDraw && /*#__PURE__*/React.createElement(Polygon, {
path: polygonPath,
options: polygonOptions
}))))), [apiToken, handleClick, center, zoom, markerList, canPolyDraw, polygonPath, polygonOptions]);
};
MapWrapper.displayName = 'MapWrapper';
export default MapWrapper;
//# sourceMappingURL=MapWrapper.js.map