100 lines
2.6 KiB
TypeScript
100 lines
2.6 KiB
TypeScript
import { useMap } from "@vis.gl/react-google-maps";
|
|
import { useEffect, useRef, useState } from "react";
|
|
import IGMapPoi from "../../types/IGMapPoi";
|
|
import MapMarker from "./MapMarker";
|
|
import {
|
|
MarkerClusterer,
|
|
DefaultRenderer,
|
|
Cluster,
|
|
Marker,
|
|
} from "@googlemaps/markerclusterer";
|
|
|
|
class CustomMarkerRenderer extends DefaultRenderer {
|
|
render({
|
|
count,
|
|
position,
|
|
}: Cluster): google.maps.marker.AdvancedMarkerElement {
|
|
const svgElement = document.createElement("div");
|
|
svgElement.innerHTML = `
|
|
<svg fill="white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240" width="50" height="50">
|
|
<circle cx="120" cy="120" opacity="1" r="70" />
|
|
</svg>
|
|
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: black; font-size: 12px; font-weight: bold;">
|
|
${count}
|
|
</div>`;
|
|
|
|
const marker = new google.maps.marker.AdvancedMarkerElement({
|
|
position,
|
|
content: svgElement,
|
|
zIndex: Math.max(1000, count),
|
|
});
|
|
|
|
return marker;
|
|
}
|
|
}
|
|
|
|
export default function GoogleMapMarkers({
|
|
data,
|
|
filter,
|
|
}: {
|
|
data: IGMapPoi[];
|
|
filter: string;
|
|
}) {
|
|
const map = useMap();
|
|
const [markers, setMarkers] = useState<{ [key: string]: Marker }>({});
|
|
const [selectedMarker, setSelectedMarker] = useState<number | null>(null);
|
|
const clusterer = useRef<MarkerClusterer | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (!map) return;
|
|
if (!clusterer.current) {
|
|
clusterer.current = new MarkerClusterer({
|
|
map: map,
|
|
renderer: new CustomMarkerRenderer(),
|
|
});
|
|
}
|
|
}, [map]);
|
|
|
|
useEffect(() => {
|
|
clusterer.current?.clearMarkers();
|
|
clusterer.current?.addMarkers(Object.values(markers));
|
|
}, [markers]);
|
|
|
|
const setMarkerRef = (marker: Marker | null, key: string) => {
|
|
if (marker && markers[key]) return;
|
|
if (!marker && !markers[key]) return;
|
|
|
|
setMarkers((prev) => {
|
|
if (prev[key] === marker) return prev;
|
|
|
|
if (marker) {
|
|
return { ...prev, [key]: marker };
|
|
} else {
|
|
const newMarkers = { ...prev };
|
|
delete newMarkers[key];
|
|
return newMarkers;
|
|
}
|
|
});
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{data.map(
|
|
(poi: IGMapPoi, index: number) =>
|
|
(filter === poi.type || filter === "All") && (
|
|
<MapMarker
|
|
key={index}
|
|
markerKey={index}
|
|
poi={poi}
|
|
setMarkerRef={setMarkerRef}
|
|
isSelected={selectedMarker === index}
|
|
setSelectedMarker={setSelectedMarker}
|
|
>
|
|
{poi.customMarker}
|
|
</MapMarker>
|
|
)
|
|
)}
|
|
</>
|
|
);
|
|
}
|