You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.3 KiB
124 lines
3.3 KiB
import maplibregl from "maplibre-gl";
|
|
import Map, { MapProvider } from "react-map-gl";
|
|
import { useEffect, useRef } from "react";
|
|
import { Sidebar } from "../modules/Sidebar/Sidebar";
|
|
import { Layers } from "./Layers";
|
|
import { MapPopup } from "./Popup";
|
|
import { Basemap } from "./Basemap";
|
|
import { SignOut } from "../SignOut";
|
|
import debounce from "lodash.debounce";
|
|
import { Table } from "../modules/Table/Table";
|
|
import { usePopup } from "../stores/usePopup";
|
|
import { useClickedPointConfig } from "../stores/useClickedPointConfig";
|
|
import { Legend } from "../modules/Sidebar/Legend";
|
|
import { AddressSearch } from "../modules/Sidebar/AddressSearch";
|
|
|
|
export const MapComponent = () => {
|
|
const mapRef = useRef(null);
|
|
const mapContainerRef = useRef(null);
|
|
const { popup, setPopup } = usePopup();
|
|
const { setClickedPointConfig } = useClickedPointConfig();
|
|
|
|
const handleClick = (event) => {
|
|
if (!event.features) {
|
|
setPopup(null);
|
|
setClickedPointConfig(null);
|
|
return;
|
|
}
|
|
|
|
const feature = event.features[0];
|
|
if (!feature) {
|
|
setPopup(null);
|
|
setClickedPointConfig(null);
|
|
return;
|
|
}
|
|
|
|
const { lng: pointLng } = event.lngLat;
|
|
|
|
if (feature.geometry.type === "Point") {
|
|
const coordinates = feature.geometry.coordinates.slice();
|
|
while (Math.abs(pointLng - coordinates[0]) > 180) {
|
|
coordinates[0] += pointLng > coordinates[0] ? 360 : -360;
|
|
}
|
|
|
|
setPopup({ features: event.features, coordinates });
|
|
}
|
|
};
|
|
|
|
const handleMouseEnter = (event) => {
|
|
const feature = event.features[0];
|
|
if (!feature) return;
|
|
|
|
mapRef.current.getCanvas().style.cursor = "pointer";
|
|
};
|
|
|
|
const handleMouseLeave = (event) => {
|
|
const feature = event.features[0];
|
|
if (!feature) {
|
|
return;
|
|
}
|
|
mapRef.current.getCanvas().style.cursor = "";
|
|
};
|
|
|
|
useEffect(() => {
|
|
const resizeObserver = new ResizeObserver(
|
|
debounce(() => {
|
|
mapRef?.current?.resize();
|
|
}, 16)
|
|
);
|
|
if (mapContainerRef.current) {
|
|
resizeObserver.observe(mapContainerRef.current);
|
|
}
|
|
|
|
return () => {
|
|
resizeObserver.disconnect();
|
|
};
|
|
}, [mapContainerRef.current]);
|
|
|
|
return (
|
|
<MapProvider>
|
|
<div ref={mapContainerRef} className="w-full flex-1">
|
|
<Map
|
|
mapLib={maplibregl}
|
|
// mapStyle={`https://api.maptiler.com/maps/voyager/style.json?key=${MAP_TILER_KEY}`}
|
|
// style={{ width: "100%", height: "100%" }}
|
|
initialViewState={{
|
|
latitude: 55.7558,
|
|
longitude: 37.6173,
|
|
zoom: 9,
|
|
}}
|
|
dragRotate={false}
|
|
ref={mapRef}
|
|
interactiveLayerIds={["match-points", "unmatch-points"]}
|
|
onClick={handleClick}
|
|
onMouseEnter={handleMouseEnter}
|
|
onMouseLeave={handleMouseLeave}
|
|
id="map"
|
|
>
|
|
{popup && (
|
|
<MapPopup
|
|
lat={popup.coordinates[1]}
|
|
lng={popup.coordinates[0]}
|
|
features={popup.features}
|
|
onClose={() => {
|
|
setPopup(null);
|
|
setClickedPointConfig(null);
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
<Basemap />
|
|
<Layers />
|
|
|
|
<Sidebar />
|
|
<AddressSearch />
|
|
|
|
<Legend />
|
|
<SignOut />
|
|
</Map>
|
|
</div>
|
|
<Table />
|
|
</MapProvider>
|
|
);
|
|
};
|