hover and selected states for markers
This commit is contained in:
@@ -34,7 +34,7 @@ export default function GoogleMap({
|
||||
map.panTo(mapCenter);
|
||||
map.setZoom(defaultZoom);
|
||||
}
|
||||
}, [mobile, mobileActive, map]);
|
||||
}, [mobile, mobileActive, defaultZoom, mapCenter, map]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!mobileActive) setMapMarkersFilter("All");
|
||||
@@ -52,7 +52,9 @@ export default function GoogleMap({
|
||||
defaultZoom={defaultZoom}
|
||||
disableDefaultUI={true}
|
||||
minZoom={minZoom}
|
||||
gestureHandling={!mobile || mobileActive ? "greedy" : "none"}
|
||||
gestureHandling={
|
||||
mobile ? (mobileActive ? "greedy" : "none") : "cooperative"
|
||||
}
|
||||
>
|
||||
{markers && (
|
||||
<GoogleMapMarkers data={markers} filter={mapMarkersFilter} />
|
||||
|
||||
@@ -42,6 +42,7 @@ export default function GoogleMapMarkers({
|
||||
}) {
|
||||
const map = useMap();
|
||||
const [markers, setMarkers] = useState<{ [key: string]: Marker }>({});
|
||||
const [selectedMarker, setSelectedMarker] = useState<number | null>(null);
|
||||
const clusterer = useRef<MarkerClusterer | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -64,6 +65,8 @@ export default function GoogleMapMarkers({
|
||||
if (!marker && !markers[key]) return;
|
||||
|
||||
setMarkers((prev) => {
|
||||
if (prev[key] === marker) return prev;
|
||||
|
||||
if (marker) {
|
||||
return { ...prev, [key]: marker };
|
||||
} else {
|
||||
@@ -84,6 +87,8 @@ export default function GoogleMapMarkers({
|
||||
markerKey={index}
|
||||
poi={poi}
|
||||
setMarkerRef={setMarkerRef}
|
||||
isSelected={selectedMarker === index}
|
||||
setSelectedMarker={setSelectedMarker}
|
||||
>
|
||||
{poi.customMarker}
|
||||
</MapMarker>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { AdvancedMarker, useMap } from "@vis.gl/react-google-maps";
|
||||
import type { Marker } from "@googlemaps/markerclusterer";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import IGMapPoi from "../../types/IGMapPoi";
|
||||
|
||||
interface IGMapMarker {
|
||||
@@ -7,6 +8,8 @@ interface IGMapMarker {
|
||||
poi: IGMapPoi;
|
||||
setMarkerRef: (marker: Marker | null, key: string) => void | undefined;
|
||||
children: React.ReactNode;
|
||||
isSelected: boolean;
|
||||
setSelectedMarker: React.Dispatch<React.SetStateAction<number | null>>;
|
||||
}
|
||||
|
||||
export default function MapMarker({
|
||||
@@ -14,30 +17,47 @@ export default function MapMarker({
|
||||
children,
|
||||
markerKey,
|
||||
setMarkerRef,
|
||||
isSelected,
|
||||
setSelectedMarker,
|
||||
}: IGMapMarker) {
|
||||
const map = useMap();
|
||||
const { location, ignoreClusterization, label } = poi;
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const markerRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ignoreClusterization) {
|
||||
setMarkerRef(markerRef.current, markerKey.toString());
|
||||
}
|
||||
}, [ignoreClusterization, markerKey, setMarkerRef]);
|
||||
|
||||
return (
|
||||
<AdvancedMarker
|
||||
key={markerKey}
|
||||
position={location}
|
||||
ref={(marker) => {
|
||||
if (!ignoreClusterization) {
|
||||
setMarkerRef(marker, markerKey.toString());
|
||||
}
|
||||
}}
|
||||
ref={markerRef}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
onClick={() => {
|
||||
map?.panTo(location);
|
||||
map?.panTo({ lat: location.lat, lng: location.lng + 0.001 }); // 0.001 is a small align to fit long labels (generally for mobile devices)
|
||||
map?.setZoom(17);
|
||||
setSelectedMarker(markerKey);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={`relative flex items-center gap-x-2 hover:[&>.label-container]:opacity-100 hover:[&>.label-container]:left-[calc(100%-38px)] hover:[&>.label-container]:pointer-events-auto hover:[&>.label-container]:z-140 hover:[&>.gmap-img-container]:z-150`}
|
||||
className={`relative flex items-center gap-x-2 ${
|
||||
isHovered || isSelected ? "[&>.gmap-img-container]:z-150" : ""
|
||||
}`}
|
||||
>
|
||||
{children}
|
||||
{label && (
|
||||
<div className="label-container text-black absolute text-s left-0 opacity-0 w-max pointer-events-none transition-[left,opacity] bg-white pl-11 pr-3 py-2.5 rounded-2xl">
|
||||
<div
|
||||
className={`label-container text-black absolute text-s left-0 opacity-0 w-max pointer-events-none transition-[left,opacity] bg-white pl-11 pr-3 py-2.5 rounded-2xl ${
|
||||
isHovered || isSelected
|
||||
? "opacity-100 left-[calc(100%-38px)] pointer-events-auto z-140"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{label}
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user