Added marker clustering when zoomed out

This commit is contained in:
PxlLoewe
2025-04-25 12:02:59 -07:00
parent 2eb2f4bf2b
commit ef93275d9c
7 changed files with 300 additions and 32 deletions

View File

@@ -1,8 +1,13 @@
import { cn } from "helpers/cn";
import { RefAttributes, useEffect, useImperativeHandle } from "react";
import {
RefAttributes,
useCallback,
useEffect,
useImperativeHandle,
} from "react";
import { createContext, Ref, useContext, useState } from "react";
import { Popup, PopupProps, useMap } from "react-leaflet";
import { Popup as LPopup, popup } from "leaflet";
import { Popup as LPopup } from "leaflet";
const PopupContext = createContext({
anchor: "topleft",
@@ -16,7 +21,11 @@ export const useSmartPopup = () => {
return context;
};
export const calculateAnchor = (id: string, mode: "popup" | "marker") => {
export const calculateAnchor = (
id: string,
mode: "popup" | "marker",
ignoreMarker?: boolean,
) => {
const otherMarkers = document.querySelectorAll(".map-collision");
// get markers and check if they are overlapping
const ownMarker =
@@ -28,6 +37,7 @@ export const calculateAnchor = (id: string, mode: "popup" | "marker") => {
const marksersInCluster = Array.from(otherMarkers).filter((marker) => {
if (mode === "popup" && marker.id === `marker-${id}`) return false;
if (ignoreMarker && marker.id.startsWith("marker")) return false;
const rect1 = (marker as HTMLElement).getBoundingClientRect();
const rect2 = (ownMarker as HTMLElement).getBoundingClientRect();
@@ -90,24 +100,24 @@ export interface SmartPopupRef {
}
export const SmartPopup = (
props: PopupProps &
RefAttributes<LPopup> & {
props: PopupProps & { ignoreMarker?: boolean } & RefAttributes<LPopup> & {
smartPopupRef?: Ref<SmartPopupRef>;
id: string;
wrapperClassName?: string;
},
) => {
const [showContent, setShowContent] = useState(false);
const { smartPopupRef, id, className, wrapperClassName } = props;
const { smartPopupRef, id, className, wrapperClassName, ignoreMarker } =
props;
const [anchor, setAnchor] = useState<
"topleft" | "topright" | "bottomleft" | "bottomright"
>("topleft");
const handleConflict = () => {
const newAnchor = calculateAnchor(id, "popup");
const handleConflict = useCallback(() => {
const newAnchor = calculateAnchor(id, "popup", ignoreMarker);
setAnchor(newAnchor);
};
}, [id, ignoreMarker]);
useImperativeHandle(smartPopupRef, () => ({
handleConflict,
@@ -125,7 +135,7 @@ export const SmartPopup = (
return () => {
map.off("zoom", handleConflict);
};
}, [map, anchor]);
}, [map, handleConflict]);
return (
<Popup {...props} className={cn("relative", wrapperClassName)}>